From 277272e2b7a130bfe7a56a734c4a51d0445ef769 Mon Sep 17 00:00:00 2001 From: Garrit Franke Date: Sun, 14 Feb 2021 21:16:45 +0100 Subject: [PATCH] feat: struct initialization --- src/generator/c.rs | 2 ++ src/generator/js.rs | 21 +++++++++++++++++++++ src/parser/node_type.rs | 1 + src/parser/rules.rs | 42 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+) diff --git a/src/generator/c.rs b/src/generator/c.rs index e108280..09b8f68 100644 --- a/src/generator/c.rs +++ b/src/generator/c.rs @@ -125,6 +125,7 @@ fn generate_expression(expr: Expression) -> String { Expression::Array(els) => generate_array(els), Expression::ArrayAccess(name, expr) => generate_array_access(name, *expr), Expression::BinOp(left, op, right) => generate_bin_op(*left, op, *right), + Expression::StructInitialization(_, _) => todo!(), } } @@ -217,6 +218,7 @@ fn generate_function_call(func: String, args: Vec) -> String { Expression::Str(s) | Expression::Variable(s) => s, Expression::Array(_) => todo!(), Expression::BinOp(left, op, right) => generate_bin_op(*left, op, *right), + Expression::StructInitialization(_, _) => todo!(), }) .collect::>() .join(","); diff --git a/src/generator/js.rs b/src/generator/js.rs index cf49194..58eb855 100644 --- a/src/generator/js.rs +++ b/src/generator/js.rs @@ -15,6 +15,7 @@ */ use crate::generator::Generator; use crate::parser::node_type::*; +use std::collections::HashMap; pub struct JsGenerator; @@ -116,6 +117,9 @@ fn generate_expression(expr: Expression) -> String { Expression::Array(els) => generate_array(els), Expression::ArrayAccess(name, expr) => generate_array_access(name, *expr), Expression::BinOp(left, op, right) => generate_bin_op(*left, op, *right), + Expression::StructInitialization(name, fields) => { + generate_struct_initialization(name, fields) + } } } @@ -224,6 +228,9 @@ fn generate_function_call(func: String, args: Vec) -> String { Expression::Str(s) | Expression::Variable(s) => s, Expression::Array(elements) => generate_array(elements), Expression::BinOp(left, op, right) => generate_bin_op(*left, op, *right), + Expression::StructInitialization(name, fields) => { + generate_struct_initialization(name, fields) + } }) .collect::>() .join(","); @@ -265,6 +272,20 @@ fn generate_bin_op(left: Expression, op: BinOp, right: Expression) -> String { ) } +fn generate_struct_initialization( + _name: String, + fields: HashMap>, +) -> String { + let mut out_str = "{".to_string(); + for (key, value) in fields { + out_str += &format!("{}: {},", key, generate_expression(*value)); + } + + out_str += "}"; + + out_str.into() +} + fn generate_assign(name: Expression, expr: Expression) -> String { format!( "{} = {}", diff --git a/src/parser/node_type.rs b/src/parser/node_type.rs index 13a2c02..39a755d 100644 --- a/src/parser/node_type.rs +++ b/src/parser/node_type.rs @@ -112,6 +112,7 @@ pub enum Expression { /// (name, index) ArrayAccess(String, Box), BinOp(Box, BinOp, Box), + StructInitialization(String, HashMap>), } impl TryFrom for Expression { diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 69bf295..6806b6e 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -18,6 +18,7 @@ use super::node_type::*; use super::parser::Parser; use crate::lexer::Keyword; use crate::lexer::{TokenKind, Value}; +use std::collections::HashMap; use std::convert::TryFrom; impl Parser { @@ -305,10 +306,51 @@ impl Parser { Ok(state) } TokenKind::SquareBraceOpen => self.parse_array(), + TokenKind::Keyword(Keyword::Struct) => self.parse_struct_initialization(), other => Err(format!("Expected Expression, found {:?}", other)), } } + /// TODO: Cleanup + fn parse_struct_initialization(&mut self) -> Result { + let name = self.match_identifier()?; + self.match_token(TokenKind::CurlyBracesOpen)?; + let fields = self.parse_struct_fields()?; + self.match_token(TokenKind::CurlyBracesClose)?; + + Ok(Expression::StructInitialization(name, fields)) + } + + fn parse_struct_fields(&mut self) -> Result>, String> { + let mut map = HashMap::new(); + + // If there is a field + if let TokenKind::Identifier(_) = self.peek()?.kind { + // Parse first field + let (name, expr) = self.parse_struct_field()?; + map.insert(name, expr); + // Then continue to parse fields + // as long as a comma token is found + while self.peek_token(TokenKind::Comma).is_ok() { + self.match_token(TokenKind::Comma)?; + let (name, expr) = self.parse_struct_field()?; + map.insert(name, expr); + } + } + + Ok(map) + } + + fn parse_struct_field(&mut self) -> Result<(String, Box), String> { + let next = self.next()?; + if let TokenKind::Identifier(name) = next.kind { + self.match_token(TokenKind::Colon)?; + return Ok((name, Box::new(self.parse_expression()?))); + } + + Err(format!("Struct field could not be parsed: {}", next.raw)) + } + fn parse_array(&mut self) -> Result { let mut elements = Vec::new(); loop {