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))
}
ExprDef::ConstDeclExpr(ref vars) => {
for var in vars.iter() {
let (name, value) = var.clone();
let val = match value {
Some(v) => self.run(&v)?,
None => Gc::new(ValueData::Null),
};
for (name, value) in vars.iter() {
self.environment
.create_immutable_binding(name.clone(), false);
let val = self.run(&value)?;
self.environment.initialize_binding(&name, val);
}
Ok(Gc::new(ValueData::Undefined))

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

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

68
src/lib/syntax/parser.rs

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

Loading…
Cancel
Save