If expressions
This commit is contained in:
parent
68bbd62ab6
commit
e3b236a15d
@ -8,7 +8,6 @@ extern crate lazy_static;
|
|||||||
extern crate maplit;
|
extern crate maplit;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate serde;
|
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -300,13 +300,19 @@ prefix_op := '+' | '-' | '!' | '~'
|
|||||||
primary := literal | paren_expr | identifier_expr
|
primary := literal | paren_expr | identifier_expr
|
||||||
|
|
||||||
paren_expr := LParen expression RParen
|
paren_expr := LParen expression RParen
|
||||||
identifier_expr := call_expr | index_expr | IDENTIFIER
|
identifier_expr := call_expr | index_expr | if_expr | IDENTIFIER
|
||||||
literal := 'true' | 'false' | number_literal | STR_LITERAL
|
literal := 'true' | 'false' | number_literal | STR_LITERAL
|
||||||
|
|
||||||
|
if_expr := 'if' expression block else_clause
|
||||||
|
else_clause := ε | 'else' block
|
||||||
|
|
||||||
|
block := '{' (statement)* '}'
|
||||||
|
|
||||||
call_expr := IDENTIFIER '(' expr_list ')' //TODO maybe make this optional? or no, have a bare identifier meant to be used as method taken care of in eval
|
call_expr := IDENTIFIER '(' expr_list ')' //TODO maybe make this optional? or no, have a bare identifier meant to be used as method taken care of in eval
|
||||||
index_expr := '[' (expression (',' (expression)* | ε) ']'
|
index_expr := '[' (expression (',' (expression)* | ε) ']'
|
||||||
expr_list := expression (',' expression)* | ε
|
expr_list := expression (',' expression)* | ε
|
||||||
|
|
||||||
|
|
||||||
// a float_literal can still be assigned to an int in type-checking
|
// a float_literal can still be assigned to an int in type-checking
|
||||||
number_literal := int_literal | float_literal
|
number_literal := int_literal | float_literal
|
||||||
int_literal = ('0x' | '0b') digits
|
int_literal = ('0x' | '0b') digits
|
||||||
@ -424,7 +430,8 @@ pub enum Expression {
|
|||||||
Index {
|
Index {
|
||||||
indexee: Box<Expression>,
|
indexee: Box<Expression>,
|
||||||
indexers: Vec<Expression>,
|
indexers: Vec<Expression>,
|
||||||
}
|
},
|
||||||
|
IfExpression(Box<Expression>, Vec<Statement>, Option<Vec<Statement>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -598,6 +605,7 @@ impl Parser {
|
|||||||
parse_method!(primary(&mut self) -> ParseResult<Expression> {
|
parse_method!(primary(&mut self) -> ParseResult<Expression> {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
LParen => self.paren_expr(),
|
LParen => self.paren_expr(),
|
||||||
|
Keyword(Kw::If) => self.if_expr(),
|
||||||
Identifier(_) => self.identifier_expr(),
|
Identifier(_) => self.identifier_expr(),
|
||||||
_ => self.literal(),
|
_ => self.literal(),
|
||||||
}
|
}
|
||||||
@ -610,7 +618,7 @@ impl Parser {
|
|||||||
Ok(expr)
|
Ok(expr)
|
||||||
});
|
});
|
||||||
|
|
||||||
fn identifier_expr(&mut self) -> ParseResult<Expression> {
|
parse_method!(identifier_expr(&mut self) -> ParseResult<Expression> {
|
||||||
let identifier = self.identifier()?;
|
let identifier = self.identifier()?;
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
LParen => {
|
LParen => {
|
||||||
@ -629,7 +637,7 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
_ => Ok(Expression::Variable(identifier))
|
_ => Ok(Expression::Variable(identifier))
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
parse_method!(call_expr(&mut self) -> ParseResult<Vec<Expression>> {
|
parse_method!(call_expr(&mut self) -> ParseResult<Vec<Expression>> {
|
||||||
let mut exprs = Vec::new();
|
let mut exprs = Vec::new();
|
||||||
@ -665,6 +673,40 @@ impl Parser {
|
|||||||
Ok(exprs)
|
Ok(exprs)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
parse_method!(if_expr(&mut self) -> ParseResult<Expression> {
|
||||||
|
expect!(self, Keyword(Kw::If), "Expected 'if'");
|
||||||
|
let condition = self.expression()?;
|
||||||
|
let then_clause = self.block()?;
|
||||||
|
let else_clause = self.else_clause()?;
|
||||||
|
Ok(Expression::IfExpression(Box::new(condition), then_clause, else_clause))
|
||||||
|
});
|
||||||
|
|
||||||
|
parse_method!(else_clause(&mut self) -> ParseResult<Option<Vec<Statement>>> {
|
||||||
|
Ok(if let Keyword(Kw::Else) = self.peek() {
|
||||||
|
self.next();
|
||||||
|
Some(self.block()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
parse_method!(block(&mut self) -> ParseResult<Vec<Statement>> {
|
||||||
|
expect!(self, LCurlyBrace, "Expected '{'");
|
||||||
|
let mut statements = Vec::new();
|
||||||
|
loop {
|
||||||
|
match self.peek() {
|
||||||
|
EOF | RCurlyBrace => break,
|
||||||
|
Newline | Semicolon => {
|
||||||
|
self.next();
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
_ => statements.push(self.statement()?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect!(self, RCurlyBrace, "Expected '}'");
|
||||||
|
Ok(statements)
|
||||||
|
});
|
||||||
|
|
||||||
parse_method!(identifier(&mut self) -> ParseResult<Rc<String>> {
|
parse_method!(identifier(&mut self) -> ParseResult<Rc<String>> {
|
||||||
match self.next() {
|
match self.next() {
|
||||||
Identifier(s) => Ok(s),
|
Identifier(s) => Ok(s),
|
||||||
@ -889,4 +931,24 @@ mod parse_tests {
|
|||||||
parse_test!("var a = 10", AST(vec![Declaration(Binding { name: rc!(a), constant: false, expr: IntLiteral(10) } )]));
|
parse_test!("var a = 10", AST(vec![Declaration(Binding { name: rc!(a), constant: false, expr: IntLiteral(10) } )]));
|
||||||
parse_test!("const a = 2 + 2", AST(vec![Declaration(Binding { name: rc!(a), constant: true, expr: binexp!("+", IntLiteral(2), IntLiteral(2)) }) ]));
|
parse_test!("const a = 2 + 2", AST(vec![Declaration(Binding { name: rc!(a), constant: true, expr: binexp!("+", IntLiteral(2), IntLiteral(2)) }) ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parsing_block_expressions() {
|
||||||
|
parse_test!("if a() { b(); c() }", AST(vec![Expression(
|
||||||
|
IfExpression(Box::new(Call { name: rc!(a), params: vec![]}),
|
||||||
|
vec![Expression(Call { name: rc!(b), params: vec![]}), Expression(Call { name: rc!(c), params: vec![] })],
|
||||||
|
None))]));
|
||||||
|
parse_test!(r#"
|
||||||
|
if true {
|
||||||
|
const a = 10
|
||||||
|
b
|
||||||
|
} else {
|
||||||
|
c
|
||||||
|
}"#,
|
||||||
|
AST(vec![Expression(IfExpression(Box::new(BoolLiteral(true)),
|
||||||
|
vec![Declaration(Binding { name: rc!(a), constant: true, expr: IntLiteral(10) }),
|
||||||
|
Expression(Variable(rc!(b)))],
|
||||||
|
Some(vec![Expression(Variable(rc!(c)))])))])
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user