From 6720631f400b21684940c3d75ef399d6318ecb2e Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Sun, 14 Feb 2021 15:31:40 +0100 Subject: [PATCH] feat: struct definitions --- src/generator/js.rs | 14 +++++++ src/generator/x86.rs | 6 ++- src/lexer/mod.rs | 2 + src/parser/node_type.rs | 7 ++++ src/parser/rules.rs | 87 ++++++++++++++++++++++++++--------------- 5 files changed, 83 insertions(+), 33 deletions(-) diff --git a/src/generator/js.rs b/src/generator/js.rs index dabb680..cf49194 100644 --- a/src/generator/js.rs +++ b/src/generator/js.rs @@ -26,6 +26,15 @@ impl Generator for JsGenerator { crate::Builtins::get("builtin.js").expect("Could not locate builtin functions"); code += std::str::from_utf8(raw_builtins.as_ref()) .expect("Unable to interpret builtin functions"); + + let structs: String = prog + .structs + .into_iter() + .map(generate_struct_definition) + .collect(); + + code += &structs; + let funcs: String = prog.func.into_iter().map(generate_function).collect(); code += &funcs; @@ -50,6 +59,11 @@ fn generate_function(func: Function) -> String { raw } +fn generate_struct_definition(struct_def: StructDef) -> String { + // JS doesn't care about field declaration + format!("class {} {{}}\n", struct_def.name) +} + /// prepend is used to pass optional statements, that will be put in front of the regular block /// Currently used in for statements, to declare local variables fn generate_block(block: Statement, prepend: Option) -> String { diff --git a/src/generator/x86.rs b/src/generator/x86.rs index 44c6c5d..c44346c 100644 --- a/src/generator/x86.rs +++ b/src/generator/x86.rs @@ -57,7 +57,11 @@ impl X86Generator { fn gen_program(&mut self, prog: Program) -> Assembly { let mut asm = Assembly::new(); - let Program { func, globals } = prog; + let Program { + func, + globals, + structs: _, + } = prog; asm.add(".intel_syntax noprefix"); asm.add(".text"); diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index dda678c..85ae242 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -141,6 +141,7 @@ pub enum Keyword { Continue, Function, Boolean, + Struct, Unknown, } @@ -361,6 +362,7 @@ impl Cursor<'_> { c if c == "in" => Keyword::In, c if c == "break" => Keyword::Break, c if c == "continue" => Keyword::Continue, + c if c == "struct" => Keyword::Struct, _ => Keyword::Unknown, } } diff --git a/src/parser/node_type.rs b/src/parser/node_type.rs index c2c5c33..13a2c02 100644 --- a/src/parser/node_type.rs +++ b/src/parser/node_type.rs @@ -23,6 +23,7 @@ pub type SymbolTable = HashMap>; #[derive(Debug)] pub struct Program { pub func: Vec, + pub structs: Vec, pub globals: Vec, } @@ -51,6 +52,12 @@ pub struct Function { pub ret_type: Option, } +#[derive(Debug, Clone)] +pub struct StructDef { + pub name: String, + pub fields: Vec, +} + #[derive(Debug, Eq, PartialEq, Clone)] pub struct Variable { pub name: String, diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 63768ca..69bf295 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -23,18 +23,68 @@ use std::convert::TryFrom; impl Parser { pub fn parse_program(&mut self) -> Result { let mut functions = Vec::new(); + let mut structs = Vec::new(); let globals = Vec::new(); while self.has_more() { - functions.push(self.parse_function()?) + let next = self.peek()?; + match next.kind { + TokenKind::Keyword(Keyword::Function) => functions.push(self.parse_function()?), + TokenKind::Keyword(Keyword::Struct) => { + structs.push(self.parse_struct_definition()?) + } + _ => return Err(format!("Unexpected token: {}", next.raw)), + } } Ok(Program { func: functions, + structs, globals, }) } + fn parse_struct_definition(&mut self) -> Result { + self.match_keyword(Keyword::Struct)?; + let name = self.match_identifier()?; + + self.match_token(TokenKind::CurlyBracesOpen)?; + let fields = self.parse_typed_variable_list()?; + self.match_token(TokenKind::CurlyBracesClose)?; + + Ok(StructDef { name, fields }) + } + + fn parse_typed_variable_list(&mut self) -> Result, String> { + let mut args = Vec::new(); + + // If there is an argument + if let TokenKind::Identifier(_) = self.peek()?.kind { + // Parse first argument + args.push(self.parse_typed_variable()?); + // Then continue to parse arguments + // as long as a comma token is found + while self.peek_token(TokenKind::Comma).is_ok() { + self.match_token(TokenKind::Comma)?; + args.push(self.parse_typed_variable()?); + } + } + + Ok(args) + } + + fn parse_typed_variable(&mut self) -> Result { + let next = self.next()?; + if let TokenKind::Identifier(name) = next.kind { + return Ok(Variable { + name, + ty: Some(self.parse_type()?), + }); + } + + Err(format!("Argument could not be parsed: {}", next.raw)) + } + fn parse_block(&mut self) -> Result { self.match_token(TokenKind::CurlyBracesOpen)?; @@ -68,7 +118,7 @@ impl Parser { let arguments: Vec = match self.peek()? { t if t.kind == TokenKind::BraceClose => Vec::new(), - _ => self.parse_arguments()?, + _ => self.parse_typed_variable_list()?, }; self.match_token(TokenKind::BraceClose)?; @@ -88,36 +138,6 @@ impl Parser { }) } - fn parse_arguments(&mut self) -> Result, String> { - let mut args = Vec::new(); - - // If there is an argument - if let TokenKind::Identifier(_) = self.peek()?.kind { - // Parse first argument - args.push(self.parse_typed_argument_list()?); - // Then continue to parse arguments - // as long as a comma token is found - while self.peek_token(TokenKind::Comma).is_ok() { - self.match_token(TokenKind::Comma)?; - args.push(self.parse_typed_argument_list()?); - } - } - - Ok(args) - } - - fn parse_typed_argument_list(&mut self) -> Result { - let next = self.next()?; - if let TokenKind::Identifier(name) = next.kind { - return Ok(Variable { - name, - ty: Some(self.parse_type()?), - }); - } - - Err(format!("Argument could not be parsed: {}", next.raw)) - } - fn parse_type(&mut self) -> Result { self.match_token(TokenKind::Colon)?; let next = self.peek()?; @@ -172,6 +192,9 @@ impl Parser { } } TokenKind::Literal(_) => Ok(Statement::Exp(self.parse_expression()?)), + TokenKind::Keyword(Keyword::Struct) => { + Err("Struct definitions inside functions are not allowed".to_string()) + } _ => Err(self.make_error(TokenKind::Unknown, token)), } }