|
|
@ -54,14 +54,14 @@ impl Parser { |
|
|
|
exprs.push(result); |
|
|
|
exprs.push(result); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// In the case of `BlockExpr` the Positions seem unnecessary
|
|
|
|
// In the case of `Block` the Positions seem unnecessary
|
|
|
|
// TODO: refactor this or the `mk!` perhaps?
|
|
|
|
// TODO: refactor this or the `mk!` perhaps?
|
|
|
|
Ok(Expr::new(ExprDef::BlockExpr(exprs))) |
|
|
|
Ok(Expr::new(ExprDef::Block(exprs))) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn get_token(&self, pos: usize) -> Result<Token, ParseError> { |
|
|
|
fn get_token(&self, pos: usize) -> Result<Token, ParseError> { |
|
|
|
if pos < self.tokens.len() { |
|
|
|
if pos < self.tokens.len() { |
|
|
|
Ok(self.tokens[pos].clone()) |
|
|
|
Ok(self.tokens.get(pos).expect("failed getting token").clone()) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Err(ParseError::AbruptEnd) |
|
|
|
Err(ParseError::AbruptEnd) |
|
|
|
} |
|
|
|
} |
|
|
@ -71,7 +71,7 @@ impl Parser { |
|
|
|
match keyword { |
|
|
|
match keyword { |
|
|
|
Keyword::Throw => { |
|
|
|
Keyword::Throw => { |
|
|
|
let thrown = self.parse()?; |
|
|
|
let thrown = self.parse()?; |
|
|
|
Ok(mk!(self, ExprDef::ThrowExpr(Box::new(thrown)))) |
|
|
|
Ok(mk!(self, ExprDef::Throw(Box::new(thrown)))) |
|
|
|
} |
|
|
|
} |
|
|
|
// vars, lets and consts are similar in parsing structure, we can group them together
|
|
|
|
// vars, lets and consts are similar in parsing structure, we can group them together
|
|
|
|
Keyword::Var | Keyword::Let => { |
|
|
|
Keyword::Var | Keyword::Let => { |
|
|
@ -124,8 +124,8 @@ impl Parser { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
match keyword { |
|
|
|
match keyword { |
|
|
|
Keyword::Let => Ok(Expr::new(ExprDef::LetDeclExpr(vars))), |
|
|
|
Keyword::Let => Ok(Expr::new(ExprDef::LetDecl(vars))), |
|
|
|
_ => Ok(Expr::new(ExprDef::VarDeclExpr(vars))), |
|
|
|
_ => Ok(Expr::new(ExprDef::VarDecl(vars))), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
Keyword::Const => { |
|
|
|
Keyword::Const => { |
|
|
@ -174,23 +174,22 @@ impl Parser { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Ok(Expr::new(ExprDef::ConstDeclExpr(vars))) |
|
|
|
Ok(Expr::new(ExprDef::ConstDecl(vars))) |
|
|
|
} |
|
|
|
} |
|
|
|
Keyword::Return => Ok(mk!( |
|
|
|
Keyword::Return => Ok(mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::ReturnExpr(Some(Box::new(self.parse()?.clone()))) |
|
|
|
ExprDef::Return(Some(Box::new(self.parse()?.clone()))) |
|
|
|
)), |
|
|
|
)), |
|
|
|
Keyword::New => { |
|
|
|
Keyword::New => { |
|
|
|
let call = self.parse()?; |
|
|
|
let call = self.parse()?; |
|
|
|
match call.def { |
|
|
|
match call.def { |
|
|
|
ExprDef::CallExpr(ref func, ref args) => Ok(mk!( |
|
|
|
ExprDef::Call(ref func, ref args) => { |
|
|
|
self, |
|
|
|
Ok(mk!(self, ExprDef::Construct(func.clone(), args.clone()))) |
|
|
|
ExprDef::ConstructExpr(func.clone(), args.clone()) |
|
|
|
} |
|
|
|
)), |
|
|
|
|
|
|
|
_ => Err(ParseError::ExpectedExpr("constructor", call)), |
|
|
|
_ => Err(ParseError::ExpectedExpr("constructor", call)), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
Keyword::TypeOf => Ok(mk!(self, ExprDef::TypeOfExpr(Box::new(self.parse()?)))), |
|
|
|
Keyword::TypeOf => Ok(mk!(self, ExprDef::TypeOf(Box::new(self.parse()?)))), |
|
|
|
Keyword::If => { |
|
|
|
Keyword::If => { |
|
|
|
self.expect_punc(Punctuator::OpenParen, "if block")?; |
|
|
|
self.expect_punc(Punctuator::OpenParen, "if block")?; |
|
|
|
let cond = self.parse()?; |
|
|
|
let cond = self.parse()?; |
|
|
@ -199,7 +198,7 @@ impl Parser { |
|
|
|
let next = self.get_token(self.pos); |
|
|
|
let next = self.get_token(self.pos); |
|
|
|
Ok(mk!( |
|
|
|
Ok(mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::IfExpr( |
|
|
|
ExprDef::If( |
|
|
|
Box::new(cond), |
|
|
|
Box::new(cond), |
|
|
|
Box::new(expr), |
|
|
|
Box::new(expr), |
|
|
|
if next.is_ok() && next.unwrap().data == TokenData::Keyword(Keyword::Else) { |
|
|
|
if next.is_ok() && next.unwrap().data == TokenData::Keyword(Keyword::Else) { |
|
|
@ -218,7 +217,7 @@ impl Parser { |
|
|
|
let expr = self.parse()?; |
|
|
|
let expr = self.parse()?; |
|
|
|
Ok(mk!( |
|
|
|
Ok(mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::WhileLoopExpr(Box::new(cond), Box::new(expr)) |
|
|
|
ExprDef::WhileLoop(Box::new(cond), Box::new(expr)) |
|
|
|
)) |
|
|
|
)) |
|
|
|
} |
|
|
|
} |
|
|
|
Keyword::Switch => { |
|
|
|
Keyword::Switch => { |
|
|
@ -257,7 +256,7 @@ impl Parser { |
|
|
|
_ => block.push(self.parse()?), |
|
|
|
_ => block.push(self.parse()?), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
default = Some(mk!(self, ExprDef::BlockExpr(block))); |
|
|
|
default = Some(mk!(self, ExprDef::Block(block))); |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::CloseBlock) => break, |
|
|
|
TokenData::Punctuator(Punctuator::CloseBlock) => break, |
|
|
|
_ => { |
|
|
|
_ => { |
|
|
@ -276,7 +275,7 @@ impl Parser { |
|
|
|
self.expect_punc(Punctuator::CloseBlock, "switch block")?; |
|
|
|
self.expect_punc(Punctuator::CloseBlock, "switch block")?; |
|
|
|
Ok(mk!( |
|
|
|
Ok(mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::SwitchExpr( |
|
|
|
ExprDef::Switch( |
|
|
|
Box::new(value.unwrap()), |
|
|
|
Box::new(value.unwrap()), |
|
|
|
cases, |
|
|
|
cases, |
|
|
|
match default { |
|
|
|
match default { |
|
|
@ -328,7 +327,7 @@ impl Parser { |
|
|
|
let block = self.parse()?; |
|
|
|
let block = self.parse()?; |
|
|
|
Ok(mk!( |
|
|
|
Ok(mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::FunctionDeclExpr(name, args, Box::new(block)) |
|
|
|
ExprDef::FunctionDecl(name, args, Box::new(block)) |
|
|
|
)) |
|
|
|
)) |
|
|
|
} |
|
|
|
} |
|
|
|
_ => Err(ParseError::UnexpectedKeyword(keyword)), |
|
|
|
_ => Err(ParseError::UnexpectedKeyword(keyword)), |
|
|
@ -349,16 +348,16 @@ impl Parser { |
|
|
|
self.parse()? |
|
|
|
self.parse()? |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::Semicolon) | TokenData::Comment(_) => { |
|
|
|
TokenData::Punctuator(Punctuator::Semicolon) | TokenData::Comment(_) => { |
|
|
|
mk!(self, ExprDef::ConstExpr(Const::Undefined)) |
|
|
|
mk!(self, ExprDef::Const(Const::Undefined)) |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::NumericLiteral(num) => mk!(self, ExprDef::ConstExpr(Const::Num(num))), |
|
|
|
TokenData::NumericLiteral(num) => mk!(self, ExprDef::Const(Const::Num(num))), |
|
|
|
TokenData::NullLiteral => mk!(self, ExprDef::ConstExpr(Const::Null)), |
|
|
|
TokenData::NullLiteral => mk!(self, ExprDef::Const(Const::Null)), |
|
|
|
TokenData::StringLiteral(text) => mk!(self, ExprDef::ConstExpr(Const::String(text))), |
|
|
|
TokenData::StringLiteral(text) => mk!(self, ExprDef::Const(Const::String(text))), |
|
|
|
TokenData::BooleanLiteral(val) => mk!(self, ExprDef::ConstExpr(Const::Bool(val))), |
|
|
|
TokenData::BooleanLiteral(val) => mk!(self, ExprDef::Const(Const::Bool(val))), |
|
|
|
TokenData::Identifier(ref s) if s == "undefined" => { |
|
|
|
TokenData::Identifier(ref s) if s == "undefined" => { |
|
|
|
mk!(self, ExprDef::ConstExpr(Const::Undefined)) |
|
|
|
mk!(self, ExprDef::Const(Const::Undefined)) |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Identifier(s) => mk!(self, ExprDef::LocalExpr(s)), |
|
|
|
TokenData::Identifier(s) => mk!(self, ExprDef::Local(s)), |
|
|
|
TokenData::Keyword(keyword) => self.parse_struct(keyword)?, |
|
|
|
TokenData::Keyword(keyword) => self.parse_struct(keyword)?, |
|
|
|
TokenData::Punctuator(Punctuator::OpenParen) => { |
|
|
|
TokenData::Punctuator(Punctuator::OpenParen) => { |
|
|
|
match self.get_token(self.pos)?.data { |
|
|
|
match self.get_token(self.pos)?.data { |
|
|
@ -370,7 +369,7 @@ impl Parser { |
|
|
|
let expr = self.parse()?; |
|
|
|
let expr = self.parse()?; |
|
|
|
mk!( |
|
|
|
mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::ArrowFunctionDeclExpr(Vec::new(), Box::new(expr)), |
|
|
|
ExprDef::ArrowFunctionDecl(Vec::new(), Box::new(expr)), |
|
|
|
token |
|
|
|
token |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
@ -384,7 +383,7 @@ impl Parser { |
|
|
|
// at this point it's probably gonna be an arrow function
|
|
|
|
// at this point it's probably gonna be an arrow function
|
|
|
|
let mut args = vec![ |
|
|
|
let mut args = vec![ |
|
|
|
match next.def { |
|
|
|
match next.def { |
|
|
|
ExprDef::LocalExpr(ref name) => (*name).clone(), |
|
|
|
ExprDef::Local(ref name) => (*name).clone(), |
|
|
|
_ => "".to_string(), |
|
|
|
_ => "".to_string(), |
|
|
|
}, |
|
|
|
}, |
|
|
|
match self.get_token(self.pos)?.data { |
|
|
|
match self.get_token(self.pos)?.data { |
|
|
@ -436,7 +435,7 @@ impl Parser { |
|
|
|
let expr = self.parse()?; |
|
|
|
let expr = self.parse()?; |
|
|
|
mk!( |
|
|
|
mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::ArrowFunctionDeclExpr(args, Box::new(expr)), |
|
|
|
ExprDef::ArrowFunctionDecl(args, Box::new(expr)), |
|
|
|
token |
|
|
|
token |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
@ -464,7 +463,7 @@ impl Parser { |
|
|
|
TokenData::Punctuator(Punctuator::Comma) => { |
|
|
|
TokenData::Punctuator(Punctuator::Comma) => { |
|
|
|
if !saw_expr_last { |
|
|
|
if !saw_expr_last { |
|
|
|
// An elision indicates that a space is saved in the array
|
|
|
|
// An elision indicates that a space is saved in the array
|
|
|
|
array.push(mk!(self, ExprDef::ConstExpr(Const::Undefined))) |
|
|
|
array.push(mk!(self, ExprDef::Const(Const::Undefined))) |
|
|
|
} |
|
|
|
} |
|
|
|
saw_expr_last = false; |
|
|
|
saw_expr_last = false; |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
@ -487,18 +486,14 @@ impl Parser { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
mk!(self, ExprDef::ArrayDeclExpr(array), token) |
|
|
|
mk!(self, ExprDef::ArrayDecl(array), token) |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::OpenBlock) |
|
|
|
TokenData::Punctuator(Punctuator::OpenBlock) |
|
|
|
if self.get_token(self.pos)?.data |
|
|
|
if self.get_token(self.pos)?.data |
|
|
|
== TokenData::Punctuator(Punctuator::CloseBlock) => |
|
|
|
== TokenData::Punctuator(Punctuator::CloseBlock) => |
|
|
|
{ |
|
|
|
{ |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
|
mk!( |
|
|
|
mk!(self, ExprDef::ObjectDecl(Box::new(BTreeMap::new())), token) |
|
|
|
self, |
|
|
|
|
|
|
|
ExprDef::ObjectDeclExpr(Box::new(BTreeMap::new())), |
|
|
|
|
|
|
|
token |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::OpenBlock) |
|
|
|
TokenData::Punctuator(Punctuator::OpenBlock) |
|
|
|
if self.get_token(self.pos + 1)?.data |
|
|
|
if self.get_token(self.pos + 1)?.data |
|
|
@ -532,7 +527,7 @@ impl Parser { |
|
|
|
map.insert(name, value); |
|
|
|
map.insert(name, value); |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
|
} |
|
|
|
} |
|
|
|
mk!(self, ExprDef::ObjectDeclExpr(map), token) |
|
|
|
mk!(self, ExprDef::ObjectDecl(map), token) |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::OpenBlock) => { |
|
|
|
TokenData::Punctuator(Punctuator::OpenBlock) => { |
|
|
|
let mut exprs = Vec::new(); |
|
|
|
let mut exprs = Vec::new(); |
|
|
@ -546,27 +541,27 @@ impl Parser { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
|
mk!(self, ExprDef::BlockExpr(exprs), token) |
|
|
|
mk!(self, ExprDef::Block(exprs), token) |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::Sub) => mk!( |
|
|
|
TokenData::Punctuator(Punctuator::Sub) => mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::UnaryOpExpr(UnaryOp::Minus, Box::new(self.parse()?)) |
|
|
|
ExprDef::UnaryOp(UnaryOp::Minus, Box::new(self.parse()?)) |
|
|
|
), |
|
|
|
), |
|
|
|
TokenData::Punctuator(Punctuator::Add) => mk!( |
|
|
|
TokenData::Punctuator(Punctuator::Add) => mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::UnaryOpExpr(UnaryOp::Plus, Box::new(self.parse()?)) |
|
|
|
ExprDef::UnaryOp(UnaryOp::Plus, Box::new(self.parse()?)) |
|
|
|
), |
|
|
|
), |
|
|
|
TokenData::Punctuator(Punctuator::Not) => mk!( |
|
|
|
TokenData::Punctuator(Punctuator::Not) => mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::UnaryOpExpr(UnaryOp::Not, Box::new(self.parse()?)) |
|
|
|
ExprDef::UnaryOp(UnaryOp::Not, Box::new(self.parse()?)) |
|
|
|
), |
|
|
|
), |
|
|
|
TokenData::Punctuator(Punctuator::Inc) => mk!( |
|
|
|
TokenData::Punctuator(Punctuator::Inc) => mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::UnaryOpExpr(UnaryOp::IncrementPre, Box::new(self.parse()?)) |
|
|
|
ExprDef::UnaryOp(UnaryOp::IncrementPre, Box::new(self.parse()?)) |
|
|
|
), |
|
|
|
), |
|
|
|
TokenData::Punctuator(Punctuator::Dec) => mk!( |
|
|
|
TokenData::Punctuator(Punctuator::Dec) => mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::UnaryOpExpr(UnaryOp::DecrementPre, Box::new(self.parse()?)) |
|
|
|
ExprDef::UnaryOp(UnaryOp::DecrementPre, Box::new(self.parse()?)) |
|
|
|
), |
|
|
|
), |
|
|
|
_ => return Err(ParseError::Expected(Vec::new(), token.clone(), "script")), |
|
|
|
_ => return Err(ParseError::Expected(Vec::new(), token.clone(), "script")), |
|
|
|
}; |
|
|
|
}; |
|
|
@ -587,10 +582,7 @@ impl Parser { |
|
|
|
let tk = self.get_token(self.pos)?; |
|
|
|
let tk = self.get_token(self.pos)?; |
|
|
|
match tk.data { |
|
|
|
match tk.data { |
|
|
|
TokenData::Identifier(ref s) => { |
|
|
|
TokenData::Identifier(ref s) => { |
|
|
|
result = mk!( |
|
|
|
result = mk!(self, ExprDef::GetConstField(Box::new(expr), s.to_string())) |
|
|
|
self, |
|
|
|
|
|
|
|
ExprDef::GetConstFieldExpr(Box::new(expr), s.to_string()) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
_ => { |
|
|
|
_ => { |
|
|
|
return Err(ParseError::Expected( |
|
|
|
return Err(ParseError::Expected( |
|
|
@ -634,7 +626,7 @@ impl Parser { |
|
|
|
expect_comma_or_end = true; |
|
|
|
expect_comma_or_end = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
result = mk!(self, ExprDef::CallExpr(Box::new(expr), args)); |
|
|
|
result = mk!(self, ExprDef::Call(Box::new(expr), args)); |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::Question) => { |
|
|
|
TokenData::Punctuator(Punctuator::Question) => { |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
@ -643,7 +635,7 @@ impl Parser { |
|
|
|
let else_e = self.parse()?; |
|
|
|
let else_e = self.parse()?; |
|
|
|
result = mk!( |
|
|
|
result = mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::IfExpr(Box::new(expr), Box::new(if_e), Some(Box::new(else_e))) |
|
|
|
ExprDef::If(Box::new(expr), Box::new(if_e), Some(Box::new(else_e))) |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::OpenBracket) => { |
|
|
|
TokenData::Punctuator(Punctuator::OpenBracket) => { |
|
|
@ -653,7 +645,7 @@ impl Parser { |
|
|
|
TokenData::Punctuator(Punctuator::CloseBracket), |
|
|
|
TokenData::Punctuator(Punctuator::CloseBracket), |
|
|
|
"array index", |
|
|
|
"array index", |
|
|
|
)?; |
|
|
|
)?; |
|
|
|
result = mk!(self, ExprDef::GetFieldExpr(Box::new(expr), Box::new(index))); |
|
|
|
result = mk!(self, ExprDef::GetField(Box::new(expr), Box::new(index))); |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::Semicolon) | TokenData::Comment(_) => { |
|
|
|
TokenData::Punctuator(Punctuator::Semicolon) | TokenData::Comment(_) => { |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
@ -661,17 +653,17 @@ impl Parser { |
|
|
|
TokenData::Punctuator(Punctuator::Assign) => { |
|
|
|
TokenData::Punctuator(Punctuator::Assign) => { |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
|
let next = self.parse()?; |
|
|
|
let next = self.parse()?; |
|
|
|
result = mk!(self, ExprDef::AssignExpr(Box::new(expr), Box::new(next))); |
|
|
|
result = mk!(self, ExprDef::Assign(Box::new(expr), Box::new(next))); |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::Arrow) => { |
|
|
|
TokenData::Punctuator(Punctuator::Arrow) => { |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
|
let mut args = Vec::with_capacity(1); |
|
|
|
let mut args = Vec::with_capacity(1); |
|
|
|
match result.def { |
|
|
|
match result.def { |
|
|
|
ExprDef::LocalExpr(ref name) => args.push((*name).clone()), |
|
|
|
ExprDef::Local(ref name) => args.push((*name).clone()), |
|
|
|
_ => return Err(ParseError::ExpectedExpr("identifier", result)), |
|
|
|
_ => return Err(ParseError::ExpectedExpr("identifier", result)), |
|
|
|
} |
|
|
|
} |
|
|
|
let next = self.parse()?; |
|
|
|
let next = self.parse()?; |
|
|
|
result = mk!(self, ExprDef::ArrowFunctionDeclExpr(args, Box::new(next))); |
|
|
|
result = mk!(self, ExprDef::ArrowFunctionDecl(args, Box::new(next))); |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::Add) => { |
|
|
|
TokenData::Punctuator(Punctuator::Add) => { |
|
|
|
result = self.binop(BinOp::Num(NumOp::Add), expr)? |
|
|
|
result = self.binop(BinOp::Num(NumOp::Add), expr)? |
|
|
@ -736,13 +728,13 @@ impl Parser { |
|
|
|
TokenData::Punctuator(Punctuator::Inc) => { |
|
|
|
TokenData::Punctuator(Punctuator::Inc) => { |
|
|
|
result = mk!( |
|
|
|
result = mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::UnaryOpExpr(UnaryOp::IncrementPost, Box::new(self.parse()?)) |
|
|
|
ExprDef::UnaryOp(UnaryOp::IncrementPost, Box::new(self.parse()?)) |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
TokenData::Punctuator(Punctuator::Dec) => { |
|
|
|
TokenData::Punctuator(Punctuator::Dec) => { |
|
|
|
result = mk!( |
|
|
|
result = mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::UnaryOpExpr(UnaryOp::DecrementPost, Box::new(self.parse()?)) |
|
|
|
ExprDef::UnaryOp(UnaryOp::DecrementPost, Box::new(self.parse()?)) |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
_ => carry_on = false, |
|
|
|
_ => carry_on = false, |
|
|
@ -759,28 +751,28 @@ impl Parser { |
|
|
|
self.pos += 1; |
|
|
|
self.pos += 1; |
|
|
|
let next = self.parse()?; |
|
|
|
let next = self.parse()?; |
|
|
|
Ok(match next.def { |
|
|
|
Ok(match next.def { |
|
|
|
ExprDef::BinOpExpr(ref op2, ref a, ref b) => { |
|
|
|
ExprDef::BinOp(ref op2, ref a, ref b) => { |
|
|
|
let other_precedence = op2.get_precedence(); |
|
|
|
let other_precedence = op2.get_precedence(); |
|
|
|
if precedence < other_precedence || (precedence == other_precedence && !assoc) { |
|
|
|
if precedence < other_precedence || (precedence == other_precedence && !assoc) { |
|
|
|
mk!( |
|
|
|
mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::BinOpExpr( |
|
|
|
ExprDef::BinOp( |
|
|
|
op2.clone(), |
|
|
|
op2.clone(), |
|
|
|
b.clone(), |
|
|
|
b.clone(), |
|
|
|
Box::new(mk!( |
|
|
|
Box::new(mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::BinOpExpr(op.clone(), Box::new(orig), a.clone()) |
|
|
|
ExprDef::BinOp(op.clone(), Box::new(orig), a.clone()) |
|
|
|
)) |
|
|
|
)) |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
mk!( |
|
|
|
mk!( |
|
|
|
self, |
|
|
|
self, |
|
|
|
ExprDef::BinOpExpr(op, Box::new(orig), Box::new(next.clone())) |
|
|
|
ExprDef::BinOp(op, Box::new(orig), Box::new(next.clone())) |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
_ => mk!(self, ExprDef::BinOpExpr(op, Box::new(orig), Box::new(next))), |
|
|
|
_ => mk!(self, ExprDef::BinOp(op, Box::new(orig), Box::new(next))), |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -812,17 +804,17 @@ mod tests { |
|
|
|
|
|
|
|
|
|
|
|
fn check_parser(js: &str, expr: &[Expr]) { |
|
|
|
fn check_parser(js: &str, expr: &[Expr]) { |
|
|
|
let mut lexer = Lexer::new(js); |
|
|
|
let mut lexer = Lexer::new(js); |
|
|
|
lexer.lex().unwrap(); |
|
|
|
lexer.lex().expect("failed to lex"); |
|
|
|
|
|
|
|
|
|
|
|
assert_eq!( |
|
|
|
assert_eq!( |
|
|
|
Parser::new(lexer.tokens).parse_all().unwrap(), |
|
|
|
Parser::new(lexer.tokens).parse_all().unwrap(), |
|
|
|
Expr::new(ExprDef::BlockExpr(expr.into())) |
|
|
|
Expr::new(ExprDef::Block(expr.into())) |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn check_invalid(js: &str) { |
|
|
|
fn check_invalid(js: &str) { |
|
|
|
let mut lexer = Lexer::new(js); |
|
|
|
let mut lexer = Lexer::new(js); |
|
|
|
lexer.lex().unwrap(); |
|
|
|
lexer.lex().expect("failed to lex"); |
|
|
|
|
|
|
|
|
|
|
|
assert!(Parser::new(lexer.tokens).parse_all().is_err()); |
|
|
|
assert!(Parser::new(lexer.tokens).parse_all().is_err()); |
|
|
|
} |
|
|
|
} |
|
|
@ -834,13 +826,13 @@ mod tests { |
|
|
|
// Check empty string
|
|
|
|
// Check empty string
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"\"\"", |
|
|
|
"\"\"", |
|
|
|
&[Expr::new(ExprDef::ConstExpr(Const::String(String::new())))], |
|
|
|
&[Expr::new(ExprDef::Const(Const::String(String::new())))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check non-empty string
|
|
|
|
// Check non-empty string
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"\"hello\"", |
|
|
|
"\"hello\"", |
|
|
|
&[Expr::new(ExprDef::ConstExpr(Const::String(String::from( |
|
|
|
&[Expr::new(ExprDef::Const(Const::String(String::from( |
|
|
|
"hello", |
|
|
|
"hello", |
|
|
|
))))], |
|
|
|
))))], |
|
|
|
); |
|
|
|
); |
|
|
@ -851,76 +843,76 @@ mod tests { |
|
|
|
use crate::syntax::ast::constant::Const; |
|
|
|
use crate::syntax::ast::constant::Const; |
|
|
|
|
|
|
|
|
|
|
|
// Check empty array
|
|
|
|
// Check empty array
|
|
|
|
check_parser("[]", &[Expr::new(ExprDef::ArrayDeclExpr(vec![]))]); |
|
|
|
check_parser("[]", &[Expr::new(ExprDef::ArrayDecl(vec![]))]); |
|
|
|
|
|
|
|
|
|
|
|
// Check array with empty slot
|
|
|
|
// Check array with empty slot
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"[,]", |
|
|
|
"[,]", |
|
|
|
&[Expr::new(ExprDef::ArrayDeclExpr(vec![Expr::new( |
|
|
|
&[Expr::new(ExprDef::ArrayDecl(vec![Expr::new( |
|
|
|
ExprDef::ConstExpr(Const::Undefined), |
|
|
|
ExprDef::Const(Const::Undefined), |
|
|
|
)]))], |
|
|
|
)]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check numeric array
|
|
|
|
// Check numeric array
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"[1, 2, 3]", |
|
|
|
"[1, 2, 3]", |
|
|
|
&[Expr::new(ExprDef::ArrayDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::ArrayDecl(vec![ |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(3.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(3.0))), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check numeric array with trailing comma
|
|
|
|
// Check numeric array with trailing comma
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"[1, 2, 3,]", |
|
|
|
"[1, 2, 3,]", |
|
|
|
&[Expr::new(ExprDef::ArrayDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::ArrayDecl(vec![ |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(3.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(3.0))), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check numeric array with an elision
|
|
|
|
// Check numeric array with an elision
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"[1, 2, , 3]", |
|
|
|
"[1, 2, , 3]", |
|
|
|
&[Expr::new(ExprDef::ArrayDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::ArrayDecl(vec![ |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Undefined)), |
|
|
|
Expr::new(ExprDef::Const(Const::Undefined)), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(3.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(3.0))), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check numeric array with repeated elision
|
|
|
|
// Check numeric array with repeated elision
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"[1, 2, ,, 3]", |
|
|
|
"[1, 2, ,, 3]", |
|
|
|
&[Expr::new(ExprDef::ArrayDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::ArrayDecl(vec![ |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Undefined)), |
|
|
|
Expr::new(ExprDef::Const(Const::Undefined)), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Undefined)), |
|
|
|
Expr::new(ExprDef::Const(Const::Undefined)), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(3.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(3.0))), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check combined array
|
|
|
|
// Check combined array
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"[1, \"a\", 2]", |
|
|
|
"[1, \"a\", 2]", |
|
|
|
&[Expr::new(ExprDef::ArrayDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::ArrayDecl(vec![ |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::String(String::from("a")))), |
|
|
|
Expr::new(ExprDef::Const(Const::String(String::from("a")))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check combined array with empty string
|
|
|
|
// Check combined array with empty string
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"[1, \"\", 2]", |
|
|
|
"[1, \"\", 2]", |
|
|
|
&[Expr::new(ExprDef::ArrayDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::ArrayDecl(vec![ |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::String(String::new()))), |
|
|
|
Expr::new(ExprDef::Const(Const::String(String::new()))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
@ -932,42 +924,39 @@ mod tests { |
|
|
|
// Check `var` declaration
|
|
|
|
// Check `var` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"var a = 5;", |
|
|
|
"var a = 5;", |
|
|
|
&[Expr::new(ExprDef::VarDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::VarDecl(vec![( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(5.0)))), |
|
|
|
)]))], |
|
|
|
)]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check `var` declaration with no spaces
|
|
|
|
// Check `var` declaration with no spaces
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"var a=5;", |
|
|
|
"var a=5;", |
|
|
|
&[Expr::new(ExprDef::VarDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::VarDecl(vec![( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(5.0)))), |
|
|
|
)]))], |
|
|
|
)]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check empty `var` declaration
|
|
|
|
// Check empty `var` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"var a;", |
|
|
|
"var a;", |
|
|
|
&[Expr::new(ExprDef::VarDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::VarDecl(vec![(String::from("a"), None)]))], |
|
|
|
String::from("a"), |
|
|
|
|
|
|
|
None, |
|
|
|
|
|
|
|
)]))], |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check multiple `var` declaration
|
|
|
|
// Check multiple `var` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"var a = 5, b, c = 6;", |
|
|
|
"var a = 5, b, c = 6;", |
|
|
|
&[Expr::new(ExprDef::VarDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::VarDecl(vec![ |
|
|
|
( |
|
|
|
( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(5.0)))), |
|
|
|
), |
|
|
|
), |
|
|
|
(String::from("b"), None), |
|
|
|
(String::from("b"), None), |
|
|
|
( |
|
|
|
( |
|
|
|
String::from("c"), |
|
|
|
String::from("c"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(6.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(6.0)))), |
|
|
|
), |
|
|
|
), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
@ -975,42 +964,39 @@ mod tests { |
|
|
|
// Check `let` declaration
|
|
|
|
// Check `let` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"let a = 5;", |
|
|
|
"let a = 5;", |
|
|
|
&[Expr::new(ExprDef::LetDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::LetDecl(vec![( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(5.0)))), |
|
|
|
)]))], |
|
|
|
)]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check `let` declaration with no spaces
|
|
|
|
// Check `let` declaration with no spaces
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"let a=5;", |
|
|
|
"let a=5;", |
|
|
|
&[Expr::new(ExprDef::LetDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::LetDecl(vec![( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(5.0)))), |
|
|
|
)]))], |
|
|
|
)]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check empty `let` declaration
|
|
|
|
// Check empty `let` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"let a;", |
|
|
|
"let a;", |
|
|
|
&[Expr::new(ExprDef::LetDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::LetDecl(vec![(String::from("a"), None)]))], |
|
|
|
String::from("a"), |
|
|
|
|
|
|
|
None, |
|
|
|
|
|
|
|
)]))], |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check multiple `let` declaration
|
|
|
|
// Check multiple `let` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"let a = 5, b, c = 6;", |
|
|
|
"let a = 5, b, c = 6;", |
|
|
|
&[Expr::new(ExprDef::LetDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::LetDecl(vec![ |
|
|
|
( |
|
|
|
( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(5.0)))), |
|
|
|
), |
|
|
|
), |
|
|
|
(String::from("b"), None), |
|
|
|
(String::from("b"), None), |
|
|
|
( |
|
|
|
( |
|
|
|
String::from("c"), |
|
|
|
String::from("c"), |
|
|
|
Some(Expr::new(ExprDef::ConstExpr(Const::Num(6.0)))), |
|
|
|
Some(Expr::new(ExprDef::Const(Const::Num(6.0)))), |
|
|
|
), |
|
|
|
), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
@ -1018,18 +1004,18 @@ mod tests { |
|
|
|
// Check `const` declaration
|
|
|
|
// Check `const` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"const a = 5;", |
|
|
|
"const a = 5;", |
|
|
|
&[Expr::new(ExprDef::ConstDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::ConstDecl(vec![( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(5.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(5.0))), |
|
|
|
)]))], |
|
|
|
)]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Check `const` declaration with no spaces
|
|
|
|
// Check `const` declaration with no spaces
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"const a=5;", |
|
|
|
"const a=5;", |
|
|
|
&[Expr::new(ExprDef::ConstDeclExpr(vec![( |
|
|
|
&[Expr::new(ExprDef::ConstDecl(vec![( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(5.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(5.0))), |
|
|
|
)]))], |
|
|
|
)]))], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -1039,14 +1025,14 @@ mod tests { |
|
|
|
// Check multiple `const` declaration
|
|
|
|
// Check multiple `const` declaration
|
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"const a = 5, c = 6;", |
|
|
|
"const a = 5, c = 6;", |
|
|
|
&[Expr::new(ExprDef::ConstDeclExpr(vec![ |
|
|
|
&[Expr::new(ExprDef::ConstDecl(vec![ |
|
|
|
( |
|
|
|
( |
|
|
|
String::from("a"), |
|
|
|
String::from("a"), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(5.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(5.0))), |
|
|
|
), |
|
|
|
), |
|
|
|
( |
|
|
|
( |
|
|
|
String::from("c"), |
|
|
|
String::from("c"), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(6.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(6.0))), |
|
|
|
), |
|
|
|
), |
|
|
|
]))], |
|
|
|
]))], |
|
|
|
); |
|
|
|
); |
|
|
@ -1057,7 +1043,7 @@ mod tests { |
|
|
|
use crate::syntax::ast::{constant::Const, op::BinOp}; |
|
|
|
use crate::syntax::ast::{constant::Const, op::BinOp}; |
|
|
|
|
|
|
|
|
|
|
|
fn create_bin_op(op: BinOp, exp1: Expr, exp2: Expr) -> Expr { |
|
|
|
fn create_bin_op(op: BinOp, exp1: Expr, exp2: Expr) -> Expr { |
|
|
|
Expr::new(ExprDef::BinOpExpr(op, Box::new(exp1), Box::new(exp2))) |
|
|
|
Expr::new(ExprDef::BinOp(op, Box::new(exp1), Box::new(exp2))) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Check numeric operations
|
|
|
|
// Check numeric operations
|
|
|
@ -1065,80 +1051,80 @@ mod tests { |
|
|
|
"a + b", |
|
|
|
"a + b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a+1", |
|
|
|
"a+1", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a - b", |
|
|
|
"a - b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Sub), |
|
|
|
BinOp::Num(NumOp::Sub), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a-1", |
|
|
|
"a-1", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Sub), |
|
|
|
BinOp::Num(NumOp::Sub), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a / b", |
|
|
|
"a / b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Div), |
|
|
|
BinOp::Num(NumOp::Div), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a/2", |
|
|
|
"a/2", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Div), |
|
|
|
BinOp::Num(NumOp::Div), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a * b", |
|
|
|
"a * b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Mul), |
|
|
|
BinOp::Num(NumOp::Mul), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a*2", |
|
|
|
"a*2", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Mul), |
|
|
|
BinOp::Num(NumOp::Mul), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a % b", |
|
|
|
"a % b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Mod), |
|
|
|
BinOp::Num(NumOp::Mod), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a%2", |
|
|
|
"a%2", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Mod), |
|
|
|
BinOp::Num(NumOp::Mod), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(2.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(2.0))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -1147,18 +1133,18 @@ mod tests { |
|
|
|
"a + d*(b-3)+1", |
|
|
|
"a + d*(b-3)+1", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
create_bin_op( |
|
|
|
create_bin_op( |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
BinOp::Num(NumOp::Add), |
|
|
|
// FIXME: shouldn't the last addition be on the right?
|
|
|
|
// FIXME: shouldn't the last addition be on the right?
|
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(1.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(1.0))), |
|
|
|
create_bin_op( |
|
|
|
create_bin_op( |
|
|
|
BinOp::Num(NumOp::Mul), |
|
|
|
BinOp::Num(NumOp::Mul), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("d"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("d"))), |
|
|
|
create_bin_op( |
|
|
|
create_bin_op( |
|
|
|
BinOp::Num(NumOp::Sub), |
|
|
|
BinOp::Num(NumOp::Sub), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
Expr::new(ExprDef::ConstExpr(Const::Num(3.0))), |
|
|
|
Expr::new(ExprDef::Const(Const::Num(3.0))), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
@ -1170,16 +1156,16 @@ mod tests { |
|
|
|
"a & b", |
|
|
|
"a & b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::And), |
|
|
|
BinOp::Bit(BitOp::And), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a&b", |
|
|
|
"a&b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::And), |
|
|
|
BinOp::Bit(BitOp::And), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -1187,16 +1173,16 @@ mod tests { |
|
|
|
"a | b", |
|
|
|
"a | b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Or), |
|
|
|
BinOp::Bit(BitOp::Or), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a|b", |
|
|
|
"a|b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Or), |
|
|
|
BinOp::Bit(BitOp::Or), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -1204,16 +1190,16 @@ mod tests { |
|
|
|
"a ^ b", |
|
|
|
"a ^ b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Xor), |
|
|
|
BinOp::Bit(BitOp::Xor), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a^b", |
|
|
|
"a^b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Xor), |
|
|
|
BinOp::Bit(BitOp::Xor), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -1221,16 +1207,16 @@ mod tests { |
|
|
|
"a << b", |
|
|
|
"a << b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Shl), |
|
|
|
BinOp::Bit(BitOp::Shl), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a<<b", |
|
|
|
"a<<b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Shl), |
|
|
|
BinOp::Bit(BitOp::Shl), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -1238,16 +1224,16 @@ mod tests { |
|
|
|
"a >> b", |
|
|
|
"a >> b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Shr), |
|
|
|
BinOp::Bit(BitOp::Shr), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
check_parser( |
|
|
|
check_parser( |
|
|
|
"a>>b", |
|
|
|
"a>>b", |
|
|
|
&[create_bin_op( |
|
|
|
&[create_bin_op( |
|
|
|
BinOp::Bit(BitOp::Shr), |
|
|
|
BinOp::Bit(BitOp::Shr), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("a"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("a"))), |
|
|
|
Expr::new(ExprDef::LocalExpr(String::from("b"))), |
|
|
|
Expr::new(ExprDef::Local(String::from("b"))), |
|
|
|
)], |
|
|
|
)], |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|