use std::slice::Iter; use std::iter::Peekable; use tokenizer::{Token, Kw}; use tokenizer::Token::*; #[derive(Debug)] pub enum AST { Name(String), LangString(String), Number(f64), BinOp(Box, Box, Box), Binding(String, Box), Statements(Vec), IfStatement(Box, Box, Option>), WhileStatement(Box, Box) } pub enum ParseResult { Ok(AST), Err(String) } type Tokens<'a> = Peekable>; /* expect calls .next() and thus advances the token list */ macro_rules! expect { ($tok:expr, $tokens:expr) => ( if !expect_token($tok, $tokens) { return ParseResult::Err(format!("Expected {:?}", $tok)); }) } fn expect_token(tok: Token, tokens: &mut Tokens) -> bool { 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, (Keyword(k1), Keyword(k2)) => k1 == k2, _ => false } } false } pub fn parse(input: Vec) -> ParseResult { let mut tokens: Tokens = input.iter().peekable(); if let Some(&&EOF) = tokens.peek() { return ParseResult::Ok(AST::Statements(vec!())); } match statements(&mut tokens) { ok@ParseResult::Ok(_) => { expect!(EOF, &mut tokens); ok }, err@ParseResult::Err(_) => err } } fn statements(tokens: &mut Tokens) -> ParseResult { let mut statements = Vec::new(); let initial_statement = match statement(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => ast }; 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) => { statements.push(ast_next); }, err@ParseResult::Err(_) => return err }; }, _ => break } } return ParseResult::Ok(AST::Statements(statements)); } fn statement(tokens: &mut Tokens) -> ParseResult { match tokens.peek().map(|i| i.clone()) { Some(&Keyword(Kw::Let)) => let_expression(tokens), _ => expression(tokens) } } 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() { if s == "=" { if let ParseResult::Ok(expr) = expression(tokens) { return ParseResult::Ok( AST::Binding(name.clone(), Box::new(expr))); } } } } return ParseResult::Err("Bad parse in let_expression()".to_string()); } fn expression(tokens: &mut Tokens) -> ParseResult { let lookahead = tokens.peek().map(|i| i.clone()); match lookahead { Some(&Keyword(Kw::If)) => { if_expression(tokens) }, Some(&Keyword(Kw::While)) => { while_expression(tokens) }, Some(&LParen) => { tokens.next(); let expr = expression(tokens); expect!(RParen, tokens); expr }, _ => binop_expression(tokens) } } fn if_expression(tokens: &mut Tokens) -> ParseResult { expect!(Keyword(Kw::If), tokens); let if_clause = match expression(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => ast }; expect!(Keyword(Kw::Then), tokens); let then_clause = match expression(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => ast }; let else_clause = match tokens.peek().map(|i| i.clone()) { Some(&Keyword(Kw::Else)) => { tokens.next(); match expression(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => Some(ast) } }, _ => None }; expect!(Keyword(Kw::End), tokens); ParseResult::Ok( AST::IfStatement( Box::new(if_clause), Box::new(then_clause), else_clause.map(|ast| Box::new(ast)) )) } fn while_expression(tokens: &mut Tokens) -> ParseResult { expect!(Keyword(Kw::While), tokens); let while_expression = match expression(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => ast }; expect!(Separator, tokens); let statements = match statements(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => ast }; expect!(Keyword(Kw::End), tokens); ParseResult::Ok(AST::WhileStatement( Box::new(while_expression), Box::new(statements), )) } fn binop_expression(tokens: &mut Tokens) -> ParseResult { let lhs = match simple_expression(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => ast }; binop_rhs(0, lhs, tokens) } fn binop_rhs(precedence: i32, lhs: AST, tokens: &mut Tokens) -> ParseResult { let lookahead_precedence = tokens.peek().and_then(|tok| get_binop_precedence(tok)); let output = match lookahead_precedence { None => lhs, Some(next) => { if next < precedence { lhs } else { let binop = match tokens.next() { Some(&Identifier(ref s)) => AST::Name(s.clone()), _ => return ParseResult::Err("Bad binop parse".to_string()) }; let preliminary_rhs = match simple_expression(tokens) { err@ParseResult::Err(_) => return err, ParseResult::Ok(ast) => ast }; let after_rhs_precedence = tokens.peek().and_then(|tok| get_binop_precedence(tok)); let true_rhs = match after_rhs_precedence { Some(arp) if arp >= next => { match binop_rhs(precedence+1, preliminary_rhs, tokens) { ParseResult::Ok(ast) => ast, err@ParseResult::Err(_) => return err } }, _ => preliminary_rhs }; AST::BinOp( Box::new(binop), Box::new(lhs), Box::new(true_rhs) ) } } }; ParseResult::Ok(output) } fn get_binop_precedence(token: &Token) -> Option { let identifier_str = match token { &Identifier(ref s) => s, _ => return None }; let precedence = match &identifier_str[..] { "+" => 20, "-" => 20, "*" => 40, "/" => 40, _ => -1 }; Some(precedence) } fn simple_expression(tokens: &mut Tokens) -> ParseResult { let next = tokens.next(); if let Some(&Identifier(ref value)) = next { return ParseResult::Ok(AST::Name(value.clone())); } if let Some(&StrLiteral(ref value)) = next { return ParseResult::Ok(AST::LangString(value.clone())); } if let Some(&NumLiteral(n)) = next { return ParseResult::Ok(AST::Number(n)); } return ParseResult::Err("Bad parse in simple_expression()".to_string()); }