Browse Source

adding Ops and expressions

pull/1/head
Jason Williams 6 years ago
parent
commit
27e4d93af7
  1. 10
      Dockerfile
  2. 34
      src/lib/syntax/ast/constant.rs
  3. 159
      src/lib/syntax/ast/expr.rs
  4. 3
      src/lib/syntax/ast/mod.rs
  5. 226
      src/lib/syntax/ast/op.rs
  6. 4
      src/lib/syntax/mod.rs
  7. 34
      src/lib/syntax/parser.rs

10
Dockerfile

@ -6,16 +6,16 @@ COPY . .
# LLDB Server
EXPOSE 9228
RUN apt-get update \
apt-get upgrade \
apt-get install -y software-properties-common
RUN apt-get -y update && \
apt-get -y upgrade && \
apt-get install -y sudo software-properties-common
# https://askubuntu.com/questions/787383/how-to-install-llvm-3-9
# http://apt.llvm.org/
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
RUN apt-add-repository "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-6.0 main"
RUN apt-get update
RUN apt-get install clang-6.0 lldb-6.0
RUN apt-get -y update
# RUN sudo apt-get -y install clang-6.0 lldb-6.0
CMD ["/bin/bash"]

34
src/lib/syntax/ast/constant.rs

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

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

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

3
src/lib/syntax/ast/mod.rs

@ -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;

226
src/lib/syntax/ast/op.rs

@ -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(),
}
)
}
}

4
src/lib/syntax/mod.rs

@ -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;

34
src/lib/syntax/parser.rs

@ -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…
Cancel
Save