diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 5256592..8ba217a 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -3,16 +3,33 @@ use std::collections::HashMap; use serde::Serialize; #[derive(Debug, Clone, Serialize)] -pub struct ParamList(pub HashMap); +pub struct FieldList(pub HashMap); + +#[derive(Debug, Clone, Serialize)] +pub struct ParamList(pub Vec); #[derive(Debug, Clone, Serialize)] pub struct Block(pub Vec); #[derive(Debug, Clone, Serialize)] -pub enum TypeExpr { - Identifier(String), +pub enum TypePostfix { + Ref, + RefMut, } +#[derive(Debug, Clone, Serialize)] +pub enum TypeExprKind { + Path(StaticPath), + PathParams(StaticPath, Vec), + Tuple(Vec), +} + +#[derive(Debug, Clone, Serialize)] +pub struct TypeExpr(pub TypeExprKind, pub Vec); + +#[derive(Debug, Clone, Serialize)] +pub struct StaticPath(pub Vec); + #[derive(Debug, Clone, Serialize)] pub enum BinaryOp { Plus, @@ -34,13 +51,13 @@ pub enum TopLevel { StructDecl { export: bool, name: String, - fields: ParamList, + fields: FieldList, }, FunctionDecl { export: bool, name: String, params: ParamList, - return_type: Option, + return_type: TypeExpr, body: Block, }, } @@ -71,13 +88,18 @@ pub enum Statement { } #[derive(Debug, Clone, Serialize)] -pub struct VarDeclStmt { +pub struct VarDecl { pub mutable: bool, pub name: String, - pub init: Option, pub type_: Option, } +#[derive(Debug, Clone, Serialize)] +pub struct VarDeclStmt { + pub decl: VarDecl, + pub init: Option, +} + #[derive(Debug, Clone, Serialize)] pub struct VarAssignStmt { pub target: Expression, @@ -107,7 +129,7 @@ pub struct ForStmt { #[derive(Debug, Clone, Serialize)] pub enum Expression { - Identifier(String), + Path(StaticPath), IntLiteral(i64), FloatLiteral(f64), BoolLiteral(bool), diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index c08f422..e60b11b 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -4,12 +4,13 @@ COMMENT = _{ "//" ~ (!"\n" ~ ANY)* } program = { SOI ~ top_level* ~ EOI } // primitives -identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* } -integer = @{ ASCII_DIGIT+ } -float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ } -boolean = { "true" | "false" } -string_lit = { "\"" ~ inner_str ~ "\"" } -inner_str = @{ (!"\"" ~ ANY)* } +identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* } +integer = @{ ASCII_DIGIT+ } +float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ } +boolean = { "true" | "false" } +string_lit = { "\"" ~ inner_str ~ "\"" } +inner_str = @{ (!"\"" ~ ANY)* } +static_path = { identifier ~ ("::" ~ identifier)* } export = { "public" } mutable = { "mut" } @@ -72,14 +73,17 @@ while_stmt = { } // ================= EXPRESSIONS ================= -type_expr = { identifier } +tuple_type = { "(" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ")" } +path_type = { static_path ~ ("<" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ">")? } +ref_type = { mutable? ~ "*" } +type_expr = { (path_type | tuple_type) ~ ref_type* } primary = { integer | float | boolean | string_lit - | identifier + | static_path } postfix = { diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 3ab17af..584c832 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use pest::Parser; use pest_derive::Parser; @@ -17,8 +15,6 @@ pub type ParseError = pest::error::Error; pub fn parse(source: &str) -> Result, ParseError> { let mut pairs = MistParser::parse(Rule::program, source)?; - println!("{pairs:#?}"); - let mut statements = vec![]; for pair in pairs.next().unwrap().into_inner() { @@ -30,44 +26,95 @@ pub fn parse(source: &str) -> Result, ParseError> { Ok(statements) } -impl TryFrom> for TypeExpr { - type Error = (); - - fn try_from(pair: pest::iterators::Pair<'_, Rule>) -> Result { - if pair.as_str() == "void" { - return Err(()); - } - - Ok(match pair.as_rule() { +impl From> for TypeExpr { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + match pair.as_rule() { Rule::type_expr => { - let inner = pair.into_inner().next().unwrap(); - TypeExpr::try_from(inner)? + let mut inner = pair.into_inner(); + TypeExpr( + TypeExprKind::from(inner.next().unwrap()), + inner.map(TypePostfix::from).collect(), + ) } - Rule::identifier => TypeExpr::Identifier(pair.as_str().to_string()), _ => unimplemented!("{pair:#?}"), - }) + } } } -impl From<(bool, pest::iterators::Pair<'_, Rule>)> for ParamList { - fn from((export_allowed, pair): (bool, pest::iterators::Pair)) -> Self { +impl From> for TypePostfix { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + match pair.as_rule() { + Rule::ref_type => { + if pair.into_inner().peek().is_some() { + TypePostfix::RefMut + } else { + TypePostfix::Ref + } + } + _ => unimplemented!("{pair:#?}"), + } + } +} + +impl From> for TypeExprKind { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + match pair.as_rule() { + Rule::tuple_type => { + TypeExprKind::Tuple(pair.into_inner().map(TypeExpr::from).collect()) + } + Rule::path_type => { + let mut inner = pair.into_inner(); + let path = StaticPath::from(inner.next().unwrap()); + let params = inner.map(TypeExpr::from).collect::>(); + + if params.len() == 0 { + TypeExprKind::Path(path) + } else { + TypeExprKind::PathParams(path, params) + } + } + _ => unimplemented!("{pair:#?}"), + } + } +} + +impl From> for StaticPath { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + match pair.as_rule() { + Rule::static_path => { + StaticPath(pair.into_inner().map(|i| i.as_str().to_string()).collect()) + } + _ => unimplemented!("{pair:#?}"), + } + } +} + +impl From> for FieldList { + fn from(pair: pest::iterators::Pair) -> Self { let params = pair .into_inner() .map(|p| { let mut param_inner = p.into_inner(); - let export = - if export_allowed && param_inner.peek().unwrap().as_rule() == Rule::export { - param_inner.next().unwrap(); - true - } else { - false - }; - let param_type = TypeExpr::try_from(param_inner.next().unwrap()).unwrap(); + let export = if param_inner.peek().unwrap().as_rule() == Rule::export { + param_inner.next().unwrap(); + true + } else { + false + }; + let param_type = TypeExpr::from(param_inner.next().unwrap()); let param_name = param_inner.next().unwrap().as_str().to_string(); (param_name, (export, param_type)) }) .collect(); + FieldList(params) + } +} + +impl From> for ParamList { + fn from(pair: pest::iterators::Pair) -> Self { + let params = pair.into_inner().map(VarDecl::from).collect(); + ParamList(params) } } @@ -94,21 +141,13 @@ impl TryFrom> for TopLevel { false }; - let return_type = if let Some(next) = inner.peek() { - if next.as_rule() == Rule::type_expr { - TypeExpr::try_from(inner.next().unwrap()).ok() - } else { - None - } - } else { - None - }; + let return_type = TypeExpr::from(inner.next().unwrap()); let name = inner.next().unwrap().as_str().to_string(); let params = if inner.peek().unwrap().as_rule() == Rule::param_list { - ParamList::from((false, inner.next().unwrap())) + ParamList::from(inner.next().unwrap()) } else { - ParamList(HashMap::new()) + ParamList(Vec::new()) }; let body = Block::from(inner.next().unwrap()); @@ -136,7 +175,7 @@ impl TryFrom> for TopLevel { }; let name = inner.next().unwrap().as_str().to_string(); let fields_pair = inner.next().unwrap(); - let fields = ParamList::from((true, fields_pair)); + let fields = FieldList::from(fields_pair); Ok(TopLevel::StructDecl { export, @@ -182,28 +221,7 @@ impl From> for Statement { Rule::block => Statement::Block(Block::from(pair.into_inner().next().unwrap())), - Rule::var_decl_statement => { - let mut inner = pair.into_inner(); - - let mut var_decl = inner.next().unwrap().into_inner(); - - let type_ = var_decl.next().map(TypeExpr::try_from).unwrap().ok(); - let mutable = if var_decl.peek().unwrap().as_rule() == Rule::mutable { - var_decl.next(); - true - } else { - false - }; - let name = var_decl.next().unwrap().as_str().to_string(); - let init = inner.next().map(Expression::from); - - Statement::VarDecl(VarDeclStmt { - mutable, - name: name.as_str().to_string(), - init, - type_, - }) - } + Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::from(pair)), Rule::return_stmt => { let mut inner = pair.into_inner(); @@ -269,7 +287,7 @@ impl From> for Expression { } } Rule::primary => Expression::from(pair.into_inner().next().unwrap()), - Rule::identifier => Expression::Identifier(pair.as_str().to_string()), + Rule::static_path => Expression::Path(StaticPath::from(pair)), Rule::integer => { let value = pair.as_str().parse::().unwrap(); Expression::IntLiteral(value) @@ -348,3 +366,48 @@ impl From> for Postfix { } } } + +impl From> for VarDeclStmt { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + match pair.as_rule() { + Rule::var_decl_statement => { + let mut inner = pair.into_inner(); + + let decl = VarDecl::from(inner.next().unwrap()); + + let init = inner.next().map(Expression::from); + + VarDeclStmt { decl, init } + } + + _ => unimplemented!(), + } + } +} + +impl From> for VarDecl { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + match pair.as_rule() { + Rule::var_decl => { + let mut inner = pair.into_inner(); + + let type_ = Some(inner.next().map(TypeExpr::from).unwrap()); + let mutable = if inner.peek().unwrap().as_rule() == Rule::mutable { + inner.next(); + true + } else { + false + }; + let name = inner.next().unwrap().as_str().to_string(); + + VarDecl { + mutable, + name, + type_, + } + } + + _ => unimplemented!("{:?}", pair.as_rule()), + } + } +} diff --git a/src/codegen.rs b/src/codegen.rs index 7c8330f..0830a5f 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,8 +1,28 @@ use parser::ast::{ - BinaryOp, Block, Expression, IfStmt, Postfix, Statement, TopLevel, TypeExpr, VarAssignStmt, - VarDeclStmt, WhileStmt, + BinaryOp, Block, Expression, IfStmt, Postfix, Statement, StaticPath, TopLevel, TypeExpr, + TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, WhileStmt, }; +// --------------------------------------------------------------------------- +// Traits +// --------------------------------------------------------------------------- + +/// Implemented by nodes that *write* into the codegen output buffer. +/// Requires `&mut RustCodegen` because it calls `add` / `addln` / indentation helpers. +pub trait ToRust { + fn to_rust(&self, cg: &mut RustCodegen); +} + +/// Implemented by nodes that *produce* a `String` without mutating the codegen. +/// Only needs `&RustCodegen` (e.g. for indent level or helper access). +pub trait GetRust { + fn get_rust(&self) -> String; +} + +// --------------------------------------------------------------------------- +// Codegen struct +// --------------------------------------------------------------------------- + pub struct RustCodegen { output: String, indent: usize, @@ -30,21 +50,154 @@ impl RustCodegen { } fn add_indentedln(&mut self, s: &str) { - self.add(&format!("{}{}\n", self.indent_str(), s)); + let line = format!("{}{}\n", self.indent_str(), s); + self.add(&line); } pub fn generate(&mut self, toplevels: &[TopLevel]) -> String { for tl in toplevels { - self.generate_toplevel(tl); + tl.to_rust(self); } self.output.clone() } +} - fn generate_toplevel(&mut self, tl: &TopLevel) { - match tl { +impl Default for RustCodegen { + fn default() -> Self { + Self::new() + } +} + +// --------------------------------------------------------------------------- +// GetRust — pure string production (expressions, types) +// --------------------------------------------------------------------------- + +impl GetRust for TypeExpr { + fn get_rust(&self) -> String { + get_type_postfixes(&self.1) + &self.0.get_rust() + } +} + +impl GetRust for TypeExprKind { + fn get_rust(&self) -> String { + match self { + TypeExprKind::Path(path) => get_static_type_path(path), + TypeExprKind::PathParams(path, params) => { + format!( + "{}<{}>", + get_static_type_path(path), + params + .iter() + .map(|t| t.get_rust()) + .collect::>() + .join(", ") + ) + } + TypeExprKind::Tuple(types) => format!( + "({})", + types + .iter() + .map(|t| t.get_rust()) + .collect::>() + .join(", ") + ), + } + } +} + +impl GetRust for Expression { + fn get_rust(&self) -> String { + match self { + Expression::Path(path) => path.get_rust(), + Expression::IntLiteral(n) => n.to_string(), + Expression::FloatLiteral(n) => n.to_string(), + Expression::BoolLiteral(b) => b.to_string(), + Expression::StringLiteral(s) => format!("\"{}\".to_string()", s), + + Expression::Postfix { initial, postfixes } => { + let base = initial.get_rust(); + postfixes.get_rust_with_base(&base) + } + } + } +} + +/// Helper — applies a slice of postfixes onto an already-rendered base string. +trait PostfixChain { + fn get_rust_with_base(&self, base: &str) -> String; +} + +impl PostfixChain for [Postfix] { + fn get_rust_with_base(&self, base: &str) -> String { + let mut result = base.to_string(); + + for postfix in self { + result = match postfix { + Postfix::FieldAccess(field) => format!("{}.{}", result, field), + + Postfix::Call(args) => { + let args = args + .iter() + .map(|a| a.get_rust()) + .collect::>() + .join(", "); + format!("{}({})", result, args) + } + + Postfix::StructCall(fields) => { + let fields = fields + .iter() + .map(|(k, v)| format!("{}: {}", k, v.get_rust())) + .collect::>() + .join(", "); + format!("{} {{ {} }}", result, fields) + } + + Postfix::Index(idx) => { + format!("{}[{}]", result, idx.get_rust()) + } + + Postfix::Binary(op, rhs) => { + let op_str = match op { + BinaryOp::Plus => "+", + BinaryOp::Minus => "-", + BinaryOp::Multiply => "*", + BinaryOp::Divide => "/", + BinaryOp::Modulo => "%", + BinaryOp::Equal => "==", + BinaryOp::NotEqual => "!=", + BinaryOp::LessThan => "<", + BinaryOp::GreaterThan => ">", + BinaryOp::LessThanOrEqual => "<=", + BinaryOp::GreaterThanOrEqual => ">=", + }; + format!("{} {} {}", result, op_str, rhs.get_rust()) + } + }; + } + + result + } +} + +// --------------------------------------------------------------------------- +// ToRust — output-writing (top-level, statements, blocks) +// --------------------------------------------------------------------------- + +impl ToRust for Block { + fn to_rust(&self, cg: &mut RustCodegen) { + for stmt in &self.0 { + stmt.to_rust(cg); + } + } +} + +impl ToRust for TopLevel { + fn to_rust(&self, cg: &mut RustCodegen) { + match self { TopLevel::Import(path) => { - let path = path.replace("\"", ""); - self.addln(&format!("use {};", path)); + let path = path.replace('"', ""); + cg.addln(&format!("use {};", path)); } TopLevel::StructDecl { @@ -53,17 +206,16 @@ impl RustCodegen { fields, } => { let vis = if *export { "pub " } else { "" }; - - self.addln(&format!("{}struct {} {{", vis, name)); - self.indent += 1; + cg.addln(&format!("{}struct {} {{", vis, name)); + cg.indent += 1; for (field_name, (_, ty)) in &fields.0 { - let ty = self.translate_type(ty); - self.add_indentedln(&format!("pub {}: {},", field_name, ty)); + let ty = ty.get_rust(); + cg.add_indentedln(&format!("pub {}: {},", field_name, ty)); } - self.indent -= 1; - self.addln("}\n"); + cg.indent -= 1; + cg.addln("}\n"); } TopLevel::FunctionDecl { @@ -78,86 +230,52 @@ impl RustCodegen { let params_str = params .0 .iter() - .map(|(n, (_, t))| format!("{}: {}", n, self.translate_type(t))) + .map(VarDecl::get_rust) .collect::>() .join(", "); - let ret = return_type - .as_ref() - .map(|t| format!(" -> {}", self.translate_type(t))) - .unwrap_or_default(); - - self.addln(&format!("{}fn {}({}){} {{", vis, name, params_str, ret)); - - self.indent += 1; - self.generate_block(body); - self.indent -= 1; - - self.addln("}\n"); + cg.addln(&format!( + "{}fn {}({}) -> {} {{", + vis, + name, + params_str, + return_type.get_rust() + )); + cg.indent += 1; + body.to_rust(cg); + cg.indent -= 1; + cg.addln("}\n"); } } } +} - fn translate_type(&self, ty: &TypeExpr) -> String { - match ty { - TypeExpr::Identifier(name) => match name.as_str() { - "int" => "i32".into(), - "float" | "float64" => "f64".into(), - "float32" => "f32".into(), - "bool" => "bool".into(), - "string" => "String".into(), - _ => name.clone(), - }, - } - } - - fn generate_block(&mut self, block: &Block) { - for stmt in &block.0 { - self.generate_statement(stmt); - } - } - - fn generate_statement(&mut self, stmt: &Statement) { - match stmt { +impl ToRust for Statement { + fn to_rust(&self, cg: &mut RustCodegen) { + match self { Statement::Expression(expr) => { - self.add_indentedln(&format!("{};", self.generate_expression(expr))); + cg.add_indentedln(&format!("{};", expr.get_rust())); } Statement::Block(block) => { - self.add_indentedln("{"); - self.indent += 1; - self.generate_block(block); - self.indent -= 1; - self.add_indentedln("}"); + cg.add_indentedln("{"); + cg.indent += 1; + block.to_rust(cg); + cg.indent -= 1; + cg.add_indentedln("}"); } - Statement::VarDecl(VarDeclStmt { - mutable, - name, - init, - type_, - }) => { - let mutability = if *mutable { "mut " } else { "" }; - - let ty = type_ - .as_ref() - .map(|t| format!(": {}", self.translate_type(t))) - .unwrap_or_default(); - + Statement::VarDecl(VarDeclStmt { decl, init }) => { let init = init .as_ref() - .map(|e| format!(" = {}", self.generate_expression(e))) + .map(|e| format!(" = {}", e.get_rust())) .unwrap_or_default(); - self.add_indentedln(&format!("let {}{}{}{};", mutability, name, ty, init)); + cg.add_indentedln(&format!("let {}{};", decl.get_rust(), init)); } Statement::VarAssign(VarAssignStmt { target, value }) => { - self.add_indentedln(&format!( - "{} = {};", - self.generate_expression(target), - self.generate_expression(value) - )); + cg.add_indentedln(&format!("{} = {};", target.get_rust(), value.get_rust(),)); } Statement::If(IfStmt { @@ -165,122 +283,83 @@ impl RustCodegen { then_branch, else_branch, }) => { - self.add_indentedln(&format!("if {} {{", self.generate_expression(condition))); - - self.indent += 1; - self.generate_statement(then_branch); - self.indent -= 1; - - self.add_indentedln("}"); + cg.add_indentedln(&format!("if {} {{", condition.get_rust())); + cg.indent += 1; + then_branch.to_rust(cg); + cg.indent -= 1; + cg.add_indentedln("}"); if let Some(else_br) = else_branch { - self.add_indentedln("else {"); - self.indent += 1; - self.generate_statement(else_br); - self.indent -= 1; - self.add_indentedln("}"); + cg.add_indentedln("else {"); + cg.indent += 1; + else_br.to_rust(cg); + cg.indent -= 1; + cg.add_indentedln("}"); } } Statement::While(WhileStmt { condition, body }) => { - self.add_indentedln(&format!("while {} {{", self.generate_expression(condition))); - - self.indent += 1; - self.generate_statement(body); - self.indent -= 1; - - self.add_indentedln("}"); + cg.add_indentedln(&format!("while {} {{", condition.get_rust())); + cg.indent += 1; + body.to_rust(cg); + cg.indent -= 1; + cg.add_indentedln("}"); } Statement::For { .. } => { - // Rust doesn't support C-style for loops - self.add_indentedln("// TODO: transform into iterator-based loop"); + cg.add_indentedln("// TODO: transform into iterator-based loop"); } Statement::Return(expr) => { - let val = expr - .as_ref() - .map(|e| self.generate_expression(e)) - .unwrap_or_default(); - - self.add_indentedln(&format!("return {};", val)); + let val = expr.as_ref().map(|e| e.get_rust()).unwrap_or_default(); + cg.add_indentedln(&format!("return {};", val)); } - Statement::Break => self.add_indentedln("break;"), - Statement::Continue => self.add_indentedln("continue;"), + Statement::Break => cg.add_indentedln("break;"), + Statement::Continue => cg.add_indentedln("continue;"), } } - - fn generate_expression(&self, expr: &Expression) -> String { - match expr { - Expression::Identifier(name) => name.clone(), - Expression::IntLiteral(n) => n.to_string(), - Expression::FloatLiteral(n) => n.to_string(), - Expression::BoolLiteral(b) => b.to_string(), - Expression::StringLiteral(s) => format!("\"{}\".to_string()", s), - - Expression::Postfix { initial, postfixes } => { - let base = self.generate_expression(initial); - self.apply_postfixes(&base, postfixes) - } - } - } - - fn apply_postfixes(&self, base: &str, postfixes: &[Postfix]) -> String { - let mut result = base.to_string(); - - for postfix in postfixes { - result = match postfix { - Postfix::FieldAccess(field) => format!("{}.{}", result, field), - - Postfix::Call(args) => { - let args = args - .iter() - .map(|a| self.generate_expression(a)) - .collect::>() - .join(", "); - format!("{}({})", result, args) - } - - Postfix::StructCall(fields) => { - let fields = fields - .iter() - .map(|(k, v)| format!("{}: {}", k, self.generate_expression(v))) - .collect::>() - .join(", "); - format!("{} {{ {} }}", result, fields) - } - - Postfix::Index(idx) => { - format!("{}[{}]", result, self.generate_expression(idx)) - } - - Postfix::Binary(op, rhs) => { - let op = match op { - BinaryOp::Plus => "+", - BinaryOp::Minus => "-", - BinaryOp::Multiply => "*", - BinaryOp::Divide => "/", - BinaryOp::Modulo => "%", - BinaryOp::Equal => "==", - BinaryOp::NotEqual => "!=", - BinaryOp::LessThan => "<", - BinaryOp::GreaterThan => ">", - BinaryOp::LessThanOrEqual => "<=", - BinaryOp::GreaterThanOrEqual => ">=", - }; - - format!("{} {} {}", result, op, self.generate_expression(rhs)) - } - }; - } - - result - } } -impl Default for RustCodegen { - fn default() -> Self { - Self::new() +impl GetRust for VarDecl { + fn get_rust(&self) -> String { + let mutability = if self.mutable { "mut " } else { "" }; + + let ty = self + .type_ + .as_ref() + .map(|t| format!(": {}", t.get_rust())) + .unwrap_or_default(); + + format!("{}{}{}", mutability, self.name, ty) } } + +impl GetRust for StaticPath { + fn get_rust(&self) -> String { + self.0.join("::") + } +} + +impl GetRust for TypePostfix { + fn get_rust(&self) -> String { + match self { + TypePostfix::Ref => format!("&"), + TypePostfix::RefMut => format!("&mut "), + } + } +} + +pub fn get_static_type_path(path: &StaticPath) -> String { + let rust_path = path.get_rust(); + + if rust_path == "void" { + format!("()") + } else { + rust_path + } +} + +pub fn get_type_postfixes(postfixes: &[TypePostfix]) -> String { + postfixes.iter().map(TypePostfix::get_rust).collect() +} diff --git a/test/src/main.mist b/test/src/main.mist index a4ec76f..9f2489e 100644 --- a/test/src/main.mist +++ b/test/src/main.mist @@ -1,3 +1 @@ -int test() { - int mut a = 10; -} +i32 add(i32* a, i32* b) {} \ No newline at end of file