use crate::parser::TokenSlice; peg::parser! { grammar forge_parser<'a>() for TokenSlice<'a> { use crate::parser::ast::*; use crate::runtime::numbers::Number; use crate::lexer::{ScriptToken, ScriptTokenType}; pub rule program() -> Program = ex:expression_list() eof() { Program(ex) } pub rule expression() -> Expression = ex:value_expression() { Expression::Value(ex) } / ex:void_expression() { Expression::Void(ex) } rule void_expression() -> VoidExpression = ex:print() { VoidExpression::Print(ex) } / "import" "{" items:identifier_list() "}" "from" source:string_value() { VoidExpression::Import(Import { source, items }) } / "export" "{" items:identifier_list() "}" { VoidExpression::Export(Export { items }) } / e:condition_loop() { VoidExpression::ConditionLoop(e) } #[cache_left_rec] rule value_expression() -> ValueExpression = co:conditional_statement() { ValueExpression::ConditionalBlock(co) } / t:type_of() { ValueExpression::Typeof(t) } // / binary_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() }) } / op:unary_operator() operand:value_expression() { ValueExpression::Unary { operator: op, operand: Box::new(operand) } } / left:value_expression() op:binary_operator() right:value_expression() { ValueExpression::Binary { lhs: Box::new(left), rhs: Box::new(right), operator: op } } / grouped() / ident:simple_identifier() !"(" { ValueExpression::Identifier(ident) } / li:literal() { ValueExpression::Literal(li) } rule grouped() -> ValueExpression = "(" ex:value_expression() ")" { ValueExpression::Grouped(GroupedExpression { inner: Box::new(ex) }) } rule print() -> Print = "print" ex:value_expression() { ex.into() } rule type_of() -> TypeofValue = "typeof" ex:value_expression() { TypeofValue(Box::new(ex)) } rule declare_function() -> DeclareFunction = "fn" ident:simple_identifier() "(" params:(function_param() ** ",") ")" body:block() { DeclareFunction { ident, params, body } } rule function_param() -> DeclareIdent = assign:assignment() { DeclareIdent::WithValue(assign) } / ident:simple_identifier() { DeclareIdent::WithoutValue(ident) } rule assignment() -> Assignment = ident:simple_identifier() "=" ex:value_expression() { Assignment { ident, value: Box::new(ex) } } rule declare_variable() -> DeclareIdent = "let" assign:assignment() { DeclareIdent::WithValue(assign) } / "let" ident:simple_identifier() { DeclareIdent::WithoutValue(ident) } rule condition_loop() -> ConditionalLoop = "while" guard:value_expression() block:block() { ConditionalLoop { block: GuardedBlock { guard: Box::new(guard), block }, fallback: None } } / "while" guard:value_expression() block:block() "finally" fallback:block() { ConditionalLoop { block: GuardedBlock { guard: Box::new(guard), block }, fallback: Some(fallback) } } rule conditional_statement() -> Conditional = blocks:(conditional_block() ++ "else") "else" fallback:block() { Conditional { blocks, fallback: Some(fallback) } } / blocks:(conditional_block() ++ "else") { Conditional { blocks, fallback: None } } rule conditional_block() -> GuardedBlock = "if" guard:value_expression() "{" block:expression_list()? "}" { GuardedBlock { block: block.unwrap_or_default(), guard: Box::new(guard) } } rule block() -> ExpressionList = "{" ex:expression_list() "}" { ex } rule expression_list() -> ExpressionList = ex:(expression() ** ";") term:";"? { ExpressionList { expressions: ex, is_void: term.is_some() } } // #[cache_left_rec] // rule precedence_expression() -> ValueExpression // = precedence! { // val:value_expression() { val } // "-" 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) }) } // } 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 } / "-" { UnaryOp::Negate } rule identifier_list() -> IdentifierList = identifier() ++ "," rule param_list() -> ParameterList = value_expression() ++ "," rule identifier() -> IdentifierNode = id:alias_identifier() { IdentifierNode::Alias(id) } / id:simple_identifier() { IdentifierNode::Direct(id) } rule alias_identifier() -> IdentifierAlias = base:simple_identifier() "as" alias:simple_identifier() { IdentifierAlias(base.0, alias.0) } rule simple_identifier() -> Identifier = [ScriptToken { token_type: ScriptTokenType::Identifier(vl), .. }] { Identifier(String::from(*vl)) } rule literal() -> LiteralNode = "true" { LiteralNode::Boolean(true) } / "false" { LiteralNode::Boolean(false) } / "null" { LiteralNode::Null } / [ScriptToken { token_type: ScriptTokenType::String(vl), .. }] { LiteralNode::String(String::from(*vl)) } / [ScriptToken { token_type: ScriptTokenType::OwnedString(vl), .. }] { LiteralNode::String(vl.clone()) } / [ScriptToken { token_type: ScriptTokenType::Integer(vl), .. }] { LiteralNode::Number(Number::Integer(*vl)) } / [ScriptToken { token_type: ScriptTokenType::Float(vl), .. }] { LiteralNode::Number(Number::Float(*vl)) } rule string_value() -> String = [ScriptToken { token_type: ScriptTokenType::String(vl), .. }] { String::from(*vl) } / [ScriptToken { token_type: ScriptTokenType::OwnedString(vl), .. }] { vl.clone() } rule eof() = ![_] } } pub use forge_parser::{expression, program};