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.
[[package]]
name = "Boa"
version = "0.2.2"
version = "0.3.0"
dependencies = [
"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)",

25
benches/string.rs

@ -13,20 +13,27 @@ fn hello_world_lexer(c: &mut Criterion) {
c.bench_function("Hello World (Lexer)", move |b| {
b.iter(|| {
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) {
c.bench_function("Hello World (Parser)", move |b| {
b.iter(|| {
let mut lexer = Lexer::new(SRC);
lexer.lex().unwrap();
let tokens = lexer.tokens;
Parser::new(black_box(tokens)).parse_all().unwrap();
})
});
// Don't include lexing as part of the parser benchmark
let mut lexer = Lexer::new(SRC);
lexer.lex().expect("failed to lex");
let tokens = lexer.tokens;
c.bench_function_over_inputs(
"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) {

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) {
// TODO: change this when error handling comes into play
panic!("Identifier {} has already been declared", name);
@ -74,6 +74,8 @@ impl EnvironmentRecordTrait for DeclerativeEnvironmentRecord {
strict,
},
);
true
}
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.
/// 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.
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.
/// 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) {
// TODO: change this when error handling comes into play
panic!("Identifier {} has already been declared", name);
@ -131,6 +131,8 @@ impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
strict,
},
);
true
}
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)
}
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) {
// TODO: change to exception
panic!("Binding already exists!");
}
self.declerative_record
.create_immutable_binding(name.clone(), strict)
}
@ -178,7 +179,7 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
}
fn set_outer_environment(&mut self, _env: Environment) {
unimplemented!()
unimplemented!();
}
fn get_environment_type(&self) -> EnvironmentType {

2
src/lib/environment/lexical_environment.rs

@ -101,7 +101,7 @@ impl LexicalEnvironment {
.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()
.borrow_mut()
.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);
}
fn create_immutable_binding(&mut self, _name: String, _strict: bool) {
unimplemented!()
fn create_immutable_binding(&mut self, _name: String, _strict: bool) -> bool {
true
}
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)]
fn run(&mut self, expr: &Expr) -> ResultValue {
match expr.def {
ExprDef::ConstExpr(Const::Null) => Ok(to_value(None::<()>)),
ExprDef::ConstExpr(Const::Undefined) => Ok(Gc::new(ValueData::Undefined)),
ExprDef::ConstExpr(Const::Num(num)) => Ok(to_value(num)),
ExprDef::ConstExpr(Const::Int(num)) => Ok(to_value(num)),
ExprDef::Const(Const::Null) => Ok(to_value(None::<()>)),
ExprDef::Const(Const::Undefined) => Ok(Gc::new(ValueData::Undefined)),
ExprDef::Const(Const::Num(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
// 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
ExprDef::ConstExpr(Const::String(ref str)) => Ok(to_value(str.to_owned())),
ExprDef::ConstExpr(Const::Bool(val)) => Ok(to_value(val)),
ExprDef::ConstExpr(Const::RegExp(_, _, _)) => Ok(to_value(None::<()>)),
ExprDef::BlockExpr(ref es) => {
ExprDef::Const(Const::String(ref str)) => Ok(to_value(str.to_owned())),
ExprDef::Const(Const::Bool(val)) => Ok(to_value(val)),
ExprDef::Const(Const::RegExp(_, _, _)) => Ok(to_value(None::<()>)),
ExprDef::Block(ref es) => {
let mut obj = to_value(None::<()>);
for e in es.iter() {
let val = self.run(e)?;
@ -70,26 +70,26 @@ impl Executor for Interpreter {
}
Ok(obj)
}
ExprDef::LocalExpr(ref name) => {
ExprDef::Local(ref name) => {
let val = self.environment.get_binding_value(name);
Ok(val)
}
ExprDef::GetConstFieldExpr(ref obj, ref field) => {
ExprDef::GetConstField(ref obj, ref field) => {
let val_obj = self.run(obj)?;
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_field = self.run(field)?;
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 {
ExprDef::GetConstFieldExpr(ref obj, ref field) => {
ExprDef::GetConstField(ref obj, ref field) => {
let obj = self.run(obj)?;
(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 field = self.run(field)?;
(
@ -135,28 +135,26 @@ impl Executor for Interpreter {
_ => Err(Gc::new(ValueData::Undefined)),
}
}
ExprDef::WhileLoopExpr(ref cond, ref expr) => {
ExprDef::WhileLoop(ref cond, ref expr) => {
let mut result = Gc::new(ValueData::Undefined);
while self.run(cond)?.borrow().is_true() {
result = self.run(expr)?;
}
Ok(result)
}
ExprDef::IfExpr(ref cond, ref expr, None) => {
Ok(if self.run(cond)?.borrow().is_true() {
self.run(expr)?
} else {
Gc::new(ValueData::Undefined)
})
}
ExprDef::IfExpr(ref cond, ref expr, Some(ref else_e)) => {
ExprDef::If(ref cond, ref expr, None) => Ok(if self.run(cond)?.borrow().is_true() {
self.run(expr)?
} else {
Gc::new(ValueData::Undefined)
}),
ExprDef::If(ref cond, ref expr, Some(ref else_e)) => {
Ok(if self.run(cond)?.borrow().is_true() {
self.run(expr)?
} else {
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 mut result = Gc::new(ValueData::Null);
let mut matched = false;
@ -180,7 +178,7 @@ impl Executor for Interpreter {
}
Ok(result)
}
ExprDef::ObjectDeclExpr(ref map) => {
ExprDef::ObjectDecl(ref map) => {
let global_val = &self.environment.get_global_object().unwrap();
let obj = ValueData::new_obj(Some(global_val));
for (key, val) in map.iter() {
@ -188,7 +186,7 @@ impl Executor for Interpreter {
}
Ok(obj)
}
ExprDef::ArrayDeclExpr(ref arr) => {
ExprDef::ArrayDecl(ref arr) => {
let global_val = &self.environment.get_global_object().unwrap();
let arr_map = ValueData::new_obj(Some(global_val));
// 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));
Ok(arr_map)
}
ExprDef::FunctionDeclExpr(ref name, ref args, ref expr) => {
ExprDef::FunctionDecl(ref name, ref args, ref expr) => {
let function =
Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
let val = Gc::new(ValueData::Function(Box::new(GcCell::new(function))));
@ -221,14 +219,14 @@ impl Executor for Interpreter {
}
Ok(val)
}
ExprDef::ArrowFunctionDeclExpr(ref args, ref expr) => {
ExprDef::ArrowFunctionDecl(ref args, ref expr) => {
let function =
Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone()));
Ok(Gc::new(ValueData::Function(Box::new(GcCell::new(
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_b = self.run(b)?;
let v_a = (*v_r_a).clone();
@ -241,7 +239,7 @@ impl Executor for Interpreter {
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_a = (*v_r_a).clone();
Ok(match *op {
@ -251,7 +249,7 @@ impl Executor for Interpreter {
_ => 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_b = self.run(b)?;
let v_a = (*v_r_a).clone();
@ -264,7 +262,7 @@ impl Executor for Interpreter {
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_b = self.run(b)?;
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(),
}))
}
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_b = from_value::<bool>(self.run(b)?).unwrap();
Ok(match *op {
@ -292,7 +290,7 @@ impl Executor for Interpreter {
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 mut v_args = Vec::with_capacity(args.len());
for arg in args.iter() {
@ -331,19 +329,19 @@ impl Executor for Interpreter {
_ => Ok(Gc::new(ValueData::Undefined)),
}
}
ExprDef::ReturnExpr(ref ret) => match *ret {
ExprDef::Return(ref ret) => match *ret {
Some(ref v) => self.run(v),
None => Ok(Gc::new(ValueData::Undefined)),
},
ExprDef::ThrowExpr(ref ex) => Err(self.run(ex)?),
ExprDef::AssignExpr(ref ref_e, ref val_e) => {
ExprDef::Throw(ref ex) => Err(self.run(ex)?),
ExprDef::Assign(ref ref_e, ref val_e) => {
let val = self.run(val_e)?;
match ref_e.def {
ExprDef::LocalExpr(ref name) => {
ExprDef::Local(ref name) => {
self.environment.create_mutable_binding(name.clone(), false);
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)?;
val_obj.borrow().set_field(field.clone(), val.clone());
}
@ -351,7 +349,7 @@ impl Executor for Interpreter {
}
Ok(val)
}
ExprDef::VarDeclExpr(ref vars) => {
ExprDef::VarDecl(ref vars) => {
for var in vars.iter() {
let (name, value) = var.clone();
let val = match value {
@ -363,7 +361,7 @@ impl Executor for Interpreter {
}
Ok(Gc::new(ValueData::Undefined))
}
ExprDef::LetDeclExpr(ref vars) => {
ExprDef::LetDecl(ref vars) => {
for var in vars.iter() {
let (name, value) = var.clone();
let val = match value {
@ -375,7 +373,7 @@ impl Executor for Interpreter {
}
Ok(Gc::new(ValueData::Undefined))
}
ExprDef::ConstDeclExpr(ref vars) => {
ExprDef::ConstDecl(ref vars) => {
for (name, value) in vars.iter() {
self.environment
.create_immutable_binding(name.clone(), false);
@ -384,7 +382,7 @@ impl Executor for Interpreter {
}
Ok(Gc::new(ValueData::Undefined))
}
ExprDef::TypeOfExpr(ref val_e) => {
ExprDef::TypeOf(ref val_e) => {
let val = self.run(val_e)?;
Ok(to_value(match *val {
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();
// 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 {
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
/// values on the end, correctly rewriting the length
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() {
let new_index = orig_length + (n as i32);
@ -296,16 +298,16 @@ mod tests {
"#;
forward(&mut engine, init);
// Empty ++ Empty
let ee = forward(&mut engine, "empty.concat(empty)");
let _ee = forward(&mut engine, "empty.concat(empty)");
//assert_eq!(ee, String::from(""));
// Empty ++ NonEmpty
let en = forward(&mut engine, "empty.concat(one)");
let _en = forward(&mut engine, "empty.concat(one)");
//assert_eq!(en, String::from("a"));
// 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"));
// 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"));
}

4
src/lib/js/console.rs

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

9
src/lib/js/error.rs

@ -11,7 +11,14 @@ use gc::Gc;
/// Create a new error
pub fn make_error(this: &Value, args: &[Value], _: &Interpreter) -> ResultValue {
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
// to its Javascript Identifier (global constructor method name)

7
src/lib/js/function.rs

@ -40,6 +40,7 @@ pub struct RegularFunction {
impl RegularFunction {
/// Make a new regular function
#[allow(clippy::cast_possible_wrap)]
pub fn new(expr: Expr, args: Vec<String>) -> Self {
let mut object = ObjectData::default();
object.properties.insert(
@ -69,7 +70,11 @@ impl NativeFunction {
impl Debug for NativeFunction {
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
/// <https://tc39.github.io/ecma262/#sec-json.parse>
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)),
Err(err) => Err(to_value(err.to_string())),
}
}
/// Process a Javascript object into a JSON string
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();
Ok(to_value(to_string_pretty(&json).unwrap()))
Ok(to_value(to_string_pretty(&json).expect("")))
}
/// Create a new `JSON` object

2
src/lib/js/object.rs

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

5
src/lib/js/string.rs

@ -7,7 +7,6 @@ use crate::{
},
};
use gc::Gc;
use gc_derive::{Finalize, Trace};
use std::{
cmp::{max, min},
f64::NAN,
@ -544,8 +543,8 @@ mod tests {
const nice = new String('Have a nice day.');
"#;
forward(&mut engine, init);
let a = forward(&mut engine, "hello.concat(world, nice)");
let b = forward(&mut engine, "hello + world + nice");
let _a = forward(&mut engine, "hello.concat(world, nice)");
let _b = forward(&mut engine, "hello + world + nice");
// Todo: fix this
//assert_eq!(a, 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() {
let obj_proto = global
.unwrap()
.expect("Expected global object in making-new-object")
.get_field_slice("Object")
.get_field_slice(PROTOTYPE);
obj.properties

9
src/lib/lib.rs

@ -23,7 +23,10 @@
clippy::missing_docs_in_private_items,
clippy::missing_inline_in_public_items,
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;
@ -47,9 +50,9 @@ extern "C" {
fn parser_expr(src: &str) -> Expr {
let mut lexer = Lexer::new(src);
lexer.lex().unwrap();
lexer.lex().expect("lexing failed");
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

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

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

19
src/lib/syntax/lexer.rs

@ -544,7 +544,7 @@ mod tests {
fn check_string() {
let s = "'aaa' \"bbb\"";
let mut lexer = Lexer::new(s);
lexer.lex().unwrap();
lexer.lex().expect("failed to lex");
assert_eq!(
lexer.tokens[0].data,
TokenData::StringLiteral("aaa".to_string())
@ -563,7 +563,7 @@ mod tests {
+ - * % -- << >> >>> & | ^ ! ~ && || ? : \
= += -= *= &= **= ++ ** <<= >>= >>>= &= |= ^= =>";
let mut lexer = Lexer::new(s);
lexer.lex().unwrap();
lexer.lex().expect("failed to lex");
assert_eq!(
lexer.tokens[0].data,
TokenData::Punctuator(Punctuator::OpenBlock)
@ -761,7 +761,7 @@ mod tests {
new return super switch this throw try typeof var void while with yield";
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[1].data, TokenData::Keyword(Keyword::Break));
assert_eq!(lexer.tokens[2].data, TokenData::Keyword(Keyword::Case));
@ -805,7 +805,7 @@ mod tests {
fn check_variable_definition_tokens() {
let s = &String::from("let a = 'hello';");
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[1].data, TokenData::Identifier("a".to_string()));
assert_eq!(
@ -823,7 +823,7 @@ mod tests {
let s = &String::from("console.log(\"hello world\");");
// -------------------123456789
let mut lexer = Lexer::new(s);
lexer.lex().unwrap();
lexer.lex().expect("failed to lex");
// The first column is 1 (not zero indexed)
assert_eq!(lexer.tokens[0].pos.column_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
let s = &String::from("let a = b--;");
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));
// 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
@ -866,7 +866,7 @@ mod tests {
#[test]
fn numbers() {
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[1].data, TokenData::NumericLiteral(2.0));
assert_eq!(lexer.tokens[2].data, TokenData::NumericLiteral(52.0));
@ -884,14 +884,13 @@ mod tests {
#[test]
fn test_single_number_without_semicolon() {
let mut lexer = Lexer::new("1");
lexer.lex().unwrap();
dbg!(lexer.tokens);
lexer.lex().expect("failed to lex");
}
#[test]
fn test_number_followed_by_dot() {
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[1].data, TokenData::Punctuator(Punctuator::Dot));
}

324
src/lib/syntax/parser.rs

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

Loading…
Cancel
Save