Newer
Older
use crate::parser::TokenSlice;
peg::parser! {
grammar script_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) }
rule expression_list() -> ExpressionList
= e:(expression() ++ ";") term:";"? { ExpressionList { expressions: e, is_void: term.is_some() } }
// rule statement() -> Expression
// Include conditional here separately from expression to allow "if" without semi
// = e:conditional() { Expression::Value(ValueExpression::ConditionalBlock(e)) }
// / e:condition_loop() { Expression::Void(VoidExpression::ConditionLoop(e)) }
// / e:expression() ";" { e }
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:raw_string() { 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() { ValueExpression::ConditionalBlock(co) }
/ decl:declare_variable() { ValueExpression::DeclareIdentifier(decl) }
/ decl:declare_function() { ValueExpression::DeclareFunction(decl) }
/ name:bare_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 } }
/ op:unary_operator() operand:value_expression()
{ ValueExpression::Unary { operator: op, operand: Box::new(operand) } }
/ grouped()
/ ident:bare_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 declare_variable() -> DeclareIdent
= "let" ex:declare_identifier() { ex }
rule declare_identifier() -> DeclareIdent
= assign:assignment() { DeclareIdent::WithValue(assign) }
/ ident:bare_identifier() { DeclareIdent::WithoutValue(ident) }
rule declare_function() -> DeclareFunction
= "fn" ident:bare_identifier() "(" params:(declare_identifier() ** ",") ")" "{" block:expression_list()? "}"
{ DeclareFunction { ident, params, body: block.unwrap_or_default() } }
= "while" guard:value_expression() "{" block:expression_list()? "}"
{ ConditionalLoop { block: GuardedBlock { guard: Box::new(guard), block: block.unwrap_or_default() }, fallback: None } }
/ "while" guard:value_expression() "{" block:expression_list()? "}" "else" "{" fallback:expression_list()? "}"
{ ConditionalLoop { block: GuardedBlock { guard: Box::new(guard), block: block.unwrap_or_default() }, fallback } }
rule conditional() -> Conditional
// = bl:guarded_block() { Conditional { fallback: None, blocks: vec![bl] } }
= blocks:(guarded_block() ++ "else") "else" "{" fallback:expression_list() "}" {
Conditional {
blocks,
fallback: Some(fallback)
}
}
/ blocks:(guarded_block() ++ "else") { Conditional { fallback: None, blocks, } }
rule guarded_block() -> GuardedBlock
= "if" guard:value_expression() "{" block:expression_list()? "}"
{ GuardedBlock { block: block.unwrap_or_default(), guard: Box::new(guard) } }
rule assignment() -> Assignment
= ident:bare_identifier() "=" expr:value_expression() { Assignment { ident, value: Box::new(expr) } }
rule binary_operator() -> BinaryOp
= "+" { BinaryOp::Add }
/ "-" { BinaryOp::Subtract }
/ "*" { BinaryOp::Multiply }
/ "/" { BinaryOp::Divide }
/ "%" { BinaryOp::Modulo }
rule unary_operator() -> UnaryOp
= "!" { UnaryOp::Not }
/ "-" { UnaryOp::Negate }
rule identifier_list() -> IdentifierList
= identifier() ++ ","
rule param_list() -> ParameterList
rule identifier() -> IdentifierNode
= id:alias_identifier() { IdentifierNode::Alias(id) }
/ id:bare_identifier() { IdentifierNode::Direct(id) }
rule alias_identifier() -> IdentifierAlias
= base:bare_identifier() "as" alias:bare_identifier() { IdentifierAlias(base.0, alias.0) }
rule bare_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 raw_string() -> String
= [ScriptToken { token_type: ScriptTokenType::String(vl), .. }] { String::from(*vl) }
/ [ScriptToken { token_type: ScriptTokenType::OwnedString(vl), .. }] { vl.clone() }