2015-07-22 03:12:01 -07:00
|
|
|
use std::slice::Iter;
|
2015-07-22 03:42:21 -07:00
|
|
|
use std::iter::Peekable;
|
2015-07-22 03:12:01 -07:00
|
|
|
|
2015-07-22 04:01:56 -07:00
|
|
|
use tokenizer::{Token, Kw};
|
2015-07-22 03:12:01 -07:00
|
|
|
use tokenizer::Token::*;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum AST {
|
2015-07-31 00:27:24 -07:00
|
|
|
Null,
|
2015-07-22 03:12:01 -07:00
|
|
|
Name(String),
|
|
|
|
LangString(String),
|
|
|
|
Number(f64),
|
|
|
|
BinOp(Box<AST>, Box<AST>, Box<AST>),
|
2015-07-24 02:05:15 -07:00
|
|
|
Binding(String, Box<AST>),
|
2015-07-24 17:59:24 -07:00
|
|
|
Statements(Vec<AST>),
|
2015-07-25 16:12:42 -07:00
|
|
|
IfStatement(Box<AST>, Box<AST>, Option<Box<AST>>),
|
2015-07-29 00:52:17 -07:00
|
|
|
WhileStatement(Box<AST>, Box<AST>),
|
|
|
|
DoNothing
|
2015-07-22 03:12:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum ParseResult {
|
|
|
|
Ok(AST),
|
|
|
|
Err(String)
|
|
|
|
}
|
|
|
|
|
2015-07-22 03:42:21 -07:00
|
|
|
type Tokens<'a> = Peekable<Iter<'a,Token>>;
|
2015-07-22 03:36:32 -07:00
|
|
|
|
2015-07-22 03:45:42 -07:00
|
|
|
/* expect calls .next() and thus advances the token list */
|
2015-07-22 03:28:26 -07:00
|
|
|
macro_rules! expect {
|
|
|
|
($tok:expr, $tokens:expr) => ( if !expect_token($tok, $tokens) {
|
|
|
|
return ParseResult::Err(format!("Expected {:?}", $tok));
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-08-05 22:30:25 -07:00
|
|
|
macro_rules! expect_parse {
|
|
|
|
($parse_fn:ident, $tokens:ident) => (
|
|
|
|
match $parse_fn($tokens) {
|
|
|
|
err@ParseResult::Err(_) => return err,
|
|
|
|
ParseResult::Ok(ast) => ast
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-07-22 03:36:32 -07:00
|
|
|
fn expect_token(tok: Token, tokens: &mut Tokens) -> bool {
|
2015-07-22 03:12:01 -07:00
|
|
|
if let Some(n) = tokens.next() {
|
|
|
|
let next = (*n).clone();
|
|
|
|
return match (tok, next) {
|
|
|
|
(EOF, EOF) => true,
|
|
|
|
(Separator, Separator) => true,
|
|
|
|
(LParen, LParen) => true,
|
|
|
|
(RParen, RParen) => true,
|
|
|
|
(Comma, Comma) => true,
|
|
|
|
(NumLiteral(_), NumLiteral(_)) => true,
|
|
|
|
(StrLiteral(_), StrLiteral(_)) => true,
|
|
|
|
(Identifier(ref i1), Identifier(ref i2)) => i1 == i2,
|
2015-07-22 04:01:56 -07:00
|
|
|
(Keyword(k1), Keyword(k2)) => k1 == k2,
|
2015-07-22 03:12:01 -07:00
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 03:45:42 -07:00
|
|
|
false
|
2015-07-22 03:12:01 -07:00
|
|
|
}
|
|
|
|
|
2015-07-22 03:45:42 -07:00
|
|
|
pub fn parse(input: Vec<Token>) -> ParseResult {
|
|
|
|
|
|
|
|
let mut tokens: Tokens = input.iter().peekable();
|
|
|
|
|
2015-07-24 02:08:55 -07:00
|
|
|
if let Some(&&EOF) = tokens.peek() {
|
|
|
|
return ParseResult::Ok(AST::Statements(vec!()));
|
|
|
|
}
|
|
|
|
|
2015-07-24 02:05:15 -07:00
|
|
|
match statements(&mut tokens) {
|
|
|
|
ok@ParseResult::Ok(_) => {
|
|
|
|
expect!(EOF, &mut tokens);
|
|
|
|
ok
|
|
|
|
},
|
|
|
|
err@ParseResult::Err(_) => err
|
2015-07-22 03:45:42 -07:00
|
|
|
}
|
2015-07-24 02:05:15 -07:00
|
|
|
}
|
2015-07-22 03:45:42 -07:00
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
fn statements(tokens: &mut Tokens) -> ParseResult {
|
2015-07-24 02:05:15 -07:00
|
|
|
|
|
|
|
let mut statements = Vec::new();
|
|
|
|
|
2015-08-05 22:30:25 -07:00
|
|
|
let initial_statement = expect_parse!(statement, tokens);
|
2015-07-25 16:55:58 -07:00
|
|
|
statements.push(initial_statement);
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let lookahead = tokens.peek().map(|i| i.clone());
|
|
|
|
match lookahead {
|
|
|
|
Some(&Separator) => {
|
|
|
|
tokens.next();
|
|
|
|
match statement(tokens) {
|
|
|
|
ParseResult::Ok(ast_next) => {
|
2015-07-24 02:05:15 -07:00
|
|
|
statements.push(ast_next);
|
2015-07-25 16:55:58 -07:00
|
|
|
},
|
|
|
|
err@ParseResult::Err(_) => return err
|
|
|
|
};
|
|
|
|
},
|
|
|
|
_ => break
|
2015-07-24 02:05:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ParseResult::Ok(AST::Statements(statements));
|
2015-07-22 03:45:42 -07:00
|
|
|
}
|
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
fn statement(tokens: &mut Tokens) -> ParseResult {
|
|
|
|
match tokens.peek().map(|i| i.clone()) {
|
|
|
|
Some(&Keyword(Kw::Let)) => let_expression(tokens),
|
|
|
|
_ => expression(tokens)
|
2015-07-24 04:15:28 -07:00
|
|
|
}
|
2015-07-24 02:05:15 -07:00
|
|
|
}
|
2015-07-22 03:45:42 -07:00
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
fn let_expression(tokens: &mut Tokens) -> ParseResult {
|
|
|
|
expect!(Keyword(Kw::Let), tokens);
|
|
|
|
if let Some(&Identifier(ref name)) = tokens.next() {
|
|
|
|
if let Some(&Identifier(ref s)) = tokens.next() {
|
2015-07-22 03:28:26 -07:00
|
|
|
if s == "=" {
|
2015-07-26 02:38:31 -07:00
|
|
|
if let ParseResult::Ok(expr) = expression(tokens) {
|
2015-07-24 02:23:18 -07:00
|
|
|
return ParseResult::Ok(
|
|
|
|
AST::Binding(name.clone(),
|
2015-07-25 17:43:44 -07:00
|
|
|
Box::new(expr)));
|
2015-07-22 03:12:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-24 02:05:15 -07:00
|
|
|
return ParseResult::Err("Bad parse in let_expression()".to_string());
|
2015-07-22 03:12:01 -07:00
|
|
|
}
|
2015-07-24 02:23:18 -07:00
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
fn expression(tokens: &mut Tokens) -> ParseResult {
|
|
|
|
let lookahead = tokens.peek().map(|i| i.clone());
|
2015-07-24 17:59:24 -07:00
|
|
|
match lookahead {
|
|
|
|
Some(&Keyword(Kw::If)) => {
|
2015-07-25 15:57:04 -07:00
|
|
|
if_expression(tokens)
|
2015-07-24 17:59:24 -07:00
|
|
|
},
|
2015-07-25 16:12:42 -07:00
|
|
|
Some(&Keyword(Kw::While)) => {
|
|
|
|
while_expression(tokens)
|
|
|
|
},
|
2015-07-26 01:54:55 -07:00
|
|
|
Some(&LParen) => {
|
|
|
|
tokens.next();
|
|
|
|
let expr = expression(tokens);
|
|
|
|
expect!(RParen, tokens);
|
|
|
|
expr
|
|
|
|
},
|
2015-08-04 02:30:05 -07:00
|
|
|
_ => binop_expression(0, tokens)
|
2015-07-24 17:59:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
fn if_expression(tokens: &mut Tokens) -> ParseResult {
|
2015-07-24 17:59:24 -07:00
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
expect!(Keyword(Kw::If), tokens);
|
2015-08-05 22:30:25 -07:00
|
|
|
let if_clause = expect_parse!(expression, tokens);
|
2015-07-25 15:22:07 -07:00
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
expect!(Keyword(Kw::Then), tokens);
|
2015-08-05 22:30:25 -07:00
|
|
|
let then_clause = expect_parse!(expression, tokens);
|
2015-07-25 15:22:07 -07:00
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
let else_clause = match tokens.peek().map(|i| i.clone()) {
|
2015-07-25 15:34:59 -07:00
|
|
|
Some(&Keyword(Kw::Else)) => {
|
2015-07-25 15:57:04 -07:00
|
|
|
tokens.next();
|
|
|
|
match expression(tokens) {
|
2015-07-25 15:34:59 -07:00
|
|
|
err@ParseResult::Err(_) => return err,
|
|
|
|
ParseResult::Ok(ast) => Some(ast)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => None
|
|
|
|
};
|
|
|
|
|
2015-07-25 15:57:04 -07:00
|
|
|
expect!(Keyword(Kw::End), tokens);
|
2015-07-24 17:59:24 -07:00
|
|
|
|
2015-07-25 15:22:07 -07:00
|
|
|
ParseResult::Ok( AST::IfStatement(
|
|
|
|
Box::new(if_clause),
|
|
|
|
Box::new(then_clause),
|
2015-07-25 15:34:59 -07:00
|
|
|
else_clause.map(|ast| Box::new(ast))
|
|
|
|
))
|
2015-07-24 04:15:28 -07:00
|
|
|
}
|
|
|
|
|
2015-07-25 16:12:42 -07:00
|
|
|
fn while_expression(tokens: &mut Tokens) -> ParseResult {
|
|
|
|
expect!(Keyword(Kw::While), tokens);
|
2015-08-05 22:30:25 -07:00
|
|
|
let while_expression = expect_parse!(expression, tokens);
|
2015-07-25 16:12:42 -07:00
|
|
|
|
|
|
|
expect!(Separator, tokens);
|
2015-08-05 22:30:25 -07:00
|
|
|
|
|
|
|
let statements = expect_parse!(statements, tokens);
|
2015-07-25 16:12:42 -07:00
|
|
|
|
|
|
|
expect!(Keyword(Kw::End), tokens);
|
|
|
|
|
|
|
|
ParseResult::Ok(AST::WhileStatement(
|
|
|
|
Box::new(while_expression),
|
|
|
|
Box::new(statements),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2015-08-04 02:30:05 -07:00
|
|
|
fn binop_expression(precedence: i32, tokens: &mut Tokens) -> ParseResult {
|
|
|
|
|
|
|
|
//TODO left needs to match on an identifiers vs. a prefix operator and return *that* AST
|
2015-08-05 22:30:25 -07:00
|
|
|
let mut left: AST = expect_parse!(simple_expression, tokens);
|
2015-07-26 14:59:01 -07:00
|
|
|
|
2015-08-05 01:21:16 -07:00
|
|
|
loop {
|
|
|
|
let lookahead: Option<&Token> = tokens.peek().map(|i| i.clone());
|
|
|
|
let next_precedence = lookahead.and_then(|t| get_binop_precedence(t));
|
|
|
|
|
|
|
|
match next_precedence {
|
|
|
|
Some(next) if precedence < next => {
|
|
|
|
left = match binop_rhs(next, left, tokens) {
|
|
|
|
err@ParseResult::Err(_) => return err,
|
|
|
|
ParseResult::Ok(ast) => ast
|
|
|
|
};
|
|
|
|
},
|
2015-07-26 14:59:01 -07:00
|
|
|
|
2015-08-05 01:21:16 -07:00
|
|
|
_ => return ParseResult::Ok(left),
|
|
|
|
}
|
2015-08-04 02:30:05 -07:00
|
|
|
}
|
2015-08-04 15:56:34 -07:00
|
|
|
}
|
|
|
|
|
2015-08-05 01:21:16 -07:00
|
|
|
fn binop_rhs(precedence: i32, lhs: AST, tokens: &mut Tokens) -> ParseResult {
|
2015-08-04 15:56:34 -07:00
|
|
|
|
|
|
|
let op: AST = match simple_expression(tokens) {
|
|
|
|
err@ParseResult::Err(_) => return err,
|
|
|
|
ParseResult::Ok(ast) => ast
|
|
|
|
};
|
|
|
|
|
2015-08-05 01:21:16 -07:00
|
|
|
let rhs: AST = match binop_expression(precedence, tokens) {
|
2015-08-04 15:56:34 -07:00
|
|
|
err@ParseResult::Err(_) => return err,
|
|
|
|
ParseResult::Ok(ast) => ast
|
|
|
|
};
|
|
|
|
|
|
|
|
ParseResult::Ok(AST::BinOp(
|
|
|
|
Box::new(op),
|
|
|
|
Box::new(lhs),
|
|
|
|
Box::new(rhs)
|
|
|
|
))
|
2015-07-26 14:59:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_binop_precedence(token: &Token) -> Option<i32> {
|
2015-08-06 00:53:50 -07:00
|
|
|
let identifier_str: &String = match token {
|
2015-07-26 14:59:01 -07:00
|
|
|
&Identifier(ref s) => s,
|
|
|
|
_ => return None
|
|
|
|
};
|
|
|
|
|
2015-08-06 00:53:50 -07:00
|
|
|
let output =
|
|
|
|
::BINOP_TABLE.with(|hm| {
|
|
|
|
let prec_table = hm.borrow();
|
|
|
|
let val: Option<i32> = prec_table.get(&identifier_str[..]).map(|i| *i);
|
|
|
|
val
|
|
|
|
});
|
|
|
|
|
|
|
|
output
|
2015-07-26 14:59:01 -07:00
|
|
|
}
|
|
|
|
|
2015-07-25 17:43:44 -07:00
|
|
|
fn simple_expression(tokens: &mut Tokens) -> ParseResult {
|
2015-07-25 15:57:04 -07:00
|
|
|
let next = tokens.next();
|
2015-07-24 02:23:18 -07:00
|
|
|
|
2015-08-06 21:54:43 -07:00
|
|
|
match next {
|
|
|
|
Some(&Identifier(ref value)) =>
|
|
|
|
ParseResult::Ok(AST::Name(value.clone())),
|
2015-07-24 02:23:18 -07:00
|
|
|
|
2015-08-06 21:54:43 -07:00
|
|
|
Some(&StrLiteral(ref value)) =>
|
|
|
|
ParseResult::Ok(AST::LangString(value.clone())),
|
|
|
|
|
|
|
|
Some(&NumLiteral(n)) =>
|
|
|
|
ParseResult::Ok(AST::Number(n)),
|
2015-07-24 02:23:18 -07:00
|
|
|
|
2015-08-06 21:54:43 -07:00
|
|
|
_ => ParseResult::Err("Bad parse in simple_expression()".to_string())
|
|
|
|
}
|
2015-07-24 02:23:18 -07:00
|
|
|
}
|
2015-08-06 04:24:24 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use tokenizer::tokenize;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn parse_tests() {
|
|
|
|
::init_binop_table();
|
|
|
|
|
|
|
|
match parse(tokenize("a + b * c")) {
|
|
|
|
ParseResult::Ok(ast) =>
|
|
|
|
assert_eq!(format!("{:?}", ast), "Statements([BinOp(Name(\"+\"), Name(\"a\"), BinOp(Name(\"*\"), Name(\"b\"), Name(\"c\")))])"),
|
|
|
|
ParseResult::Err(err) => panic!("err: {:?}", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|