diff --git a/README.md b/README.md index 74dfe8a..16c49e5 100644 --- a/README.md +++ b/README.md @@ -27,3 +27,31 @@ - [ ] IO Intrinsics - [x] Print - [ ] ReadLine + +## Grammar +### Expressions +``` +LITERAL = I64 | Str +expr_primary = LITERAL | IDENT | "(" expr ")" | "-" expr_primary +expr_mul = expr_primary (("*" | "/" | "%") expr_primary)* +expr_add = expr_mul (("+" | "-") expr_mul)* +expr_shift = expr_add ((">>" | "<<") expr_add)* +expr_rel = expr_shift ((">" | ">=" | "<" | "<=") expr_shift)* +expr_equ = expr_rel (("==" | "!=") expr_rel)* +expr_band = expr_equ ("&" expr_equ)* +expr_bxor = expr_band ("^" expr_band)* +expr_bor = expr_bxor ("|" expr_bxor)* +expr = expr_bor +``` + +## Statements +``` +stmt_expr = expr +stmt_let = "let" IDENT "=" expr +stmt_while = "while" expr "{" (stmt)* "}" +stmt_for = "for" stmt_let ";" expr ";" expr "{" (stmt)* "}" +stmt_if = "if" expr "{" (stmt)* "}" ( "else" "{" (stmt)* "}" ) +stmt_dbgprint = "$$" expr +stmt_print = "$" expr +stmt = stmt_expr | stmt_let | stmt_while | stmt_for | stmt_if | stmt_dbgprint | stmt_print +``` diff --git a/src/ast.rs b/src/ast.rs new file mode 100644 index 0000000..b8ffa42 --- /dev/null +++ b/src/ast.rs @@ -0,0 +1,104 @@ +use std::rc::Rc; + +/// Types for binary operators +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum BinOpType { + /// Addition + Add, + + /// Subtraction + Sub, + + /// Multiplication + Mul, + + /// Divide + Div, + + /// Modulo + Mod, + + /// Bitwise OR (inclusive or) + BOr, + + /// Bitwise And + BAnd, + + /// Bitwise Xor (exclusive or) + BXor, + + /// Shift Left + Shl, + + /// Shift Right + Shr, + + /// Check equality + Equ, + + /// Check unequality + Neq, + + /// Check greater than + Gt, + + /// Check greater or equal + Ge, + + /// Check less than + Lt, + + /// Check less or equal + Le, + + /// Assign to a variable + Assign, +} + +/// Types for unary operators +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum UnOpType { + /// Negation + Neg, +} + +/// A full program abstract syntax tree. This consists of zero or more statements that represents +/// a program. +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Ast { + pub prog: Vec, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Stmt { + /// Just a simple expression. This might be an assignment, a function call or a calculation. + Expr(Expr), + /// A variable declaration and assignment. (variable name, assigned value) + Let(String, Expr), + /// A while loop consisting of a condition and a body. (condition, body) + While(Expr, Ast), + /// A for loop consisting of an initialization declaration, a condition, an advancement and a + /// body. ((variable name, initial value), condition, advancement, body) + For((String, Expr), Expr, Expr, Ast), + /// If statement consisting of a condition, a true_body and a false_body. + /// (condition, true_body, false_body) + If(Expr, Ast, Ast), + /// Debug print the value of an expression (show the internal type together with the value) + DbgPrint(Expr), + /// Print the value of an expression + Print(Expr), +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Expr { + /// Integer literal (64-bit) + I64(i64), + /// String literal + Str(Rc), + /// Identifier (variable name) + Ident(String), + /// Binary operation. Consists of type, left hand side and right hand side + BinOp(BinOpType, Box, Box), + /// Unary operation. Consists of type and the value that is operated on + UnOp(UnOpType, Box), +} \ No newline at end of file diff --git a/src/interpreter.rs b/src/interpreter.rs index 9b66b54..245e64f 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,6 +1,10 @@ -use std::{collections::HashMap, rc::Rc, fmt::Display}; +use std::{collections::HashMap, fmt::Display, rc::Rc}; -use crate::{parser::{Expr, BinOpType, UnOpType, Ast, Stmt, parse}, lexer::lex}; +use crate::{ + ast::{Ast, BinOpType, Expr, Stmt, UnOpType}, + lexer::lex, + parser::parse, +}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Value { @@ -10,7 +14,7 @@ pub enum Value { pub struct Interpreter { /// The variable table maps all variables by their names to their values - vartable: HashMap + vartable: HashMap, } impl Interpreter { @@ -103,12 +107,10 @@ impl Interpreter { Expr::Str(name) => Value::Str(name.clone()), Expr::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, &lhs, &rhs), Expr::UnOp(uo, val) => self.resolve_unop(uo, &val), - Expr::Ident(name) => { - match self.vartable.get(name) { - None => panic!("Runtime error: Use of undeclared variable '{}'", name), - Some(val) => val.clone() - } - } + Expr::Ident(name) => match self.vartable.get(name) { + None => panic!("Runtime error: Use of undeclared variable '{}'", name), + Some(val) => val.clone(), + }, } } @@ -125,7 +127,6 @@ impl Interpreter { } } - let lhs = self.resolve_expr(lhs); let rhs = self.resolve_expr(rhs); @@ -158,11 +159,10 @@ impl Interpreter { match val { Value::I64(val) => match uo { UnOpType::Neg => Value::I64(-val), - } + }, _ => panic!("Invalid unary operation for type"), } } - } impl Display for Value { @@ -174,11 +174,10 @@ impl Display for Value { } } - #[cfg(test)] mod test { use super::{Interpreter, Value}; - use crate::parser::{Expr, BinOpType}; + use crate::ast::{BinOpType, Expr}; #[test] fn test_interpreter_expr() { diff --git a/src/lib.rs b/src/lib.rs index 02e6110..1921d05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,4 @@ pub mod lexer; pub mod parser; pub mod interpreter; pub mod token; +pub mod ast; diff --git a/src/parser.rs b/src/parser.rs index 5918b98..72be4ee 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,124 +1,9 @@ -use std::{iter::Peekable, rc::Rc}; +use std::iter::Peekable; -use crate::token::{Keyword, Literal, Token}; - -/// Types for binary operators -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum BinOpType { - /// Addition - Add, - - /// Subtraction - Sub, - - /// Multiplication - Mul, - - /// Divide - Div, - - /// Modulo - Mod, - - /// Bitwise OR (inclusive or) - BOr, - - /// Bitwise And - BAnd, - - /// Bitwise Xor (exclusive or) - BXor, - - /// Shift Left - Shl, - - /// Shift Right - Shr, - - /// Check equality - Equ, - - /// Check unequality - Neq, - - /// Check greater than - Gt, - - /// Check greater or equal - Ge, - - /// Check less than - Lt, - - /// Check less or equal - Le, - - /// Assign to a variable - Assign, -} - -/// Types for unary operators -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum UnOpType { - /// Negation - Neg, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Ast { - pub prog: Vec, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Stmt { - Expr(Expr), - Let(String, Expr), - While(Expr, Ast), - For((String, Expr), Expr, Expr, Ast), - If(Expr, Ast, Ast), - DbgPrint(Expr), - Print(Expr), -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Expr { - /// Integer literal (64-bit) - I64(i64), - /// String literal - Str(Rc), - /// Identifier (variable name) - Ident(String), - /// Binary operation. Consists of type, left hand side and right hand side - BinOp(BinOpType, Box, Box), - /// Unary operation. Consists of type and the value that is operated on - UnOp(UnOpType, Box), -} - -/* -## Grammar -### Expressions -LITERAL = I64 | Str -expr_primary = LITERAL | IDENT | "(" expr ")" | "-" expr_primary -expr_mul = expr_primary (("*" | "/" | "%") expr_primary)* -expr_add = expr_mul (("+" | "-") expr_mul)* -expr_shift = expr_add ((">>" | "<<") expr_add)* -expr_rel = expr_shift ((">" | ">=" | "<" | "<=") expr_shift)* -expr_equ = expr_rel (("==" | "!=") expr_rel)* -expr_band = expr_equ ("&" expr_equ)* -expr_bxor = expr_band ("^") expr_band)* -expr_bor = expr_bxor ("|" expr_bxor)* -expr = expr_bor - -## Statements -stmt_expr = expr -stmt_let = "let" IDENT "=" expr -stmt_while = "while" expr "{" (stmt)* "}" -stmt_for = "for" stmt_let ";" expr ";" expr "{" (stmt)* "}" -stmt_if = "if" expr "{" (stmt)* "}" ( "else" "{" (stmt)* "}" ) -stmt_dbgprint = "$$" expr -stmt_print = "$" expr -stmt = stmt_expr | stmt_let | stmt_while | stmt_for | stmt_if | stmt_dbgprint | stmt_print -*/ +use crate::{ + ast::{Ast, BinOpType, Expr, Stmt, UnOpType}, + token::{Keyword, Literal, Token}, +}; struct Parser> { tokens: Peekable, @@ -131,6 +16,16 @@ impl> Parser { Self { tokens } } + /// Get the next Token without removing it + fn peek(&mut self) -> &Token { + self.tokens.peek().unwrap_or(&Token::EoF) + } + + /// Advance to next Token and return the removed Token + fn next(&mut self) -> Token { + self.tokens.next().unwrap_or(Token::EoF) + } + fn parse(&mut self) -> Ast { let mut prog = Vec::new(); @@ -340,15 +235,6 @@ impl> Parser { } } - /// Get the next Token without removing it - fn peek(&mut self) -> &Token { - self.tokens.peek().unwrap_or(&Token::EoF) - } - - /// Advance to next Token and return the removed Token - fn next(&mut self) -> Token { - self.tokens.next().unwrap_or(Token::EoF) - } } pub fn parse, A: IntoIterator>(tokens: A) -> Ast { diff --git a/src/token.rs b/src/token.rs index 06efeb3..c9a1ddc 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1,4 +1,4 @@ -use crate::parser::BinOpType; +use crate::ast::BinOpType; #[derive(Debug, PartialEq, Eq)] pub enum Literal {