Skip to content
Snippets Groups Projects
Verified Commit b777f752 authored by Louis's avatar Louis :fire:
Browse files

Use precedence expression instead of value expression in wrappers

parent 128a9930
No related branches found
No related tags found
No related merge requests found
Pipeline #502 failed with stages
in 33 seconds
......@@ -10,7 +10,7 @@ peg::parser! {
= ex:expression_list() eof() { Program(ex) }
pub rule expression() -> Expression
= ex:value_expression() { Expression::Value(ex) }
= ex:precedence_expression() { Expression::Value(ex) }
/ ex:void_expression() { Expression::Void(ex) }
rule void_expression() -> VoidExpression
......@@ -21,14 +21,16 @@ peg::parser! {
#[cache_left_rec]
rule value_expression() -> ValueExpression
= co:conditional_statement() { ValueExpression::ConditionalBlock(co) }
=
co:conditional_statement() { ValueExpression::ConditionalBlock(co) }
/ t:type_of() { ValueExpression::Typeof(t) }
/ precedence_expression()
/ decl:declare_variable() { ValueExpression::DeclareIdentifier(decl) }
/ decl:declare_function() { ValueExpression::DeclareFunction(decl) }
/ name:simple_identifier() "(" params:param_list()? ")"
{ ValueExpression::FunctionCall(FunctionCall { name, params: params.unwrap_or_default() }) }
/ left:value_expression() op:binary_operator() right:value_expression()
{ ValueExpression::Binary { lhs: Box::new(left), rhs: Box::new(right), operator: op } }
// / left:value_expression() op:binary_operator() right:value_expression()
// { ValueExpression::Binary { lhs: Box::new(left), rhs: Box::new(right), operator: op } }
/ op:unary_operator() operand:value_expression()
{ ValueExpression::Unary { operator: op, operand: Box::new(operand) } }
/ grouped()
......@@ -82,15 +84,37 @@ peg::parser! {
rule expression_list() -> ExpressionList
= ex:(expression() ** ";") term:";"? { ExpressionList { expressions: ex, is_void: term.is_some() } }
rule binary_operator() -> BinaryOp
= "+" { BinaryOp::Add }
/ "-" { BinaryOp::Subtract }
/ "*" { BinaryOp::Multiply }
/ "/" { BinaryOp::Divide }
/ "%" { BinaryOp::Modulo }
/ "==" { BinaryOp::Equals }
/ "&&" { BinaryOp::BoolAnd }
/ "||" { BinaryOp::BoolOr }
#[cache_left_rec]
rule precedence_expression() -> ValueExpression
= precedence! {
"-" z:(@) { ValueExpression::Unary { operator: UnaryOp::Negate, operand: Box::new(z) } }
--
x:(@) "+" y:@ { ValueExpression::Binary { operator: BinaryOp::Add, lhs: Box::new(x), rhs: Box::new(y) } }
x:(@) "-" y:@ { ValueExpression::Binary { operator: BinaryOp::Subtract, lhs: Box::new(x), rhs: Box::new(y) } }
--
x:(@) "*" y:@ { ValueExpression::Binary { operator: BinaryOp::Multiply, lhs: Box::new(x), rhs: Box::new(y) } }
x:(@) "/" y:@ { ValueExpression::Binary { operator: BinaryOp::Divide, lhs: Box::new(x), rhs: Box::new(y) } }
x:(@) "%" y:@ { ValueExpression::Binary { operator: BinaryOp::Modulo, lhs: Box::new(x), rhs: Box::new(y) } }
--
x:(@) "==" y:@ { ValueExpression::Binary { operator: BinaryOp::Equals, lhs: Box::new(x), rhs: Box::new(y) } }
x:(@) "&&" y:@ { ValueExpression::Binary { operator: BinaryOp::BoolAnd, lhs: Box::new(x), rhs: Box::new(y) } }
x:(@) "||" y:@ { ValueExpression::Binary { operator: BinaryOp::BoolOr, lhs: Box::new(x), rhs: Box::new(y) } }
--
"!" z:(@) { ValueExpression::Unary { operator: UnaryOp::Not, operand: Box::new(z) } }
--
"(" ex:precedence_expression() ")" { ValueExpression::Grouped(GroupedExpression { inner: Box::new(ex) }) }
val:value_expression() { val }
}
// rule binary_operator() -> BinaryOp
// = "+" { BinaryOp::Add }
// / "-" { BinaryOp::Subtract }
// / "*" { BinaryOp::Multiply }
// / "/" { BinaryOp::Divide }
// / "%" { BinaryOp::Modulo }
// / "==" { BinaryOp::Equals }
// / "&&" { BinaryOp::BoolAnd }
// / "||" { BinaryOp::BoolOr }
rule unary_operator() -> UnaryOp
= "!" { UnaryOp::Not }
......
use crate::format_forge_error;
use crate::parse::ast::{BinaryOp, Program, UnaryOp, ValueExpression, VoidExpression};
use crate::parser::ast::GroupedExpression;
use crate::parser::parse_program;
use crate::runtime::executor::Visitor;
use crate::runtime::value::ForgeValue;
use crate::runtime::vm::{Chunk, ChunkRef, OpCode, VmError};
pub struct ChunkBuilder {
current_chunk: Chunk,
}
impl ChunkBuilder {
pub fn new() -> Self {
Self {
current_chunk: Chunk::default(),
}
}
pub fn parse(code: &str) -> Result<Chunk, VmError> {
let mut builder = ChunkBuilder::new();
let program =
parse_program(code).map_err(|fe| VmError::ast_parser(format_forge_error(code, &fe)))?;
builder.evaluate_program(&program)?;
Ok(builder.take_chunk())
}
pub fn chunk_ref(&self) -> ChunkRef {
self.current_chunk.as_ref()
}
pub fn take_chunk(&mut self) -> Chunk {
std::mem::take(&mut self.current_chunk)
}
}
impl Visitor for ChunkBuilder {
type Output = ();
type Error = VmError;
fn evaluate_value_expression(
&mut self,
expression: &ValueExpression,
) -> Result<Self::Output, Self::Error> {
match expression {
ValueExpression::Unary { operator, operand } => {
self.evaluate_value_expression(operand.as_ref())?;
match operator {
UnaryOp::Not => Err(VmError::chunk_parser("Unsupported expression")),
UnaryOp::Negate => {
self.current_chunk.push_op(OpCode::Invert);
Ok(())
}
}
}
ValueExpression::Binary { lhs, rhs, operator } => {
self.evaluate_value_expression(lhs.as_ref())?;
self.evaluate_value_expression(rhs.as_ref())?;
match operator {
BinaryOp::Add => {
self.current_chunk.push_op(OpCode::Add);
Ok(())
}
BinaryOp::Subtract => {
self.current_chunk.push_op(OpCode::Subtract);
Ok(())
}
BinaryOp::Multiply => {
self.current_chunk.push_op(OpCode::Multiply);
Ok(())
}
BinaryOp::Divide => {
self.current_chunk.push_op(OpCode::Divide);
Ok(())
}
BinaryOp::Modulo => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::Equals => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::BoolAnd => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::BoolOr => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::NotEquals => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::LessThan => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::GreaterThan => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::LessThanEqual => Err(VmError::chunk_parser("Unsupported expression")),
BinaryOp::GreaterThanEqual => {
Err(VmError::chunk_parser("Unsupported expression"))
}
}
}
ValueExpression::Grouped(GroupedExpression { inner }) => {
self.evaluate_value_expression(inner.as_ref())
}
ValueExpression::Block(_) => Err(VmError::chunk_parser("Unsupported expression")),
ValueExpression::Literal(val) => {
self.current_chunk
.op_constant(ForgeValue::from(val.clone()));
Ok(())
}
ValueExpression::DeclareIdentifier(_) => {
Err(VmError::chunk_parser("Unsupported expression"))
}
ValueExpression::Assignment(_) => Err(VmError::chunk_parser("Unsupported expression")),
ValueExpression::ConditionalBlock(_) => {
Err(VmError::chunk_parser("Unsupported expression"))
}
ValueExpression::Identifier(_) => Err(VmError::chunk_parser("Unsupported expression")),
ValueExpression::FunctionCall(_) => {
Err(VmError::chunk_parser("Unsupported expression"))
}
ValueExpression::DeclareFunction(_) => {
Err(VmError::chunk_parser("Unsupported expression"))
}
ValueExpression::Typeof(_) => Err(VmError::chunk_parser("Unsupported expression")),
}
}
fn evaluate_void_expression(
&mut self,
expression: &VoidExpression,
) -> Result<Self::Output, Self::Error> {
match expression {
VoidExpression::ConditionLoop(_) => {
Err(VmError::chunk_parser("Unsupported expression"))
}
VoidExpression::Import(_) => Err(VmError::chunk_parser("Unsupported expression")),
VoidExpression::Export(_) => Err(VmError::chunk_parser("Unsupported expression")),
VoidExpression::Print(_) => Err(VmError::chunk_parser("Unsupported expression")),
}
}
fn evaluate_program(&mut self, program: &Program) -> Result<Self::Output, Self::Error> {
for expr in program.0.iter() {
self.evaluate_expression(expr)?;
}
self.current_chunk.push_op(OpCode::Return);
Ok(())
}
}
use crate::parser::ast::BinaryOp;
use crate::parser::parse_program;
use crate::runtime::value::{ForgeValue, UnsupportedOperation};
use crate::runtime::vm::chunk_builder::ChunkBuilder;
use crate::runtime::vm::chunks::Chunk;
use crate::runtime::vm::{ChunkOps, OpCode};
use crate::{format_forge_error, ForgeErrorKind};
use std::collections::VecDeque;
use std::error::Error;
use std::fmt::{Display, Formatter};
const INITIAL_STACK: usize = 512;
......@@ -29,10 +33,25 @@ pub enum RuntimeErrorKind {
UnsupportedOperation(BinaryOp),
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum CompilerErrorKind {
AstParser(String),
Chunkbuilder(String),
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum VmError {
RuntimeError(RuntimeErrorKind),
CompilerError,
CompilerError(CompilerErrorKind),
}
impl VmError {
pub fn ast_parser(reason: impl ToString) -> VmError {
VmError::CompilerError(CompilerErrorKind::AstParser(reason.to_string()))
}
pub fn chunk_parser(reason: impl ToString) -> VmError {
VmError::CompilerError(CompilerErrorKind::Chunkbuilder(reason.to_string()))
}
}
impl From<UnsupportedOperation> for VmError {
......@@ -44,12 +63,40 @@ impl From<UnsupportedOperation> for VmError {
impl Display for VmError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::RuntimeError(kind) => write!(f, "{:?}", kind),
Self::CompilerError => write!(f, "Compiler Error"),
Self::RuntimeError(kind) => write!(f, "[Runtime Error] {}", kind),
Self::CompilerError(kind) => write!(f, "[Compiler Error] {}", kind),
}
}
}
impl Display for RuntimeErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
RuntimeErrorKind::MissingEof => write!(f, "Unexpected end of file"),
RuntimeErrorKind::InvalidConstData => {
write!(f, "Tried to access invalid constant data")
}
RuntimeErrorKind::InvalidStackData => write!(f, "Tried to access invalid stack data"),
RuntimeErrorKind::UnsupportedOperation(op) => write!(f, "Unsupported op: {:?}", op),
}
}
}
impl Display for CompilerErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
CompilerErrorKind::AstParser(err) => err.as_str(),
CompilerErrorKind::Chunkbuilder(err) => err.as_str(),
}
)
}
}
impl Error for VmError {}
pub type VmResult = Result<ForgeValue, VmError>;
impl Forge {
......@@ -105,6 +152,16 @@ impl Forge {
Ok((second, first))
}
pub fn compile(value: impl ToString) -> Result<Chunk, VmError> {
let value = value.to_string();
ChunkBuilder::parse(value.as_str())
}
pub fn compile_and_run(value: impl ToString) -> VmResult {
let chunk = Forge::compile(value)?;
Forge::exec(chunk)
}
/// Execute a chunk of code in a new VM instance
pub fn exec(chunk: impl ChunkOps) -> VmResult {
let mut vm = Forge::from_chunk(chunk.as_chunk());
......@@ -128,7 +185,6 @@ impl Forge {
OpCode::Return => return Ok(self.peek_stack().cloned().unwrap_or_default()),
OpCode::Constant(idx) => {
if let Some(value) = self.get_const(idx) {
println!("Load Const {:?}", &value);
self.push_stack(value.clone());
} else {
return Err(VmError::RuntimeError(RuntimeErrorKind::InvalidConstData));
......
mod chunk_builder;
mod chunks;
mod const_data;
mod machine;
......
......@@ -64,8 +64,14 @@ impl Repl {
println!("=============\n");
}
other => {
println!("{}", other);
self.buffer.push(String::from(other));
println!(
"{}",
match Forge::compile_and_run(other) {
Ok(val) => format!("{}", val),
Err(e) => format!("{}", e),
}
);
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment