Browse Source

preparing for Rust 2018 and constructor work

pull/5/head
Jason Williams 6 years ago
parent
commit
5e4999c5fa
  1. 1
      Cargo.toml
  2. 71
      src/lib/exec.rs
  3. 4
      src/lib/js/array.rs
  4. 4
      src/lib/js/console.rs
  5. 6
      src/lib/js/error.rs
  6. 8
      src/lib/js/function.rs
  7. 4
      src/lib/js/json.rs
  8. 4
      src/lib/js/math.rs
  9. 4
      src/lib/js/object.rs
  10. 16
      src/lib/js/string.rs
  11. 22
      src/lib/js/value.rs
  12. 10
      src/lib/syntax/ast/expr.rs
  13. 2
      src/lib/syntax/ast/keyword.rs
  14. 6
      src/lib/syntax/ast/token.rs
  15. 4
      src/lib/syntax/lexer.rs
  16. 164
      src/lib/syntax/parser.rs
  17. 4
      tests/js/test.js

1
Cargo.toml

@ -8,6 +8,7 @@ repository = "https://github.com/jasonwilliams/boa"
keywords = ["javascript", "compiler", "lexer", "parser", "js"]
license = "Unlicense OR MIT"
exclude = [".vscode/*", "Dockerfile", "Makefile", ".editorConfig"]
edition = "2018"
[dependencies]
gc = "0.3.2"

71
src/lib/exec.rs

