Newer
Older
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: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) }
=
co:conditional_statement() { ValueExpression::ConditionalBlock(co) }
/ t:type_of() { ValueExpression::Typeof(t) }
/ 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) }
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) }
= "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() } }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// #[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) }
= 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() }
pub use forge_parser::{expression, program};