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 op; |
||||
pub mod pos; |
||||
pub mod punc; |
||||
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; |
||||
/// Parses a string stream into a sequence of tokens
|
||||
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