Partial refactoring of parser

This commit is contained in:
Daniel M 2022-01-29 19:20:51 +01:00
parent 9e3a642810
commit e28b3c4f37
6 changed files with 162 additions and 144 deletions

View File

@ -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
```

104
src/ast.rs Normal file
View File

@ -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<Stmt>,
}
#[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<String>),
/// Identifier (variable name)
Ident(String),
/// Binary operation. Consists of type, left hand side and right hand side
BinOp(BinOpType, Box<Expr>, Box<Expr>),
/// Unary operation. Consists of type and the value that is operated on
UnOp(UnOpType, Box<Expr>),
}

View File

@ -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<String, Value>
vartable: HashMap<String, Value>,
}
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() {

View File

@ -2,3 +2,4 @@ pub mod lexer;
pub mod parser;
pub mod interpreter;
pub mod token;
pub mod ast;

View File

@ -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<Stmt>,
}
#[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<String>),
/// Identifier (variable name)
Ident(String),
/// Binary operation. Consists of type, left hand side and right hand side
BinOp(BinOpType, Box<Expr>, Box<Expr>),
/// Unary operation. Consists of type and the value that is operated on
UnOp(UnOpType, Box<Expr>),
}
/*
## 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<T: Iterator<Item = Token>> {
tokens: Peekable<T>,
@ -131,6 +16,16 @@ impl<T: Iterator<Item = Token>> Parser<T> {
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<T: Iterator<Item = Token>> Parser<T> {
}
}
/// 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<T: Iterator<Item = Token>, A: IntoIterator<IntoIter = T>>(tokens: A) -> Ast {

View File

@ -1,4 +1,4 @@
use crate::parser::BinOpType;
use crate::ast::BinOpType;
#[derive(Debug, PartialEq, Eq)]
pub enum Literal {