Browse Source

Updated the definition of constant declarations, it fixes #46 (#60)

pull/65/head
Iban Eguia 5 years ago committed by Jason Williams
parent
commit
b5bd54293b
  1. 8
      src/lib/exec.rs
  2. 19
      src/lib/syntax/ast/expr.rs
  3. 68
      src/lib/syntax/parser.rs

8
src/lib/exec.rs

@ -368,14 +368,10 @@ impl Executor for Interpreter {
Ok(Gc::new(ValueData::Undefined)) Ok(Gc::new(ValueData::Undefined))
} }
ExprDef::ConstDeclExpr(ref vars) => { ExprDef::ConstDeclExpr(ref vars) => {
for var in vars.iter() { for (name, value) in vars.iter() {
let (name, value) = var.clone();
let val = match value {
Some(v) => self.run(&v)?,
None => Gc::new(ValueData::Null),
};
self.environment self.environment
.create_immutable_binding(name.clone(), false); .create_immutable_binding(name.clone(), false);
let val = self.run(&value)?;
self.environment.initialize_binding(&name, val); self.environment.initialize_binding(&name, val);
} }
Ok(Gc::new(ValueData::Undefined)) Ok(Gc::new(ValueData::Undefined))

19
src/lib/syntax/ast/expr.rs

@ -36,7 +36,7 @@ pub enum ExprDef {
/// Make a constant value /// Make a constant value
ConstExpr(Const), ConstExpr(Const),
/// Const declaration /// Const declaration
ConstDeclExpr(Vec<(String, Option<Expr>)>), ConstDeclExpr(Vec<(String, Expr)>),
/// Construct an object from the function and arg{ /// Construct an object from the function and arg{
ConstructExpr(Box<Expr>, Vec<Expr>), ConstructExpr(Box<Expr>, Vec<Expr>),
/// Run several expressions from top-to-bottom /// Run several expressions from top-to-bottom
@ -192,17 +192,26 @@ impl Display for ExprDef {
ExprDef::ReturnExpr(None) => write!(f, "return"), ExprDef::ReturnExpr(None) => write!(f, "return"),
ExprDef::ThrowExpr(ref ex) => write!(f, "throw {}", ex), ExprDef::ThrowExpr(ref ex) => write!(f, "throw {}", ex),
ExprDef::AssignExpr(ref ref_e, ref val) => write!(f, "{} = {}", ref_e, val), ExprDef::AssignExpr(ref ref_e, ref val) => write!(f, "{} = {}", ref_e, val),
ExprDef::VarDeclExpr(ref vars) ExprDef::VarDeclExpr(ref vars) | ExprDef::LetDeclExpr(ref vars) => {
| ExprDef::LetDeclExpr(ref vars) if let ExprDef::VarDeclExpr(_) = *self {
| ExprDef::ConstDeclExpr(ref vars) => {
f.write_str("var ")?; f.write_str("var ")?;
} else {
f.write_str("let ")?;
}
for (key, val) in vars.iter() { for (key, val) in vars.iter() {
match val { match val {
Some(x) => f.write_fmt(format_args!("{} = {}", key, x))?, Some(x) => f.write_fmt(format_args!("{} = {}", key, x))?,
None => f.write_fmt(format_args!("{}", key))?, None => f.write_fmt(format_args!("{}", key))?,
} }
} }
f.write_str("") Ok(())
}
ExprDef::ConstDeclExpr(ref vars) => {
f.write_str("const ")?;
for (key, val) in vars.iter() {
f.write_fmt(format_args!("{} = {}", key, val))?
}
Ok(())
} }
ExprDef::TypeOfExpr(ref e) => write!(f, "typeof {}", e), ExprDef::TypeOfExpr(ref e) => write!(f, "typeof {}", e),
} }

68
src/lib/syntax/parser.rs

@ -74,7 +74,7 @@ impl Parser {
Ok(mk!(self, ExprDef::ThrowExpr(Box::new(thrown)))) Ok(mk!(self, ExprDef::ThrowExpr(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::Const => { Keyword::Var | Keyword::Let => {
let mut vars = Vec::new(); let mut vars = Vec::new();
loop { loop {
let name = match self.get_token(self.pos) { let name = match self.get_token(self.pos) {
@ -86,7 +86,7 @@ impl Parser {
return Err(ParseError::Expected( return Err(ParseError::Expected(
vec![TokenData::Identifier("identifier".to_string())], vec![TokenData::Identifier("identifier".to_string())],
tok, tok,
"var statement", "var/let declaration",
)) ))
} }
Err(ParseError::AbruptEnd) => break, Err(ParseError::AbruptEnd) => break,
@ -125,10 +125,57 @@ impl Parser {
match keyword { match keyword {
Keyword::Let => Ok(Expr::new(ExprDef::LetDeclExpr(vars))), Keyword::Let => Ok(Expr::new(ExprDef::LetDeclExpr(vars))),
Keyword::Const => Ok(Expr::new(ExprDef::ConstDeclExpr(vars))),
_ => Ok(Expr::new(ExprDef::VarDeclExpr(vars))), _ => Ok(Expr::new(ExprDef::VarDeclExpr(vars))),
} }
} }
Keyword::Const => {
let mut vars = Vec::new();
loop {
let name = match self.get_token(self.pos) {
Ok(Token {
data: TokenData::Identifier(ref name),
..
}) => name.clone(),
Ok(tok) => {
return Err(ParseError::Expected(
vec![TokenData::Identifier("identifier".to_string())],
tok,
"const declaration",
))
}
Err(ParseError::AbruptEnd) => break,
Err(e) => return Err(e),
};
self.pos += 1;
match self.get_token(self.pos) {
Ok(Token {
data: TokenData::Punctuator(Punctuator::Assign),
..
}) => {
self.pos += 1;
let val = self.parse()?;
vars.push((name, val));
match self.get_token(self.pos) {
Ok(Token {
data: TokenData::Punctuator(Punctuator::Comma),
..
}) => self.pos += 1,
_ => break,
}
}
Ok(tok) => {
return Err(ParseError::Expected(
vec![TokenData::Punctuator(Punctuator::Assign)],
tok,
"const declration",
))
}
_ => break,
}
}
Ok(Expr::new(ExprDef::ConstDeclExpr(vars)))
}
Keyword::Return => Ok(mk!( Keyword::Return => Ok(mk!(
self, self,
ExprDef::ReturnExpr(Some(Box::new(self.parse()?.clone()))) ExprDef::ReturnExpr(Some(Box::new(self.parse()?.clone())))
@ -947,7 +994,7 @@ mod tests {
"const a = 5;", "const a = 5;",
&[Expr::new(ExprDef::ConstDeclExpr(vec![( &[Expr::new(ExprDef::ConstDeclExpr(vec![(
String::from("a"), String::from("a"),
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), Expr::new(ExprDef::ConstExpr(Const::Num(5.0))),
)]))], )]))],
); );
@ -956,27 +1003,24 @@ mod tests {
"const a=5;", "const a=5;",
&[Expr::new(ExprDef::ConstDeclExpr(vec![( &[Expr::new(ExprDef::ConstDeclExpr(vec![(
String::from("a"), String::from("a"),
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), Expr::new(ExprDef::ConstExpr(Const::Num(5.0))),
)]))], )]))],
); );
// Check empty `const` declaration // Check empty `const` declaration
// FIXME: This does not work, it should fail to parse an unitialized const declaration: check_invalid("const a;");
// <https://tc39.es/ecma262/#sec-let-and-const-declarations-static-semantics-early-errors>
// check_invalid("const a;");
// Check multiple `const` declaration // Check multiple `const` declaration
check_parser( check_parser(
"const a = 5, b, c = 6;", "const a = 5, c = 6;",
&[Expr::new(ExprDef::ConstDeclExpr(vec![ &[Expr::new(ExprDef::ConstDeclExpr(vec![
( (
String::from("a"), String::from("a"),
Some(Expr::new(ExprDef::ConstExpr(Const::Num(5.0)))), Expr::new(ExprDef::ConstExpr(Const::Num(5.0))),
), ),
(String::from("b"), None),
( (
String::from("c"), String::from("c"),
Some(Expr::new(ExprDef::ConstExpr(Const::Num(6.0)))), Expr::new(ExprDef::ConstExpr(Const::Num(6.0))),
), ),
]))], ]))],
); );

Loading…
Cancel
Save