Browse Source

clippy changes, including benchmark updates for more accuracy, fixes #84

pull/86/head
Jason Williams 5 years ago committed by GitHub
parent
commit
111d232c94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      Cargo.lock
  2. 25
      benches/string.rs
  3. 4
      src/lib/environment/declerative_environment_record.rs
  4. 2
      src/lib/environment/environment_record_trait.rs
  5. 4
      src/lib/environment/function_environment_record.rs
  6. 5
      src/lib/environment/global_environment_record.rs
  7. 2
      src/lib/environment/lexical_environment.rs
  8. 4
      src/lib/environment/object_environment_record.rs
  9. 84
      src/lib/exec.rs
  10. 14
      src/lib/js/array.rs
  11. 4
      src/lib/js/console.rs
  12. 9
      src/lib/js/error.rs
  13. 7
      src/lib/js/function.rs
  14. 12
      src/lib/js/json.rs
  15. 2
      src/lib/js/object.rs
  16. 5
      src/lib/js/string.rs
  17. 2
      src/lib/js/value.rs
  18. 9
      src/lib/lib.rs
  19. 132
      src/lib/syntax/ast/expr.rs
  20. 19
      src/lib/syntax/lexer.rs
  21. 324
      src/lib/syntax/parser.rs

2
Cargo.lock generated

