Skip to content

Instantly share code, notes, and snippets.

@cronokirby
Created January 11, 2020 09:21
Show Gist options
  • Select an option

  • Save cronokirby/ac6f9d6545aeee784c383b0d2133a621 to your computer and use it in GitHub Desktop.

Select an option

Save cronokirby/ac6f9d6545aeee784c383b0d2133a621 to your computer and use it in GitHub Desktop.
use crate::ast::*;
use crate::lexer;
grammar;
Comma<T>: Vec<T> = {
<v:(<T> ",")*> <e: T?> => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
}
pub AST: AST = {
<functions:(<Function> ";"?)*> => AST {<>},
};
Function: Function = {
"func" <name:name> "(" <args:Comma<name>>")" <body:Block> => Function { name, args, body },
};
Block: Vec<Expr> = {
"{" <v:(<Expr> ";")*> <e: Expr?> "}" => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
};
Expr: Expr = {
<value:name> ":=" <e:Expr> => Expr::Declare(value, Box::new(e)),
<value:name> "=" <e:Expr> => Expr::Assign(value, Box::new(e)),
Expr1
}
Expr1: Expr = {
<left:Expr2> "&&" <right:Expr1> => Expr::ConditionalOp(BoolOp::And, Box::new(left), Box::new(right)),
Expr2,
};
Expr2: Expr = {
<left:Expr3> "==" <right:Expr3> => Expr::BinOp(Op::Equal, Box::new(left), Box::new(right)),
<left:Expr3> "!=" <right:Expr3> => Expr::BinOp(Op::NotEqual, Box::new(left), Box::new(right)),
Expr3,
};
Expr3: Expr = {
<left:Expr4> "<=" <right:Expr4> => Expr::BinOp(Op::Leq, Box::new(left), Box::new(right)),
<left:Expr4> "<" <right:Expr4> => Expr::BinOp(Op::Less, Box::new(left), Box::new(right)),
<left:Expr4> ">=" <right:Expr4> => Expr::BinOp(Op::Geq, Box::new(left), Box::new(right)),
<left:Expr4> ">" <right:Expr4> => Expr::BinOp(Op::Greater, Box::new(left), Box::new(right)),
Expr4
};
Expr4: Expr = {
<left:Expr4> "+" <right:Expr5> => Expr::BinOp(Op::Add, Box::new(left), Box::new(right)),
<left:Expr4> "-" <right:Expr5> => Expr::BinOp(Op::Sub, Box::new(left), Box::new(right)),
Expr5,
};
Expr5: Expr = {
<left:Expr5> "*" <right:Expr6> => Expr::BinOp(Op::Mul, Box::new(left), Box::new(right)),
<left:Expr5> "/" <right:Expr6> => Expr::BinOp(Op::Div, Box::new(left), Box::new(right)),
<left:Expr5> "%" <right:Expr6> => Expr::BinOp(Op::Mod, Box::new(left), Box::new(right)),
Expr6,
};
Expr6: Expr = {
<value:name> "(" <args:Comma<Expr>> ")" => Expr::Call(value, args),
<l:Litteral> => Expr::Litt(l),
<value:name> => Expr::Name(value),
<Block> => Expr::Block(<>),
<ExprIfElse>,
"(" <Expr> ")",
};
ExprIfElse: Expr = {
"if" <cond:Expr> <left:Block> <right:("else" <ExprAfterElse>)?> => {
let right = match right {
None => Vec::new(),
Some(v) => v,
};
Expr::IfElse(Box::new(cond), left, right)
}
}
ExprAfterElse: Vec<Expr> = {
<ExprIfElse> => vec![<>],
<Block>,
}
Litteral: Litteral = {
<value:int> => Litteral::I64(value),
<value:string> => Litteral::Str(value),
<value:bool> => Litteral::Bool(value),
};
extern {
type Location = lexer::Location;
type Error = lexer::LexError;
enum lexer::Token {
"{" => lexer::Token::OpenBrace,
"}" => lexer::Token::CloseBrace,
"(" => lexer::Token::OpenParens,
")" => lexer::Token::CloseParens,
";" => lexer::Token::Semicolon,
":=" => lexer::Token::Define,
"==" => lexer::Token::DoubleEquals,
"!=" => lexer::Token::NotEquals,
"=" => lexer::Token::Equals,
"<=" => lexer::Token::LessEquals,
"<" => lexer::Token::Less,
">" => lexer::Token::Greater,
">=" => lexer::Token::GreaterEquals,
"," => lexer::Token::Comma,
"+" => lexer::Token::Plus,
"-" => lexer::Token::Minus,
"*" => lexer::Token::Asterisk,
"/" => lexer::Token::Slash,
"%" => lexer::Token::Percent,
"&&" => lexer::Token::DoubleAmpersand,
"func" => lexer::Token::Func,
"if" => lexer::Token::If,
"else" => lexer::Token::Else,
name => lexer::Token::Name { value: <String> },
int => lexer::Token::IntLitteral { value: <i64> },
string => lexer::Token::StringLitteral { value: <String> },
bool => lexer::Token::BoolLitteral { value: <bool> },
}
}
use crate::ast::*;
use crate::lexer;
grammar;
Comma<T>: Vec<T> = {
<v:(<T> ",")*> <e: T?> => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
}
pub AST: AST = {
<functions:(<Function> ";"?)*> => AST {<>},
};
Function: Function = {
"func" <name:name> "(" <args:Comma<name>>")" <body:Block> => Function { name, args, body },
};
Block: Vec<Expr> = {
"{" <v:(<Expr> ";")*> <e: Expr?> "}" => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
};
Expr: Expr = {
<value:name> ":=" <e:Expr> => Expr::Declare(value, Box::new(e)),
<value:name> "=" <e:Expr> => Expr::Assign(value, Box::new(e)),
Expr1
};
Expr1: Expr = {
<left:Expr2> "||" <right:Expr1> => Expr::ConditionalOp(BoolOp::Or, Box::new(left), Box::new(right)),
Expr2,
};
Expr2: Expr = {
<left:Expr3> "&&" <right:Expr2> => Expr::ConditionalOp(BoolOp::And, Box::new(left), Box::new(right)),
Expr2,
};
Expr3: Expr = {
<left:Expr4> "==" <right:Expr4> => Expr::BinOp(Op::Equal, Box::new(left), Box::new(right)),
<left:Expr4> "!=" <right:Expr4> => Expr::BinOp(Op::NotEqual, Box::new(left), Box::new(right)),
Expr4,
};
Expr4: Expr = {
<left:Expr5> "<=" <right:Expr5> => Expr::BinOp(Op::Leq, Box::new(left), Box::new(right)),
<left:Expr5> "<" <right:Expr5> => Expr::BinOp(Op::Less, Box::new(left), Box::new(right)),
<left:Expr5> ">=" <right:Expr5> => Expr::BinOp(Op::Geq, Box::new(left), Box::new(right)),
<left:Expr5> ">" <right:Expr5> => Expr::BinOp(Op::Greater, Box::new(left), Box::new(right)),
Expr5,
};
Expr5: Expr = {
<left:Expr5> "+" <right:Expr6> => Expr::BinOp(Op::Add, Box::new(left), Box::new(right)),
<left:Expr5> "-" <right:Expr6> => Expr::BinOp(Op::Sub, Box::new(left), Box::new(right)),
Expr6,
};
Expr6: Expr = {
<left:Expr6> "*" <right:Expr7> => Expr::BinOp(Op::Mul, Box::new(left), Box::new(right)),
<left:Expr6> "/" <right:Expr7> => Expr::BinOp(Op::Div, Box::new(left), Box::new(right)),
<left:Expr6> "%" <right:Expr7> => Expr::BinOp(Op::Mod, Box::new(left), Box::new(right)),
Expr7,
};
Expr7: Expr = {
<value:name> "(" <args:Comma<Expr>> ")" => Expr::Call(value, args),
<l:Litteral> => Expr::Litt(l),
<value:name> => Expr::Name(value),
<Block> => Expr::Block(<>),
<ExprIfElse>,
"(" <Expr> ")",
};
ExprIfElse: Expr = {
"if" <cond:Expr> <left:Block> <right:("else" <ExprAfterElse>)?> => {
let right = match right {
None => Vec::new(),
Some(v) => v,
};
Expr::IfElse(Box::new(cond), left, right)
}
}
ExprAfterElse: Vec<Expr> = {
<ExprIfElse> => vec![<>],
<Block>,
}
Litteral: Litteral = {
<value:int> => Litteral::I64(value),
<value:string> => Litteral::Str(value),
<value:bool> => Litteral::Bool(value),
};
extern {
type Location = lexer::Location;
type Error = lexer::LexError;
enum lexer::Token {
"{" => lexer::Token::OpenBrace,
"}" => lexer::Token::CloseBrace,
"(" => lexer::Token::OpenParens,
")" => lexer::Token::CloseParens,
";" => lexer::Token::Semicolon,
":=" => lexer::Token::Define,
"==" => lexer::Token::DoubleEquals,
"!=" => lexer::Token::NotEquals,
"=" => lexer::Token::Equals,
"<=" => lexer::Token::LessEquals,
"<" => lexer::Token::Less,
">" => lexer::Token::Greater,
">=" => lexer::Token::GreaterEquals,
"," => lexer::Token::Comma,
"+" => lexer::Token::Plus,
"-" => lexer::Token::Minus,
"*" => lexer::Token::Asterisk,
"/" => lexer::Token::Slash,
"%" => lexer::Token::Percent,
"&&" => lexer::Token::DoubleAmpersand,
"||" => lexer::Token::DoublePipe,
"func" => lexer::Token::Func,
"if" => lexer::Token::If,
"else" => lexer::Token::Else,
name => lexer::Token::Name { value: <String> },
int => lexer::Token::IntLitteral { value: <i64> },
string => lexer::Token::StringLitteral { value: <String> },
bool => lexer::Token::BoolLitteral { value: <bool> },
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment