added parser for v1 (calculator with no types)

This commit is contained in:
Andrew Segavac
2020-04-08 00:04:36 -06:00
parent 7e8287c6cb
commit 76c539cf5c
10 changed files with 926 additions and 4 deletions

63
src/ast.rs Normal file
View File

@@ -0,0 +1,63 @@
pub enum Operator {
Mul,
Div,
Plus,
Minus,
Gt,
Gte,
Lt,
Lte,
Eq,
Mod,
Exp,
FloorDiv,
}
pub struct LiteralInt {
pub value: i32
}
// pub struct LiteralString {
// value: String
// }
pub struct Identifier {
pub name: String
}
pub enum Expression {
LiteralInt(LiteralInt),
// LiteralString(LiteralString),
Identifier(Identifier),
Op(Box<Expression>, Operator, Box<Expression>),
}
pub struct Block {
pub expression: Box<Expression>
}
pub struct VariableDeclaration {
pub name: Identifier,
// type: Identifier,
}
pub struct Function {
pub name: Identifier,
// return_type: Identifier,
pub arguments: Vec<VariableDeclaration>,
pub block: Block,
}
// pub struct Assignment {
// variable: VariableDeclaration,
// expression: Expression,
// }
pub struct Program {
pub functions: Vec<Function>,
}

63
src/grammar.lalrpop Normal file
View File

@@ -0,0 +1,63 @@
use std::str::FromStr;
use crate::ast;
grammar;
pub LiteralInt: ast::LiteralInt = {
r"[0-9]+" => ast::LiteralInt{value: i32::from_str(<>).unwrap()}
};
pub Identifier: ast::Identifier = {
r"[A-Za-z][A-Za-z0-9_]*" => ast::Identifier{name: <>.to_string()}
};
pub Expression: Box<ast::Expression> = {
<l:Expression> "+" <r:Factor> => Box::new(ast::Expression::Op(l, ast::Operator::Plus, r)),
<l:Expression> "-" <r:Factor> => Box::new(ast::Expression::Op(l, ast::Operator::Minus, r)),
Factor,
}
pub Factor: Box<ast::Expression> = {
<l:Factor> "*" <r:Term> => Box::new(ast::Expression::Op(l, ast::Operator::Mul, r)),
<l:Factor> "/" <r:Term> => Box::new(ast::Expression::Op(l, ast::Operator::Div, r)),
Term,
}
pub Term: Box<ast::Expression> = {
LiteralInt => Box::new(ast::Expression::LiteralInt(<>)),
Identifier => Box::new(ast::Expression::Identifier(<>)),
"(" <Expression> ")",
}
pub Block: ast::Block = {
"{" <e:Expression> "}" => ast::Block{expression: e}
}
pub VariableDeclaration: ast::VariableDeclaration = {
Identifier => ast::VariableDeclaration{name: <>}
}
pub Function: ast::Function = {
"fn" <n:Identifier> "(" <args:Comma<VariableDeclaration>> ")" <b:Block> => ast::Function{name: n, arguments: args, block: b}
}
pub Program: ast::Program = {
<fs:Function*> => ast::Program{functions: fs}
}
// From https://lalrpop.github.io/lalrpop/tutorial/006_macros.html
// Comma seperated list of T with optional trailing comma
Comma<T>: Vec<T> = {
<v:(<T> ",")*> <e:T?> => match e {
None => v,
Some(e) => {
let mut v = v;
v.push(e);
v
}
}
};

37
src/main.rs Normal file
View File

@@ -0,0 +1,37 @@
mod ast;
#[macro_use] extern crate lalrpop_util;
lalrpop_mod!(pub grammar); // synthesized by LALRPOP
fn main() {
println!("Hello, world!");
}
#[test]
fn grammar() {
assert!(grammar::LiteralIntParser::new().parse("22").is_ok());
assert!(grammar::IdentifierParser::new().parse("foo").is_ok());
assert!(grammar::LiteralIntParser::new().parse("2a").is_err());
assert!(grammar::TermParser::new().parse("22").is_ok());
assert!(grammar::TermParser::new().parse("foo").is_ok());
assert!(grammar::ExpressionParser::new().parse("22 * foo").is_ok());
assert!(grammar::ExpressionParser::new().parse("22 * 33").is_ok());
assert!(grammar::ExpressionParser::new().parse("(22 * 33) + 24").is_ok());
assert!(grammar::BlockParser::new().parse("{ (22 * 33) + 24 }").is_ok());
assert!(grammar::BlockParser::new().parse("{ }").is_err());
assert!(grammar::VariableDeclarationParser::new().parse("foo").is_ok());
assert!(grammar::VariableDeclarationParser::new().parse("1234").is_err());
assert!(grammar::FunctionParser::new().parse("fn add(a, b) { a + b }").is_ok());
assert!(grammar::FunctionParser::new().parse("fn random_dice_roll() { 4 }").is_ok());
assert!(grammar::FunctionParser::new().parse("fn add(a, b) { a + }").is_err());
assert!(grammar::FunctionParser::new().parse("fn add(a, b)").is_err());
assert!(grammar::ProgramParser::new().parse("fn add(a, b) { a + b }").is_ok());
assert!(grammar::ProgramParser::new().parse("fn add(a, b) { a + b } fn subtract(a, b) { a - b }").is_ok());
}