@ -2,7 +2,7 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "Boa" name = "Boa"
version = "0.2.2" version = "0.3.0"
dependencies = [ dependencies = [
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",

25
benches/string.rs

@ -13,20 +13,27 @@ fn hello_world_lexer(c: &mut Criterion) {
c.bench_function("Hello World (Lexer)", move |b| { c.bench_function("Hello World (Lexer)", move |b| {
b.iter(|| { b.iter(|| {
let mut lexer = Lexer::new(black_box(SRC)); let mut lexer = Lexer::new(black_box(SRC));
let _ = lexer.lex(); // return the value into the blackbox so its not optimized away
// https://gist.github.com/jasonwilliams/5325da61a794d8211dcab846d466c4fd
lexer.lex()
}) })
}); });
} }
fn hello_world_parser(c: &mut Criterion) { fn hello_world_parser(c: &mut Criterion) {
c.bench_function("Hello World (Parser)", move |b| { // Don't include lexing as part of the parser benchmark
b.iter(|| { let mut lexer = Lexer::new(SRC);
let mut lexer = Lexer::new(SRC); lexer.lex().expect("failed to lex");
lexer.lex().unwrap(); let tokens = lexer.tokens;
let tokens = lexer.tokens; c.bench_function_over_inputs(
Parser::new(black_box(tokens)).parse_all().unwrap(); "Hello World (Parser)",
}) move |b, tok| {
}); b.iter(|| {
Parser::new(black_box(tok.to_vec())).parse_all().unwrap();
})
},
vec![tokens],
);
} }
fn hello_world(c: &mut Criterion) { fn hello_world(c: &mut Criterion) {

4
src/lib/environment/declerative_environment_record.rs

@ -59,7 +59,7 @@ impl EnvironmentRecordTrait for DeclerativeEnvironmentRecord {
); );
} }
fn create_immutable_binding(&mut self, name: String, strict: bool) { fn create_immutable_binding(&mut self, name: String, strict: bool) -> bool {
if self.env_rec.contains_key(&name) { if self.env_rec.contains_key(&name) {
// TODO: change this when error handling comes into play // TODO: change this when error handling comes into play
panic!("Identifier {} has already been declared", name); panic!("Identifier {} has already been declared", name);
@ -74,6 +74,8 @@ impl EnvironmentRecordTrait for DeclerativeEnvironmentRecord {
strict, strict,
}, },
); );
true
} }
fn initialize_binding(&mut self, name: &str, value: Value) { fn initialize_binding(&mut self, name: &str, value: Value) {

2
src/lib/environment/environment_record_trait.rs

@ -31,7 +31,7 @@ pub trait EnvironmentRecordTrait: Debug + Trace + Finalize {
/// The String value N is the text of the bound name. /// The String value N is the text of the bound name.
/// If strict is true then attempts to set it after it has been initialized will always throw an exception, /// If strict is true then attempts to set it after it has been initialized will always throw an exception,
/// regardless of the strict mode setting of operations that reference that binding. /// regardless of the strict mode setting of operations that reference that binding.
fn create_immutable_binding(&mut self, name: String, strict: bool); fn create_immutable_binding(&mut self, name: String, strict: bool) -> bool;
/// Set the value of an already existing but uninitialized binding in an Environment Record. /// Set the value of an already existing but uninitialized binding in an Environment Record.
/// The String value N is the text of the bound name. /// The String value N is the text of the bound name.

4
src/lib/environment/function_environment_record.rs

@ -116,7 +116,7 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
); );
} }
fn create_immutable_binding(&mut self, name: String, strict: bool) { fn create_immutable_binding(&mut self, name: String, strict: bool) -> bool {
if self.env_rec.contains_key(&name) { if self.env_rec.contains_key(&name) {
// TODO: change this when error handling comes into play // TODO: change this when error handling comes into play
panic!("Identifier {} has already been declared", name); panic!("Identifier {} has already been declared", name);
@ -131,6 +131,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
strict, strict,
}, },
); );
true
} }
fn initialize_binding(&mut self, name: &str, value: Value) { fn initialize_binding(&mut self, name: &str, value: Value) {

5
src/lib/environment/global_environment_record.rs

@ -108,11 +108,12 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
.create_mutable_binding(name.clone(), deletion) .create_mutable_binding(name.clone(), deletion)
} }
fn create_immutable_binding(&mut self, name: String, strict: bool) { fn create_immutable_binding(&mut self, name: String, strict: bool) -> bool {
if self.declerative_record.has_binding(&name) { if self.declerative_record.has_binding(&name) {
// TODO: change to exception // TODO: change to exception
panic!("Binding already exists!"); panic!("Binding already exists!");
} }
self.declerative_record self.declerative_record
.create_immutable_binding(name.clone(), strict) .create_immutable_binding(name.clone(), strict)
} }
@ -178,7 +179,7 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
} }
fn set_outer_environment(&mut self, _env: Environment) { fn set_outer_environment(&mut self, _env: Environment) {
unimplemented!() unimplemented!();
} }
fn get_environment_type(&self) -> EnvironmentType { fn get_environment_type(&self) -> EnvironmentType {

2
src/lib/environment/lexical_environment.rs

@ -101,7 +101,7 @@ impl LexicalEnvironment {
.create_mutable_binding(name, deletion) .create_mutable_binding(name, deletion)
} }
pub fn create_immutable_binding(&mut self, name: String, deletion: bool) { pub fn create_immutable_binding(&mut self, name: String, deletion: bool) -> bool {
self.get_current_environment() self.get_current_environment()
.borrow_mut() .borrow_mut()
.create_immutable_binding(name, deletion) .create_immutable_binding(name, deletion)

4
src/lib/environment/object_environment_record.rs

@ -50,8 +50,8 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord {
bindings.set_prop(name, prop); bindings.set_prop(name, prop);
} }
fn create_immutable_binding(&mut self, _name: String, _strict: bool) { fn create_immutable_binding(&mut self, _name: String, _strict: bool) -> bool {
unimplemented!() true
} }
fn initialize_binding(&mut self, name: &str, value: Value) { fn initialize_binding(&mut self, name: &str, value: Value) {

84
src/lib/exec.rs

@ -50,17 +50,17 @@ impl Executor for Interpreter {
#[allow(clippy::match_same_arms)] #[allow(clippy::match_same_arms)]
fn run(&mut self, expr: &Expr) -> ResultValue { fn run(&mut self, expr: &Expr) -> ResultValue {
match expr.def { match expr.def {
ExprDef::ConstExpr(Const::Null) => Ok(to_value(None::<()>)), ExprDef::Const(Const::Null) => Ok(to_value(None::<()>)),
ExprDef::ConstExpr(Const::Undefined) => Ok(Gc::new(ValueData::Undefined)), ExprDef::Const(Const::Undefined) => Ok(Gc::new(ValueData::Undefined)),
ExprDef::ConstExpr(Const::Num(num)) => Ok(to_value(num)), ExprDef::Const(Const::Num(num)) => Ok(to_value(num)),
ExprDef::ConstExpr(Const::Int(num)) => Ok(to_value(num)), ExprDef::Const(Const::Int(num)) => Ok(to_value(num)),
// we can't move String from Const into value, because const is a garbage collected value // we can't move String from Const into value, because const is a garbage collected value
// Which means Drop() get's called on Const, but str will be gone at that point. // Which means Drop() get's called on Const, but str will be gone at that point.
// Do Const values need to be garbage collected? We no longer need them once we've generated Values // Do Const values need to be garbage collected? We no longer need them once we've generated Values
ExprDef::ConstExpr(Const::String(ref str)) => Ok(to_value(str.to_owned())), ExprDef::Const(Const::String(ref str)) => Ok(to_value(str.to_owned())),
ExprDef::ConstExpr(Const::Bool(val)) => Ok(to_value(val)), ExprDef::Const(Const::Bool(val)) => Ok(to_value(val)),
ExprDef::ConstExpr(Const::RegExp(_, _, _)) => Ok(to_value(None::<()>)), ExprDef::Const(Const::RegExp(_, _, _)) => Ok(to_value(None::<()>)),
ExprDef::BlockExpr(ref es) => { ExprDef::Block(ref es) => {
let mut obj = to_value(None::<()>); let mut obj = to_value(None::<()>);
for e in es.iter() { for e in es.iter() {
let val = self.run(e)?; let val = self.run(e)?;
@ -70,26 +70,26 @@ impl Executor for Interpreter {
} }
Ok(obj) Ok(obj)
} }
ExprDef::LocalExpr(ref name) => { ExprDef::Local(ref name) => {
let val = self.environment.get_binding_value(name); let val = self.environment.get_binding_value(name);
Ok(val) Ok(val)
} }
ExprDef::GetConstFieldExpr(ref obj, ref field) => { ExprDef::GetConstField(ref obj, ref field) => {
let val_obj = self.run(obj)?; let val_obj = self.run(obj)?;
Ok(val_obj.borrow().get_field(field)) Ok(val_obj.borrow().get_field(field))
} }
ExprDef::GetFieldExpr(ref obj, ref field) => { ExprDef::GetField(ref obj, ref field) => {
let val_obj = self.run(obj)?; let val_obj = self.run(obj)?;
let val_field = self.run(field)?; let val_field = self.run(field)?;
Ok(val_obj.borrow().get_field(&val_field.borrow().to_string())) Ok(val_obj.borrow().get_field(&val_field.borrow().to_string()))
} }
ExprDef::CallExpr(ref callee, ref args) => { ExprDef::Call(ref callee, ref args) => {
let (this, func) = match callee.def { let (this, func) = match callee.def {
ExprDef::GetConstFieldExpr(ref obj, ref field) => { ExprDef::GetConstField(ref obj, ref field) => {
let obj = self.run(obj)?; let obj = self.run(obj)?;
(obj.clone(), obj.borrow().get_field(field)) (obj.clone(), obj.borrow().get_field(field))
} }
ExprDef::GetFieldExpr(ref obj, ref field) => { ExprDef::GetField(ref obj, ref field) => {
let obj = self.run(obj)?; let obj = self.run(obj)?;
let field = self.run(field)?; let field = self.run(field)?;
( (
@ -135,28 +135,26 @@ impl Executor for Interpreter {
_ => Err(Gc::new(ValueData::Undefined)), _ => Err(Gc::new(ValueData::Undefined)),
} }
} }
ExprDef::WhileLoopExpr(ref cond, ref expr) => { ExprDef::WhileLoop(ref cond, ref expr) => {
let mut result = Gc::new(ValueData::Undefined); let mut result = Gc::new(ValueData::Undefined);
while self.run(cond)?.borrow().is_true() { while self.run(cond)?.borrow().is_true() {
result = self.run(expr)?; result = self.run(expr)?;
} }
Ok(result) Ok(result)
} }
ExprDef::IfExpr(ref cond, ref expr, None) => { ExprDef::If(ref cond, ref expr, None) => Ok(if self.run(cond)?.borrow().is_true() {
Ok(if self.run(cond)?.borrow().is_true() { self.run(expr)?
self.run(expr)? } else {
} else { Gc::new(ValueData::Undefined)
Gc::new(ValueData::Undefined) }),
}) ExprDef::If(ref cond, ref expr, Some(ref else_e)) => {
}
ExprDef::IfExpr(ref cond, ref expr, Some(ref else_e)) => {
Ok(if self.run(cond)?.borrow().is_true() { Ok(if self.run(cond)?.borrow().is_true() {
self.run(expr)? self.run(expr)?
} else { } else {
self.run(else_e)? self.run(else_e)?
}) })
} }
ExprDef::SwitchExpr(ref val_e, ref vals, ref default) => { ExprDef::Switch(ref val_e, ref vals, ref default) => {
let val = self.run(val_e)?.clone(); let val = self.run(val_e)?.clone();
let mut result = Gc::new(ValueData::Null); let mut result = Gc::new(ValueData::Null);
let mut matched = false; let mut matched = false;
@ -180,7 +178,7 @@ impl Executor for Interpreter {
} }
Ok(result) Ok(result)
} }
ExprDef::ObjectDeclExpr(ref map) => { ExprDef::ObjectDecl(ref map) => {
let global_val = &self.environment.get_global_object().unwrap(); let global_val = &self.environment.get_global_object().unwrap();
let obj = ValueData::new_obj(Some(global_val)); let obj = ValueData::new_obj(Some(global_val));
for (key, val) in map.iter() { for (key, val) in map.iter() {
@ -188,7 +186,7 @@ impl Executor for Interpreter {
} }
Ok(obj) Ok(obj)
} }
ExprDef::ArrayDeclExpr(ref arr) => { ExprDef::ArrayDecl(ref arr) => {
let global_val = &self.environment.get_global_object().unwrap(); let global_val = &self.environment.get_global_object().unwrap();
let arr_map = ValueData::new_obj(Some(global_val)); let arr_map = ValueData::new_obj(Some(global_val));
// Note that this object is an Array // Note that this object is an Array
@ -209,7 +207,7 @@ impl Executor for Interpreter {
arr_map.borrow().set_field_slice("length", to_value(index)); arr_map.borrow().set_field_slice("length", to_value(index));
Ok(arr_map) Ok(arr_map)
} }
ExprDef::FunctionDeclExpr(ref name, ref args, ref expr) => { ExprDef::FunctionDecl(ref name, ref args, ref expr) => {
let function = let function =
Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone())); Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
let val = Gc::new(ValueData::Function(Box::new(GcCell::new(function)))); let val = Gc::new(ValueData::Function(Box::new(GcCell::new(function))));
@ -221,14 +219,14 @@ impl Executor for Interpreter {
} }
Ok(val) Ok(val)
} }
ExprDef::ArrowFunctionDeclExpr(ref args, ref expr) => { ExprDef::ArrowFunctionDecl(ref args, ref expr) => {
let function = let function =
Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone())); Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
Ok(Gc::new(ValueData::Function(Box::new(GcCell::new( Ok(Gc::new(ValueData::Function(Box::new(GcCell::new(
function, function,
))))) )))))
} }
ExprDef::BinOpExpr(BinOp::Num(ref op), ref a, ref b) => { ExprDef::BinOp(BinOp::Num(ref op), ref a, ref b) => {
let v_r_a = self.run(a)?; let v_r_a = self.run(a)?;
let v_r_b = self.run(b)?; let v_r_b = self.run(b)?;
let v_a = (*v_r_a).clone(); let v_a = (*v_r_a).clone();
@ -241,7 +239,7 @@ impl Executor for Interpreter {
NumOp::Mod => v_a % v_b, NumOp::Mod => v_a % v_b,
})) }))
} }
ExprDef::UnaryOpExpr(ref op, ref a) => { ExprDef::UnaryOp(ref op, ref a) => {
let v_r_a = self.run(a)?; let v_r_a = self.run(a)?;
let v_a = (*v_r_a).clone(); let v_a = (*v_r_a).clone();
Ok(match *op { Ok(match *op {
@ -251,7 +249,7 @@ impl Executor for Interpreter {
_ => unreachable!(), _ => unreachable!(),
}) })
} }
ExprDef::BinOpExpr(BinOp::Bit(ref op), ref a, ref b) => { ExprDef::BinOp(BinOp::Bit(ref op), ref a, ref b) => {
let v_r_a = self.run(a)?; let v_r_a = self.run(a)?;
let v_r_b = self.run(b)?; let v_r_b = self.run(b)?;
let v_a = (*v_r_a).clone(); let v_a = (*v_r_a).clone();
@ -264,7 +262,7 @@ impl Executor for Interpreter {
BitOp::Shr => v_a >> v_b, BitOp::Shr => v_a >> v_b,
})) }))
} }
ExprDef::BinOpExpr(BinOp::Comp(ref op), ref a, ref b) => { ExprDef::BinOp(BinOp::Comp(ref op), ref a, ref b) => {
let v_r_a = self.run(a)?; let v_r_a = self.run(a)?;
let v_r_b = self.run(b)?; let v_r_b = self.run(b)?;
let v_a = v_r_a.borrow(); let v_a = v_r_a.borrow();
@ -284,7 +282,7 @@ impl Executor for Interpreter {
CompOp::LessThanOrEqual => v_a.to_num() <= v_b.to_num(), CompOp::LessThanOrEqual => v_a.to_num() <= v_b.to_num(),
})) }))
} }
ExprDef::BinOpExpr(BinOp::Log(ref op), ref a, ref b) => { ExprDef::BinOp(BinOp::Log(ref op), ref a, ref b) => {
let v_a = from_value::<bool>(self.run(a)?).unwrap(); let v_a = from_value::<bool>(self.run(a)?).unwrap();
let v_b = from_value::<bool>(self.run(b)?).unwrap(); let v_b = from_value::<bool>(self.run(b)?).unwrap();
Ok(match *op { Ok(match *op {
@ -292,7 +290,7 @@ impl Executor for Interpreter {
LogOp::Or => to_value(v_a || v_b), LogOp::Or => to_value(v_a || v_b),
}) })
} }
ExprDef::ConstructExpr(ref callee, ref args) => { ExprDef::Construct(ref callee, ref args) => {
let func = self.run(callee)?; let func = self.run(callee)?;
let mut v_args = Vec::with_capacity(args.len()); let mut v_args = Vec::with_capacity(args.len());
for arg in args.iter() { for arg in args.iter() {
@ -331,19 +329,19 @@ impl Executor for Interpreter {
_ => Ok(Gc::new(ValueData::Undefined)), _ => Ok(Gc::new(ValueData::Undefined)),
} }
} }
ExprDef::ReturnExpr(ref ret) => match *ret { ExprDef::Return(ref ret) => match *ret {
Some(ref v) => self.run(v), Some(ref v) => self.run(v),
None => Ok(Gc::new(ValueData::Undefined)), None => Ok(Gc::new(ValueData::Undefined)),
}, },
ExprDef::ThrowExpr(ref ex) => Err(self.run(ex)?), ExprDef::Throw(ref ex) => Err(self.run(ex)?),
ExprDef::AssignExpr(ref ref_e, ref val_e) => { ExprDef::Assign(ref ref_e, ref val_e) => {
let val = self.run(val_e)?; let val = self.run(val_e)?;
match ref_e.def { match ref_e.def {
ExprDef::LocalExpr(ref name) => { ExprDef::Local(ref name) => {
self.environment.create_mutable_binding(name.clone(), false); self.environment.create_mutable_binding(name.clone(), false);
self.environment.initialize_binding(name, val.clone()); self.environment.initialize_binding(name, val.clone());
} }
ExprDef::GetConstFieldExpr(ref obj, ref field) => { ExprDef::GetConstField(ref obj, ref field) => {
let val_obj = self.run(obj)?; let val_obj = self.run(obj)?;
val_obj.borrow().set_field(field.clone(), val.clone()); val_obj.borrow().set_field(field.clone(), val.clone());
} }
@ -351,7 +349,7 @@ impl Executor for Interpreter {
} }
Ok(val) Ok(val)
} }
ExprDef::VarDeclExpr(ref vars) => { ExprDef::VarDecl(ref vars) => {
for var in vars.iter() { for var in vars.iter() {
let (name, value) = var.clone(); let (name, value) = var.clone();
let val = match value { let val = match value {
@ -363,7 +361,7 @@ impl Executor for Interpreter {
} }
Ok(Gc::new(ValueData::Undefined)) Ok(Gc::new(ValueData::Undefined))
} }
ExprDef::LetDeclExpr(ref vars) => { ExprDef::LetDecl(ref vars) => {
for var in vars.iter() { for var in vars.iter() {
let (name, value) = var.clone(); let (name, value) = var.clone();
let val = match value { let val = match value {
@ -375,7 +373,7 @@ impl Executor for Interpreter {
} }
Ok(Gc::new(ValueData::Undefined)) Ok(Gc::new(ValueData::Undefined))
} }
ExprDef::ConstDeclExpr(ref vars) => { ExprDef::ConstDecl(ref vars) => {
for (name, value) in vars.iter() { for (name, value) in vars.iter() {
self.environment self.environment
.create_immutable_binding(name.clone(), false); .create_immutable_binding(name.clone(), false);
@ -384,7 +382,7 @@ impl Executor for Interpreter {
} }
Ok(Gc::new(ValueData::Undefined)) Ok(Gc::new(ValueData::Undefined))
} }
ExprDef::TypeOfExpr(ref val_e) => { ExprDef::TypeOf(ref val_e) => {
let val = self.run(val_e)?; let val = self.run(val_e)?;
Ok(to_value(match *val { Ok(to_value(match *val {
ValueData::Undefined => "undefined", ValueData::Undefined => "undefined",

14
src/lib/js/array.rs

@ -14,7 +14,8 @@ fn create_array_object(array_obj: &Value, array_contents: &[Value]) -> ResultVal
let array_obj_ptr = array_obj.clone(); let array_obj_ptr = array_obj.clone();
// Wipe existing contents of the array object // Wipe existing contents of the array object
let orig_length: i32 = from_value(array_obj.get_field_slice("length")).unwrap(); let orig_length: i32 =
from_value(array_obj.get_field_slice("length")).expect("failed to convert length to i32");
for n in 0..orig_length { for n in 0..orig_length {
array_obj_ptr.remove_prop(&n.to_string()); array_obj_ptr.remove_prop(&n.to_string());
} }
@ -29,7 +30,8 @@ fn create_array_object(array_obj: &Value, array_contents: &[Value]) -> ResultVal
/// Utility function which takes an existing array object and puts additional /// Utility function which takes an existing array object and puts additional
/// values on the end, correctly rewriting the length /// values on the end, correctly rewriting the length
fn add_to_array_object(array_ptr: &Value, add_values: &[Value]) -> ResultValue { fn add_to_array_object(array_ptr: &Value, add_values: &[Value]) -> ResultValue {
let orig_length: i32 = from_value(array_ptr.get_field_slice("length")).unwrap(); let orig_length: i32 =
from_value(array_ptr.get_field_slice("length")).expect("failed to conveert lenth to i32");
for (n, value) in add_values.iter().enumerate() { for (n, value) in add_values.iter().enumerate() {
let new_index = orig_length + (n as i32); let new_index = orig_length + (n as i32);
@ -296,16 +298,16 @@ mod tests {
"#; "#;
forward(&mut engine, init); forward(&mut engine, init);
// Empty ++ Empty // Empty ++ Empty
let ee = forward(&mut engine, "empty.concat(empty)"); let _ee = forward(&mut engine, "empty.concat(empty)");
//assert_eq!(ee, String::from("")); //assert_eq!(ee, String::from(""));
// Empty ++ NonEmpty // Empty ++ NonEmpty
let en = forward(&mut engine, "empty.concat(one)"); let _en = forward(&mut engine, "empty.concat(one)");
//assert_eq!(en, String::from("a")); //assert_eq!(en, String::from("a"));
// NonEmpty ++ Empty // NonEmpty ++ Empty
let ne = forward(&mut engine, "one.concat(empty)"); let _ne = forward(&mut engine, "one.concat(empty)");
//assert_eq!(ne, String::from("a.b.c")); //assert_eq!(ne, String::from("a.b.c"));
// NonEmpty ++ NonEmpty // NonEmpty ++ NonEmpty
let nn = forward(&mut engine, "one.concat(one)"); let _nn = forward(&mut engine, "one.concat(one)");
//assert_eq!(nn, String::from("a.b.c")); //assert_eq!(nn, String::from("a.b.c"));
} }

4
src/lib/js/console.rs

@ -23,10 +23,10 @@ fn log_string_from(x: Value) -> String {
v.borrow() v.borrow()
.internal_slots .internal_slots
.get("PrimitiveValue") .get("PrimitiveValue")
.unwrap() .expect("Cannot get primitive value from String")
.clone(), .clone(),
) )
.unwrap(); .expect("Cannot clone primitive value from String");
write!(s, "{}", str_val).unwrap(); write!(s, "{}", str_val).unwrap();
} }
ObjectKind::Array => { ObjectKind::Array => {

9
src/lib/js/error.rs

@ -11,7 +11,14 @@ use gc::Gc;
/// Create a new error /// Create a new error
pub fn make_error(this: &Value, args: &[Value], _: &Interpreter) -> ResultValue { pub fn make_error(this: &Value, args: &[Value], _: &Interpreter) -> ResultValue {
if !args.is_empty() { if !args.is_empty() {
this.set_field_slice("message", to_value(args.get(0).unwrap().to_string())); this.set_field_slice(
"message",
to_value(
args.get(0)
.expect("failed getting error message")
.to_string(),
),
);
} }
// This value is used by console.log and other routines to match Object type // This value is used by console.log and other routines to match Object type
// to its Javascript Identifier (global constructor method name) // to its Javascript Identifier (global constructor method name)

7
src/lib/js/function.rs

@ -40,6 +40,7 @@ pub struct RegularFunction {
impl RegularFunction { impl RegularFunction {
/// Make a new regular function /// Make a new regular function
#[allow(clippy::cast_possible_wrap)]
pub fn new(expr: Expr, args: Vec<String>) -> Self { pub fn new(expr: Expr, args: Vec<String>) -> Self {
let mut object = ObjectData::default(); let mut object = ObjectData::default();
object.properties.insert( object.properties.insert(
@ -69,7 +70,11 @@ impl NativeFunction {
impl Debug for NativeFunction { impl Debug for NativeFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:?})", self.object) write!(f, "{{")?;
for (key, val) in self.object.properties.iter() {
write!(f, "{}: {}", key, val.value.clone())?;
}
write!(f, "}}")
} }
} }

12
src/lib/js/json.rs

@ -8,16 +8,22 @@ use serde_json::{self, to_string_pretty, Value as JSONValue};
/// Parse a JSON string into a Javascript object /// Parse a JSON string into a Javascript object
/// <https://tc39.github.io/ecma262/#sec-json.parse> /// <https://tc39.github.io/ecma262/#sec-json.parse>
pub fn parse(_: &Value, args: &[Value], _: &Interpreter) -> ResultValue { pub fn parse(_: &Value, args: &[Value], _: &Interpreter) -> ResultValue {
match serde_json::from_str::<JSONValue>(&args.get(0).unwrap().clone().to_string()) { match serde_json::from_str::<JSONValue>(
&args
.get(0)
.expect("cannot get argument for JSON.parse")
.clone()
.to_string(),
) {
Ok(json) => Ok(to_value(json)), Ok(json) => Ok(to_value(json)),
Err(err) => Err(to_value(err.to_string())), Err(err) => Err(to_value(err.to_string())),
} }
} }
/// Process a Javascript object into a JSON string /// Process a Javascript object into a JSON string
pub fn stringify(_: &Value, args: &[Value], _: &Interpreter) -> ResultValue { pub fn stringify(_: &Value, args: &[Value], _: &Interpreter) -> ResultValue {
let obj = args.get(0).unwrap(); let obj = args.get(0).expect("cannot get argument for JSON.stringify");
let json = obj.to_json(); let json = obj.to_json();
Ok(to_value(to_string_pretty(&json).unwrap())) Ok(to_value(to_string_pretty(&json).expect("")))
} }
/// Create a new `JSON` object /// Create a new `JSON` object

2
src/lib/js/object.rs

@ -32,7 +32,7 @@ pub struct ObjectData {
impl ObjectData { impl ObjectData {
/// Return a new ObjectData struct, with `kind` set to Ordinary /// Return a new ObjectData struct, with `kind` set to Ordinary
pub fn default() -> ObjectData { pub fn default() -> Self {
Self { Self {
kind: ObjectKind::Ordinary, kind: ObjectKind::Ordinary,
internal_slots: Box::new(HashMap::new()), internal_slots: Box::new(HashMap::new()),

5
src/lib/js/string.rs

@ -7,7 +7,6 @@ use crate::{
}, },
}; };
use gc::Gc; use gc::Gc;
use gc_derive::{Finalize, Trace};
use std::{ use std::{
cmp::{max, min}, cmp::{max, min},
f64::NAN, f64::NAN,
@ -544,8 +543,8 @@ mod tests {
const nice = new String('Have a nice day.'); const nice = new String('Have a nice day.');
"#; "#;
forward(&mut engine, init); forward(&mut engine, init);
let a = forward(&mut engine, "hello.concat(world, nice)"); let _a = forward(&mut engine, "hello.concat(world, nice)");
let b = forward(&mut engine, "hello + world + nice"); let _b = forward(&mut engine, "hello + world + nice");
// Todo: fix this // Todo: fix this
//assert_eq!(a, String::from("Hello, world! Have a nice day.")); //assert_eq!(a, String::from("Hello, world! Have a nice day."));
//assert_eq!(b, String::from("Hello, world! Have a nice day.")); //assert_eq!(b, String::from("Hello, world! Have a nice day."));

2
src/lib/js/value.rs

@ -46,7 +46,7 @@ impl ValueData {
if global.is_some() { if global.is_some() {
let obj_proto = global let obj_proto = global
.unwrap() .expect("Expected global object in making-new-object")
.get_field_slice("Object") .get_field_slice("Object")
.get_field_slice(PROTOTYPE); .get_field_slice(PROTOTYPE);
obj.properties obj.properties

9
src/lib/lib.rs

@ -23,7 +23,10 @@
clippy::missing_docs_in_private_items, clippy::missing_docs_in_private_items,
clippy::missing_inline_in_public_items, clippy::missing_inline_in_public_items,
clippy::implicit_return, clippy::implicit_return,
clippy::wildcard_enum_match_arm clippy::wildcard_enum_match_arm,
clippy::cognitive_complexity,
clippy::module_name_repetitions,
clippy::print_stdout
)] )]
pub mod environment; pub mod environment;
@ -47,9 +50,9 @@ extern "C" {
fn parser_expr(src: &str) -> Expr { fn parser_expr(src: &str) -> Expr {
let mut lexer = Lexer::new(src); let mut lexer = Lexer::new(src);
lexer.lex().unwrap(); lexer.lex().expect("lexing failed");
let tokens = lexer.tokens; let tokens = lexer.tokens;
Parser::new(tokens).parse_all().unwrap() Parser::new(tokens).parse_all().expect("parsing failed")
} }
/// Execute the code using an existing Interpreter /// Execute the code using an existing Interpreter

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

@ -31,81 +31,81 @@ impl Display for Expr {
/// A Javascript Expression /// A Javascript Expression
pub enum ExprDef { pub enum ExprDef {
/// Run a operation between 2 expressions /// Run a operation between 2 expressions
BinOpExpr(BinOp, Box<Expr>, Box<Expr>), BinOp(BinOp, Box<Expr>, Box<Expr>),
/// Run an operation on a value /// Run an operation on a value
UnaryOpExpr(UnaryOp, Box<Expr>), UnaryOp(UnaryOp, Box<Expr>),
/// Make a constant value /// Make a constant value
ConstExpr(Const), Const(Const),
/// Const declaration /// Const declaration
ConstDeclExpr(Vec<(String, Expr)>), ConstDecl(Vec<(String, Expr)>),
/// Construct an object from the function and arg{ /// Construct an object from the function and arg{
ConstructExpr(Box<Expr>, Vec<Expr>), Construct(Box<Expr>, Vec<Expr>),
/// Run several expressions from top-to-bottom /// Run several expressions from top-to-bottom
BlockExpr(Vec<Expr>), Block(Vec<Expr>),
/// Load a reference to a value /// Load a reference to a value
LocalExpr(String), Local(String),
/// Gets the constant field of a value /// Gets the constant field of a value
GetConstFieldExpr(Box<Expr>, String), GetConstField(Box<Expr>, String),
/// Gets the field of a value /// Gets the field of a value
GetFieldExpr(Box<Expr>, Box<Expr>), GetField(Box<Expr>, Box<Expr>),
/// Call a function with some values /// Call a function with some values
CallExpr(Box<Expr>, Vec<Expr>), Call(Box<Expr>, Vec<Expr>),
/// Repeatedly run an expression while the conditional expression resolves to true /// Repeatedly run an expression while the conditional expression resolves to true
WhileLoopExpr(Box<Expr>, Box<Expr>), WhileLoop(Box<Expr>, Box<Expr>),
/// Check if a conditional expression is true and run an expression if it is and another expression if it isn't /// Check if a conditional expression is true and run an expression if it is and another expression if it isn't
IfExpr(Box<Expr>, Box<Expr>, Option<Box<Expr>>), If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
/// Run blocks whose cases match the expression /// Run blocks whose cases match the expression
SwitchExpr(Box<Expr>, Vec<(Expr, Vec<Expr>)>, Option<Box<Expr>>), Switch(Box<Expr>, Vec<(Expr, Vec<Expr>)>, Option<Box<Expr>>),
/// Create an object out of the binary tree given /// Create an object out of the binary tree given
ObjectDeclExpr(Box<BTreeMap<String, Expr>>), ObjectDecl(Box<BTreeMap<String, Expr>>),
/// Create an array with items inside /// Create an array with items inside
ArrayDeclExpr(Vec<Expr>), ArrayDecl(Vec<Expr>),
/// Create a function with the given name, arguments, and expression /// Create a function with the given name, arguments, and expression
FunctionDeclExpr(Option<String>, Vec<String>, Box<Expr>), FunctionDecl(Option<String>, Vec<String>, Box<Expr>),
/// Create an arrow function with the given arguments and expression /// Create an arrow function with the given arguments and expression
ArrowFunctionDeclExpr(Vec<String>, Box<Expr>), ArrowFunctionDecl(Vec<String>, Box<Expr>),
/// Return the expression from a function /// Return the expression from a function
ReturnExpr(Option<Box<Expr>>), Return(Option<Box<Expr>>),
/// Throw a value /// Throw a value
ThrowExpr(Box<Expr>), Throw(Box<Expr>),
/// Assign an expression to a value /// Assign an expression to a value
AssignExpr(Box<Expr>, Box<Expr>), Assign(Box<Expr>, Box<Expr>),
/// { /// {
/// A variable declaratio /// A variable declaratio
/// } /// }
VarDeclExpr(Vec<(String, Option<Expr>)>), VarDecl(Vec<(String, Option<Expr>)>),
/// Let declaraton /// Let declaraton
LetDeclExpr(Vec<(String, Option<Expr>)>), LetDecl(Vec<(String, Option<Expr>)>),
/// Return a string representing the type of the given expression /// Return a string representing the type of the given expression
TypeOfExpr(Box<Expr>), TypeOf(Box<Expr>),
} }
impl Operator for ExprDef { impl Operator for ExprDef {
fn get_assoc(&self) -> bool { fn get_assoc(&self) -> bool {
match *self { match *self {
ExprDef::ConstructExpr(_, _) ExprDef::Construct(_, _)
| ExprDef::UnaryOpExpr(_, _) | ExprDef::UnaryOp(_, _)
| ExprDef::TypeOfExpr(_) | ExprDef::TypeOf(_)
| ExprDef::IfExpr(_, _, _) | ExprDef::If(_, _, _)
| ExprDef::AssignExpr(_, _) => false, | ExprDef::Assign(_, _) => false,
_ => true, _ => true,
} }
} }
fn get_precedence(&self) -> u64 { fn get_precedence(&self) -> u64 {
match self { match self {
ExprDef::GetFieldExpr(_, _) | ExprDef::GetConstFieldExpr(_, _) => 1, ExprDef::GetField(_, _) | ExprDef::GetConstField(_, _) => 1,
ExprDef::CallExpr(_, _) | ExprDef::ConstructExpr(_, _) => 2, ExprDef::Call(_, _) | ExprDef::Construct(_, _) => 2,
ExprDef::UnaryOpExpr(UnaryOp::IncrementPost, _) ExprDef::UnaryOp(UnaryOp::IncrementPost, _)
| ExprDef::UnaryOpExpr(UnaryOp::IncrementPre, _) | ExprDef::UnaryOp(UnaryOp::IncrementPre, _)
| ExprDef::UnaryOpExpr(UnaryOp::DecrementPost, _) | ExprDef::UnaryOp(UnaryOp::DecrementPost, _)
| ExprDef::UnaryOpExpr(UnaryOp::DecrementPre, _) => 3, | ExprDef::UnaryOp(UnaryOp::DecrementPre, _) => 3,
ExprDef::UnaryOpExpr(UnaryOp::Not, _) ExprDef::UnaryOp(UnaryOp::Not, _)
| ExprDef::UnaryOpExpr(UnaryOp::Minus, _) | ExprDef::UnaryOp(UnaryOp::Minus, _)
| ExprDef::TypeOfExpr(_) => 4, | ExprDef::TypeOf(_) => 4,
ExprDef::BinOpExpr(op, _, _) => op.get_precedence(), ExprDef::BinOp(op, _, _) => op.get_precedence(),
ExprDef::IfExpr(_, _, _) => 15, ExprDef::If(_, _, _) => 15,
// 16 should be yield // 16 should be yield
ExprDef::AssignExpr(_, _) => 17, ExprDef::Assign(_, _) => 17,
_ => 19, _ => 19,
} }
} }
@ -114,23 +114,23 @@ impl Operator for ExprDef {
impl Display for ExprDef { impl Display for ExprDef {
fn fmt(&self, f: &mut Formatter) -> Result { fn fmt(&self, f: &mut Formatter) -> Result {
match *self { match *self {
ExprDef::ConstExpr(ref c) => write!(f, "{}", c), ExprDef::Const(ref c) => write!(f, "{}", c),
ExprDef::BlockExpr(ref block) => { ExprDef::Block(ref block) => {
write!(f, "{{")?; write!(f, "{{")?;
for expr in block.iter() { for expr in block.iter() {
write!(f, "{};", expr)?; write!(f, "{};", expr)?;
} }
write!(f, "}}") write!(f, "}}")
} }
ExprDef::LocalExpr(ref s) => write!(f, "{}", s), ExprDef::Local(ref s) => write!(f, "{}", s),
ExprDef::GetConstFieldExpr(ref ex, ref field) => write!(f, "{}.{}", ex, field), ExprDef::GetConstField(ref ex, ref field) => write!(f, "{}.{}", ex, field),
ExprDef::GetFieldExpr(ref ex, ref field) => write!(f, "{}[{}]", ex, field), ExprDef::GetField(ref ex, ref field) => write!(f, "{}[{}]", ex, field),
ExprDef::CallExpr(ref ex, ref args) => { ExprDef::Call(ref ex, ref args) => {
write!(f, "{}(", ex)?; write!(f, "{}(", ex)?;
let arg_strs: Vec<String> = args.iter().map(ToString::to_string).collect(); let arg_strs: Vec<String> = args.iter().map(ToString::to_string).collect();
write!(f, "{})", arg_strs.join(",")) write!(f, "{})", arg_strs.join(","))
} }
ExprDef::ConstructExpr(ref func, ref args) => { ExprDef::Construct(ref func, ref args) => {
f.write_fmt(format_args!("new {}", func))?; f.write_fmt(format_args!("new {}", func))?;
f.write_str("(")?; f.write_str("(")?;
let mut first = true; let mut first = true;
@ -143,12 +143,12 @@ impl Display for ExprDef {
} }
f.write_str(")") f.write_str(")")
} }
ExprDef::WhileLoopExpr(ref cond, ref expr) => write!(f, "while({}) {}", cond, expr), ExprDef::WhileLoop(ref cond, ref expr) => write!(f, "while({}) {}", cond, expr),
ExprDef::IfExpr(ref cond, ref expr, None) => write!(f, "if({}) {}", cond, expr), ExprDef::If(ref cond, ref expr, None) => write!(f, "if({}) {}", cond, expr),
ExprDef::IfExpr(ref cond, ref expr, Some(ref else_e)) => { ExprDef::If(ref cond, ref expr, Some(ref else_e)) => {
write!(f, "if({}) {} else {}", cond, expr, else_e) write!(f, "if({}) {} else {}", cond, expr, else_e)
} }
ExprDef::SwitchExpr(ref val, ref vals, None) => { ExprDef::Switch(ref val, ref vals, None) => {
f.write_fmt(format_args!("switch({})", val))?; f.write_fmt(format_args!("switch({})", val))?;
f.write_str(" {")?; f.write_str(" {")?;
for e in vals.iter() { for e in vals.iter() {
@ -157,7 +157,7 @@ impl Display for ExprDef {
} }
f.write_str("}") f.write_str("}")
} }
ExprDef::SwitchExpr(ref val, ref vals, Some(ref def)) => { ExprDef::Switch(ref val, ref vals, Some(ref def)) => {
f.write_fmt(format_args!("switch({})", val))?; f.write_fmt(format_args!("switch({})", val))?;
f.write_str(" {")?; f.write_str(" {")?;
for e in vals.iter() { for e in vals.iter() {
@ -168,33 +168,33 @@ impl Display for ExprDef {
Display::fmt(def, f)?; Display::fmt(def, f)?;
f.write_str("}") f.write_str("}")
} }
ExprDef::ObjectDeclExpr(ref map) => { ExprDef::ObjectDecl(ref map) => {
f.write_str("{")?; f.write_str("{")?;
for (key, value) in map.iter() { for (key, value) in map.iter() {
f.write_fmt(format_args!("{}: {},", key, value))?; f.write_fmt(format_args!("{}: {},", key, value))?;
} }
f.write_str("}") f.write_str("}")
} }
ExprDef::ArrayDeclExpr(ref arr) => { ExprDef::ArrayDecl(ref arr) => {
f.write_str("[")?; f.write_str("[")?;
join_expr(f, arr)?; join_expr(f, arr)?;
f.write_str("]") f.write_str("]")
} }
ExprDef::FunctionDeclExpr(ref name, ref args, ref expr) => match name { ExprDef::FunctionDecl(ref name, ref args, ref expr) => match name {
Some(val) => write!(f, "function {}({}){}", val, args.join(", "), expr), Some(val) => write!(f, "function {}({}){}", val, args.join(", "), expr),
None => write!(f, "function ({}){}", args.join(", "), expr), None => write!(f, "function ({}){}", args.join(", "), expr),
}, },
ExprDef::ArrowFunctionDeclExpr(ref args, ref expr) => { ExprDef::ArrowFunctionDecl(ref args, ref expr) => {
write!(f, "({}) => {}", args.join(", "), expr) write!(f, "({}) => {}", args.join(", "), expr)
} }
ExprDef::BinOpExpr(ref op, ref a, ref b) => write!(f, "{} {} {}", a, op, b), ExprDef::BinOp(ref op, ref a, ref b) => write!(f, "{} {} {}", a, op, b),
ExprDef::UnaryOpExpr(ref op, ref a) => write!(f, "{}{}", op, a), ExprDef::UnaryOp(ref op, ref a) => write!(f, "{}{}", op, a),
ExprDef::ReturnExpr(Some(ref ex)) => write!(f, "return {}", ex), ExprDef::Return(Some(ref ex)) => write!(f, "return {}", ex),
ExprDef::ReturnExpr(None) => write!(f, "return"), ExprDef::Return(None) => write!(f, "return"),
ExprDef::ThrowExpr(ref ex) => write!(f, "throw {}", ex), ExprDef::Throw(ref ex) => write!(f, "throw {}", ex),
ExprDef::AssignExpr(ref ref_e, ref val) => write!(f, "{} = {}", ref_e, val), ExprDef::Assign(ref ref_e, ref val) => write!(f, "{} = {}", ref_e, val),
ExprDef::VarDeclExpr(ref vars) | ExprDef::LetDeclExpr(ref vars) => { ExprDef::VarDecl(ref vars) | ExprDef::LetDecl(ref vars) => {
if let ExprDef::VarDeclExpr(_) = *self { if let ExprDef::VarDecl(_) = *self {
f.write_str("var ")?; f.write_str("var ")?;
} else { } else {
f.write_str("let ")?; f.write_str("let ")?;
@ -207,14 +207,14 @@ impl Display for ExprDef {
} }
Ok(()) Ok(())
} }
ExprDef::ConstDeclExpr(ref vars) => { ExprDef::ConstDecl(ref vars) => {
f.write_str("const ")?; f.write_str("const ")?;
for (key, val) in vars.iter() { for (key, val) in vars.iter() {
f.write_fmt(format_args!("{} = {}", key, val))? f.write_fmt(format_args!("{} = {}", key, val))?
} }
Ok(()) Ok(())
} }
ExprDef::TypeOfExpr(ref e) => write!(f, "typeof {}", e), ExprDef::TypeOf(ref e) => write!(f, "typeof {}", e),
} }
} }
} }

19
src/lib/syntax/lexer.rs

@ -544,7 +544,7 @@ mod tests {
fn check_string() { fn check_string() {
let s = "'aaa' \"bbb\""; let s = "'aaa' \"bbb\"";
let mut lexer = Lexer::new(s); let mut lexer = Lexer::new(s);
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
assert_eq!( assert_eq!(
lexer.tokens[0].data, lexer.tokens[0].data,
TokenData::StringLiteral("aaa".to_string()) TokenData::StringLiteral("aaa".to_string())
@ -563,7 +563,7 @@ mod tests {
+ - * % -- << >> >>> & | ^ ! ~ && || ? : \ + - * % -- << >> >>> & | ^ ! ~ && || ? : \
= += -= *= &= **= ++ ** <<= >>= >>>= &= |= ^= =>"; = += -= *= &= **= ++ ** <<= >>= >>>= &= |= ^= =>";
let mut lexer = Lexer::new(s); let mut lexer = Lexer::new(s);
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
assert_eq!( assert_eq!(
lexer.tokens[0].data, lexer.tokens[0].data,
TokenData::Punctuator(Punctuator::OpenBlock) TokenData::Punctuator(Punctuator::OpenBlock)
@ -761,7 +761,7 @@ mod tests {
new return super switch this throw try typeof var void while with yield"; new return super switch this throw try typeof var void while with yield";
let mut lexer = Lexer::new(s); let mut lexer = Lexer::new(s);
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
assert_eq!(lexer.tokens[0].data, TokenData::Keyword(Keyword::Await)); assert_eq!(lexer.tokens[0].data, TokenData::Keyword(Keyword::Await));
assert_eq!(lexer.tokens[1].data, TokenData::Keyword(Keyword::Break)); assert_eq!(lexer.tokens[1].data, TokenData::Keyword(Keyword::Break));
assert_eq!(lexer.tokens[2].data, TokenData::Keyword(Keyword::Case)); assert_eq!(lexer.tokens[2].data, TokenData::Keyword(Keyword::Case));
@ -805,7 +805,7 @@ mod tests {
fn check_variable_definition_tokens() { fn check_variable_definition_tokens() {
let s = &String::from("let a = 'hello';"); let s = &String::from("let a = 'hello';");
let mut lexer = Lexer::new(s); let mut lexer = Lexer::new(s);
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
assert_eq!(lexer.tokens[0].data, TokenData::Keyword(Keyword::Let)); assert_eq!(lexer.tokens[0].data, TokenData::Keyword(Keyword::Let));
assert_eq!(lexer.tokens[1].data, TokenData::Identifier("a".to_string())); assert_eq!(lexer.tokens[1].data, TokenData::Identifier("a".to_string()));
assert_eq!( assert_eq!(
@ -823,7 +823,7 @@ mod tests {
let s = &String::from("console.log(\"hello world\");"); let s = &String::from("console.log(\"hello world\");");
// -------------------123456789 // -------------------123456789
let mut lexer = Lexer::new(s); let mut lexer = Lexer::new(s);
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
// The first column is 1 (not zero indexed) // The first column is 1 (not zero indexed)
assert_eq!(lexer.tokens[0].pos.column_number, 1); assert_eq!(lexer.tokens[0].pos.column_number, 1);
assert_eq!(lexer.tokens[0].pos.line_number, 1); assert_eq!(lexer.tokens[0].pos.line_number, 1);
@ -853,7 +853,7 @@ mod tests {
// Here we want an example of decrementing an integer // Here we want an example of decrementing an integer
let s = &String::from("let a = b--;"); let s = &String::from("let a = b--;");
let mut lexer = Lexer::new(s); let mut lexer = Lexer::new(s);
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
assert_eq!(lexer.tokens[4].data, TokenData::Punctuator(Punctuator::Dec)); assert_eq!(lexer.tokens[4].data, TokenData::Punctuator(Punctuator::Dec));
// Decrementing means adding 2 characters '--', the lexer should consume it as a single token // Decrementing means adding 2 characters '--', the lexer should consume it as a single token
// and move the curser forward by 2, meaning the next token should be a semicolon // and move the curser forward by 2, meaning the next token should be a semicolon
@ -866,7 +866,7 @@ mod tests {
#[test] #[test]
fn numbers() { fn numbers() {
let mut lexer = Lexer::new("1 2 0x34 056 7.89 42. 5e3 5e+3 5e-3 0b10 0O123 0999"); let mut lexer = Lexer::new("1 2 0x34 056 7.89 42. 5e3 5e+3 5e-3 0b10 0O123 0999");
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
assert_eq!(lexer.tokens[0].data, TokenData::NumericLiteral(1.0)); assert_eq!(lexer.tokens[0].data, TokenData::NumericLiteral(1.0));
assert_eq!(lexer.tokens[1].data, TokenData::NumericLiteral(2.0)); assert_eq!(lexer.tokens[1].data, TokenData::NumericLiteral(2.0));
assert_eq!(lexer.tokens[2].data, TokenData::NumericLiteral(52.0)); assert_eq!(lexer.tokens[2].data, TokenData::NumericLiteral(52.0));
@ -884,14 +884,13 @@ mod tests {
#[test] #[test]
fn test_single_number_without_semicolon() { fn test_single_number_without_semicolon() {
let mut lexer = Lexer::new("1"); let mut lexer = Lexer::new("1");
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
dbg!(lexer.tokens);
} }
#[test] #[test]
fn test_number_followed_by_dot() { fn test_number_followed_by_dot() {
let mut lexer = Lexer::new("1.."); let mut lexer = Lexer::new("1..");
lexer.lex().unwrap(); lexer.lex().expect("failed to lex");
assert_eq!(lexer.tokens[0].data, TokenData::NumericLiteral(1.0)); assert_eq!(lexer.tokens[0].data, TokenData::NumericLiteral(1.0));
assert_eq!(lexer.tokens[1].data, TokenData::Punctuator(Punctuator::Dot)); assert_eq!(lexer.tokens[1].data, TokenData::Punctuator(Punctuator::Dot));
} }

324
src/lib/syntax/parser.rs

@ -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"))),
)], )],
); );
} }

Loading…
Cancel
Save