use crate::lexer::ScriptTokenType; use crate::parser::ast::*; use crate::runtime::numbers::Number; grammar<'a>; pub Program: Program = { <ExpressionList> => Program(<>), } ExpressionBlock: ExpressionList = { "{" "}" => ExpressionList::empty(), "{" <ExpressionList> "}" => <>, } ExpressionList: ExpressionList = { <Expression> => ExpressionList::production(vec![<>]), <mut list:ExpressionList> ";" <expr:Expression> => { list.expressions.push(expr); list }, <mut opt:ExpressionList> ";" => { opt.is_void = true; opt }, } FunctionDeclParamList = CommaSeperatedList<FunctionDeclParam>; FunctionDeclParam: DeclareIdent = { Identifier => DeclareIdent::WithoutValue(<>), <id:Identifier> "=" <def:ValueExpression> => DeclareIdent::WithValue(Assignment { ident: id, value: Box::new(def), }), } ParameterList: Vec<ValueExpression> = { "(" <CommaSeperatedValueExpressionList> ")" => <>, "(" ")" => Vec::new(), } CommaSeperatedValueExpressionList = CommaSeperatedList<ValueExpression>; pub Expression: Expression = { ValueExpression => Expression::Value(<>), VoidExpression => Expression::Void(<>), } ValueExpression: ValueExpression = { FirstClassDeclareExpression => <>, "let" <Identifier> => DeclareIdent::WithoutValue(<>).into(), "let" <id:Identifier> "=" <expr:FirstClassDeclareExpression> => DeclareIdent::WithValue( Assignment { ident: id, value :Box::new(expr) } ).into(), } VoidExpression: VoidExpression = { UnaryStatement => <> } FirstClassDeclareExpression: ValueExpression = { BoolOrExpression => <>, DeclareFunction => <>.into(), } BoolOrExpression: ValueExpression = { BoolAndExpression => <>, <lhs:BoolOrExpression> "||" <rhs:BoolAndExpression> => ValueExpression::bool_or(lhs, rhs), } BoolAndExpression: ValueExpression = { EqualityExpression => <>, <lhs:BoolAndExpression> "&&" <rhs:EqualityExpression> => ValueExpression::bool_and(lhs, rhs), } EqualityExpression: ValueExpression = { ComparisonExpression => <>, <lhs:EqualityExpression> "==" <rhs:ComparisonExpression> => ValueExpression::equals(lhs, rhs), <lhs:EqualityExpression> "!=" <rhs:ComparisonExpression> => ValueExpression::not_equals(lhs, rhs), } ComparisonExpression: ValueExpression = { AdditiveExpression => <>, <lhs:ComparisonExpression> "<" <rhs:AdditiveExpression> => ValueExpression::less_than(lhs, rhs), <lhs:ComparisonExpression> ">" <rhs:AdditiveExpression> => ValueExpression::greater_than(lhs, rhs), <lhs:ComparisonExpression> "<=" <rhs:AdditiveExpression> => ValueExpression::greater_than_equal(lhs, rhs), <lhs:ComparisonExpression> ">=" <rhs:AdditiveExpression> => ValueExpression::greater_than_equal(lhs, rhs), } AdditiveExpression: ValueExpression = { MultiplicativeExpression => <>, <lhs:AdditiveExpression> "+" <rhs:MultiplicativeExpression> => ValueExpression::add(lhs, rhs), <lhs:AdditiveExpression> "-" <rhs:MultiplicativeExpression> => ValueExpression::sub(lhs, rhs), } MultiplicativeExpression: ValueExpression = { UnaryExpression => <>, <lhs:MultiplicativeExpression> "*" <rhs:UnaryExpression> => ValueExpression::mul(lhs, rhs), <lhs:MultiplicativeExpression> "/" <rhs:UnaryExpression> => ValueExpression::div(lhs, rhs), <lhs:MultiplicativeExpression> "%" <rhs:UnaryExpression> => ValueExpression::modulo(lhs, rhs), } UnaryStatement: VoidExpression = { "print" <FirstClassDeclareExpression> => Print { expr: Box::new(<>) }.into(), "return" <FirstClassDeclareExpression> => Return { expr: Box::new(<>) }.into(), } UnaryExpression: ValueExpression = { IndexedExpression => <>, "typeof" <UnaryExpression> => TypeofValue(Box::new(<>)).into(), "!" <UnaryExpression> => ValueExpression::Unary { operand: Box::new(<>), operator: UnaryOp::Not }, "-" <UnaryExpression> => ValueExpression::Unary { operand: Box::new(<>), operator: UnaryOp::Negate }, } IndexedExpression: ValueExpression = { CallExpression => <>, <init:CallExpression> "." <acc:AccessorChainAnyEnding> => AccessorPath { initialiser: Box::new(init), path: acc, }.into(), } CallExpression: ValueExpression = { BaseExpression => <>, FunctionCall => <>.into(), } BaseExpression: ValueExpression = { Literal => <>.into(), Identifier => <>.into(), Conditional => <>, "(" <ValueExpression> ")" => GroupedExpression { inner: Box::new(<>) }.into(), } DeclareFunction: DeclareFunction = { "fn" <ident:Identifier> "(" <params:FunctionDeclParamList?> ")" <body:ExpressionBlock> => DeclareFunction { ident, params: params.unwrap_or_default(), body, } } AccessorChainAnyEnding: Vec<AccessorType> = { AccessorChainEndingWithProperty => <>, FunctionCall => vec![AccessorType::FunctionCall(<>)], <mut ls:AccessorChainEndingWithProperty> "." <func:FunctionCall> => { ls.push(AccessorType::FunctionCall(func)); ls }, } AccessorChainEndingWithProperty: Vec<AccessorType> = { Identifier => vec![AccessorType::Identifier(<>)], <func:FunctionCall> "." <id:Identifier> => vec![ AccessorType::FunctionCall(func), AccessorType::Identifier(id), ], <mut first:AccessorChainEndingWithProperty> "." <id:Identifier> => { first.push(AccessorType::Identifier(id)); first }, <mut first:AccessorChainEndingWithProperty> "." <func:FunctionCall> "." <id:Identifier> => { first.push(AccessorType::FunctionCall(func)); first.push(AccessorType::Identifier(id)); first }, } Conditional: ValueExpression = { GuardedBlockList => Conditional { blocks: <>, fallback: None }.into(), <ls:GuardedBlockList> "else" <fb:ExpressionBlock> => Conditional { blocks: ls, fallback: Some(fb) }.into(), } GuardedBlockList: Vec<GuardedBlock> = { GuardedBlock => vec![<>], <mut ls:GuardedBlockList> "else" <gb:GuardedBlock> => { ls.push(gb); ls }, } GuardedBlock: GuardedBlock = { "if" <guard:ValueExpression> <block:ExpressionBlock> => GuardedBlock { guard: Box::new(guard), block, }, } FunctionCall: FunctionCall = { <id:Identifier> <params:ParameterList> => FunctionCall { name: id, params, } } IdentifierAsAlias: 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" => <>, }; CommaSeperatedList<Type>: Vec<Type> = { Type => vec![<>], <mut ls:CommaSeperatedList<Type>> "," <ty:Type> => { ls.push(ty); ls } } 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::Colon, "/" => 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>), } }