@ -1,13 +1,13 @@
use gc::{Gc, GcCell};
use js::function::{Function, RegularFunction};
use js::object::{INSTANCE_PROTOTYPE, PROTOTYPE};
use js::value::{from_value, to_value, ResultValue, Value, ValueData};
use js::{array, console, function, json, math, object, string};
use crate::js::function::{Function, RegularFunction};
use crate::js::object::{INSTANCE_PROTOTYPE, PROTOTYPE};
use crate::js::value::{from_value, to_value, ResultValue, Value, ValueData};
use crate::js::{array, console, function, json, math, object, string};
use std::borrow::Borrow;
use std::collections::HashMap;
use syntax::ast::constant::Const;
use syntax::ast::expr::{Expr, ExprDef};
use syntax::ast::op::{BinOp, BitOp, CompOp, LogOp, NumOp, UnaryOp};
use crate::syntax::ast::constant::Const;
use crate::syntax::ast::expr::{Expr, ExprDef};
use crate::syntax::ast::op::{BinOp, BitOp, CompOp, LogOp, NumOp, UnaryOp};
/// A variable scope
#[derive(Trace, Finalize, Clone, Debug)]
pub struct Scope {
@ -188,32 +188,32 @@ impl Executor for Interpreter {
Ok(result)
}
ExprDef::IfExpr(ref cond, ref expr, None) => {
Ok(if try!(self.run(cond)).borrow().is_true() {
try!(self.run(expr))
Ok(if r#try!(self.run(cond)).borrow().is_true() {
r#try!(self.run(expr))
} else {
Gc::new(ValueData::Undefined)
})
}
ExprDef::IfExpr(ref cond, ref expr, Some(ref else_e)) => {
Ok(if try!(self.run(cond)).borrow().is_true() {
try!(self.run(expr))
Ok(if r#try!(self.run(cond)).borrow().is_true() {
r#try!(self.run(expr))
} else {
try!(self.run(else_e))
r#try!(self.run(else_e))
})
}
ExprDef::SwitchExpr(ref val_e, ref vals, ref default) => {
let val = try!(self.run(val_e)).clone();
let val = r#try!(self.run(val_e)).clone();
let mut result = Gc::new(ValueData::Null);
let mut matched = false;
for tup in vals.iter() {
let tup: &(Expr, Vec<Expr>) = tup;
let cond = &tup.0;
let block = &tup.1;
if val == try!(self.run(cond)) {
if val == r#try!(self.run(cond)) {
matched = true;
let last_expr = block.last().unwrap();
for expr in block.iter() {
let e_result = try!(self.run(expr));
let e_result = r#try!(self.run(expr));
if expr == last_expr {
result = e_result;
}
@ -221,14 +221,14 @@ impl Executor for Interpreter {
}
}
if !matched && default.is_some() {
result = try!(self.run(default.as_ref().unwrap()));
result = r#try!(self.run(default.as_ref().unwrap()));
}
Ok(result)
}
ExprDef::ObjectDeclExpr(ref map) => {
let obj = ValueData::new_obj(Some(self.global.clone()));
for (key, val) in map.iter() {
obj.borrow().set_field(key.clone(), try!(self.run(val)));
obj.borrow().set_field(key.clone(), r#try!(self.run(val)));
}
Ok(obj)
}
@ -236,7 +236,7 @@ impl Executor for Interpreter {
let arr_map = ValueData::new_obj(Some(self.global.clone()));
let mut index: i32 = 0;
for val in arr.iter() {
let val = try!(self.run(val));
let val = r#try!(self.run(val));
arr_map.borrow().set_field(index.to_string(), val);
index += 1;
}
@ -266,8 +266,8 @@ impl Executor for Interpreter {
Ok(Gc::new(ValueData::Function(GcCell::new(function))))
}
ExprDef::BinOpExpr(BinOp::Num(ref op), ref a, ref b) => {
let v_r_a = try!(self.run(a));
let v_r_b = try!(self.run(b));
let v_r_a = r#try!(self.run(a));
let v_r_b = r#try!(self.run(b));
let v_a = (*v_r_a).clone();
let v_b = (*v_r_b).clone();
Ok(Gc::new(match *op {
@ -279,7 +279,7 @@ impl Executor for Interpreter {
}))
}
ExprDef::UnaryOpExpr(ref op, ref a) => {
let v_r_a = try!(self.run(a));
let v_r_a = r#try!(self.run(a));
let v_a = (*v_r_a).clone();
Ok(match *op {
UnaryOp::Minus => to_value(-v_a.to_num()),
@ -289,8 +289,8 @@ impl Executor for Interpreter {
})
}
ExprDef::BinOpExpr(BinOp::Bit(ref op), ref a, ref b) => {
let v_r_a = try!(self.run(a));
let v_r_b = try!(self.run(b));
let v_r_a = r#try!(self.run(a));
let v_r_b = r#try!(self.run(b));
let v_a = (*v_r_a).clone();
let v_b = (*v_r_b).clone();
Ok(Gc::new(match *op {
@ -302,8 +302,8 @@ impl Executor for Interpreter {
}))
}
ExprDef::BinOpExpr(BinOp::Comp(ref op), ref a, ref b) => {
let v_r_a = try!(self.run(a));
let v_r_b = try!(self.run(b));
let v_r_a = r#try!(self.run(a));
let v_r_b = r#try!(self.run(b));
let v_a = v_r_a.borrow();
let v_b = v_r_b.borrow();
Ok(to_value(match *op {
@ -322,18 +322,18 @@ impl Executor for Interpreter {
}))
}
ExprDef::BinOpExpr(BinOp::Log(ref op), ref a, ref b) => {
let v_a = from_value::<bool>(try!(self.run(a))).unwrap();
let v_b = from_value::<bool>(try!(self.run(b))).unwrap();
let v_a = from_value::<bool>(r#try!(self.run(a))).unwrap();
let v_b = from_value::<bool>(r#try!(self.run(b))).unwrap();
Ok(match *op {
LogOp::And => to_value(v_a && v_b),
LogOp::Or => to_value(v_a || v_b),
})
}
ExprDef::ConstructExpr(ref callee, ref args) => {
let func = try!(self.run(callee));
let func = self.run(callee)?;
let mut v_args = Vec::with_capacity(args.len());
for arg in args.iter() {
v_args.push(try!(self.run(arg)));
v_args.push(r#try!(self.run(arg)));
}
let this = Gc::new(ValueData::Object(GcCell::new(HashMap::new())));
this.borrow()
@ -342,7 +342,8 @@ impl Executor for Interpreter {
ValueData::Function(ref func) => match func.clone().into_inner() {
Function::NativeFunc(ref ntv) => {
let func = ntv.data;
func(this, try!(self.run(callee)), v_args)
println!("{:#?}", this);
func(this, self.run(callee)?, v_args)
}
Function::RegularFunc(ref data) => {
let scope = self.make_scope(this);
@ -364,9 +365,9 @@ impl Executor for Interpreter {
Some(ref v) => self.run(v),
None => Ok(Gc::new(ValueData::Undefined)),
},
ExprDef::ThrowExpr(ref ex) => Err(try!(self.run(ex))),
ExprDef::ThrowExpr(ref ex) => Err(r#try!(self.run(ex))),
ExprDef::AssignExpr(ref ref_e, ref val_e) => {
let val = try!(self.run(val_e));
let val = r#try!(self.run(val_e));
match ref_e.def {
ExprDef::LocalExpr(ref name) => {
self.scope()
@ -375,7 +376,7 @@ impl Executor for Interpreter {
.set_field(name.clone(), val.clone());
}
ExprDef::GetConstFieldExpr(ref obj, ref field) => {
let val_obj = try!(self.run(obj));
let val_obj = r#try!(self.run(obj));
val_obj.borrow().set_field(field.clone(), val.clone());
}
_ => (),
@ -388,7 +389,7 @@ impl Executor for Interpreter {
for var in vars.iter() {
let (name, value) = var.clone();
let val = match value {
Some(v) => try!(self.run(&v)),
Some(v) => r#try!(self.run(&v)),
None => Gc::new(ValueData::Null),
};
scope_vars_ptr.set_field(name.clone(), val);
@ -396,7 +397,7 @@ impl Executor for Interpreter {
Ok(Gc::new(ValueData::Undefined))
}
ExprDef::TypeOfExpr(ref val_e) => {
let val = try!(self.run(val_e));
let val = r#try!(self.run(val_e));
Ok(to_value(match *val {
ValueData::Undefined => "undefined",
ValueData::Null | ValueData::Object(_) => "object",

4
src/lib/js/array.rs

@ -1,6 +1,6 @@
use gc::Gc;
use js::function::NativeFunctionData;
use js::value::{to_value, ResultValue, Value, ValueData};
use crate::js::function::NativeFunctionData;
use crate::js::value::{to_value, ResultValue, Value, ValueData};
/// Create a new array
pub fn make_array(this: Value, _: Value, _: Vec<Value>) -> ResultValue {

4
src/lib/js/console.rs

@ -1,6 +1,6 @@
use gc::Gc;
use js::function::NativeFunctionData;
use js::value::{from_value, to_value, ResultValue, Value, ValueData};
use crate::js::function::NativeFunctionData;
use crate::js::value::{from_value, to_value, ResultValue, Value, ValueData};
use std::iter::FromIterator;
use time::{now, strftime};
/// Print a javascript value to the standard output stream

6
src/lib/js/error.rs

@ -1,7 +1,7 @@
use gc::Gc;
use js::function::NativeFunctionData;
use js::object::PROTOTYPE;
use js::value::{to_value, ResultValue, Value, ValueData};
use crate::js::function::NativeFunctionData;
use crate::js::object::PROTOTYPE;
use crate::js::value::{to_value, ResultValue, Value, ValueData};
/// Create a new error
pub fn make_error(this: Value, _: Value, args: Vec<Value>) -> ResultValue {

8
src/lib/js/function.rs

@ -1,10 +1,12 @@
use gc::Gc;
use js::object::{ObjectData, Property};
use js::value::{to_value, ResultValue, Value, ValueData};
use crate::js::object::{ObjectData, Property};
use crate::js::value::{to_value, ResultValue, Value, ValueData};
use std::collections::HashMap;
use syntax::ast::expr::Expr;
use crate::syntax::ast::expr::Expr;
/// fn(this, callee, arguments)
pub type NativeFunctionData = fn(Value, Value, Vec<Value>) -> ResultValue;
/// A Javascript function
/// A member of the Object type that may be invoked as a subroutine
/// https://tc39.github.io/ecma262/#sec-terms-and-definitions-function

4
src/lib/js/json.rs

@ -1,7 +1,7 @@
use js::function::NativeFunctionData;
use crate::js::function::NativeFunctionData;
/// The JSON Object
/// https://tc39.github.io/ecma262/#sec-json-object
use js::value::{to_value, ResultValue, Value, ValueData};
use crate::js::value::{to_value, ResultValue, Value, ValueData};
use serde_json::{self, to_string_pretty, Value as JSONValue};
/// Parse a JSON string into a Javascript object

4
src/lib/js/math.rs

@ -1,5 +1,5 @@
use js::function::NativeFunctionData;
use js::value::{from_value, to_value, ResultValue, Value, ValueData};
use crate::js::function::NativeFunctionData;
use crate::js::value::{from_value, to_value, ResultValue, Value, ValueData};
use rand::random;
use std::f64;

4
src/lib/js/object.rs

@ -1,6 +1,6 @@
use gc::Gc;
use js::function::NativeFunctionData;
use js::value::{from_value, to_value, FromValue, ResultValue, ToValue, Value, ValueData};
use crate::js::function::NativeFunctionData;
use crate::js::value::{from_value, to_value, FromValue, ResultValue, ToValue, Value, ValueData};
use std::collections::HashMap;
pub static PROTOTYPE: &'static str = "prototype";
pub static INSTANCE_PROTOTYPE: &'static str = "__proto__";

16
src/lib/js/string.rs

@ -1,12 +1,16 @@
use gc::Gc;
use js::function::NativeFunctionData;
use js::object::{Property, PROTOTYPE};
use js::value::{from_value, to_value, ResultValue, Value, ValueData};
use crate::js::function::NativeFunctionData;
use crate::js::object::{Property, PROTOTYPE};
use crate::js::value::{from_value, to_value, ResultValue, Value, ValueData};
/// Create new string
pub fn make_string(this: Value, _: Value, _: Vec<Value>) -> ResultValue {
this.set_field_slice("length", to_value(0i32));
Ok(Gc::new(ValueData::Undefined))
/// https://searchfox.org/mozilla-central/source/js/src/vm/StringObject.h#19
pub fn make_string(this: Value, _: Value, args: Vec<Value>) -> ResultValue {
// If we're constructing a string, we should set the initial length
// To do this we need to convert the string back to a Rust String, then get the .len()
let a: String = from_value(args[0].clone()).unwrap();
this.set_field_slice("length", to_value(a.len() as i32));
Ok(this)
}
/// Get a string's length
pub fn get_string_length(this: Value, _: Value, _: Vec<Value>) -> ResultValue {

22
src/lib/js/value.rs

@ -1,6 +1,6 @@
use gc::{Gc, GcCell};
use js::function::{Function, NativeFunction, NativeFunctionData};
use js::object::{ObjectData, Property, INSTANCE_PROTOTYPE, PROTOTYPE};
use crate::js::function::{Function, NativeFunction, NativeFunctionData};
use crate::js::object::{ObjectData, Property, INSTANCE_PROTOTYPE, PROTOTYPE};
use serde_json::map::Map;
use serde_json::Number as JSONNumber;
use serde_json::Value as JSONValue;
@ -36,6 +36,7 @@ pub enum ValueData {
/// `Number` - A 32-bit integer, such as `42`
Integer(i32),
/// `Object` - An object, such as `Math`, represented by a binary tree of string keys to Javascript values
/// Some Objects will need an internal slot to hold private values, so our second ObjectData is for that
Object(GcCell<ObjectData>),
/// `Function` - A runnable block of code, such as `Math.sqrt`, which can take some variables and return a useful value or act upon an object
Function(GcCell<Function>),
@ -160,7 +161,7 @@ impl ValueData {
/// Returns a copy of the Property
pub fn get_prop(&self, field: String) -> Option<Property> {
// Spidermonkey has its own GetLengthProperty: https://searchfox.org/mozilla-central/source/js/src/vm/Interpreter-inl.h#154
// TODO: Move this to a better place
// This is only for primitive strings, String() objects have their lengths calculated in string.rs
if self.is_string() && field == "length" {
if let ValueData::String(ref s) = *self {
return Some(Property::new(to_value(s.len() as i32)))
@ -173,7 +174,10 @@ impl ValueData {
hash.into_inner()
}
// Accesing .object on borrow() seems to automatically dereference it, so we don't need the *
// ValueData::Function(ref func) => func.clone().object,
ValueData::Function(ref func) => match func.clone().into_inner() {
Function::NativeFunc(ref func) => func.object.clone(),
Function::RegularFunc(ref func) => func.object.clone()
}
_ => return None,
};
match obj.get(&field) {
@ -332,13 +336,13 @@ impl Display for ValueData {
}
),
ValueData::Object(ref v) => {
try!(write!(f, "{}", "{"));
r#try!(write!(f, "{}", "{"));
match v.borrow().iter().last() {
Some((last_key, _)) => {
for (key, val) in v.borrow().iter() {
try!(write!(f, "{}: {}", key, val.value.clone()));
r#try!(write!(f, "{}: {}", key, val.value.clone()));
if key != last_key {
try!(write!(f, "{}", ", "));
r#try!(write!(f, "{}", ", "));
}
}
}
@ -555,7 +559,7 @@ impl<T: FromValue> FromValue for Vec<T> {
let len = v.get_field_slice("length").to_int();
let mut vec = Vec::with_capacity(len as usize);
for i in 0..len {
vec.push(try!(from_value(v.get_field(i.to_string()))))
vec.push(r#try!(from_value(v.get_field(i.to_string()))))
}
Ok(vec)
}
@ -616,7 +620,7 @@ impl<T: FromValue> FromValue for Option<T> {
Ok(if value.is_null_or_undefined() {
None
} else {
Some(try!(FromValue::from_value(value)))
Some(r#try!(FromValue::from_value(value)))
})
}
}

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

@ -1,7 +1,7 @@
use std::collections::btree_map::BTreeMap;
use std::fmt::{Display, Formatter, Result};
use syntax::ast::constant::Const;
use syntax::ast::op::{BinOp, Operator, UnaryOp};
use crate::syntax::ast::constant::Const;
use crate::syntax::ast::op::{BinOp, Operator, UnaryOp};
#[derive(Clone, Trace, Finalize, Debug, PartialEq)]
pub struct Expr {
@ -109,9 +109,9 @@ impl Display for ExprDef {
return match *self {
ExprDef::ConstExpr(ref c) => write!(f, "{}", c),
ExprDef::BlockExpr(ref block) => {
try!(write!(f, "{}", "{"));
r#try!(write!(f, "{}", "{"));
for expr in block.iter() {
try!(write!(f, "{};", expr));
r#try!(write!(f, "{};", expr));
}
write!(f, "{}", "}")
}
@ -119,7 +119,7 @@ impl Display for ExprDef {
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) => {
try!(write!(f, "{}(", ex));
r#try!(write!(f, "{}(", ex));
let arg_strs: Vec<String> = args.iter().map(|arg| arg.to_string()).collect();
write!(f, "{})", arg_strs.join(","))
}

2
src/lib/syntax/ast/keyword.rs

@ -2,7 +2,7 @@ use std::error;
use std::fmt::Error;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use syntax::ast::keyword::Keyword::*;
use crate::syntax::ast::keyword::Keyword::*;
#[derive(Clone, PartialEq, Debug)]
/// A Javascript Keyword

6
src/lib/syntax/ast/token.rs

@ -1,7 +1,7 @@
use std::fmt::{Debug, Display, Formatter, Result};
use syntax::ast::keyword::Keyword;
use syntax::ast::pos::Position;
use syntax::ast::punc::Punctuator;
use crate::syntax::ast::keyword::Keyword;
use crate::syntax::ast::pos::Position;
use crate::syntax::ast::punc::Punctuator;
#[derive(Clone, PartialEq)]
/// Represents a token

4
src/lib/syntax/lexer.rs

@ -8,8 +8,8 @@ use std::fmt;
use std::iter::Peekable;
use std::str::Chars;
use std::str::FromStr;
use syntax::ast::punc::Punctuator;
use syntax::ast::token::{Token, TokenData};
use crate::syntax::ast::punc::Punctuator;
use crate::syntax::ast::token::{Token, TokenData};
#[allow(unused)]
macro_rules! vop {

164
src/lib/syntax/parser.rs

@ -1,10 +1,10 @@
use std::collections::btree_map::BTreeMap;
use syntax::ast::constant::Const;
use syntax::ast::expr::{Expr, ExprDef};
use syntax::ast::keyword::Keyword;
use syntax::ast::op::{BinOp, BitOp, CompOp, LogOp, NumOp, Operator, UnaryOp};
use syntax::ast::punc::Punctuator;
use syntax::ast::token::{Token, TokenData};
use crate::syntax::ast::constant::Const;
use crate::syntax::ast::expr::{Expr, ExprDef};
use crate::syntax::ast::keyword::Keyword;
use crate::syntax::ast::op::{BinOp, BitOp, CompOp, LogOp, NumOp, Operator, UnaryOp};
use crate::syntax::ast::punc::Punctuator;
use crate::syntax::ast::token::{Token, TokenData};
macro_rules! mk (
($this:expr, $def:expr) => {
@ -52,7 +52,7 @@ impl Parser {
pub fn parse_all(&mut self) -> ParseResult {
let mut exprs = Vec::new();
while self.pos < self.tokens.len() {
let result = try!(self.parse());
let result = r#try!(self.parse());
exprs.push(result);
}
@ -72,7 +72,7 @@ impl Parser {
fn parse_struct(&mut self, keyword: Keyword) -> ParseResult {
match keyword {
Keyword::Throw => {
let thrown = try!(self.parse());
let thrown = r#try!(self.parse());
Ok(mk!(self, ExprDef::ThrowExpr(Box::new(thrown))))
}
Keyword::Var => {
@ -171,10 +171,10 @@ impl Parser {
))
}
Keyword::Switch => {
try!(self.expect_punc(Punctuator::OpenParen, "switch value"));
r#try!(self.expect_punc(Punctuator::OpenParen, "switch value"));
let value = self.parse();
try!(self.expect_punc(Punctuator::CloseParen, "switch value"));
try!(self.expect_punc(Punctuator::OpenBlock, "switch block"));
r#try!(self.expect_punc(Punctuator::CloseParen, "switch value"));
r#try!(self.expect_punc(Punctuator::OpenBlock, "switch block"));
let mut cases = Vec::new();
let mut default = None;
while self.pos + 1 < self.tokens.len() {
@ -184,26 +184,26 @@ impl Parser {
TokenData::Keyword(Keyword::Case) => {
let cond = self.parse();
let mut block = Vec::new();
try!(self.expect_punc(Punctuator::Colon, "switch case"));
r#try!(self.expect_punc(Punctuator::Colon, "switch case"));
loop {
match try!(self.get_token(self.pos)).data {
match r#try!(self.get_token(self.pos)).data {
TokenData::Keyword(Keyword::Case)
| TokenData::Keyword(Keyword::Default) => break,
TokenData::Punctuator(Punctuator::CloseBlock) => break,
_ => block.push(try!(self.parse())),
_ => block.push(r#try!(self.parse())),
}
}
cases.push((cond.unwrap(), block));
}
TokenData::Keyword(Keyword::Default) => {
let mut block = Vec::new();
try!(self.expect_punc(Punctuator::Colon, "default switch case"));
r#try!(self.expect_punc(Punctuator::Colon, "default switch case"));
loop {
match try!(self.get_token(self.pos)).data {
match r#try!(self.get_token(self.pos)).data {
TokenData::Keyword(Keyword::Case)
| TokenData::Keyword(Keyword::Default) => break,
TokenData::Punctuator(Punctuator::CloseBlock) => break,
_ => block.push(try!(self.parse())),
_ => block.push(r#try!(self.parse())),
}
}
default = Some(mk!(self, ExprDef::BlockExpr(block)));
@ -222,7 +222,7 @@ impl Parser {
}
}
}
try!(self.expect_punc(Punctuator::CloseBlock, "switch block"));
r#try!(self.expect_punc(Punctuator::CloseBlock, "switch block"));
Ok(mk!(
self,
ExprDef::SwitchExpr(
@ -237,7 +237,7 @@ impl Parser {
}
Keyword::Function => {
// function [identifier] () { etc }
let tk = try!(self.get_token(self.pos));
let tk = r#try!(self.get_token(self.pos));
let name = match tk.data {
TokenData::Identifier(ref name) => {
self.pos += 1;
@ -268,7 +268,7 @@ impl Parser {
}
}
self.pos += 1;
if try!(self.get_token(self.pos)).data
if r#try!(self.get_token(self.pos)).data
== TokenData::Punctuator(Punctuator::Comma)
{
self.pos += 1;
@ -291,13 +291,13 @@ impl Parser {
if self.pos > self.tokens.len() {
return Err(ParseError::AbruptEnd);
}
let token = try!(self.get_token(self.pos));
let token = r#try!(self.get_token(self.pos));
self.pos += 1;
let expr: Expr = match token.data {
TokenData::Punctuator(Punctuator::Semicolon) | TokenData::Comment(_)
if self.pos < self.tokens.len() =>
{
try!(self.parse())
r#try!(self.parse())
}
TokenData::Punctuator(Punctuator::Semicolon) | TokenData::Comment(_) => {
mk!(self, ExprDef::ConstExpr(Const::Undefined))
@ -310,15 +310,15 @@ impl Parser {
mk!(self, ExprDef::ConstExpr(Const::Undefined))
}
TokenData::Identifier(s) => mk!(self, ExprDef::LocalExpr(s)),
TokenData::Keyword(keyword) => try!(self.parse_struct(keyword)),
TokenData::Keyword(keyword) => r#try!(self.parse_struct(keyword)),
TokenData::Punctuator(Punctuator::OpenParen) => {
match try!(self.get_token(self.pos)).data {
match r#try!(self.get_token(self.pos)).data {
TokenData::Punctuator(Punctuator::CloseParen)
if try!(self.get_token(self.pos + 1)).data
if r#try!(self.get_token(self.pos + 1)).data
== TokenData::Punctuator(Punctuator::Arrow) =>
{
self.pos += 2;
let expr = try!(self.parse());
let expr = r#try!(self.parse());
mk!(
self,
ExprDef::ArrowFunctionDeclExpr(Vec::new(), Box::new(expr)),
@ -326,8 +326,8 @@ impl Parser {
)
}
_ => {
let next = try!(self.parse());
let next_tok = try!(self.get_token(self.pos));
let next = r#try!(self.parse());
let next_tok = r#try!(self.get_token(self.pos));
self.pos += 1;
match next_tok.data {
TokenData::Punctuator(Punctuator::CloseParen) => next,
@ -338,7 +338,7 @@ impl Parser {
ExprDef::LocalExpr(ref name) => (*name).clone(),
_ => "".to_string(),
},
match try!(self.get_token(self.pos)).data {
match r#try!(self.get_token(self.pos)).data {
TokenData::Identifier(ref id) => id.clone(),
_ => "".to_string(),
},
@ -346,7 +346,7 @@ impl Parser {
let mut expect_ident = true;
loop {
self.pos += 1;
let curr_tk = try!(self.get_token(self.pos));
let curr_tk = r#try!(self.get_token(self.pos));
match curr_tk.data {
TokenData::Identifier(ref id) if expect_ident => {
args.push(id.clone());
@ -380,11 +380,11 @@ impl Parser {
}
}
}
try!(self.expect(
r#try!(self.expect(
TokenData::Punctuator(Punctuator::Arrow),
"arrow function"
));
let expr = try!(self.parse());
let expr = r#try!(self.parse());
mk!(
self,
ExprDef::ArrowFunctionDeclExpr(args, Box::new(expr)),
@ -404,10 +404,10 @@ impl Parser {
}
TokenData::Punctuator(Punctuator::OpenBracket) => {
let mut array: Vec<Expr> = Vec::new();
let mut expect_comma_or_end = try!(self.get_token(self.pos)).data
let mut expect_comma_or_end = r#try!(self.get_token(self.pos)).data
== TokenData::Punctuator(Punctuator::CloseBracket);
loop {
let token = try!(self.get_token(self.pos));
let token = r#try!(self.get_token(self.pos));
if token.data == TokenData::Punctuator(Punctuator::CloseBracket)
&& expect_comma_or_end
{
@ -432,7 +432,7 @@ impl Parser {
"array declaration",
));
} else {
let parsed = try!(self.parse());
let parsed = r#try!(self.parse());
self.pos -= 1;
array.push(parsed);
expect_comma_or_end = true;
@ -442,7 +442,7 @@ impl Parser {
mk!(self, ExprDef::ArrayDeclExpr(array), token)
}
TokenData::Punctuator(Punctuator::OpenBlock)
if try!(self.get_token(self.pos)).data
if r#try!(self.get_token(self.pos)).data
== TokenData::Punctuator(Punctuator::CloseBlock) =>
{
self.pos += 1;
@ -453,15 +453,15 @@ impl Parser {
)
}
TokenData::Punctuator(Punctuator::OpenBlock)
if try!(self.get_token(self.pos + 1)).data
if r#try!(self.get_token(self.pos + 1)).data
== TokenData::Punctuator(Punctuator::Colon) =>
{
let mut map = Box::new(BTreeMap::new());
while try!(self.get_token(self.pos - 1)).data
while r#try!(self.get_token(self.pos - 1)).data
== TokenData::Punctuator(Punctuator::Comma)
|| map.len() == 0
{
let tk = try!(self.get_token(self.pos));
let tk = r#try!(self.get_token(self.pos));
let name = match tk.data {
TokenData::Identifier(ref id) => id.clone(),
TokenData::StringLiteral(ref str) => str.clone(),
@ -477,11 +477,11 @@ impl Parser {
}
};
self.pos += 1;
try!(self.expect(
r#try!(self.expect(
TokenData::Punctuator(Punctuator::Colon),
"object declaration"
));
let value = try!(self.parse());
let value = r#try!(self.parse());
map.insert(name, value);
self.pos += 1;
}
@ -490,12 +490,12 @@ impl Parser {
TokenData::Punctuator(Punctuator::OpenBlock) => {
let mut exprs = Vec::new();
loop {
if try!(self.get_token(self.pos)).data
if r#try!(self.get_token(self.pos)).data
== TokenData::Punctuator(Punctuator::CloseBlock)
{
break;
} else {
exprs.push(try!(self.parse()));
exprs.push(r#try!(self.parse()));
}
}
self.pos += 1;
@ -503,23 +503,23 @@ impl Parser {
}
TokenData::Punctuator(Punctuator::Sub) => mk!(
self,
ExprDef::UnaryOpExpr(UnaryOp::Minus, Box::new(try!(self.parse())))
ExprDef::UnaryOpExpr(UnaryOp::Minus, Box::new(r#try!(self.parse())))
),
TokenData::Punctuator(Punctuator::Add) => mk!(
self,
ExprDef::UnaryOpExpr(UnaryOp::Plus, Box::new(try!(self.parse())))
ExprDef::UnaryOpExpr(UnaryOp::Plus, Box::new(r#try!(self.parse())))
),
TokenData::Punctuator(Punctuator::Not) => mk!(
self,
ExprDef::UnaryOpExpr(UnaryOp::Not, Box::new(try!(self.parse())))
ExprDef::UnaryOpExpr(UnaryOp::Not, Box::new(r#try!(self.parse())))
),
TokenData::Punctuator(Punctuator::Inc) => mk!(
self,
ExprDef::UnaryOpExpr(UnaryOp::IncrementPre, Box::new(try!(self.parse())))
ExprDef::UnaryOpExpr(UnaryOp::IncrementPre, Box::new(r#try!(self.parse())))
),
TokenData::Punctuator(Punctuator::Dec) => mk!(
self,
ExprDef::UnaryOpExpr(UnaryOp::DecrementPre, Box::new(try!(self.parse())))
ExprDef::UnaryOpExpr(UnaryOp::DecrementPre, Box::new(r#try!(self.parse())))
),
_ => return Err(ParseError::Expected(Vec::new(), token.clone(), "script")),
};
@ -537,7 +537,7 @@ impl Parser {
match next.data {
TokenData::Punctuator(Punctuator::Dot) => {
self.pos += 1;
let tk = try!(self.get_token(self.pos));
let tk = r#try!(self.get_token(self.pos));
match tk.data {
TokenData::Identifier(ref s) => {
result = mk!(
@ -557,11 +557,11 @@ impl Parser {
}
TokenData::Punctuator(Punctuator::OpenParen) => {
let mut args = Vec::new();
let mut expect_comma_or_end = try!(self.get_token(self.pos + 1)).data
let mut expect_comma_or_end = r#try!(self.get_token(self.pos + 1)).data
== TokenData::Punctuator(Punctuator::CloseParen);
loop {
self.pos += 1;
let token = try!(self.get_token(self.pos));
let token = r#try!(self.get_token(self.pos));
if token.data == TokenData::Punctuator(Punctuator::CloseParen)
&& expect_comma_or_end
{
@ -581,7 +581,7 @@ impl Parser {
"function call arguments",
));
} else {
let parsed = try!(self.parse());
let parsed = r#try!(self.parse());
self.pos -= 1;
args.push(parsed);
expect_comma_or_end = true;
@ -591,9 +591,9 @@ impl Parser {
}
TokenData::Punctuator(Punctuator::Question) => {
self.pos += 1;
let if_e = try!(self.parse());
try!(self.expect(TokenData::Punctuator(Punctuator::Colon), "if expression"));
let else_e = try!(self.parse());
let if_e = r#try!(self.parse());
r#try!(self.expect(TokenData::Punctuator(Punctuator::Colon), "if expression"));
let else_e = r#try!(self.parse());
result = mk!(
self,
ExprDef::IfExpr(Box::new(expr), Box::new(if_e), Some(Box::new(else_e)))
@ -601,8 +601,8 @@ impl Parser {
}
TokenData::Punctuator(Punctuator::OpenBracket) => {
self.pos += 1;
let index = try!(self.parse());
try!(self.expect(
let index = r#try!(self.parse());
r#try!(self.expect(
TokenData::Punctuator(Punctuator::CloseBracket),
"array index"
));
@ -613,7 +613,7 @@ impl Parser {
}
TokenData::Punctuator(Punctuator::Assign) => {
self.pos += 1;
let next = try!(self.parse());
let next = r#try!(self.parse());
result = mk!(self, ExprDef::AssignExpr(Box::new(expr), Box::new(next)));
}
TokenData::Punctuator(Punctuator::Arrow) => {
@ -623,79 +623,79 @@ impl Parser {
ExprDef::LocalExpr(ref name) => args.push((*name).clone()),
_ => return Err(ParseError::ExpectedExpr("identifier", result)),
}
let next = try!(self.parse());
let next = r#try!(self.parse());
result = mk!(self, ExprDef::ArrowFunctionDeclExpr(args, Box::new(next)));
}
TokenData::Punctuator(Punctuator::Add) => {
result = try!(self.binop(BinOp::Num(NumOp::Add), expr))
result = r#try!(self.binop(BinOp::Num(NumOp::Add), expr))
}
TokenData::Punctuator(Punctuator::Sub) => {
result = try!(self.binop(BinOp::Num(NumOp::Sub), expr))
result = r#try!(self.binop(BinOp::Num(NumOp::Sub), expr))
}
TokenData::Punctuator(Punctuator::Mul) => {
result = try!(self.binop(BinOp::Num(NumOp::Mul), expr))
result = r#try!(self.binop(BinOp::Num(NumOp::Mul), expr))
}
TokenData::Punctuator(Punctuator::Div) => {
result = try!(self.binop(BinOp::Num(NumOp::Div), expr))
result = r#try!(self.binop(BinOp::Num(NumOp::Div), expr))
}
TokenData::Punctuator(Punctuator::Mod) => {
result = try!(self.binop(BinOp::Num(NumOp::Mod), expr))
result = r#try!(self.binop(BinOp::Num(NumOp::Mod), expr))
}
TokenData::Punctuator(Punctuator::BoolAnd) => {
result = try!(self.binop(BinOp::Log(LogOp::And), expr))
result = r#try!(self.binop(BinOp::Log(LogOp::And), expr))
}
TokenData::Punctuator(Punctuator::BoolOr) => {
result = try!(self.binop(BinOp::Log(LogOp::Or), expr))
result = r#try!(self.binop(BinOp::Log(LogOp::Or), expr))
}
TokenData::Punctuator(Punctuator::And) => {
result = try!(self.binop(BinOp::Bit(BitOp::And), expr))
result = r#try!(self.binop(BinOp::Bit(BitOp::And), expr))
}
TokenData::Punctuator(Punctuator::Or) => {
result = try!(self.binop(BinOp::Bit(BitOp::Or), expr))
result = r#try!(self.binop(BinOp::Bit(BitOp::Or), expr))
}
TokenData::Punctuator(Punctuator::Xor) => {
result = try!(self.binop(BinOp::Bit(BitOp::Xor), expr))
result = r#try!(self.binop(BinOp::Bit(BitOp::Xor), expr))
}
TokenData::Punctuator(Punctuator::LeftSh) => {
result = try!(self.binop(BinOp::Bit(BitOp::Shl), expr))
result = r#try!(self.binop(BinOp::Bit(BitOp::Shl), expr))
}
TokenData::Punctuator(Punctuator::RightSh) => {
result = try!(self.binop(BinOp::Bit(BitOp::Shr), expr))
result = r#try!(self.binop(BinOp::Bit(BitOp::Shr), expr))
}
TokenData::Punctuator(Punctuator::Eq) => {
result = try!(self.binop(BinOp::Comp(CompOp::Equal), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::Equal), expr))
}
TokenData::Punctuator(Punctuator::NotEq) => {
result = try!(self.binop(BinOp::Comp(CompOp::NotEqual), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::NotEqual), expr))
}
TokenData::Punctuator(Punctuator::StrictEq) => {
result = try!(self.binop(BinOp::Comp(CompOp::StrictEqual), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::StrictEqual), expr))
}
TokenData::Punctuator(Punctuator::StrictNotEq) => {
result = try!(self.binop(BinOp::Comp(CompOp::StrictNotEqual), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::StrictNotEqual), expr))
}
TokenData::Punctuator(Punctuator::LessThan) => {
result = try!(self.binop(BinOp::Comp(CompOp::LessThan), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::LessThan), expr))
}
TokenData::Punctuator(Punctuator::LessThanOrEq) => {
result = try!(self.binop(BinOp::Comp(CompOp::LessThanOrEqual), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::LessThanOrEqual), expr))
}
TokenData::Punctuator(Punctuator::GreaterThan) => {
result = try!(self.binop(BinOp::Comp(CompOp::GreaterThan), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::GreaterThan), expr))
}
TokenData::Punctuator(Punctuator::GreaterThanOrEq) => {
result = try!(self.binop(BinOp::Comp(CompOp::GreaterThanOrEqual), expr))
result = r#try!(self.binop(BinOp::Comp(CompOp::GreaterThanOrEqual), expr))
}
TokenData::Punctuator(Punctuator::Inc) => {
result = mk!(
self,
ExprDef::UnaryOpExpr(UnaryOp::IncrementPost, Box::new(try!(self.parse())))
ExprDef::UnaryOpExpr(UnaryOp::IncrementPost, Box::new(r#try!(self.parse())))
)
}
TokenData::Punctuator(Punctuator::Dec) => {
result = mk!(
self,
ExprDef::UnaryOpExpr(UnaryOp::DecrementPost, Box::new(try!(self.parse())))
ExprDef::UnaryOpExpr(UnaryOp::DecrementPost, Box::new(r#try!(self.parse())))
)
}
_ => carry_on = false,
@ -710,7 +710,7 @@ impl Parser {
fn binop(&mut self, op: BinOp, orig: Expr) -> Result<Expr, ParseError> {
let (precedence, assoc) = op.get_precedence_and_assoc();
self.pos += 1;
let next = try!(self.parse());
let next = r#try!(self.parse());
Ok(match next.def {
ExprDef::BinOpExpr(ref op2, ref a, ref b) => {
let other_precedence = op2.get_precedence();

4
tests/js/test.js

@ -1,2 +1,2 @@
var a = 'jabrjjja888';
a.length;
var a = new String("test");
a;
Loading…
Cancel
Save