From 794a630d02c9f29bd8f061f0d8ffee8928e82b9f Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Wed, 18 Feb 2026 13:25:45 +0100 Subject: [PATCH 01/10] Mr gpt and i added symbol table impl functions, so its ready to use basically. Look at the return types before using, some return types are Result (basically tells u if Ok or Err) and then there are Option type, and those functions either return Some(value) or None, then u need to unwrap that some value. Its like the maybe type in haskell --- src/lexer/lexer.rs | 3 -- src/lexer/token.rs | 3 -- src/main.rs | 1 + src/parser/parser.rs | 0 src/semantic/mod.rs | 3 +- src/semantic/symbol_table.rs | 68 ++++++++++++++++++++++++++++++++++-- src/semantic/types.rs | 5 --- 7 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 src/parser/parser.rs delete mode 100644 src/semantic/types.rs diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index 3d24724..1ed2ab9 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -1,5 +1,3 @@ -use std::{any::Any, string}; - use crate::lexer::token::{Token, TokenType}; @@ -214,7 +212,6 @@ impl Lexer { "Boolean"=> Token::new(TokenType::Boolean, line, col), "True" => Token::new(TokenType::True, line, col), "False" => Token::new(TokenType::False, line, col), - "Eof" => Token::new(TokenType::Eof, line, col), _ => Token::new(TokenType::Identifier(name.to_string()), line, col), } } diff --git a/src/lexer/token.rs b/src/lexer/token.rs index d3c7e0a..077cd79 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -43,9 +43,6 @@ pub enum TokenType { RightBrace, // } Comma, // , Semicolon, // ; - - // Special - Eof, } #[derive(Debug, Clone)] diff --git a/src/main.rs b/src/main.rs index ef90e80..2835d59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod lexer; +mod semantic; use std::env; use std::fs; diff --git a/src/parser/parser.rs b/src/parser/parser.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/semantic/mod.rs b/src/semantic/mod.rs index 3533058..eed35c2 100644 --- a/src/semantic/mod.rs +++ b/src/semantic/mod.rs @@ -1,2 +1 @@ -pub mod Type; -pub mod SymbolTable; \ No newline at end of file +pub mod symbol_table; \ No newline at end of file diff --git a/src/semantic/symbol_table.rs b/src/semantic/symbol_table.rs index 815f864..abd6011 100644 --- a/src/semantic/symbol_table.rs +++ b/src/semantic/symbol_table.rs @@ -1,11 +1,73 @@ use std::collections::HashMap; + +#[derive(Debug, Clone, PartialEq)] +pub enum Type { + Integer, + Boolean, + String, + Void, //mayhaps not needed dunno, only if we allow functiions that dont return anything + Function { + params: Vec, + return_type: Box, + }, +} + pub struct Symbol { + name: String, symbol_type: Type, scope_level: usize, //perchance we need to add some more info, for functions (return types, param names) } +impl Symbol { + pub fn new(_name: String, s_type: Type, scope_lvl: usize ) -> Self{ + Self{ + name: _name, + symbol_type: s_type, + scope_level: scope_lvl, + } + } +} + pub struct SymbolTable { - scopes: Vec>, - //key = name i figured, so no "name" property in Symbol struct -} \ No newline at end of file + scopes: Vec>, +} +impl SymbolTable { + pub fn new() -> Self { + Self{ + scopes: Vec::new(), + } + } + pub fn enter_scope(&mut self) { + self.scopes.push(HashMap::new()); + } + pub fn exit_scope(&mut self) { + if self.scopes.len() > 1 { + self.scopes.pop(); + } + } + pub fn insert(&mut self, symbol: Symbol) -> Result<(), String> { + let current = self.scopes.last_mut().unwrap(); + + if current.contains_key(&symbol.name) { + return Err(format!("Symbol '{}' already declared in this scope", symbol.name)); + } + + current.insert(symbol.name.clone(), symbol); + Ok(()) + } + pub fn lookup(&self, name: &str) -> Option<&Symbol> { + for scope in self.scopes.iter().rev() { + if let Some(symbol) = scope.get(name) { + Some(symbol); + } + } + None + } + pub fn lookup_current(&self, name: &str) -> Option<&Symbol> { + self.scopes.last()?.get(name) + } + + + +} diff --git a/src/semantic/types.rs b/src/semantic/types.rs deleted file mode 100644 index da7232b..0000000 --- a/src/semantic/types.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[derive(Debug, Clone, PartialEq)] -pub enum Type { - Integer, - Boolean, -} From 2c3a00e9c3f0a13e1f86f1877321ff003490d0f5 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Wed, 18 Feb 2026 15:29:30 +0100 Subject: [PATCH 02/10] filled out some of the skeleton of the parser, needs simply to be implemented --- src/main.rs | 1 + src/parser/mod.rs | 1 + src/parser/parser.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/parser/mod.rs diff --git a/src/main.rs b/src/main.rs index 2835d59..50442b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod parser; mod lexer; mod semantic; diff --git a/src/parser/mod.rs b/src/parser/mod.rs new file mode 100644 index 0000000..b2819a7 --- /dev/null +++ b/src/parser/mod.rs @@ -0,0 +1 @@ +pub mod parser; \ No newline at end of file diff --git a/src/parser/parser.rs b/src/parser/parser.rs index e69de29..fbe562d 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -0,0 +1,79 @@ +use crate::lexer::token::{Token, TokenType}; +pub enum Expr { + Integer(i64), + Boolean(bool), + String(String), + Variable(String), + BinaryOp(Box, BinOp, Box), + UnaryOp(UnOp, Box), + Call(String, Vec), //I do not understand what this one is, but the expert recommended it +} + +pub enum Stmt { + Let(String, Expr), + ExprStmt(Expr), + If(Expr, Box, Option>), + While(Expr, Box), + Block(Vec), + Print(Expr), +} + +pub enum BinOp { + Add, + Sub, + Mul, + Equals, + GreaterThan, + LessThan, +} + +pub enum UnOp { + Not, + Neg, +} +pub type AST = Vec; +pub struct Parser{ + input: Vec, + position: usize +} + +impl Parser { + pub fn new(token_vector: Vec) -> Self{ + Self { + input: Vec::new(), + position: 1 + } + } + pub fn parse_program(&mut self) -> AST { + Vec::new() //Todo: implement + } + //Todo: Implement the following funcs/helper funcs-> + // fn parse_stmt + + // fn parse_expr + + // fn parse_term + + // fn parse_factor + + //Even more parse functions my fella + + //Here im making some helper functions i reckon mate + + //peek (look at current token without consuming) + + fn advance(&mut self){ + self.position += 1; + } + + fn expect(&mut self, expected: TokenType) -> Result { + let tok = self.input.get(self.position).unwrap(); + if tok.token_type == expected { + Ok(tok.clone()) + }else{ + Err(format!("Expected {:?} at {}:{}, found {:?}", + expected, tok.line, tok.column, tok.token_type)) + } + } + +} \ No newline at end of file From 3f9bf282b9c59af7c6960c71556762628573ea95 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Thu, 19 Feb 2026 14:13:36 +0100 Subject: [PATCH 03/10] there you go --- src/lexer/lexer.rs | 39 +++++++++---------- src/lexer/token.rs | 68 ++++++++++++++++++++++++++++++++- src/main.rs | 12 ++++-- src/parser/parser.rs | 73 ++++++++++++++++++++++++++---------- src/semantic/symbol_table.rs | 2 +- 5 files changed, 149 insertions(+), 45 deletions(-) diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index 1ed2ab9..81bf39f 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -40,43 +40,43 @@ impl Lexer { tokens.push(self.assign_or_equals()); } ':' => { - tokens.push(self.simple_token(TokenType::Colon)); + tokens.push(self.simple_token(ch.to_string(),TokenType::Colon)); } '+' => { - tokens.push(self.simple_token(TokenType::Plus)); + tokens.push(self.simple_token(ch.to_string(),TokenType::Plus)); } '-' => { tokens.push(self.minus_or_arrow()); } '*' => { - tokens.push(self.simple_token(TokenType::Multiply)); + tokens.push(self.simple_token(ch.to_string(),TokenType::Multiply)); } '{' => { - tokens.push(self.simple_token(TokenType::LeftBrace)); + tokens.push(self.simple_token(ch.to_string(),TokenType::LeftBrace)); } '}' => { - tokens.push(self.simple_token(TokenType::RightBrace)); + tokens.push(self.simple_token(ch.to_string(),TokenType::RightBrace)); } '(' => { - tokens.push(self.simple_token(TokenType::LeftParen)); + tokens.push(self.simple_token(ch.to_string(),TokenType::LeftParen)); } ')' => { - tokens.push(self.simple_token(TokenType::RightParen)); + tokens.push(self.simple_token(ch.to_string(),TokenType::RightParen)); } '>' =>{ - tokens.push(self.simple_token(TokenType::GreaterThan)); + tokens.push(self.simple_token(ch.to_string(),TokenType::GreaterThan)); } '<' =>{ - tokens.push(self.simple_token(TokenType::LessThan)); + tokens.push(self.simple_token(ch.to_string(),TokenType::LessThan)); } ';' =>{ - tokens.push(self.simple_token(TokenType::Semicolon)); + tokens.push(self.simple_token(ch.to_string(),TokenType::Semicolon)); } '"' => { tokens.push(self.read_string_literal()); } ',' => { - tokens.push(self.simple_token(TokenType::Comma)); + tokens.push(self.simple_token(ch.to_string(),TokenType::Comma)); } '#' => { self.read_comment(); @@ -84,6 +84,7 @@ impl Lexer { _ => panic!("Suuuper wrongdog in here, unexpected char '{}' at {}:{}", ch, self.line, self.column), } } + tokens.push(self.simple_token("EOF".to_string(),TokenType::Eof)); tokens } fn current_char(&self) -> Option { @@ -101,28 +102,28 @@ impl Lexer { self.column = 1; } - fn simple_token(&mut self, token_type: TokenType) -> Token { + fn simple_token(&mut self,value: String, token_type: TokenType) -> Token { let start_col_num = self.column; self.advance(); - Token::new(token_type, self.line, start_col_num) + Token::new(value, token_type, self.line, start_col_num) } fn assign_or_equals(&mut self) -> Token{ let original_col = self.column; self.advance(); if self.current_char().unwrap() == '=' { - Token::new(TokenType::Equals, self.line, original_col) + Token::new("=".to_string(),TokenType::Equals, self.line, original_col) } else { - Token::new(TokenType::Assign, self.line, original_col) + Token::new("==".to_string(),TokenType::Assign, self.line, original_col) } } fn minus_or_arrow(&mut self) -> Token { let original_col = self.column; self.advance(); if self.current_char().unwrap() == '>' { - Token::new(TokenType::Arrow, self.line, original_col) + Token::new("->".to_string(),TokenType::Arrow, self.line, original_col) } else { - Token::new(TokenType::Minus, self.line, original_col) + Token::new("-".to_string(),TokenType::Minus, self.line, original_col) } } fn read_comment(&mut self) { @@ -154,7 +155,7 @@ impl Lexer { } } let num = num_string.parse::().unwrap(); - Token::new(TokenType::IntegerLiteral(num), self.line, start_col_num) + Token::new(num_string, TokenType::IntegerLiteral(num), self.line, start_col_num) } fn read_string_literal(&mut self) -> Token{ @@ -175,7 +176,7 @@ impl Lexer { } } } - Token::new(TokenType::StringLiteral(the_litteral), self.line, start_col_num) + Token::new(the_litteral, TokenType::StringLiteral(the_litteral), self.line, start_col_num) } fn read_identifier(&mut self, first_ch: char) -> Token { diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 077cd79..f01f882 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -1,3 +1,5 @@ +use std::fmt; + #[derive(Debug, Clone, PartialEq)] pub enum TokenType { // Keywords @@ -43,24 +45,88 @@ pub enum TokenType { RightBrace, // } Comma, // , Semicolon, // ; + //special + Eof, // End of file } #[derive(Debug, Clone)] pub struct Token { + pub value: String, pub token_type: TokenType, pub line: usize, pub column: usize, } impl Token { - pub fn new(token_type: TokenType, line: usize, column: usize) -> Self { + pub fn new(value: String,token_type: TokenType, line: usize, column: usize) -> Self { Token { + value:value, token_type, line, column, } } } +impl fmt::Display for TokenType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + // Keywords + TokenType::Func => write!(f, "func"), + TokenType::Let => write!(f, "let"), + TokenType::If => write!(f, "if"), + TokenType::Then => write!(f, "then"), + TokenType::Else => write!(f, "else"), + TokenType::Not => write!(f, "not"), + TokenType::While => write!(f, "while"), + TokenType::Print => write!(f, "print"), + TokenType::Do => write!(f, "do"), + TokenType::Is => write!(f, "is"), + + // Types + TokenType::Integer => write!(f, "Integer"), + TokenType::Boolean => write!(f, "Boolean"), + + // Literals + TokenType::True => write!(f, "true"), + TokenType::False => write!(f, "false"), + TokenType::IntegerLiteral(val) => write!(f, "{val}"), + TokenType::StringLiteral(val) => write!(f, "\"{val}\""), + + // Identifiers + TokenType::Identifier(name) => write!(f, "{name}"), + + // Operators + TokenType::Colon => write!(f, ":"), + TokenType::Arrow => write!(f, "->"), + TokenType::Assign => write!(f, "="), + TokenType::GreaterThan => write!(f, ">"), + TokenType::LessThan => write!(f, "<"), + TokenType::Equals => write!(f, "=="), + TokenType::Plus => write!(f, "+"), + TokenType::Minus => write!(f, "-"), + TokenType::Multiply => write!(f, "*"), + + // Punctuation + TokenType::LeftParen => write!(f, "("), + TokenType::RightParen => write!(f, ")"), + TokenType::LeftBrace => write!(f, "{{"), + TokenType::RightBrace => write!(f, "}}"), + TokenType::Comma => write!(f, ","), + TokenType::Semicolon => write!(f, ";"), + TokenType::Eof => write!(f, "Eof"), + } + } +} + +impl fmt::Display for Token { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} at {}:{}", + self.token_type, self.line, self.column + ) + } +} impl PartialEq for Token { fn eq(&self, other: &Self) -> bool { self.token_type == other.token_type && diff --git a/src/main.rs b/src/main.rs index 50442b8..6d630c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,10 @@ mod semantic; use std::env; use std::fs; - +use lexer::token::Token; use lexer::lexer::Lexer; // adjust if needed +use parser::parser::AST; +use parser::parser::Parser; fn main() { let args: Vec = env::args().collect(); @@ -20,10 +22,12 @@ fn main() { let source = fs::read_to_string(filename) .expect("Failed to read file"); - let mut lexer = Lexer::new(source); - let _tokens = lexer.tokenize(); + let mut lexer: Lexer = Lexer::new(source); + let _tokens: Vec = lexer.tokenize(); + let mut parser: Parser = Parser::new(_tokens); + let _ast: AST = parser.parse_program(); - println!("Lexing completed successfully."); + println!("Lexing and parsing completed successfully."); } #[cfg(test)] diff --git a/src/parser/parser.rs b/src/parser/parser.rs index fbe562d..ff45b70 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1,4 +1,22 @@ -use crate::lexer::token::{Token, TokenType}; +use crate::lexer::token::{self, Token, TokenType}; +pub enum Stmt { + Let(String, Expr), + ExprStmt(Expr), + If(Expr, Box, Option>), + While(Expr, Box), + Block(Vec), + Print(Expr), + Function { + name: String, + params: Vec, + return_type: Option, + body: Box, + }, +} +pub struct Param { + name: String, + param_type: Expr, // or some Type enum +} pub enum Expr { Integer(i64), Boolean(bool), @@ -9,14 +27,6 @@ pub enum Expr { Call(String, Vec), //I do not understand what this one is, but the expert recommended it } -pub enum Stmt { - Let(String, Expr), - ExprStmt(Expr), - If(Expr, Box, Option>), - While(Expr, Box), - Block(Vec), - Print(Expr), -} pub enum BinOp { Add, @@ -33,43 +43,66 @@ pub enum UnOp { } pub type AST = Vec; pub struct Parser{ - input: Vec, + tokens: Vec, position: usize } impl Parser { pub fn new(token_vector: Vec) -> Self{ Self { - input: Vec::new(), + tokens: token_vector, position: 1 } } pub fn parse_program(&mut self) -> AST { - Vec::new() //Todo: implement + let mut ast: AST = Vec::new(); + while !self.match_token(TokenType::Eof) { + match self.peek().token_type.clone() { + TokenType::Func =>{ + ast.push(self.parse_func()); + } + TokenType::Let(a) => { + ast.push(self.parse_let()); + } + _ => panic!("Wrong token {} at {}:{}", self.peek(), self.peek().line, self.peek().column) + } + } + ast } //Todo: Implement the following funcs/helper funcs-> - // fn parse_stmt + fn parse_func(&mut self) -> Stmt{ + self.expect(TokenType::Func); + let name = self.expect() + } // fn parse_expr - // fn parse_term + // fn parse_bin_op - // fn parse_factor + // fn parse_un_op //Even more parse functions my fella //Here im making some helper functions i reckon mate - - //peek (look at current token without consuming) + fn peek(&self) -> &Token { + self.tokens.get(self.position).unwrap() + } fn advance(&mut self){ self.position += 1; } - + fn consume(&mut self)-> Token{ + let token = self.peek().clone(); + self.advance(); + token + } + fn match_token(&self, expected: TokenType) -> bool{ + self.peek().token_type == expected + } fn expect(&mut self, expected: TokenType) -> Result { - let tok = self.input.get(self.position).unwrap(); + let tok = self.peek(); if tok.token_type == expected { - Ok(tok.clone()) + Ok(self.consume()) }else{ Err(format!("Expected {:?} at {}:{}, found {:?}", expected, tok.line, tok.column, tok.token_type)) diff --git a/src/semantic/symbol_table.rs b/src/semantic/symbol_table.rs index abd6011..3871dc5 100644 --- a/src/semantic/symbol_table.rs +++ b/src/semantic/symbol_table.rs @@ -59,7 +59,7 @@ impl SymbolTable { pub fn lookup(&self, name: &str) -> Option<&Symbol> { for scope in self.scopes.iter().rev() { if let Some(symbol) = scope.get(name) { - Some(symbol); + return Some(symbol); } } None From b488bf6f2d46dec8794562a1a88a7a7351153cac Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Thu, 19 Feb 2026 14:50:51 +0100 Subject: [PATCH 04/10] more changes --- src/lexer/lexer.rs | 44 ++++++++++++++++++++--------------------- src/lexer/token.rs | 12 +++++------ src/parser/parser.rs | 47 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index 81bf39f..b76918e 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -155,7 +155,7 @@ impl Lexer { } } let num = num_string.parse::().unwrap(); - Token::new(num_string, TokenType::IntegerLiteral(num), self.line, start_col_num) + Token::new(num_string, TokenType::IntegerLiteral, self.line, start_col_num) } fn read_string_literal(&mut self) -> Token{ @@ -176,7 +176,7 @@ impl Lexer { } } } - Token::new(the_litteral, TokenType::StringLiteral(the_litteral), self.line, start_col_num) + Token::new(the_litteral.clone(), TokenType::StringLiteral, self.line, start_col_num) } fn read_identifier(&mut self, first_ch: char) -> Token { @@ -199,21 +199,21 @@ impl Lexer { } fn give_keyword_or_literal_token(&mut self, name: &str, line: usize, col: usize) -> Token{ match name { - "let" => Token::new(TokenType::Let, line, col), - "func" => Token::new(TokenType::Func, line, col), - "if" => Token::new(TokenType::If, line, col), - "then" => Token::new(TokenType::Then, line, col), - "else" => Token::new(TokenType::Else, line, col), - "not" => Token::new(TokenType::Not, line, col), - "while" => Token::new(TokenType::While, line, col), - "print" => Token::new(TokenType::Print, line, col), - "do" => Token::new(TokenType::Do, line, col), - "is" => Token::new(TokenType::Is, line, col), - "Integer"=> Token::new(TokenType::Integer, line, col), - "Boolean"=> Token::new(TokenType::Boolean, line, col), - "True" => Token::new(TokenType::True, line, col), - "False" => Token::new(TokenType::False, line, col), - _ => Token::new(TokenType::Identifier(name.to_string()), line, col), + "let" => Token::new("let".to_string(), TokenType::Let, line, col), + "func" => Token::new("func".to_string(), TokenType::Func, line, col), + "if" => Token::new("if".to_string(), TokenType::If, line, col), + "then" => Token::new("then".to_string(), TokenType::Then, line, col), + "else" => Token::new("else".to_string(), TokenType::Else, line, col), + "not" => Token::new("not".to_string(), TokenType::Not, line, col), + "while" => Token::new("while".to_string(), TokenType::While, line, col), + "print" => Token::new("print".to_string(), TokenType::Print, line, col), + "do" => Token::new("do".to_string(), TokenType::Do, line, col), + "is" => Token::new("is".to_string(), TokenType::Is, line, col), + "Integer"=> Token::new("Integer".to_string(), TokenType::Integer, line, col), + "Boolean"=> Token::new("Boolean".to_string(), TokenType::Boolean, line, col), + "True" => Token::new("True".to_string(), TokenType::True, line, col), + "False" => Token::new("False".to_string(), TokenType::False, line, col), + _ => Token::new(name.to_string(), TokenType::Identifier, line, col), } } } @@ -246,9 +246,9 @@ mod tests{ let actual_token_vec: Vec = lex.tokenize(); let expected: Vec = vec![ - Token::new(TokenType::Identifier("abc_def".to_string()), 1, 1), - Token::new(TokenType::Assign, 1, 9), - Token::new(TokenType::IntegerLiteral(2), 1, 11), + Token::new("abc_def".to_string(), TokenType::Identifier, 1, 1), + Token::new("=".to_string(), TokenType::Assign, 1, 9), + Token::new(2.to_string(), TokenType::IntegerLiteral, 1, 11), ]; assert_eq!(actual_token_vec, expected); @@ -274,9 +274,9 @@ mod tests{ let actual_token_vec: Vec = lex.tokenize(); let expected: Vec = vec![ - Token::new(TokenType::StringLiteral("\"test\"".to_string()), 1, 1) + Token::new("\"test\"".to_string(), TokenType::StringLiteral, 1, 1) ]; assert_eq!(actual_token_vec, expected); } -} \ No newline at end of file +} diff --git a/src/lexer/token.rs b/src/lexer/token.rs index f01f882..293d22e 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -21,11 +21,11 @@ pub enum TokenType { // Literals True, False, - IntegerLiteral(i64), - StringLiteral(String), + IntegerLiteral, + StringLiteral, // Identifiers - Identifier(String), + Identifier, // Operators Colon, // : @@ -89,11 +89,11 @@ impl fmt::Display for TokenType { // Literals TokenType::True => write!(f, "true"), TokenType::False => write!(f, "false"), - TokenType::IntegerLiteral(val) => write!(f, "{val}"), - TokenType::StringLiteral(val) => write!(f, "\"{val}\""), + TokenType::IntegerLiteral => write!(f, "IntegerLiteral"), + TokenType::StringLiteral => write!(f, "StringLiteral"), // Identifiers - TokenType::Identifier(name) => write!(f, "{name}"), + TokenType::Identifier => write!(f, "Identifier"), // Operators TokenType::Colon => write!(f, ":"), diff --git a/src/parser/parser.rs b/src/parser/parser.rs index ff45b70..3d6adcb 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -15,7 +15,12 @@ pub enum Stmt { } pub struct Param { name: String, - param_type: Expr, // or some Type enum + param_type: Type, // or some Type enum +} + +pub enum Type { + Integer, + Boolean } pub enum Expr { Integer(i64), @@ -61,9 +66,9 @@ impl Parser { TokenType::Func =>{ ast.push(self.parse_func()); } - TokenType::Let(a) => { - ast.push(self.parse_let()); - } + // TokenType::Let(a) => { + // ast.push(self.parse_let()); + // } _ => panic!("Wrong token {} at {}:{}", self.peek(), self.peek().line, self.peek().column) } } @@ -72,7 +77,37 @@ impl Parser { //Todo: Implement the following funcs/helper funcs-> fn parse_func(&mut self) -> Stmt{ self.expect(TokenType::Func); - let name = self.expect() + let name = self.expect(TokenType::Identifier).unwrap().value; + self.expect(TokenType::LeftParen); + let params = Vec::new(); + while !self.match_token(TokenType::RightParen) { + let name = self.expect(TokenType::Identifier).unwrap().value; + self.expect(TokenType::Colon); + + let mut typevalue; + match self.peek().token_type { + TokenType::Integer => { + self.expect(TokenType::Integer).unwrap().value; + typevalue = Type::Integer; + } + TokenType::Boolean => { + self.expect(TokenType::Boolean).unwrap().value; + typevalue = Type::Boolean; + } + _ => panic!("Unknown type for parameter") + } + params.push(Param {name: name, param_type: typevalue}); + if !self.match_token(TokenType::RightParen) { + self.expect(TokenType::Comma); + } + } + + self.expect(TokenType::RightParen); + + self.expect(TokenType::Arrow); + + + Stmt::Function { name, params: (), return_type: (), body: () } } // fn parse_expr @@ -109,4 +144,4 @@ impl Parser { } } -} \ No newline at end of file +} From ff9e67b8173ae8493058c3d4382b485c3b9b67b0 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Thu, 19 Feb 2026 15:49:17 +0100 Subject: [PATCH 05/10] Added stuff to parser --- src/parser/parser.rs | 92 +++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 3d6adcb..25b1b8f 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -4,14 +4,17 @@ pub enum Stmt { ExprStmt(Expr), If(Expr, Box, Option>), While(Expr, Box), - Block(Vec), Print(Expr), - Function { - name: String, - params: Vec, - return_type: Option, - body: Box, - }, +} + +pub struct Function { + pub name: String, + pub params: Vec, + pub return_type: Type, + pub body: Block, +} +pub struct Block{ + pub statements: Vec } pub struct Param { name: String, @@ -46,7 +49,7 @@ pub enum UnOp { Not, Neg, } -pub type AST = Vec; +pub type AST = Vec; pub struct Parser{ tokens: Vec, position: usize @@ -62,36 +65,35 @@ impl Parser { pub fn parse_program(&mut self) -> AST { let mut ast: AST = Vec::new(); while !self.match_token(TokenType::Eof) { - match self.peek().token_type.clone() { + match self.current().token_type.clone() { TokenType::Func =>{ ast.push(self.parse_func()); } - // TokenType::Let(a) => { - // ast.push(self.parse_let()); - // } - _ => panic!("Wrong token {} at {}:{}", self.peek(), self.peek().line, self.peek().column) + _ => panic!("Wrong token {} at {}:{}", self.current(), self.current().line, self.current().column) } } ast } //Todo: Implement the following funcs/helper funcs-> - fn parse_func(&mut self) -> Stmt{ + fn parse_func(&mut self) -> Function{ self.expect(TokenType::Func); + let name = self.expect(TokenType::Identifier).unwrap().value; self.expect(TokenType::LeftParen); - let params = Vec::new(); + + let mut params = Vec::new(); while !self.match_token(TokenType::RightParen) { let name = self.expect(TokenType::Identifier).unwrap().value; self.expect(TokenType::Colon); let mut typevalue; - match self.peek().token_type { + match self.current().token_type { TokenType::Integer => { - self.expect(TokenType::Integer).unwrap().value; + self.expect(TokenType::Integer); typevalue = Type::Integer; } TokenType::Boolean => { - self.expect(TokenType::Boolean).unwrap().value; + self.expect(TokenType::Boolean); typevalue = Type::Boolean; } _ => panic!("Unknown type for parameter") @@ -106,10 +108,46 @@ impl Parser { self.expect(TokenType::Arrow); + let mut return_type; + match self.current().token_type { + TokenType::Integer => { + self.expect(TokenType::Integer); + return_type = Type::Integer; + } + TokenType::Boolean => { + self.expect(TokenType::Boolean); + return_type = Type::Boolean; + } + _ => panic!("Unknown return type for function") + } + + self.expect(TokenType::LeftBrace); + let body: Block = self.parse_block(); + Function { name, params, return_type, body} + } - Stmt::Function { name, params: (), return_type: (), body: () } + fn parse_block(&mut self) -> Block { + let mut statements:Vec = Vec::new(); + let cur_tok = self.current(); + while !self.match_token(TokenType::Eof) && + !self.match_token(TokenType::RightBrace){ + if self.match_token(TokenType::Let){ + statements.push(self.parse_let()); + }else if self.match_token(TokenType::If){ + statements.push(self.parse_if()); + }else if self.match_token(TokenType::While){ + statements.push(self.parse_while()); + }else if self.match_token(TokenType::Identifier) && self.match_token(TokenType::Assign){ + statements.push(self.parse_assignment()); + }else{ + let expression = self.parse_expression(); + statements.push(Stmt::ExprStmt(expression)); + } + } + Block { statements } } + // fn parse_expr // fn parse_bin_op @@ -119,7 +157,15 @@ impl Parser { //Even more parse functions my fella //Here im making some helper functions i reckon mate - fn peek(&self) -> &Token { + fn peek(&self, token_type: TokenType) -> bool { + if self.position+1 < self.tokens.len(){ + self.tokens.get(self.position + 1).unwrap().token_type == token_type + }else { + false + } + } + + fn current(&self) -> &Token { self.tokens.get(self.position).unwrap() } @@ -127,15 +173,15 @@ impl Parser { self.position += 1; } fn consume(&mut self)-> Token{ - let token = self.peek().clone(); + let token = self.current().clone(); self.advance(); token } fn match_token(&self, expected: TokenType) -> bool{ - self.peek().token_type == expected + self.current().token_type == expected } fn expect(&mut self, expected: TokenType) -> Result { - let tok = self.peek(); + let tok = self.current(); if tok.token_type == expected { Ok(self.consume()) }else{ From fcfbfd2421881f1d023c282174eab33952b12ebb Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Fri, 20 Feb 2026 09:03:39 +0100 Subject: [PATCH 06/10] after revert trying stuff out --- src/parser/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 25b1b8f..4b6c8a1 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -132,7 +132,7 @@ impl Parser { while !self.match_token(TokenType::Eof) && !self.match_token(TokenType::RightBrace){ if self.match_token(TokenType::Let){ - statements.push(self.parse_let()); + statements.push(self.parse_let())//dingdong test commit after revert; }else if self.match_token(TokenType::If){ statements.push(self.parse_if()); }else if self.match_token(TokenType::While){ From 932ebc82830fb08e00ddea2f9172eeac97c2d593 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Fri, 20 Feb 2026 11:04:39 +0100 Subject: [PATCH 07/10] added some more shizzle (parse expr is started and parse let) --- src/lexer/lexer.rs | 3 + src/lexer/token.rs | 3 + src/parser/parser.rs | 210 +++++++++++++++++++++++++++++-------------- 3 files changed, 147 insertions(+), 69 deletions(-) diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index b76918e..64c1001 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -51,6 +51,9 @@ impl Lexer { '*' => { tokens.push(self.simple_token(ch.to_string(),TokenType::Multiply)); } + '/' => { + tokens.push(self.simple_token(ch.to_string(),TokenType::Division)); + } '{' => { tokens.push(self.simple_token(ch.to_string(),TokenType::LeftBrace)); } diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 293d22e..45d1c79 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -37,6 +37,7 @@ pub enum TokenType { Plus, // + Minus, // - Multiply, // * + Division, // Punctuation LeftParen, // ( @@ -105,6 +106,8 @@ impl fmt::Display for TokenType { TokenType::Plus => write!(f, "+"), TokenType::Minus => write!(f, "-"), TokenType::Multiply => write!(f, "*"), + TokenType::Division => write!(f, "/"), + // Punctuation TokenType::LeftParen => write!(f, "("), diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 4b6c8a1..5b92f2f 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1,20 +1,27 @@ -use crate::lexer::token::{self, Token, TokenType}; +use crate::lexer::token::{ self, Token, TokenType }; pub enum Stmt { - Let(String, Expr), + Let(String, Type, Expr), ExprStmt(Expr), - If(Expr, Box, Option>), - While(Expr, Box), + If { + condition: Expr, + block: Block, + option: Option, + }, + While { + expr: Expr, + block: Block, + }, Print(Expr), } pub struct Function { - pub name: String, - pub params: Vec, - pub return_type: Type, - pub body: Block, + pub name: String, + pub params: Vec, + pub return_type: Type, + pub body: Block, } -pub struct Block{ - pub statements: Vec +pub struct Block { + pub statements: Vec, } pub struct Param { name: String, @@ -23,19 +30,18 @@ pub struct Param { pub enum Type { Integer, - Boolean + Boolean, } pub enum Expr { - Integer(i64), - Boolean(bool), - String(String), - Variable(String), + IntegerLiteral(i64), + BooleanLiteral(bool), + StringLiteral(String), + Identifier(String), BinaryOp(Box, BinOp, Box), UnaryOp(UnOp, Box), - Call(String, Vec), //I do not understand what this one is, but the expert recommended it + Call(Vec), //I do not understand what this one is, but the expert recommended it } - pub enum BinOp { Add, Sub, @@ -47,37 +53,42 @@ pub enum BinOp { pub enum UnOp { Not, - Neg, } pub type AST = Vec; -pub struct Parser{ +pub struct Parser { tokens: Vec, - position: usize + position: usize, } impl Parser { - pub fn new(token_vector: Vec) -> Self{ - Self { - tokens: token_vector, - position: 1 + pub fn new(token_vector: Vec) -> Self { + Self { + tokens: token_vector, + position: 1, } } pub fn parse_program(&mut self) -> AST { let mut ast: AST = Vec::new(); while !self.match_token(TokenType::Eof) { match self.current().token_type.clone() { - TokenType::Func =>{ + TokenType::Func => { ast.push(self.parse_func()); } - _ => panic!("Wrong token {} at {}:{}", self.current(), self.current().line, self.current().column) + _ => + panic!( + "Wrong token {} at {}:{}", + self.current(), + self.current().line, + self.current().column + ), } } ast - } + } //Todo: Implement the following funcs/helper funcs-> - fn parse_func(&mut self) -> Function{ + fn parse_func(&mut self) -> Function { self.expect(TokenType::Func); - + let name = self.expect(TokenType::Identifier).unwrap().value; self.expect(TokenType::LeftParen); @@ -85,7 +96,7 @@ impl Parser { while !self.match_token(TokenType::RightParen) { let name = self.expect(TokenType::Identifier).unwrap().value; self.expect(TokenType::Colon); - + let mut typevalue; match self.current().token_type { TokenType::Integer => { @@ -96,50 +107,52 @@ impl Parser { self.expect(TokenType::Boolean); typevalue = Type::Boolean; } - _ => panic!("Unknown type for parameter") + _ => panic!("Unknown type for parameter"), } - params.push(Param {name: name, param_type: typevalue}); + params.push(Param { name: name, param_type: typevalue }); if !self.match_token(TokenType::RightParen) { self.expect(TokenType::Comma); } } self.expect(TokenType::RightParen); - + self.expect(TokenType::Arrow); let mut return_type; - match self.current().token_type { - TokenType::Integer => { - self.expect(TokenType::Integer); - return_type = Type::Integer; - } - TokenType::Boolean => { - self.expect(TokenType::Boolean); - return_type = Type::Boolean; - } - _ => panic!("Unknown return type for function") + match self.current().token_type { + TokenType::Integer => { + self.expect(TokenType::Integer); + return_type = Type::Integer; + } + TokenType::Boolean => { + self.expect(TokenType::Boolean); + return_type = Type::Boolean; } - + _ => panic!("Unknown return type for function"), + } + self.expect(TokenType::LeftBrace); let body: Block = self.parse_block(); - Function { name, params, return_type, body} + Function { name, params, return_type, body } } fn parse_block(&mut self) -> Block { - let mut statements:Vec = Vec::new(); + let mut statements: Vec = Vec::new(); let cur_tok = self.current(); - while !self.match_token(TokenType::Eof) && - !self.match_token(TokenType::RightBrace){ - if self.match_token(TokenType::Let){ - statements.push(self.parse_let())//dingdong test commit after revert; - }else if self.match_token(TokenType::If){ + while !self.match_token(TokenType::Eof) && !self.match_token(TokenType::RightBrace) { + if self.match_token(TokenType::Let) { + statements.push(self.parse_let()); //dingdong test commit after revert; + } else if self.match_token(TokenType::If) { statements.push(self.parse_if()); - }else if self.match_token(TokenType::While){ + } else if self.match_token(TokenType::While) { statements.push(self.parse_while()); - }else if self.match_token(TokenType::Identifier) && self.match_token(TokenType::Assign){ + } else if + self.match_token(TokenType::Identifier) && + self.match_token(TokenType::Assign) + { statements.push(self.parse_assignment()); - }else{ + } else { let expression = self.parse_expression(); statements.push(Stmt::ExprStmt(expression)); } @@ -147,20 +160,70 @@ impl Parser { Block { statements } } + fn parse_let(&mut self) -> Stmt { + self.consume(); + let var_name = self.expect(TokenType::Identifier).unwrap().value; + self.expect(TokenType::Colon); + let type_of_var = match self.current().token_type { + TokenType::Integer => Type::Integer, + TokenType::Boolean => Type::Boolean, + _ => + panic!( + "Expected type, got something else at {}:{}", + self.current().line, + self.current().column + ), + }; + self.consume(); + self.expect(TokenType::Assign); + let expr = self.parse_expression(); + Stmt::Let(var_name, type_of_var, expr) + } + fn parse_expression(&mut self) -> Expr { + let tok = self.consume(); + match tok.token_type { + TokenType::Integer => { + if + self.match_any( + &[ + TokenType::Minus, + TokenType::Plus, + TokenType::Multiply, + TokenType::Division, + TokenType::GreaterThan, + TokenType::LessThan, + TokenType::Equals, + ] + ) + { + Expr::BinaryOp(Expr::IntegerLiteral(tok.value.parse::().unwrap()), , ()) + }else{ + Expr::IntegerLiteral(tok.value.parse::().unwrap()) + } + } + TokenType::Boolean => Expr::BooleanLiteral(tok.value.parse::().unwrap()), + TokenType::StringLiteral => Expr::StringLiteral(tok.value.clone()), + TokenType::Identifier => Expr::Identifier(tok.value.clone()), + TokenType::Not => { + let exprs = self.parse_expression(); + Expr::UnaryOp(UnOp::Not, Box::new(exprs)) + } + _ => panic!(""), + } + } + // fn parse_expr - // fn parse_expr - - // fn parse_bin_op + // fn parse_bin_op - // fn parse_un_op + // fn parse_un_op - //Even more parse functions my fella + //Even more parse functions my fella //Here im making some helper functions i reckon mate fn peek(&self, token_type: TokenType) -> bool { - if self.position+1 < self.tokens.len(){ + if self.position + 1 < self.tokens.len() { self.tokens.get(self.position + 1).unwrap().token_type == token_type - }else { + } else { false } } @@ -169,25 +232,34 @@ impl Parser { self.tokens.get(self.position).unwrap() } - fn advance(&mut self){ + fn advance(&mut self) { self.position += 1; - } - fn consume(&mut self)-> Token{ + } + fn consume(&mut self) -> Token { let token = self.current().clone(); self.advance(); token } - fn match_token(&self, expected: TokenType) -> bool{ + fn match_token(&self, expected: TokenType) -> bool { self.current().token_type == expected } + fn match_any(&self, token_types: &[TokenType]) -> bool { + token_types.contains(&self.current().token_type) + } fn expect(&mut self, expected: TokenType) -> Result { let tok = self.current(); if tok.token_type == expected { Ok(self.consume()) - }else{ - Err(format!("Expected {:?} at {}:{}, found {:?}", - expected, tok.line, tok.column, tok.token_type)) + } else { + Err( + format!( + "Expected {:?} at {}:{}, found {:?}", + expected, + tok.line, + tok.column, + tok.token_type + ) + ) } } - } From bf9bf9bfdc927077bc27e1ec09247cc92e131c0b Mon Sep 17 00:00:00 2001 From: pbaekgaard Date: Fri, 20 Feb 2026 16:10:05 +0100 Subject: [PATCH 08/10] Lot of changes --- .gitignore | 1 + program.trv | 1 - simple.trv | 9 ++ src/lexer/lexer.rs | 20 ++- src/lexer/token.rs | 12 +- src/main.rs | 13 +- src/parser/mod.rs | 2 +- src/parser/parser.rs | 295 +++++++++++++++++++++++++++++++------------ 8 files changed, 243 insertions(+), 110 deletions(-) create mode 100644 simple.trv diff --git a/.gitignore b/.gitignore index a5ff07f..0dc7ebb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ # already existing elements were commented out #/target +/tmp diff --git a/program.trv b/program.trv index 28e349b..44ad443 100644 --- a/program.trv +++ b/program.trv @@ -10,7 +10,6 @@ func is_greater_than_44(params : Integer) -> Integer { } } - func otherFunction() -> Boolean { let number : Integer = 20; let is_greater : Integer = is_greater_than_44(number); diff --git a/simple.trv b/simple.trv new file mode 100644 index 0000000..e9aba45 --- /dev/null +++ b/simple.trv @@ -0,0 +1,9 @@ +func main() -> Integer { + let num : Integer = 0; + + while num < 10 do { + num = 11; + } + + return num; +} diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index 64c1001..53d523d 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -87,7 +87,7 @@ impl Lexer { _ => panic!("Suuuper wrongdog in here, unexpected char '{}' at {}:{}", ch, self.line, self.column), } } - tokens.push(self.simple_token("EOF".to_string(),TokenType::Eof)); + tokens.push(self.simple_token("EOF".to_string(),TokenType::EOF)); tokens } fn current_char(&self) -> Option { @@ -124,6 +124,7 @@ impl Lexer { let original_col = self.column; self.advance(); if self.current_char().unwrap() == '>' { + self.advance(); Token::new("->".to_string(),TokenType::Arrow, self.line, original_col) } else { Token::new("-".to_string(),TokenType::Minus, self.line, original_col) @@ -214,8 +215,9 @@ impl Lexer { "is" => Token::new("is".to_string(), TokenType::Is, line, col), "Integer"=> Token::new("Integer".to_string(), TokenType::Integer, line, col), "Boolean"=> Token::new("Boolean".to_string(), TokenType::Boolean, line, col), - "True" => Token::new("True".to_string(), TokenType::True, line, col), - "False" => Token::new("False".to_string(), TokenType::False, line, col), + "return"=> Token::new("Return".to_string(), TokenType::Return, line, col), + "True" => Token::new("True".to_string(), TokenType::BooleanLiteral, line, col), + "False" => Token::new("False".to_string(), TokenType::BooleanLiteral, line, col), _ => Token::new(name.to_string(), TokenType::Identifier, line, col), } } @@ -252,6 +254,7 @@ mod tests{ Token::new("abc_def".to_string(), TokenType::Identifier, 1, 1), Token::new("=".to_string(), TokenType::Assign, 1, 9), Token::new(2.to_string(), TokenType::IntegerLiteral, 1, 11), + Token::new("EOF".to_string(), TokenType::EOF, 1, 12), ]; assert_eq!(actual_token_vec, expected); @@ -260,14 +263,16 @@ mod tests{ fn reading_comments_tokenize_lexer_line_col_are_correct(){ let mut lex: Lexer = Lexer::new("#abc_def = 2\n".to_string()); lex.tokenize(); - assert_eq!((lex.line, lex.column), (2,1)); + assert_eq!((lex.line, lex.column), (2,2)); } #[test] - fn reading_comments_tokenize_returns_empty_vector(){ + fn reading_comments_tokenize_returns_eof_vector(){ let mut lex: Lexer = Lexer::new("#abc_def = 2\n".to_string()); let actual_token_vec: Vec = lex.tokenize(); - let expected: Vec = vec![]; + let expected: Vec = vec![ + Token::new("EOF".to_string(), TokenType::EOF, 2, 1) + ]; assert_eq!(actual_token_vec, expected); } @@ -277,7 +282,8 @@ mod tests{ let actual_token_vec: Vec = lex.tokenize(); let expected: Vec = vec![ - Token::new("\"test\"".to_string(), TokenType::StringLiteral, 1, 1) + Token::new("\"test\"".to_string(), TokenType::StringLiteral, 1, 1), + Token::new("EOF".to_string(), TokenType::EOF, 1, 7) ]; assert_eq!(actual_token_vec, expected); diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 45d1c79..b9d04f9 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -19,8 +19,7 @@ pub enum TokenType { Boolean, // Literals - True, - False, + BooleanLiteral, IntegerLiteral, StringLiteral, @@ -47,7 +46,8 @@ pub enum TokenType { Comma, // , Semicolon, // ; //special - Eof, // End of file + Return, + EOF, // End of file } #[derive(Debug, Clone)] @@ -88,8 +88,7 @@ impl fmt::Display for TokenType { TokenType::Boolean => write!(f, "Boolean"), // Literals - TokenType::True => write!(f, "true"), - TokenType::False => write!(f, "false"), + TokenType::BooleanLiteral => write!(f, "BooleanLiteral"), TokenType::IntegerLiteral => write!(f, "IntegerLiteral"), TokenType::StringLiteral => write!(f, "StringLiteral"), @@ -116,7 +115,8 @@ impl fmt::Display for TokenType { TokenType::RightBrace => write!(f, "}}"), TokenType::Comma => write!(f, ","), TokenType::Semicolon => write!(f, ";"), - TokenType::Eof => write!(f, "Eof"), + TokenType::EOF => write!(f, "EOF"), + TokenType::Return => write!(f, "Return"), } } } diff --git a/src/main.rs b/src/main.rs index 6d630c5..972f265 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,12 +12,12 @@ use parser::parser::Parser; fn main() { let args: Vec = env::args().collect(); - if args.len() < 3 { + if args.len() < 2 { eprintln!("Usage: triviC "); std::process::exit(1); } - let filename = &args[2]; + let filename = &args[1]; let source = fs::read_to_string(filename) .expect("Failed to read file"); @@ -29,12 +29,3 @@ fn main() { println!("Lexing and parsing completed successfully."); } - -#[cfg(test)] -mod tests{ - use pretty_assertions::{assert_eq}; - #[test] - fn zero_eq_zero(){ - assert_eq!(0,0); - } -} \ No newline at end of file diff --git a/src/parser/mod.rs b/src/parser/mod.rs index b2819a7..67c567f 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1 +1 @@ -pub mod parser; \ No newline at end of file +pub mod parser; diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 5b92f2f..91d4e8a 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -1,7 +1,9 @@ -use crate::lexer::token::{ self, Token, TokenType }; +use crate::lexer::token::{Token, TokenType}; +#[derive(Debug, Clone, PartialEq)] pub enum Stmt { Let(String, Type, Expr), - ExprStmt(Expr), + AssignStatement(String, Expr), + ExprStatement(Expr), If { condition: Expr, block: Block, @@ -12,26 +14,32 @@ pub enum Stmt { block: Block, }, Print(Expr), + Return(Expr) } +#[derive(Debug, Clone, PartialEq)] pub struct Function { pub name: String, pub params: Vec, pub return_type: Type, pub body: Block, } +#[derive(Debug, Clone, PartialEq)] pub struct Block { pub statements: Vec, } +#[derive(Debug, Clone, PartialEq)] pub struct Param { - name: String, - param_type: Type, // or some Type enum + pub name: String, + pub param_type: Type, } +#[derive(Debug, Clone, PartialEq)] pub enum Type { Integer, Boolean, } +#[derive(Debug, Clone, PartialEq)] pub enum Expr { IntegerLiteral(i64), BooleanLiteral(bool), @@ -42,15 +50,18 @@ pub enum Expr { Call(Vec), //I do not understand what this one is, but the expert recommended it } +#[derive(Debug, Clone, PartialEq)] pub enum BinOp { Add, Sub, Mul, Equals, + NotEquals, GreaterThan, LessThan, } +#[derive(Debug, Clone, PartialEq)] pub enum UnOp { Not, } @@ -64,97 +75,104 @@ impl Parser { pub fn new(token_vector: Vec) -> Self { Self { tokens: token_vector, - position: 1, + position: 0, } } pub fn parse_program(&mut self) -> AST { let mut ast: AST = Vec::new(); - while !self.match_token(TokenType::Eof) { - match self.current().token_type.clone() { + while !self.match_token(TokenType::EOF) { + match self.current().token_type { TokenType::Func => { ast.push(self.parse_func()); } - _ => - panic!( - "Wrong token {} at {}:{}", - self.current(), - self.current().line, - self.current().column - ), + _ => panic!( + "Wrong token {} at {}:{}", + self.current(), + self.current().line, + self.current().column, + ), } } ast } //Todo: Implement the following funcs/helper funcs-> fn parse_func(&mut self) -> Function { - self.expect(TokenType::Func); + let _ = self.expect(TokenType::Func); let name = self.expect(TokenType::Identifier).unwrap().value; - self.expect(TokenType::LeftParen); + let _ = self.expect(TokenType::LeftParen); let mut params = Vec::new(); while !self.match_token(TokenType::RightParen) { let name = self.expect(TokenType::Identifier).unwrap().value; - self.expect(TokenType::Colon); + let _ = self.expect(TokenType::Colon); - let mut typevalue; - match self.current().token_type { + let typevalue = match self.current().token_type { TokenType::Integer => { - self.expect(TokenType::Integer); - typevalue = Type::Integer; + let _ = self.expect(TokenType::Integer); + Type::Integer } TokenType::Boolean => { - self.expect(TokenType::Boolean); - typevalue = Type::Boolean; + let _ = self.expect(TokenType::Boolean); + Type::Boolean } _ => panic!("Unknown type for parameter"), - } - params.push(Param { name: name, param_type: typevalue }); + }; + params.push(Param { + name, + param_type: typevalue, + }); if !self.match_token(TokenType::RightParen) { - self.expect(TokenType::Comma); + let _ = self.expect(TokenType::Comma); } } - self.expect(TokenType::RightParen); + let _ = self.expect(TokenType::RightParen); - self.expect(TokenType::Arrow); + let _ = self.expect(TokenType::Arrow); - let mut return_type; - match self.current().token_type { + let return_type = match self.current().token_type { TokenType::Integer => { - self.expect(TokenType::Integer); - return_type = Type::Integer; + let _ = self.expect(TokenType::Integer); + Type::Integer } TokenType::Boolean => { - self.expect(TokenType::Boolean); - return_type = Type::Boolean; + let _ = self.expect(TokenType::Boolean); + Type::Boolean } - _ => panic!("Unknown return type for function"), - } + _ => panic!( + "Unknown return type for function: {}", + self.current().token_type + ), + }; - self.expect(TokenType::LeftBrace); + let _ = self.expect(TokenType::LeftBrace); let body: Block = self.parse_block(); - Function { name, params, return_type, body } + let _ = self.expect(TokenType::RightBrace); + Function { + name, + params, + return_type, + body, + } } fn parse_block(&mut self) -> Block { let mut statements: Vec = Vec::new(); let cur_tok = self.current(); - while !self.match_token(TokenType::Eof) && !self.match_token(TokenType::RightBrace) { + while !self.match_token(TokenType::EOF) && !self.match_token(TokenType::RightBrace) { if self.match_token(TokenType::Let) { statements.push(self.parse_let()); //dingdong test commit after revert; } else if self.match_token(TokenType::If) { - statements.push(self.parse_if()); + // statements.push(self.parse_if()); } else if self.match_token(TokenType::While) { - statements.push(self.parse_while()); - } else if - self.match_token(TokenType::Identifier) && - self.match_token(TokenType::Assign) + // statements.push(self.parse_while()); + } else if self.match_token(TokenType::Identifier) && self.match_token(TokenType::Assign) { - statements.push(self.parse_assignment()); + // statements.push(self.parse_assignment()); } else { let expression = self.parse_expression(); - statements.push(Stmt::ExprStmt(expression)); + statements.push(Stmt::ExprStatement(expression)); } } Block { statements } @@ -163,52 +181,117 @@ impl Parser { fn parse_let(&mut self) -> Stmt { self.consume(); let var_name = self.expect(TokenType::Identifier).unwrap().value; - self.expect(TokenType::Colon); + let _ = self.expect(TokenType::Colon); let type_of_var = match self.current().token_type { TokenType::Integer => Type::Integer, TokenType::Boolean => Type::Boolean, - _ => - panic!( - "Expected type, got something else at {}:{}", - self.current().line, - self.current().column - ), + _ => panic!( + "Expected type, got something else at {}:{}", + self.current().line, + self.current().column + ), }; self.consume(); - self.expect(TokenType::Assign); + let _ = self.expect(TokenType::Assign); let expr = self.parse_expression(); + let _ = self.expect(TokenType::Semicolon); Stmt::Let(var_name, type_of_var, expr) } + + fn token_to_binop(&self, tt: &TokenType) -> BinOp { + match tt { + TokenType::Plus => BinOp::Add, + TokenType::Minus => BinOp::Sub, + TokenType::Multiply => BinOp::Mul, + TokenType::Equals => BinOp::Equals, + TokenType::GreaterThan => BinOp::GreaterThan, + TokenType::LessThan => BinOp::LessThan, + _ => panic!("Not a binary operator"), + } + } + fn parse_expression(&mut self) -> Expr { let tok = self.consume(); match tok.token_type { - TokenType::Integer => { - if - self.match_any( - &[ - TokenType::Minus, - TokenType::Plus, - TokenType::Multiply, - TokenType::Division, - TokenType::GreaterThan, - TokenType::LessThan, - TokenType::Equals, - ] + TokenType::IntegerLiteral | TokenType::Identifier => { + if self.match_any(&[ + TokenType::Minus, + TokenType::Plus, + TokenType::Multiply, + TokenType::Division, + TokenType::GreaterThan, + TokenType::LessThan, + TokenType::Equals, + ]) { + let op_token = self.consume(); + let op = self.token_to_binop(&op_token.token_type); + let right = self.parse_expression(); + Expr::BinaryOp( + match tok.token_type { + TokenType::IntegerLiteral => { + Box::new(Expr::IntegerLiteral(tok.value.parse::().unwrap())) + } + TokenType::Identifier => Box::new(Expr::Identifier(tok.value)), + _ => panic!("SOMETHING IS WRONGDOG"), + }, + op, + Box::new(right), ) - { - Expr::BinaryOp(Expr::IntegerLiteral(tok.value.parse::().unwrap()), , ()) - }else{ + } else { Expr::IntegerLiteral(tok.value.parse::().unwrap()) } } - TokenType::Boolean => Expr::BooleanLiteral(tok.value.parse::().unwrap()), - TokenType::StringLiteral => Expr::StringLiteral(tok.value.clone()), - TokenType::Identifier => Expr::Identifier(tok.value.clone()), + TokenType::BooleanLiteral => { + if self.match_token(TokenType::Equals) { + let op_token = self.consume(); + let op = self.token_to_binop(&op_token.token_type); + let right = self.parse_expression(); + Expr::BinaryOp( + Box::new(Expr::BooleanLiteral(tok.value.parse::().unwrap())), + op, + Box::new(right), + ) + } else if self.match_token(TokenType::Not) { + let _ = self.expect(TokenType::Equals); + let op = BinOp::NotEquals; + let right = self.parse_expression(); + Expr::BinaryOp( + Box::new(Expr::BooleanLiteral(tok.value.parse::().unwrap())), + op, + Box::new(right), + ) + } else { + Expr::BooleanLiteral(tok.value.parse::().unwrap()) + } + } + TokenType::StringLiteral => { + if self.match_token(TokenType::Equals) { + let op_token = self.consume(); + let op = self.token_to_binop(&op_token.token_type); + let right = self.expect(TokenType::StringLiteral).unwrap(); + Expr::BinaryOp( + Box::new(Expr::StringLiteral(tok.value.parse::().unwrap())), + op, + Box::new(Expr::StringLiteral(right.value.parse::().unwrap())), + ) + } else if self.match_token(TokenType::Not) { + let _ = self.expect(TokenType::Equals); + let op = BinOp::NotEquals; + let right = self.expect(TokenType::StringLiteral).unwrap(); + Expr::BinaryOp( + Box::new(Expr::StringLiteral(tok.value.parse::().unwrap())), + op, + Box::new(Expr::StringLiteral(right.value.parse::().unwrap())), + ) + } else { + Expr::StringLiteral(tok.value.clone()) + } + } TokenType::Not => { let exprs = self.parse_expression(); Expr::UnaryOp(UnOp::Not, Box::new(exprs)) } - _ => panic!(""), + _ => panic!("Unexpected token {:?} in expression", tok.token_type), } } // fn parse_expr @@ -243,23 +326,67 @@ impl Parser { fn match_token(&self, expected: TokenType) -> bool { self.current().token_type == expected } - fn match_any(&self, token_types: &[TokenType]) -> bool { - token_types.contains(&self.current().token_type) + fn match_any(&self, types: &[TokenType]) -> bool { + types.contains(&self.current().token_type) } fn expect(&mut self, expected: TokenType) -> Result { let tok = self.current(); if tok.token_type == expected { Ok(self.consume()) } else { - Err( - format!( - "Expected {:?} at {}:{}, found {:?}", - expected, - tok.line, - tok.column, - tok.token_type - ) - ) + Err(format!( + "Expected {:?} at {}:{}, found {:?}", + expected, tok.line, tok.column, tok.token_type + )) } } } + +mod tests { + + use crate::parser::parser::Parser; + use crate::{ + lexer::{ + lexer::Lexer, + token::{Token, TokenType}, + }, + parser::parser::{AST, BinOp, Block, Expr, Function, Type}, + }; + + #[test] + fn test_parser_parses_correct_ast() { + use crate::parser::parser::Stmt; + use std::fs; + let source = fs::read_to_string("simple.trv").expect("Failed to read file"); + let mut lexer = Lexer::new(source); + let tokens = lexer.tokenize(); + let mut parser = Parser::new(tokens); + let actual = parser.parse_program(); + + let expected: AST = vec![Function { + name: "main".to_string(), + params: vec![], + return_type: Type::Integer, + body: Block { + statements: vec![ + Stmt::Let("num".to_string(), Type::Integer, Expr::IntegerLiteral(0)), + Stmt::While{ + expr: Expr::BinaryOp( + Box::new(Expr::Identifier("num".to_string())), + BinOp::LessThan, + Box::new(Expr::IntegerLiteral(10)) + ), + block: Block{ + statements: vec![ + Stmt::AssignStatement("num".to_string(), Expr::IntegerLiteral(11)) + ] + } + }, + Stmt::Return(Expr::Identifier("num".to_string())) + ], + }, + }]; + + assert_eq!(actual, expected); + } +} From 3a1d3726aff3022487f45b479b86c72d9b439456 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Tue, 24 Feb 2026 12:27:36 +0100 Subject: [PATCH 09/10] added, parse return, if, while, and assignment, haven't run tests ofc, expect one more commit --- program.trv | 4 +-- src/parser/parser.rs | 65 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/program.trv b/program.trv index 44ad443..fd640f1 100644 --- a/program.trv +++ b/program.trv @@ -2,7 +2,7 @@ func is_greater_than_44(params : Integer) -> Integer { let x : Integer = params; - if x > 44 is True then { + if x > 44 then { 1 } else { @@ -13,7 +13,7 @@ func is_greater_than_44(params : Integer) -> Integer { func otherFunction() -> Boolean { let number : Integer = 20; let is_greater : Integer = is_greater_than_44(number); - if is_greater == 0 is True then { + if is_greater == 0 then { print("Didnt work the first time!"); } while is_greater == 0 do { diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 91d4e8a..21ca87f 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -159,24 +159,70 @@ impl Parser { fn parse_block(&mut self) -> Block { let mut statements: Vec = Vec::new(); - let cur_tok = self.current(); + while !self.match_token(TokenType::EOF) && !self.match_token(TokenType::RightBrace) { if self.match_token(TokenType::Let) { statements.push(self.parse_let()); //dingdong test commit after revert; } else if self.match_token(TokenType::If) { - // statements.push(self.parse_if()); + statements.push(self.parse_if()); } else if self.match_token(TokenType::While) { - // statements.push(self.parse_while()); - } else if self.match_token(TokenType::Identifier) && self.match_token(TokenType::Assign) + statements.push(self.parse_while()); + } else if self.match_token(TokenType::Identifier) && self.peek(TokenType::Assign) { - // statements.push(self.parse_assignment()); - } else { + statements.push(self.parse_assignment()); + } else if self.match_token(TokenType::Return) { + statements.push(self.parse_return()); + } + else { let expression = self.parse_expression(); statements.push(Stmt::ExprStatement(expression)); } } Block { statements } } + fn parse_return(&mut self) -> Stmt{ + self.consume(); + let expr = self.parse_expression(); + let _ = self.expect(TokenType::Semicolon); + Stmt::Return(expr) + } + + fn parse_assignment(&mut self) -> Stmt{ + let var_name = self.expect(TokenType::Identifier).unwrap().value; + let _ = self.expect(TokenType::Assign); + let expr = self.parse_expression(); + let _ = self.expect(TokenType::Semicolon); + Stmt::AssignStatement(var_name, expr) + } + + fn parse_while(&mut self) -> Stmt{ + self.consume(); + let expr = self.parse_expression(); + let _ = self.expect(TokenType::Do); + let _ = self.expect(TokenType::LeftBrace); + let block = self.parse_block(); + let _ = self.expect(TokenType::RightBrace); + Stmt::While { expr, block } + } + + fn parse_if(&mut self) -> Stmt{ + self.consume(); + let condition = self.parse_expression(); + let _ = self.expect(TokenType::Then); + let _ = self.expect(TokenType::LeftBrace); + let block = self.parse_block(); + let _ = self.expect(TokenType::RightBrace); + let option = match self.current().token_type { + TokenType::Else => { + self.consume(); + let _ = self.expect(TokenType::LeftBrace); + Some(self.parse_block()) + } + _ => None + }; + let _ = self.expect(TokenType::RightBrace); + Stmt::If { condition , block, option } + } fn parse_let(&mut self) -> Stmt { self.consume(); @@ -294,13 +340,6 @@ impl Parser { _ => panic!("Unexpected token {:?} in expression", tok.token_type), } } - // fn parse_expr - - // fn parse_bin_op - - // fn parse_un_op - - //Even more parse functions my fella //Here im making some helper functions i reckon mate fn peek(&self, token_type: TokenType) -> bool { From 166074ea0da42f3a51ae16271b33e443bf177603 Mon Sep 17 00:00:00 2001 From: Aasmundur Date: Tue, 24 Feb 2026 13:26:38 +0100 Subject: [PATCH 10/10] made changes to the test and fixed bugs that made em fail as well --- simple.trv | 6 +++++- src/parser/parser.rs | 25 +++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/simple.trv b/simple.trv index e9aba45..ecb9a22 100644 --- a/simple.trv +++ b/simple.trv @@ -4,6 +4,10 @@ func main() -> Integer { while num < 10 do { num = 11; } - + if num > 10 { + num = 11; + } else { + num = 11; + } return num; } diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 21ca87f..5717655 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -283,8 +283,12 @@ impl Parser { op, Box::new(right), ) - } else { - Expr::IntegerLiteral(tok.value.parse::().unwrap()) + }else { + match tok.token_type{ + TokenType::IntegerLiteral => Expr::IntegerLiteral(tok.value.parse::().unwrap()), + TokenType::Identifier => Expr::Identifier(tok.value), + _ => panic!("tokentype wrong, should be integer literal or identifyer") + } } } TokenType::BooleanLiteral => { @@ -421,6 +425,23 @@ mod tests { ] } }, + Stmt::If { + condition: Expr::BinaryOp( + Box::new(Expr::Identifier("num".to_string())), + BinOp::GreaterThan, + Box::new(Expr::IntegerLiteral(10)) + ), + block: Block{ + statements: vec![ + Stmt::AssignStatement("num".to_string(), Expr::IntegerLiteral(11)) + ] + }, + option: Some(Block{ + statements: vec![ + Stmt:: AssignStatement("num".to_string(), Expr::IntegerLiteral(11)) + ] + }) + }, Stmt::Return(Expr::Identifier("num".to_string())) ], },