Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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:(statement() / 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) }
#[cache_left_rec]
rule value_expression() -> ValueExpression
= "(" ex:value_expression() ")" { ValueExpression::Grouped(GroupedExpression { inner: Box::new(ex) }) }
/ co:conditional() { ValueExpression::ConditionalBlock(co) }
/ 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) } }
/ li:literal() { ValueExpression::Literal(li) }
rule print() -> Print
= "print" ex:value_expression() { ex.into() }
rule condition_loop() -> ConditionalLoop
= "while" guard:value_expression() "{" block:expression_list() "}" { ConditionalLoop { block: GuardedBlock { guard: Box::new(guard), block}, fallback: None } }
/ "while" guard:value_expression() "{" block:expression_list() "}" "else" "{" fallback:expression_list() "}"
{ ConditionalLoop { block: GuardedBlock { guard: Box::new(guard), block}, fallback: Some(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, guard: Box::new(guard) } }
rule binary_operator() -> BinaryOp
= "+" { BinaryOp::Add }
/ "-" { BinaryOp::Subtract }
/ "*" { BinaryOp::Multiply }
/ "/" { BinaryOp::Divide }
/ "%" { BinaryOp::Modulo }
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
rule unary_operator() -> UnaryOp
= "!" { UnaryOp::Not }
/ "-" { UnaryOp::Negate }
rule identifier_list() -> IdentifierList
= identifier() ++ ","
rule param_list() -> ParameterList
= ids:bare_identifier() ++ ","
{ ids.iter().cloned().map(IdentifierNode::Direct).collect() }
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 eof() = ![_]
}
}
pub use script_parser::{expression, program};