mirror of https://github.com/boa-dev/boa.git
Jason Williams
6 years ago
7 changed files with 465 additions and 5 deletions
@ -0,0 +1,34 @@ |
|||||||
|
use std::fmt::{Display, Formatter, Result}; |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A Javascript Constant
|
||||||
|
pub enum Const { |
||||||
|
/// A UTF-8 string, such as `"Hello, world"`
|
||||||
|
String(String), |
||||||
|
// A regular expression, such as `/where('s| is) [wW]ally/`
|
||||||
|
RegExp(String, bool, bool), |
||||||
|
// A 64-bit floating-point number, such as `3.1415`
|
||||||
|
Num(f64), |
||||||
|
// A 32-bit integer, such as `42`
|
||||||
|
Int(i32), |
||||||
|
// A boolean, which is either `true` or `false` and is used to check if criteria are met
|
||||||
|
Bool(bool), |
||||||
|
// The `null` value, which represents a non-existant value
|
||||||
|
Null, |
||||||
|
// The `undefined` value, which represents a field or index that doesn't exist
|
||||||
|
Undefined, |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for Const { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
return match *self { |
||||||
|
Const::String(ref st) => write!(f, "\"{}\"", st), |
||||||
|
Const::RegExp(ref reg, _, _) => write!(f, "~/{}/", reg), |
||||||
|
Const::Num(num) => write!(f, "{}", num), |
||||||
|
Const::Int(num) => write!(f, "{}", num), |
||||||
|
Const::Bool(v) => write!(f, "{}", v), |
||||||
|
Const::Null => write!(f, "null"), |
||||||
|
Const::Undefined => write!(f, "undefined"), |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,159 @@ |
|||||||
|
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 syntax::ast::pos::Position; |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
pub struct Expr { |
||||||
|
/// The expression definition
|
||||||
|
pub def: ExprDef, |
||||||
|
/// The starting position
|
||||||
|
pub start: Position, |
||||||
|
/// The ending position
|
||||||
|
pub end: Position, |
||||||
|
} |
||||||
|
|
||||||
|
impl Expr { |
||||||
|
/// Create a new expression with a starting and ending position
|
||||||
|
pub fn new(def: ExprDef, start: Position, end: Position) -> Expr { |
||||||
|
Expr { |
||||||
|
def: def, |
||||||
|
start: start, |
||||||
|
end: end, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for Expr { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
write!(f, "{}", self.def) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A Javascript Expression
|
||||||
|
pub enum ExprDef { |
||||||
|
/// Run a operation between 2 expressions
|
||||||
|
BinOpExpr(BinOp, Box<Expr>, Box<Expr>), |
||||||
|
/// Run an operation on a value
|
||||||
|
UnaryOpExpr(UnaryOp, Box<Expr>), |
||||||
|
/// Make a constant value
|
||||||
|
ConstExpr(Const), |
||||||
|
/// Construct an object from the function and arguments given
|
||||||
|
ConstructExpr(Box<Expr>, Vec<Expr>), |
||||||
|
/// Run several expressions from top-to-bottom
|
||||||
|
BlockExpr(Vec<Expr>), |
||||||
|
/// Load a reference to a value
|
||||||
|
LocalExpr(String), |
||||||
|
/// Gets the constant field of a value
|
||||||
|
GetConstFieldExpr(Box<Expr>, String), |
||||||
|
/// Gets the field of a value
|
||||||
|
GetFieldExpr(Box<Expr>, Box<Expr>), |
||||||
|
/// Call a function with some values
|
||||||
|
CallExpr(Box<Expr>, Vec<Expr>), |
||||||
|
/// Repeatedly run an expression while the conditional expression resolves to true
|
||||||
|
WhileLoopExpr(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>>), |
||||||
|
/// Run blocks whose cases match the expression
|
||||||
|
SwitchExpr(Box<Expr>, Vec<(Expr, Vec<Expr>)>, Option<Box<Expr>>), |
||||||
|
/// Create an object out of the binary tree given
|
||||||
|
ObjectDeclExpr(Box<BTreeMap<String, Expr>>), |
||||||
|
/// Create an array with items inside
|
||||||
|
ArrayDeclExpr(Vec<Expr>), |
||||||
|
/// Create a function with the given name, arguments, and expression
|
||||||
|
FunctionDeclExpr(Option<String>, Vec<String>, Box<Expr>), |
||||||
|
/// Create an arrow function with the given arguments and expression
|
||||||
|
ArrowFunctionDeclExpr(Vec<String>, Box<Expr>), |
||||||
|
/// Return the expression from a function
|
||||||
|
ReturnExpr(Option<Box<Expr>>), |
||||||
|
/// Throw a value
|
||||||
|
ThrowExpr(Box<Expr>), |
||||||
|
/// Assign an expression to a value
|
||||||
|
AssignExpr(Box<Expr>, Box<Expr>), |
||||||
|
/// A variable declaration
|
||||||
|
VarDeclExpr(Vec<(String, Option<Expr>)>), |
||||||
|
/// Return a string representing the type of the given expression
|
||||||
|
TypeOfExpr(Box<Expr>), |
||||||
|
} |
||||||
|
|
||||||
|
impl Operator for ExprDef { |
||||||
|
fn get_assoc(&self) -> bool { |
||||||
|
match *self { |
||||||
|
ExprDef::ConstructExpr(_, _) |
||||||
|
| ExprDef::UnaryOpExpr(_, _) |
||||||
|
| ExprDef::TypeOfExpr(_) |
||||||
|
| ExprDef::IfExpr(_, _, _) |
||||||
|
| ExprDef::AssignExpr(_, _) => 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, |
||||||
|
// 16 should be yield
|
||||||
|
ExprDef::AssignExpr(_, _) => 17, |
||||||
|
_ => 19, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for ExprDef { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
return match *self { |
||||||
|
ExprDef::ConstExpr(ref c) => write!(f, "{}", c), |
||||||
|
ExprDef::BlockExpr(ref block) => { |
||||||
|
try!(write!(f, "{}", "{")); |
||||||
|
for expr in block.iter() { |
||||||
|
try!(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) => { |
||||||
|
try!(write!(f, "{}(", ex)); |
||||||
|
let arg_strs: Vec<String> = args.iter().map(|arg| arg.to_string()).collect(); |
||||||
|
write!(f, "{})", arg_strs.connect(",")) |
||||||
|
} |
||||||
|
ExprDef::ConstructExpr(ref func, ref args) => write!(f, "new {}({})", func, args), |
||||||
|
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)) => { |
||||||
|
write!(f, "if({}) {} else {}", cond, expr, else_e) |
||||||
|
} |
||||||
|
ExprDef::SwitchExpr(ref val, ref vals, None) => write!(f, "switch({}){}", val, vals), |
||||||
|
ExprDef::SwitchExpr(ref val, ref vals, Some(ref def)) => { |
||||||
|
write!(f, "switch({}){}default:{}", val, vals, def) |
||||||
|
} |
||||||
|
ExprDef::ObjectDeclExpr(ref map) => write!(f, "{}", map), |
||||||
|
ExprDef::ArrayDeclExpr(ref arr) => write!(f, "{}", arr), |
||||||
|
ExprDef::FunctionDeclExpr(ref name, ref args, ref expr) => { |
||||||
|
write!(f, "function {}({}){}", name, args.connect(", "), expr) |
||||||
|
} |
||||||
|
ExprDef::ArrowFunctionDeclExpr(ref args, ref expr) => { |
||||||
|
write!(f, "({}) => {}", args.connect(", "), 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) => write!(f, "var {}", vars), |
||||||
|
ExprDef::TypeOfExpr(ref e) => write!(f, "typeof {}", e), |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,7 @@ |
|||||||
|
pub mod constant; |
||||||
|
pub mod expr; |
||||||
pub mod keyword; |
pub mod keyword; |
||||||
|
pub mod op; |
||||||
pub mod pos; |
pub mod pos; |
||||||
pub mod punc; |
pub mod punc; |
||||||
pub mod token; |
pub mod token; |
||||||
|
@ -0,0 +1,226 @@ |
|||||||
|
use std::fmt::{Display, Formatter, Result}; |
||||||
|
|
||||||
|
/// Represents an operator
|
||||||
|
pub trait Operator { |
||||||
|
/// Get the associativity as a boolean that is true if it goes rightwards
|
||||||
|
fn get_assoc(&self) -> bool; |
||||||
|
/// Get the precedence as an unsigned integer, where the lower it is, the more precedence/priority it has
|
||||||
|
fn get_precedence(&self) -> u64; |
||||||
|
/// Get the precedence and associativity of this operator
|
||||||
|
fn get_precedence_and_assoc(&self) -> (u64, bool) { |
||||||
|
(self.get_precedence(), self.get_assoc()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A numeric operation between 2 values
|
||||||
|
pub enum NumOp { |
||||||
|
/// `a + b` - Addition
|
||||||
|
Add, |
||||||
|
/// `a - b` - Subtraction
|
||||||
|
Sub, |
||||||
|
/// `a / b` - Division
|
||||||
|
Div, |
||||||
|
/// `a * b` - Multiplication
|
||||||
|
Mul, |
||||||
|
/// `a % b` - Modulus
|
||||||
|
Mod, |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for NumOp { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
write!( |
||||||
|
f, |
||||||
|
"{}", |
||||||
|
match *self { |
||||||
|
NumOp::Add => "+", |
||||||
|
NumOp::Sub => "-", |
||||||
|
NumOp::Div => "/", |
||||||
|
NumOp::Mul => "*", |
||||||
|
NumOp::Mod => "%", |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A unary operation on a single value
|
||||||
|
pub enum UnaryOp { |
||||||
|
/// `a++` - increment the value
|
||||||
|
IncrementPost, |
||||||
|
/// `++a` - increment the value
|
||||||
|
IncrementPre, |
||||||
|
/// `a--` - decrement the value
|
||||||
|
DecrementPost, |
||||||
|
/// `--a` - decrement the value
|
||||||
|
DecrementPre, |
||||||
|
/// `-a` - negate the value
|
||||||
|
Minus, |
||||||
|
/// `+a` - convert to a number
|
||||||
|
Plus, |
||||||
|
/// `!a` - get the opposite of the boolean value
|
||||||
|
Not, |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for UnaryOp { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
write!( |
||||||
|
f, |
||||||
|
"{}", |
||||||
|
match *self { |
||||||
|
UnaryOp::IncrementPost | UnaryOp::IncrementPre => "++", |
||||||
|
UnaryOp::DecrementPost | UnaryOp::DecrementPre => "--", |
||||||
|
UnaryOp::Plus => "+", |
||||||
|
UnaryOp::Minus => "-", |
||||||
|
UnaryOp::Not => "!", |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A bitwise operation between 2 values
|
||||||
|
pub enum BitOp { |
||||||
|
/// `a & b` - Bitwise and
|
||||||
|
And, |
||||||
|
/// `a | b` - Bitwise or
|
||||||
|
Or, |
||||||
|
/// `a ^ b` - Bitwise xor
|
||||||
|
Xor, |
||||||
|
/// `a << b` - Bit-shift leftwards
|
||||||
|
Shl, |
||||||
|
/// `a >> b` - Bit-shift rightrights
|
||||||
|
Shr, |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for BitOp { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
write!( |
||||||
|
f, |
||||||
|
"{}", |
||||||
|
match *self { |
||||||
|
BitOp::And => "&", |
||||||
|
BitOp::Or => "|", |
||||||
|
BitOp::Xor => "^", |
||||||
|
BitOp::Shl => "<<", |
||||||
|
BitOp::Shr => ">>", |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A comparitive operation between 2 values
|
||||||
|
pub enum CompOp { |
||||||
|
/// `a == b` - Equality
|
||||||
|
Equal, |
||||||
|
/// `a != b` - Unequality
|
||||||
|
NotEqual, |
||||||
|
/// `a === b` - Strict equality
|
||||||
|
StrictEqual, |
||||||
|
/// `a !== b` - Strict unequality
|
||||||
|
StrictNotEqual, |
||||||
|
/// `a > b` - If `a` is greater than `b`
|
||||||
|
GreaterThan, |
||||||
|
/// `a >= b` - If `a` is greater than or equal to `b`
|
||||||
|
GreaterThanOrEqual, |
||||||
|
/// `a < b` - If `a` is less than `b`
|
||||||
|
LessThan, |
||||||
|
/// `a <= b` - If `a` is less than or equal to `b`
|
||||||
|
LessThanOrEqual, |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for CompOp { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
write!( |
||||||
|
f, |
||||||
|
"{}", |
||||||
|
match *self { |
||||||
|
CompOp::Equal => "==", |
||||||
|
CompOp::NotEqual => "!=", |
||||||
|
CompOp::StrictEqual => "===", |
||||||
|
CompOp::StrictNotEqual => "!==", |
||||||
|
CompOp::GreaterThan => ">", |
||||||
|
CompOp::GreaterThanOrEqual => ">=", |
||||||
|
CompOp::LessThan => "<", |
||||||
|
CompOp::LessThanOrEqual => "<=", |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A logical operation between 2 boolean values
|
||||||
|
pub enum LogOp { |
||||||
|
/// `a && b` - Logical and
|
||||||
|
And, |
||||||
|
/// `a || b` - Logical or
|
||||||
|
Or, |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for LogOp { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
write!( |
||||||
|
f, |
||||||
|
"{}", |
||||||
|
match *self { |
||||||
|
LogOp::And => "&&", |
||||||
|
LogOp::Or => "||", |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)] |
||||||
|
/// A binary operation between 2 values
|
||||||
|
pub enum BinOp { |
||||||
|
/// Numeric operation
|
||||||
|
Num(NumOp), |
||||||
|
/// Bitwise operation
|
||||||
|
Bit(BitOp), |
||||||
|
/// Comparitive operation
|
||||||
|
Comp(CompOp), |
||||||
|
/// Logical operation
|
||||||
|
Log(LogOp), |
||||||
|
} |
||||||
|
|
||||||
|
impl Operator for BinOp { |
||||||
|
fn get_assoc(&self) -> bool { |
||||||
|
true |
||||||
|
} |
||||||
|
fn get_precedence(&self) -> u64 { |
||||||
|
match *self { |
||||||
|
BinOp::Num(NumOp::Mul) | BinOp::Num(NumOp::Div) | BinOp::Num(NumOp::Mod) => 5, |
||||||
|
BinOp::Num(NumOp::Add) | BinOp::Num(NumOp::Sub) => 6, |
||||||
|
BinOp::Bit(BitOp::Shl) | BinOp::Bit(BitOp::Shr) => 7, |
||||||
|
BinOp::Comp(CompOp::LessThan) |
||||||
|
| BinOp::Comp(CompOp::LessThanOrEqual) |
||||||
|
| BinOp::Comp(CompOp::GreaterThan) |
||||||
|
| BinOp::Comp(CompOp::GreaterThanOrEqual) => 8, |
||||||
|
BinOp::Comp(CompOp::Equal) |
||||||
|
| BinOp::Comp(CompOp::NotEqual) |
||||||
|
| BinOp::Comp(CompOp::StrictEqual) |
||||||
|
| BinOp::Comp(CompOp::StrictNotEqual) => 9, |
||||||
|
BinOp::Bit(BitAnd) => 10, |
||||||
|
BinOp::Bit(BitXor) => 11, |
||||||
|
BinOp::Bit(BitOr) => 12, |
||||||
|
BinOp::Log(LogAnd) => 13, |
||||||
|
BinOp::Log(LogOr) => 14, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl Display for BinOp { |
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result { |
||||||
|
write!( |
||||||
|
f, |
||||||
|
"{}", |
||||||
|
match *self { |
||||||
|
BinOp::Num(op) => op.to_string(), |
||||||
|
BinOp::Bit(op) => op.to_string(), |
||||||
|
BinOp::Comp(op) => op.to_string(), |
||||||
|
BinOp::Log(op) => op.to_string(), |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -1,2 +1,6 @@ |
|||||||
|
/// The Javascript Abstract Syntax Tree
|
||||||
pub mod ast; |
pub mod ast; |
||||||
|
/// Parses a string stream into a sequence of tokens
|
||||||
pub mod lexer; |
pub mod lexer; |
||||||
|
/// Parses a sequence of tokens into expressions
|
||||||
|
pub mod parser; |
||||||
|
@ -0,0 +1,34 @@ |
|||||||
|
use syntax::ast::expr::Expr; |
||||||
|
use syntax::ast::keyword::Keyword; |
||||||
|
use syntax::ast::token::{Token, TokenData}; |
||||||
|
|
||||||
|
/// An error encounted during parsing an expression
|
||||||
|
pub enum ParseError { |
||||||
|
/// When it expected a certain kind of token, but got another as part of something
|
||||||
|
Expected(Vec<TokenData>, Token, &'static str), |
||||||
|
/// When it expected a certain expression, but got another
|
||||||
|
ExpectedExpr(&'static str, Expr), |
||||||
|
/// When it didn't expect this keyword
|
||||||
|
UnexpectedKeyword(Keyword), |
||||||
|
/// When there is an abrupt end to the parsing
|
||||||
|
AbruptEnd, |
||||||
|
} |
||||||
|
|
||||||
|
pub type ParseResult = Result<Expr, ParseError>; |
||||||
|
|
||||||
|
pub struct Parser { |
||||||
|
/// The tokens being input
|
||||||
|
tokens: Vec<Token>, |
||||||
|
/// The current position within the tokens
|
||||||
|
pos: u64, |
||||||
|
} |
||||||
|
|
||||||
|
impl Parser { |
||||||
|
/// Create a new parser, using `tokens` as input
|
||||||
|
pub fn new(tokens: Vec<Token>) -> Parser { |
||||||
|
Parser { |
||||||
|
tokens: tokens, |
||||||
|
pos: 0, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue