use crate::lexer::ScriptTokenType; use crate::parser::ast::*; use crate::runtime::numbers::Number; grammar<'a>; pub Program: Program = { ExpressionList => Program(<>) }; Block: Option<ExpressionList> = { "{" <ExpressionList?> "}" => <>, }; ExpressionList: ExpressionList = { <e:Expression> <b:";"?> => { ExpressionList { expressions: vec![e], is_void: b.is_some(), } }, <e:Expression> ";" <mut ls:ExpressionList> => { let mut new = vec![e]; new.append(&mut ls.expressions); ExpressionList { expressions: new, is_void: ls.is_void, } } }; pub Expression: Expression = { ValueExpression => Expression::Value(<>), VoidExpression => Expression::Void(<>), }; VoidExpression: VoidExpression = { AsVoid<PrintStmt> => <>, AsVoid<ImportStmt> => <>, AsVoid<ExportStmt> => <>, }; ValueExpression: ValueExpression = { AsValue<Literal> => <>, AsValue<Identifier> => <>, AsValue<IfStatement> => <>, "(" <lhs:ValueExpression> "+" <rhs:ValueExpression> ")" => ValueExpression::Binary { lhs: Box::new(lhs), rhs: Box::new(rhs), operator: BinaryOp::Add }, "typeof" <expr:ValueExpression> => TypeofValue(Box::new(expr)).into(), "-" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Negate }, "!" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Not }, "(" <expr:ValueExpression> ")" => GroupedExpression { inner: Box::new(expr) }.into(), } //ValueExpression: ValueExpression = { // #[precedence(level="100")] // "(" <expr:ValueExpression> ")" => GroupedExpression { inner: Box::new(expr) }.into(), // #[precedence(level="0")] // Literal => ValueExpression::Literal(<>), // #[precedence(level="0")] // Identifier => <>.into(), // // #[precedence(level="2")] // "typeof" <expr:ValueExpression> => TypeofValue(Box::new(expr)).into(), // #[precedence(level="2")] // "-" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Negate }, // #[precedence(level="2")] // "!" <expr:ValueExpression> => ValueExpression::Unary { operand: Box::new(expr), operator: UnaryOp::Not }, // // #[precedence(level = "3")] // IfStatement => <>.into(), // // #[precedence(level="4")] #[assoc(side="left")] // <lhs:ValueExpression> "*" <rhs:ValueExpression> => { // ValueExpression::Binary { // lhs: Box::new(lhs), // rhs: Box::new(rhs), // operator: BinaryOp::Multiply, // } // }, // #[precedence(level="4")] #[assoc(side="left")] // <lhs:ValueExpression> "/" <rhs:ValueExpression> => { // ValueExpression::Binary { // lhs: Box::new(lhs), // rhs: Box::new(rhs), // operator: BinaryOp::Divide, // } // }, // #[precedence(level="6")] #[assoc(side="left")] // <lhs:ValueExpression> "+" <rhs:ValueExpression> => { // ValueExpression::Binary { // lhs: Box::new(lhs), // rhs: Box::new(rhs), // operator: BinaryOp::Add, // } // }, // #[precedence(level="6")] #[assoc(side="left")] // <lhs:ValueExpression> "-" <rhs:ValueExpression> => { // ValueExpression::Binary { // lhs: Box::new(lhs), // rhs: Box::new(rhs), // operator: BinaryOp::Subtract, // } // }, //}; AsVoid<R>: VoidExpression = { R => <>.into() } AsValue<R>: ValueExpression = { R => <>.into() } TypeofStmt: TypeofValue = { "typeof" <ValueExpression> => TypeofValue(Box::new(<>)) } PrintStmt: Print = { "print" <expr:ValueExpression> => Print { expr: Box::new(expr) }, } ImportStmt: Import = { "import" "{" <items:IdentifierList> "}" "from" <source:StringValue> => Import { source, items }, } ExportStmt: Export = { "export" "{" <items:IdentifierList> "}" => Export { items }, } IfStatement: Conditional = { BareIfStatement => Conditional { blocks: vec![<>], fallback: None }, <fi:BareIfStatement> "else" <bl:Block> => Conditional { blocks: vec![fi], fallback: bl }, <fi:BareIfStatement> "else" <ls:IfStatement> => { let mut ls = ls; let mut new = vec![fi]; new.append(&mut ls.blocks); Conditional { blocks: new, fallback: ls.fallback, } } }; BareIfStatement: GuardedBlock = { "if" <guard:ValueExpression> <bl:Block> => { GuardedBlock { block: bl.unwrap_or_default(), guard: Box::new(guard), } } }; ParameterList = ListOf<ValueExpression>; IdentifierList = ListOf<IdentifierNode>; IdentifierNode: IdentifierNode = { IdentifierAlias => IdentifierNode::Alias(<>), Identifier => IdentifierNode::Direct(<>), }; IdentifierAlias: IdentifierAlias = { <base:Identifier> "as" <alias:Identifier> => IdentifierAlias(base.0, alias.0), }; Identifier: Identifier = { "identifier" => Identifier(String::from(<>)) }; Literal: LiteralNode = { "boolean" => LiteralNode::Boolean(<>), "null" => LiteralNode::Null, "float" => LiteralNode::Number(Number::Float(<>)), "integer" => LiteralNode::Number(Number::Integer(<>)), "string" => LiteralNode::String(String::from(<>)), "owned_string" => LiteralNode::String(<>), }; StringValue: String = { "string" => String::from(<>), "owned_string" => <>, }; ListOf<T>: Vec<T> = { <mut v:(<T> ",")+> <e:T?> => match e { None => v, Some(e) => { v.push(e); v } } }; extern { type Location = usize; type Error = String; enum ScriptTokenType { "(" => ScriptTokenType::LeftParen, ")" => ScriptTokenType::RightParen, "{" => ScriptTokenType::LeftBrace, "}" => ScriptTokenType::RightBrace, "," => ScriptTokenType::Comma, "." => ScriptTokenType::Dot, "-" => ScriptTokenType::Minus, "+" => ScriptTokenType::Plus, ";" => ScriptTokenType::Semicolon, "/" => ScriptTokenType::Slash, "*" => ScriptTokenType::Asterisk, "!" => ScriptTokenType::Bang, "!=" => ScriptTokenType::BangEqual, "=" => ScriptTokenType::Equal, "==" => ScriptTokenType::EqualEqual, ">" => ScriptTokenType::Greater, ">=" => ScriptTokenType::GreaterEqual, "<" => ScriptTokenType::Less, "<=" => ScriptTokenType::LessEqual, "||" => ScriptTokenType::DoublePipe, "&&" => ScriptTokenType::DoubleAmpersand, "%" => ScriptTokenType::Modulo, "^" => ScriptTokenType::Caret, "struct" => ScriptTokenType::Class, "else" => ScriptTokenType::Else, "fn" => ScriptTokenType::Function, "for" => ScriptTokenType::For, "if" => ScriptTokenType::If, "null" => ScriptTokenType::Null, "print" => ScriptTokenType::Print, "return" => ScriptTokenType::Return, "super" => ScriptTokenType::Super, "this" => ScriptTokenType::This, "let" => ScriptTokenType::Let, "while" => ScriptTokenType::While, "export" => ScriptTokenType::Export, "import" => ScriptTokenType::Import, "as" => ScriptTokenType::Alias, "from" => ScriptTokenType::From, "typeof" => ScriptTokenType::Typeof, "finally" => ScriptTokenType::Finally, "boolean" => ScriptTokenType::Boolean(<bool>), "float" => ScriptTokenType::Float(<f64>), "integer" => ScriptTokenType::Integer(<i64>), "owned_string" => ScriptTokenType::OwnedString(<String>), "string" => ScriptTokenType::String(<String>), "identifier" => ScriptTokenType::Identifier(<String>), } }