Get basic compiler working
This commit is contained in:
		
							parent
							
								
									3414aaee9b
								
							
						
					
					
						commit
						b0a4f9dc7e
					
				
							
								
								
									
										183
									
								
								src/compiler.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/compiler.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | ||||
| use std::collections::HashMap; | ||||
| 
 | ||||
| use super::errors::CompilerError; | ||||
| use super::parser::{Expression, LiteralPattern, ParsedReid, Pattern, Position, Statement}; | ||||
| 
 | ||||
| type Variable = (VariableID, VariableType); | ||||
| type VariableID = u32; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum Command { | ||||
|     InitializeVariable(VariableID, VariableType), | ||||
|     BeginScope, | ||||
|     EndScope, | ||||
|     Pop(u32),                        // Pop into registery u32
 | ||||
|     Push(u32),                       // Push out of registery 32
 | ||||
|     AssignVariable(VariableID, u32), // Assign variable from registery u32
 | ||||
|     VarToReg(VariableID, u32),       // Bring Variable to registery u32
 | ||||
|     StringLit(String),               // Bring String Literal to Heap
 | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub enum VariableType { | ||||
|     TypeString, | ||||
| } | ||||
| 
 | ||||
| pub struct Compiler { | ||||
|     parsed: ParsedReid, | ||||
|     root_scope: Scope, | ||||
|     list: Vec<Command>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct CompiledReid { | ||||
|     pub list: Vec<Command>, | ||||
| } | ||||
| 
 | ||||
| impl Compiler { | ||||
|     pub fn from(parsed: ParsedReid) -> Compiler { | ||||
|         Compiler { | ||||
|             parsed, | ||||
|             root_scope: Scope::default(), | ||||
|             list: Vec::new(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn compile(mut self) -> Result<CompiledReid, CompilerError> { | ||||
|         self.handle_expression(self.parsed.0.clone())?; | ||||
|         Ok(CompiledReid { list: self.list }) | ||||
|     } | ||||
| 
 | ||||
|     fn handle_expression( | ||||
|         &mut self, | ||||
|         exp: Expression, | ||||
|     ) -> Result<Option<VariableType>, CompilerError> { | ||||
|         match exp { | ||||
|             Expression::BlockExpr(pos, list) => { | ||||
|                 self.list.push(Command::BeginScope); | ||||
|                 self.root_scope.begin_scope(); | ||||
| 
 | ||||
|                 for statement in list { | ||||
|                     self.handle_statement(statement)?; | ||||
|                 } | ||||
| 
 | ||||
|                 self.root_scope.end_scope(pos)?; | ||||
|                 self.list.push(Command::EndScope); | ||||
|                 Ok(None) | ||||
|             } | ||||
|             Expression::ValueRef(_, val) => match val { | ||||
|                 Pattern::IdentPattern(pos, ident) => { | ||||
|                     if let Some(var) = self.root_scope.get(ident.clone()) { | ||||
|                         self.list.push(Command::VarToReg(var.0, 0)); | ||||
|                         self.list.push(Command::Push(0)); | ||||
|                         Ok(Some(var.1)) | ||||
|                     } else { | ||||
|                         Err(CompilerError::VariableNotExists(pos, ident)) | ||||
|                     } | ||||
|                 } | ||||
|                 Pattern::LiteralPattern(_, literal) => { | ||||
|                     let vtype = self.handle_literal(literal)?; | ||||
|                     Ok(Some(vtype)) | ||||
|                 } | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn handle_statement( | ||||
|         &mut self, | ||||
|         statement: Statement, | ||||
|     ) -> Result<Option<VariableType>, CompilerError> { | ||||
|         match statement { | ||||
|             Statement::LetStatement(pos, ident, val) => { | ||||
|                 let res = self.handle_expression(*val); | ||||
|                 match res { | ||||
|                     Ok(vtype) => { | ||||
|                         if let Some(vtype) = vtype { | ||||
|                             self.root_scope.add_var(pos, ident.clone(), vtype)?; | ||||
|                             let var = self.root_scope.get(ident).unwrap(); | ||||
|                             self.list.push(Command::InitializeVariable(var.0, var.1)); | ||||
|                             self.list.push(Command::Pop(0)); | ||||
|                             self.list.push(Command::AssignVariable(var.0, 0)); | ||||
|                             Ok(None) | ||||
|                         } else { | ||||
|                             Err(CompilerError::LetFailed( | ||||
|                                 pos, | ||||
|                                 Box::new(CompilerError::CanNotAssignVoidType), | ||||
|                             )) | ||||
|                         } | ||||
|                     } | ||||
|                     Err(err) => Err(CompilerError::LetFailed(pos, Box::new(err))), | ||||
|                 } | ||||
|             } | ||||
|             Statement::ExprStatement(pos, expr) => self.handle_expression(expr), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn handle_literal(&mut self, pattern: LiteralPattern) -> Result<VariableType, CompilerError> { | ||||
|         match pattern { | ||||
|             LiteralPattern::StringLit(string) => self.list.push(Command::StringLit(string)), | ||||
|         } | ||||
|         Ok(VariableType::TypeString) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Default)] | ||||
| pub struct Scope { | ||||
|     counter: VariableID, | ||||
|     variables: HashMap<String, Variable>, | ||||
|     innerScope: Option<Box<Scope>>, | ||||
| } | ||||
| 
 | ||||
| impl Scope { | ||||
|     fn get(&self, variable: String) -> Option<Variable> { | ||||
|         if let Some(val) = self.variables.get(&variable) { | ||||
|             Some(*val) | ||||
|         } else if let Some(inner) = &self.innerScope { | ||||
|             if let Some(val) = inner.get(variable) { | ||||
|                 Some((val.0 + self.counter, val.1)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn add_var( | ||||
|         &mut self, | ||||
|         pos: Position, | ||||
|         variable: String, | ||||
|         vtype: VariableType, | ||||
|     ) -> Result<(), CompilerError> { | ||||
|         if self.variables.contains_key(&variable) { | ||||
|             Err(CompilerError::VariableExists(pos, variable)) | ||||
|         } else if let Some(inner) = &mut self.innerScope { | ||||
|             inner.add_var(pos, variable, vtype) | ||||
|         } else { | ||||
|             self.variables.insert(variable, (self.counter, vtype)); | ||||
|             self.counter += 1; | ||||
|             Ok(()) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn begin_scope(&mut self) { | ||||
|         if let Some(inner) = &mut self.innerScope { | ||||
|             inner.begin_scope(); | ||||
|         } else { | ||||
|             self.innerScope = Some(Box::default()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn end_scope(&mut self, pos: Position) -> Result<(), CompilerError> { | ||||
|         if let Some(inner) = &mut self.innerScope { | ||||
|             if inner.innerScope.is_some() { | ||||
|                 inner.end_scope(pos)?; | ||||
|             } else { | ||||
|                 self.innerScope = None; | ||||
|             } | ||||
|             Ok(()) | ||||
|         } else { | ||||
|             Err(CompilerError::InvalidScopeExit(pos)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -15,17 +15,17 @@ impl From<io::Error> for GenericError { | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum CompilerError { | ||||
| pub enum SyntaxError { | ||||
|     Fatal, | ||||
|     ExpectedToken(Position, char), | ||||
|     ExpectedExpression(Position, Option<Box<CompilerError>>), | ||||
|     ExpectedExpression(Position, Option<Box<SyntaxError>>), | ||||
|     ExpectedIdent(Position), | ||||
|     ExpectedStatement(Position, Option<Box<CompilerError>>), | ||||
|     ExpectedStatement(Position, Option<Box<SyntaxError>>), | ||||
|     ExpectedPattern(Position), | ||||
| } | ||||
| 
 | ||||
| impl CompilerError { | ||||
|     fn from_opt(from: &Option<Box<CompilerError>>) -> String { | ||||
| impl SyntaxError { | ||||
|     fn from_opt(from: &Option<Box<SyntaxError>>) -> String { | ||||
|         if let Some(err) = from { | ||||
|             format!("\n  {}", err) | ||||
|         } else { | ||||
| @ -34,24 +34,44 @@ impl CompilerError { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for CompilerError { | ||||
| impl Display for SyntaxError { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         let text = match self { | ||||
|             CompilerError::Fatal => "Fatal error".to_string(), | ||||
|             CompilerError::ExpectedToken(pos, c) => format!("Expected token '{}' at {}", c, pos), | ||||
|             CompilerError::ExpectedExpression(pos, err) => format!( | ||||
|             SyntaxError::Fatal => "Fatal error".to_string(), | ||||
|             SyntaxError::ExpectedToken(pos, c) => format!("Expected token '{}' at {}", c, pos), | ||||
|             SyntaxError::ExpectedExpression(pos, err) => format!( | ||||
|                 "Expected expression at {}{}", | ||||
|                 pos, | ||||
|                 CompilerError::from_opt(err) | ||||
|                 SyntaxError::from_opt(err) | ||||
|             ), | ||||
|             CompilerError::ExpectedIdent(pos) => format!("Expected ident at {}", pos), | ||||
|             CompilerError::ExpectedStatement(pos, err) => format!( | ||||
|             SyntaxError::ExpectedIdent(pos) => format!("Expected ident at {}", pos), | ||||
|             SyntaxError::ExpectedStatement(pos, err) => format!( | ||||
|                 "Expected statement at {}{}", | ||||
|                 pos, | ||||
|                 CompilerError::from_opt(err) | ||||
|                 SyntaxError::from_opt(err) | ||||
|             ), | ||||
|             CompilerError::ExpectedPattern(pos) => format!("Expected pattern at {}", pos), | ||||
|             SyntaxError::ExpectedPattern(pos) => format!("Expected pattern at {}", pos), | ||||
|         }; | ||||
|         write!(f, "{}", text) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum CompilerError { | ||||
|     Fatal, | ||||
|     VariableExists(Position, String), | ||||
|     VariableNotExists(Position, String), | ||||
|     InvalidScopeExit(Position), | ||||
|     LetFailed(Position, Box<CompilerError>), | ||||
|     CanNotAssignVoidType, | ||||
| } | ||||
| 
 | ||||
| impl CompilerError { | ||||
|     fn from_opt(from: &Option<Box<SyntaxError>>) -> String { | ||||
|         if let Some(err) = from { | ||||
|             format!("\n  {}", err) | ||||
|         } else { | ||||
|             String::new() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -1,17 +1,29 @@ | ||||
| mod compiler; | ||||
| mod errors; | ||||
| mod file_io; | ||||
| mod parser; | ||||
| 
 | ||||
| use compiler::Compiler; | ||||
| use file_io::open_file; | ||||
| use parser::Parser; | ||||
| use std::path::Path; | ||||
| 
 | ||||
| fn main() { | ||||
|     let path = Path::new("reid_src/test.reid"); | ||||
|     let reid = Parser::from(open_file(&path).ok().unwrap()).parse(); | ||||
|     if let Err(error) = reid { | ||||
|     let parsed = Parser::from(open_file(&path).ok().unwrap()).parse(); | ||||
|     match parsed { | ||||
|         Err(error) => { | ||||
|             eprintln!("Syntax error: {}", error); | ||||
|             std::process::exit(1); | ||||
|         } | ||||
|     dbg!(reid); | ||||
|         Ok(parsed) => { | ||||
|             dbg!(&parsed); | ||||
|             let compiled = Compiler::from(parsed).compile(); | ||||
|             if let Err(error) = compiled { | ||||
|                 eprintln!("Compilation error: {:#?}", error); | ||||
|                 std::process::exit(1); | ||||
|             } | ||||
|             dbg!(compiled); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| mod parsed_reid; | ||||
| 
 | ||||
| use super::errors::CompilerError; | ||||
| use parsed_reid::{Expression, ParsedReid, Statement}; | ||||
| use super::errors::SyntaxError; | ||||
| pub use parsed_reid::*; | ||||
| use std::fmt; | ||||
| use std::fmt::Display; | ||||
| 
 | ||||
| @ -31,7 +31,7 @@ impl Parser { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn parse(mut self) -> Result<ParsedReid, CompilerError> { | ||||
|     pub fn parse(mut self) -> Result<ParsedReid, SyntaxError> { | ||||
|         let mut statement_list = Vec::new(); | ||||
| 
 | ||||
|         let mut error = None; | ||||
| @ -211,7 +211,7 @@ impl Expect<'_> { | ||||
|         } | ||||
|         self.text | ||||
|     } | ||||
|     pub fn get_or(self, error: CompilerError) -> Result<String, CompilerError> { | ||||
|     pub fn get_or(self, error: SyntaxError) -> Result<String, SyntaxError> { | ||||
|         match self.get() { | ||||
|             Some(text) => Ok(text), | ||||
|             None => Err(error), | ||||
|  | ||||
| @ -1,35 +1,35 @@ | ||||
| use super::{CompilerError, Parser, Position}; | ||||
| use super::{Parser, Position, SyntaxError}; | ||||
| 
 | ||||
| type Ident = String; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct ParsedReid(pub Expression); | ||||
| #[derive(Debug)] | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Statement { | ||||
|     LetStatement(Position, Ident, Box<Expression>), | ||||
|     ExprStatement(Position, Expression), | ||||
| } | ||||
| 
 | ||||
| impl Statement { | ||||
|     pub fn parse(parser: &mut Parser) -> Result<Statement, CompilerError> { | ||||
|     pub fn parse(parser: &mut Parser) -> Result<Statement, SyntaxError> { | ||||
|         let pos = parser.pos(); | ||||
| 
 | ||||
|         if let Some(_) = parser.expect("let").get() { | ||||
|             let ident = parser | ||||
|                 .expect_ident() | ||||
|                 .get_or(CompilerError::ExpectedIdent(pos))?; | ||||
|                 .get_or(SyntaxError::ExpectedIdent(pos))?; | ||||
|             parser | ||||
|                 .expect("=") | ||||
|                 .get_or(CompilerError::ExpectedToken(pos, '='))?; | ||||
|                 .get_or(SyntaxError::ExpectedToken(pos, '='))?; | ||||
|             match Expression::parse(parser) { | ||||
|                 Ok(expr) => { | ||||
|                     parser | ||||
|                         .expect(";") | ||||
|                         .get_or(CompilerError::ExpectedToken(pos, ';'))?; | ||||
|                         .get_or(SyntaxError::ExpectedToken(pos, ';'))?; | ||||
|                     Ok(Statement::LetStatement(pos, ident, Box::new(expr))) | ||||
|                 } | ||||
|                 Err(err) => Err(CompilerError::ExpectedExpression(pos, Some(Box::new(err)))), | ||||
|                 Err(err) => Err(SyntaxError::ExpectedExpression(pos, Some(Box::new(err)))), | ||||
|             } | ||||
|         } else { | ||||
|             match Expression::parse(parser) { | ||||
| @ -37,23 +37,23 @@ impl Statement { | ||||
|                     let statement = Statement::ExprStatement(pos, expr); | ||||
|                     parser | ||||
|                         .expect(";") | ||||
|                         .get_or(CompilerError::ExpectedToken(pos, ';'))?; | ||||
|                         .get_or(SyntaxError::ExpectedToken(pos, ';'))?; | ||||
|                     Ok(statement) | ||||
|                 } | ||||
|                 Err(err) => Err(CompilerError::ExpectedStatement(pos, Some(Box::new(err)))), | ||||
|                 Err(err) => Err(SyntaxError::ExpectedStatement(pos, Some(Box::new(err)))), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Expression { | ||||
|     BlockExpr(Position, Vec<Statement>), | ||||
|     ValueRef(Position, Pattern), | ||||
| } | ||||
| 
 | ||||
| impl Expression { | ||||
|     pub fn parse(parser: &mut Parser) -> Result<Expression, CompilerError> { | ||||
|     pub fn parse(parser: &mut Parser) -> Result<Expression, SyntaxError> { | ||||
|         let begin_pos = parser.pos(); | ||||
| 
 | ||||
|         let expect = parser.expect("{"); | ||||
| @ -71,24 +71,24 @@ impl Expression { | ||||
|             if let Some(_) = parser.expect("}").get() { | ||||
|                 Ok(Expression::BlockExpr(begin_pos, statement_list)) | ||||
|             } else { | ||||
|                 Err(CompilerError::ExpectedToken(parser.pos(), '}')) | ||||
|                 Err(SyntaxError::ExpectedToken(parser.pos(), '}')) | ||||
|             } | ||||
|         } else if let Ok(pattern) = Pattern::parse(parser) { | ||||
|             Ok(Expression::ValueRef(begin_pos, pattern)) | ||||
|         } else { | ||||
|             Err(CompilerError::ExpectedExpression(begin_pos, None)) | ||||
|             Err(SyntaxError::ExpectedExpression(begin_pos, None)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum Pattern { | ||||
|     IdentPattern(Position, Ident), | ||||
|     LiteralPattern(Position, LiteralPattern), | ||||
| } | ||||
| 
 | ||||
| impl Pattern { | ||||
|     fn parse(parser: &mut Parser) -> Result<Pattern, CompilerError> { | ||||
|     fn parse(parser: &mut Parser) -> Result<Pattern, SyntaxError> { | ||||
|         let pos = parser.pos(); | ||||
|         if let Some(string) = parser.expect_string_lit().get() { | ||||
|             Ok(Pattern::LiteralPattern( | ||||
| @ -98,12 +98,12 @@ impl Pattern { | ||||
|         } else if let Some(ident) = parser.expect_ident().get() { | ||||
|             Ok(Pattern::IdentPattern(pos, ident)) | ||||
|         } else { | ||||
|             Err(CompilerError::ExpectedPattern(pos)) | ||||
|             Err(SyntaxError::ExpectedPattern(pos)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum LiteralPattern { | ||||
|     StringLit(String), | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user