From 68cf239f92ba86b0a82054b9e7e87e2afc016df1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 2 Jul 2026 06:25:44 +0200 Subject: [PATCH 1/6] Top level as statement #103 --- crates/codegen/src/fmt/statement.rs | 1 + crates/codegen/src/statement.rs | 5 +++-- crates/parser/src/ast/expr.rs | 12 ++++++++++++ crates/parser/src/ast/statement.rs | 1 + crates/parser/src/grammar.pest | 2 ++ crates/parser/src/semantics.rs | 1 + mist-test/src/main.mist | 1 + 7 files changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/codegen/src/fmt/statement.rs b/crates/codegen/src/fmt/statement.rs index e38a87e..087c2d6 100644 --- a/crates/codegen/src/fmt/statement.rs +++ b/crates/codegen/src/fmt/statement.rs @@ -33,6 +33,7 @@ impl GenMist for Statement { cg.add("unsafe "); block.gen_mist(ctx, cg); } + Statement::TopLevel(tl) => tl.gen_mist(ctx, cg), Statement::Block(block) => block.gen_mist(ctx, cg), Statement::VarDecl(VarDeclStmt { decl, init }) => { if decl.type_.is_some() { diff --git a/crates/codegen/src/statement.rs b/crates/codegen/src/statement.rs index 9a94947..98dfaf7 100644 --- a/crates/codegen/src/statement.rs +++ b/crates/codegen/src/statement.rs @@ -31,13 +31,14 @@ impl GenRust for Block { impl GenRust for Statement { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { match self { + Statement::TopLevel(tl) => tl.gen_rust(ctx, cg), + Statement::Block(block) => block.gen_rust(ctx, cg), + Statement::UnsafeBlock(block) => { cg.add("unsafe "); block.gen_rust(ctx, cg); } - Statement::Block(block) => block.gen_rust(ctx, cg), - Statement::VarDecl(VarDeclStmt { decl, init }) => { cg.add("let "); decl.gen_rust(ctx, cg); diff --git a/crates/parser/src/ast/expr.rs b/crates/parser/src/ast/expr.rs index d1f5f20..10e7129 100644 --- a/crates/parser/src/ast/expr.rs +++ b/crates/parser/src/ast/expr.rs @@ -119,3 +119,15 @@ impl From for ExprPath { ) } } + +impl Expression { + pub fn is_semicolon_required(&self) -> bool { + match self { + Self::Statement(v) => match &**v { + Statement::TopLevel(_) => false, + _ => true, + }, + _ => true, + } + } +} diff --git a/crates/parser/src/ast/statement.rs b/crates/parser/src/ast/statement.rs index f152c44..04ff4aa 100644 --- a/crates/parser/src/ast/statement.rs +++ b/crates/parser/src/ast/statement.rs @@ -12,6 +12,7 @@ pub struct Block { pub enum Statement { UnsafeBlock(Block), Block(Block), + TopLevel(Box), If { initial: StatementBranch, else_if: Vec, diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index 8172ceb..e6e0eef 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -24,6 +24,7 @@ keyword = { | "class" | "trait" | "impl" + | "use" | "pub" | "mut" | "let" @@ -389,6 +390,7 @@ statement_list = { statement = _{ control_flow | (expr ~ semicolon) + | top_level } // ------------------------------------------------------ diff --git a/crates/parser/src/semantics.rs b/crates/parser/src/semantics.rs index 6ecda9e..a7d557d 100644 --- a/crates/parser/src/semantics.rs +++ b/crates/parser/src/semantics.rs @@ -129,6 +129,7 @@ impl GetMutability for Block { impl GetMutability for Statement { fn get_mutability(&self) -> Vec { match self { + Statement::TopLevel(_) => Vec::new(), Statement::Block(body) | Statement::UnsafeBlock(body) => body.get_mutability(), Statement::If { initial, diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index e5fd2e4..df47271 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -1,5 +1,6 @@ void main() { + use std::fmt; println!("running common tests..."); common::test_package(); common::expr_test::run_tests(); From 4579c656b96746b4838559029c108e0bb6e626af Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 2 Jul 2026 06:33:17 +0200 Subject: [PATCH 2/6] Possibly removed the need for ensure_semicolon --- crates/codegen/src/class_decl.rs | 2 -- crates/codegen/src/expr.rs | 16 ---------------- crates/codegen/src/fmt/expr.rs | 14 -------------- crates/codegen/src/lib.rs | 2 -- crates/codegen/src/statement.rs | 20 +++++++++++--------- crates/parser/src/ast/expr.rs | 20 +++++++++----------- 6 files changed, 20 insertions(+), 54 deletions(-) diff --git a/crates/codegen/src/class_decl.rs b/crates/codegen/src/class_decl.rs index ce0fd09..b53e7e9 100644 --- a/crates/codegen/src/class_decl.rs +++ b/crates/codegen/src/class_decl.rs @@ -362,7 +362,6 @@ impl ClassProcessedData { if *i > 0 { cg.add(", "); } - ctx.expr_ensure_semicolon = false; param.name.gen_rust(ctx, cg); } cg.addln(");"); @@ -599,7 +598,6 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC for (_, param) in ¶ms { cg.add(", "); - ctx.expr_ensure_semicolon = false; param.name.gen_rust(ctx, cg); } diff --git a/crates/codegen/src/expr.rs b/crates/codegen/src/expr.rs index 2a41a91..38f4e3b 100644 --- a/crates/codegen/src/expr.rs +++ b/crates/codegen/src/expr.rs @@ -68,14 +68,6 @@ impl GenRust for Literal { impl GenRust for Expression { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { - let ensure_semicolon = if ctx.expr_ensure_semicolon { - ctx.expr_ensure_semicolon = false; - - true - } else { - false - }; - match self { Expression::Path(path) => cg.add(&path.get_rust_ctx(ctx)), Expression::Literal(literal) => literal.gen_rust(ctx, cg), @@ -152,14 +144,6 @@ impl GenRust for Expression { } } } - - if ensure_semicolon { - ctx.expr_ensure_semicolon = true; - - if !self.is_block() { - cg.add(";"); - } - } } } diff --git a/crates/codegen/src/fmt/expr.rs b/crates/codegen/src/fmt/expr.rs index f787346..a73605b 100644 --- a/crates/codegen/src/fmt/expr.rs +++ b/crates/codegen/src/fmt/expr.rs @@ -4,13 +4,6 @@ use crate::fmt::{Context, GenMist, GetMist, MistCodegen}; impl GenMist for Expression { fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - let ensure_semicolon = if ctx.expr_ensure_semicolon { - ctx.expr_ensure_semicolon = false; - true - } else { - false - }; - match self { Expression::Path(path) => cg.add(&path.get_mist()), Expression::Literal(literal) => literal.gen_mist(ctx, cg), @@ -75,13 +68,6 @@ impl GenMist for Expression { } } } - - if ensure_semicolon { - ctx.expr_ensure_semicolon = true; - if !self.is_block() { - cg.add(";"); - } - } } } diff --git a/crates/codegen/src/lib.rs b/crates/codegen/src/lib.rs index 3e0610a..6642487 100644 --- a/crates/codegen/src/lib.rs +++ b/crates/codegen/src/lib.rs @@ -12,7 +12,6 @@ use mist_parser::{ }; pub struct Context { - pub expr_ensure_semicolon: bool, pub expr_super: Option, } @@ -81,7 +80,6 @@ impl RustCodegen { pub fn generate(&mut self, toplevels: Vec) -> String { let mut ctx = Context { - expr_ensure_semicolon: true, expr_super: None, }; diff --git a/crates/codegen/src/statement.rs b/crates/codegen/src/statement.rs index 98dfaf7..e428011 100644 --- a/crates/codegen/src/statement.rs +++ b/crates/codegen/src/statement.rs @@ -10,14 +10,15 @@ impl GenRust for Block { cg.indent += 1; for stmt in &self.statements { - ctx.expr_ensure_semicolon = true; cg.add_indented(""); stmt.gen_rust(ctx, cg); + if stmt.item.is_semicolon_required() { + cg.add(";"); + } cg.addln(""); } if let Some(soft_return) = &self.soft_return { - ctx.expr_ensure_semicolon = false; cg.add_indented(""); soft_return.gen_rust(ctx, cg); cg.addln(""); @@ -86,14 +87,12 @@ impl GenRust for Statement { else_branch, } => { cg.add("if "); - ctx.expr_ensure_semicolon = false; initial.condition.gen_rust(ctx, cg); cg.add(" "); initial.body.gen_rust(ctx, cg); for else_if_branch in else_if { cg.add(" else if "); - ctx.expr_ensure_semicolon = false; else_if_branch.condition.gen_rust(ctx, cg); cg.add(" "); else_if_branch.body.gen_rust(ctx, cg); @@ -126,17 +125,18 @@ impl GenRust for Statement { cg.addln("{"); cg.indent += 1; - ctx.expr_ensure_semicolon = true; - cg.add_indented(""); init.gen_rust(ctx, cg); + if init.is_semicolon_required() { + cg.add(";"); + } + cg.addln(""); cg.add_indented("while "); - ctx.expr_ensure_semicolon = false; condition.gen_rust(ctx, cg); cg.add(" "); @@ -144,12 +144,14 @@ impl GenRust for Statement { cg.add("{"); cg.indent += 1; - ctx.expr_ensure_semicolon = true; - body.gen_rust(ctx, cg); update.gen_rust(ctx, cg); + if update.is_semicolon_required() { + cg.add(";"); + } + cg.addln(""); cg.indent -= 1; diff --git a/crates/parser/src/ast/expr.rs b/crates/parser/src/ast/expr.rs index 10e7129..ad814c3 100644 --- a/crates/parser/src/ast/expr.rs +++ b/crates/parser/src/ast/expr.rs @@ -96,16 +96,6 @@ pub enum Generic { Type(TypeExpr), } -impl Expression { - pub fn is_block(&self) -> bool { - if let Expression::Statement(stmt) = self { - stmt.is_block() - } else { - false - } - } -} - impl From for ExprPath { fn from(path: Path) -> Self { Self( @@ -125,9 +115,17 @@ impl Expression { match self { Self::Statement(v) => match &**v { Statement::TopLevel(_) => false, - _ => true, + stmt => !stmt.is_block(), }, _ => true, } } + + pub fn is_block(&self) -> bool { + if let Expression::Statement(stmt) = self { + stmt.is_block() + } else { + false + } + } } From 493c6684953e2eed8882c70acecf345fab8f429b Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 2 Jul 2026 06:40:20 +0200 Subject: [PATCH 3/6] Working top level statement #103 --- crates/parser/src/grammar.pest | 2 +- crates/parser/src/parser/common/expr.rs | 3 ++- crates/parser/src/parser/common/statement.rs | 2 ++ mist-test/src/main.mist | 1 - 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index e6e0eef..f2dbf9f 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -389,8 +389,8 @@ statement_list = { statement = _{ control_flow - | (expr ~ semicolon) | top_level + | (expr ~ semicolon) } // ------------------------------------------------------ diff --git a/crates/parser/src/parser/common/expr.rs b/crates/parser/src/parser/common/expr.rs index a973103..a9db8df 100644 --- a/crates/parser/src/parser/common/expr.rs +++ b/crates/parser/src/parser/common/expr.rs @@ -94,7 +94,8 @@ impl<'a> TryFrom> for Expression { | Rule::basic_stmt | Rule::control_flow | Rule::block - | Rule::unsafe_block => Ok(Expression::Statement(Box::new(pair.try_into()?))), + | Rule::unsafe_block + | Rule::top_level => Ok(Expression::Statement(Box::new(pair.try_into()?))), _ => AstError::bug_unimplemented(pair), } diff --git a/crates/parser/src/parser/common/statement.rs b/crates/parser/src/parser/common/statement.rs index e4ed5ff..a433775 100644 --- a/crates/parser/src/parser/common/statement.rs +++ b/crates/parser/src/parser/common/statement.rs @@ -51,6 +51,8 @@ impl<'a> TryFrom> for Statement { Rule::block => Ok(Statement::Block(pair.try_into()?)), + Rule::top_level => Ok(Statement::TopLevel(Box::new(pair.try_into()?))), + Rule::var_decl_statement => Ok(Statement::VarDecl(pair.try_into()?)), Rule::return_stmt => Ok(Statement::Return( diff --git a/mist-test/src/main.mist b/mist-test/src/main.mist index df47271..e5fd2e4 100644 --- a/mist-test/src/main.mist +++ b/mist-test/src/main.mist @@ -1,6 +1,5 @@ void main() { - use std::fmt; println!("running common tests..."); common::test_package(); common::expr_test::run_tests(); From 5346cd05bef64aa5fdab978bc291eff6f885437b Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 2 Jul 2026 06:51:04 +0200 Subject: [PATCH 4/6] constants and static #102 --- crates/codegen/src/fmt/top_level.rs | 20 ++++++++++++++++++++ crates/codegen/src/top_level.rs | 22 ++++++++++++++++++++++ crates/parser/src/ast/top_level.rs | 2 ++ crates/parser/src/grammar.pest | 9 ++++++++- crates/parser/src/parser/items/mod.rs | 3 +++ 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/crates/codegen/src/fmt/top_level.rs b/crates/codegen/src/fmt/top_level.rs index 13439ab..6d65979 100644 --- a/crates/codegen/src/fmt/top_level.rs +++ b/crates/codegen/src/fmt/top_level.rs @@ -167,6 +167,26 @@ impl GenMist for TopLevelKind { fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { match self { Self::ModAttribute => {} + Self::StaticDecl(decl) => { + cg.add("static "); + decl.decl.gen_mist(ctx, cg); + + if let Some(init) = &decl.init { + cg.add(" = "); + init.gen_mist(ctx, cg); + } + cg.add(";"); + } + Self::ConstDecl(decl) => { + cg.add("const "); + decl.decl.gen_mist(ctx, cg); + + if let Some(init) = &decl.init { + cg.add(" = "); + init.gen_mist(ctx, cg); + } + cg.add(";"); + } Self::Import(vis, path) => { cg.addln(&format!("{}use {};", vis.get_mist(), path.get_mist())) } diff --git a/crates/codegen/src/top_level.rs b/crates/codegen/src/top_level.rs index 2d627a8..58433e7 100644 --- a/crates/codegen/src/top_level.rs +++ b/crates/codegen/src/top_level.rs @@ -191,6 +191,28 @@ impl GenRust for TopLevelKind { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { match self { Self::ModAttribute => {} + Self::ConstDecl(decl) => { + cg.add("const "); + decl.decl.gen_rust(ctx, cg); + + if let Some(init) = &decl.init { + cg.add(" = "); + init.gen_rust(ctx, cg); + } + + cg.add(";"); + } + Self::StaticDecl(decl) => { + cg.add("static "); + decl.decl.gen_rust(ctx, cg); + + if let Some(init) = &decl.init { + cg.add(" = "); + init.gen_rust(ctx, cg); + } + + cg.add(";"); + } Self::Import(vis, path) => { cg.addln(&format!("{}use {};", vis.get_rust(), path.get_rust())) } diff --git a/crates/parser/src/ast/top_level.rs b/crates/parser/src/ast/top_level.rs index d7d58ad..e6c4394 100644 --- a/crates/parser/src/ast/top_level.rs +++ b/crates/parser/src/ast/top_level.rs @@ -30,6 +30,8 @@ pub enum TopLevelKind { Import(Visibility, Path), DeclareModule(Visibility, Identifier), ImplDecl(ImplDecl), + StaticDecl(VarDeclStmt), + ConstDecl(VarDeclStmt), TraitDecl { visibility: Visibility, name: Identifier, diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index f2dbf9f..d77efac 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -34,6 +34,7 @@ keyword = { | "loop" | "unsafe" | "override" + | "const" } identifier = @{ @@ -362,13 +363,19 @@ function_decl = { visibility? ~ ("void" | type_expr) ~ identifier ~ generics_decl? ~ "(" ~ method_args ~ ")" ~ override_kw? ~ (block | semicolon) } +// ====================================================== +// CONSTANTS / STATIC +// ====================================================== +const_decl = { "const" ~ var_decl_statement ~ ";" } +static_decl = { "static" ~ var_decl_statement ~ ";" } + // ====================================================== // TOP LEVEL // ====================================================== top_level = { mod_attribute - | (attributes ~ (import | impl_for_decl | impl_decl | trait_decl | struct_decl | enum_decl | class_decl | declare_module | function_decl)) + | (attributes ~ (import | impl_for_decl | impl_decl | trait_decl | struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl)) } // ====================================================== diff --git a/crates/parser/src/parser/items/mod.rs b/crates/parser/src/parser/items/mod.rs index 7d451ca..b6bd1cb 100644 --- a/crates/parser/src/parser/items/mod.rs +++ b/crates/parser/src/parser/items/mod.rs @@ -122,6 +122,9 @@ impl<'a> TryFrom> for TopLevelKind { items: collect_recovered(&mut inner)?, }), + Rule::const_decl => Ok(TopLevelKind::ConstDecl(inner.next().unwrap().try_into()?)), + Rule::static_decl => Ok(TopLevelKind::StaticDecl(inner.next().unwrap().try_into()?)), + _ => AstError::bug_unimplemented(pair), } } From d62d884add8bc4d138c48c7c2bbf06863e768a84 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 2 Jul 2026 06:53:47 +0200 Subject: [PATCH 5/6] Removed fmt (will add when i have close to 1:1 syntax support) --- crates/analyzer/src/transpiler.rs | 14 +- crates/codegen/src/fmt/expr.rs | 157 ---------- crates/codegen/src/fmt/mod.rs | 450 ---------------------------- crates/codegen/src/fmt/statement.rs | 158 ---------- crates/codegen/src/fmt/top_level.rs | 356 ---------------------- crates/codegen/src/lib.rs | 1 - 6 files changed, 7 insertions(+), 1129 deletions(-) delete mode 100644 crates/codegen/src/fmt/expr.rs delete mode 100644 crates/codegen/src/fmt/mod.rs delete mode 100644 crates/codegen/src/fmt/statement.rs delete mode 100644 crates/codegen/src/fmt/top_level.rs diff --git a/crates/analyzer/src/transpiler.rs b/crates/analyzer/src/transpiler.rs index 7379da6..1f43af0 100644 --- a/crates/analyzer/src/transpiler.rs +++ b/crates/analyzer/src/transpiler.rs @@ -1,7 +1,6 @@ use std::path::{Path, PathBuf}; use mist_codegen::RustCodegen; -use mist_codegen::fmt::MistCodegen; use mist_parser::rev_mapper::Mapping; use mist_parser::{MistFmtConfig, parse}; @@ -85,12 +84,13 @@ pub fn transpile_mist_no_sem( }) } -pub fn format_mist(source: &str, config: MistFmtConfig) -> Result { - let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?; +pub fn format_mist(source: &str, _config: MistFmtConfig) -> Result { + // let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?; - let mut codegen = MistCodegen::new(config); - codegen.generate(parsed.mod_attributes); - let output = codegen.generate(parsed.items); + // let mut codegen = MistCodegen::new(config); + // codegen.generate(parsed.mod_attributes); + // let output = codegen.generate(parsed.items); - Ok(output) + // Ok(output) + Ok(source.to_string()) } diff --git a/crates/codegen/src/fmt/expr.rs b/crates/codegen/src/fmt/expr.rs deleted file mode 100644 index a73605b..0000000 --- a/crates/codegen/src/fmt/expr.rs +++ /dev/null @@ -1,157 +0,0 @@ -use mist_parser::ast::*; - -use crate::fmt::{Context, GenMist, GetMist, MistCodegen}; - -impl GenMist for Expression { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Expression::Path(path) => cg.add(&path.get_mist()), - Expression::Literal(literal) => literal.gen_mist(ctx, cg), - Expression::Statement(stmt) => stmt.gen_mist(ctx, cg), - Expression::Array(values) => { - cg.add("["); - for (i, val) in values.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - val.gen_mist(ctx, cg); - } - cg.add("]"); - } - Expression::ArrayRepeat(value, repeat) => { - cg.add("["); - value.gen_mist(ctx, cg); - cg.add("; "); - repeat.gen_mist(ctx, cg); - cg.add("]"); - } - Expression::Fix { - initial, - prefixes, - postfixes, - } => { - for prefix in prefixes { - prefix.gen_mist(ctx, cg); - } - initial.gen_mist(ctx, cg); - for postfix in postfixes { - postfix.gen_mist(ctx, cg); - } - } - Expression::Binary { lhs, op, rhs } => { - lhs.gen_mist(ctx, cg); - cg.add(" "); - cg.add(op); - cg.add(" "); - rhs.gen_mist(ctx, cg); - } - Expression::Closure { - return_type, - params, - body, - } => { - cg.add("("); - for (i, arg) in params.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - arg.gen_mist(ctx, cg); - } - cg.add(") => "); - - if let Some(ty) = return_type { - cg.add(&ty.get_mist()); - cg.add(" "); - cg.ensure_brackets_expr(ctx, body); - } else { - body.gen_mist(ctx, cg); - } - } - } - } -} - -impl GenMist for Prefix { - fn gen_mist(&self, _ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Self::Deref => cg.add("*"), - Self::Ref => cg.add("&"), - Self::RefMut => cg.add("&mut "), - Self::Not => cg.add("!"), - Self::Neg => cg.add("-"), - } - } -} - -impl GenMist for Postfix { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Postfix::TupleFieldAccess(field, generics) => { - cg.add(&format!( - ".{}{}", - field, - generics - .iter() - .map(|v| format!("{}", v.get_mist())) - .collect::() - )); - } - Postfix::FieldAccess(field, generics) => { - cg.add(&format!( - ".{}{}", - field.get_mist(), - generics - .iter() - .map(|v| format!("{}", v.get_mist())) - .collect::() - )); - } - Postfix::Call(args) => { - cg.add("("); - for (i, arg) in args.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - arg.gen_mist(ctx, cg); - } - cg.add(")"); - } - Postfix::MacroCall { inner, delimiter } => { - let (open, close) = match delimiter { - MacroDelimiter::Paren => ("!(", ")"), - MacroDelimiter::Bracket => ("![", "]"), - MacroDelimiter::Brace => ("!{", "}"), - }; - cg.add(open); - cg.add(inner); - cg.add(close); - } - Postfix::StructCall(fields) => { - cg.addln(" {"); - cg.indent += 1; - for (name, expr) in fields { - cg.add_indented(&name.get_mist()); - if let Some(expr) = expr { - cg.add(": "); - expr.gen_mist(ctx, cg); - } - cg.addln(","); - } - cg.indent -= 1; - cg.add_indented("}"); - } - Postfix::Index(idx) => { - cg.add("["); - idx.gen_mist(ctx, cg); - cg.add("]"); - } - Postfix::As(ty) => { - cg.add(" as "); - cg.add(&ty.get_mist()); - } - Postfix::Try => cg.add("?"), - Postfix::Increment => cg.add("++"), - Postfix::Decrement => cg.add("--"), - } - } -} diff --git a/crates/codegen/src/fmt/mod.rs b/crates/codegen/src/fmt/mod.rs deleted file mode 100644 index 278827b..0000000 --- a/crates/codegen/src/fmt/mod.rs +++ /dev/null @@ -1,450 +0,0 @@ -pub mod expr; -pub mod statement; -pub mod top_level; - -use mist_parser::{MistFmtConfig, ast::*}; - -pub struct Context { - pub expr_ensure_semicolon: bool, -} - -pub struct MistCodegen { - config: MistFmtConfig, - indent_amount: u8, - output: String, - indent: usize, -} - -impl MistCodegen { - pub fn new(config: MistFmtConfig) -> Self { - Self { - config, - output: String::new(), - indent: 0, - indent_amount: 4, - } - } - - fn indent_str(&self) -> String { - " ".repeat(self.indent_amount as usize).repeat(self.indent) - } - - pub fn add(&mut self, s: &str) { - self.output.push_str(s); - } - - pub fn addln(&mut self, s: &str) { - self.add(s); - self.add("\n"); - } - - pub fn add_indented(&mut self, s: &str) { - let line = format!("{}{}", self.indent_str(), s); - self.add(&line); - } - - pub fn add_indentedln(&mut self, s: &str) { - let line = format!("{}{}\n", self.indent_str(), s); - self.add(&line); - } - - pub fn start_indent(&mut self) { - if self.config.allman_bracket_style { - self.addln(""); - self.add_indented(""); - } else { - self.add(" "); - } - } - - pub fn start_bracket(&mut self) { - if self.config.allman_bracket_style { - self.addln(""); - self.add_indentedln("{"); - } else { - self.addln(" {"); - } - - self.indent += 1; - } - - pub fn into_output(self) -> String { - self.output - } - - pub fn generate(&mut self, toplevels: Vec) -> String { - let mut ctx = Context { - expr_ensure_semicolon: true, - }; - - for (i, tl) in toplevels.iter().enumerate() { - if i > 0 { - self.add("\n"); - } - tl.gen_mist(&mut ctx, self); - } - - self.output.clone() - } - - pub fn ensure_brackets(&mut self, ctx: &mut Context, stmt: &Box) { - match &**stmt { - Statement::Block(_) => stmt.gen_mist(ctx, self), - _ => { - self.add("{"); - self.indent += 1; - stmt.gen_mist(ctx, self); - self.indent -= 1; - self.add_indented("}"); - } - } - } - - pub fn ensure_brackets_expr(&mut self, ctx: &mut Context, expr: &Expression) { - match expr { - Expression::Statement(stmt) => self.ensure_brackets(ctx, stmt), - _ => { - self.add("{"); - self.indent += 1; - expr.gen_mist(ctx, self); - self.indent -= 1; - self.add_indented("}"); - } - } - } -} - -pub trait GenMist { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen); -} - -pub trait GetMist { - fn get_mist(&self) -> String; -} - -impl GetMist for Path { - fn get_mist(&self) -> String { - self.0 - .iter() - .map(Identifier::get_mist) - .collect::>() - .join("::") - } -} - -impl GetMist for Identifier { - fn get_mist(&self) -> String { - self.0.clone() - } -} - -impl GetMist for Visibility { - fn get_mist(&self) -> String { - match self { - Visibility::Public => "pub ".to_string(), - Visibility::PublicTarget(path) => format!("pub({}) ", path.get_mist()), - Visibility::Private => "".to_string(), - } - } -} - -impl GetMist for TypeExpr { - fn get_mist(&self) -> String { - match self { - Self::Path(path, generics) => { - if let Some(generics) = generics { - format!("{}{}", path.get_mist(), generics.get_mist()) - } else { - path.get_mist() - } - } - Self::Lifetime(name) => format!("'{}", name.get_mist()), - Self::Tuple(types) => format!( - "({})", - types - .iter() - .map(|t| t.get_mist()) - .collect::>() - .join(", ") - ), - Self::StaticFn(types, return_type) => { - if let Some(return_type) = return_type { - format!( - "fn({}) -> {}", - types - .iter() - .map(|t| t.get_mist()) - .collect::>() - .join(", "), - return_type.get_mist() - ) - } else { - format!( - "fn({})", - types - .iter() - .map(|t| t.get_mist()) - .collect::>() - .join(", "), - ) - } - } - Self::UnsafePtr { mutable, ty } => { - let mutable = if *mutable { "mut " } else { "const " }; - format!("{} {mutable} unsafe&", ty.get_mist()) - } - Self::Ref { - lifetime, - mutable, - ty, - } => { - let base = ty.get_mist(); - if let Some(lifetime) = lifetime { - format!( - "{} {} '{}&", - base, - if *mutable { "mut" } else { "" }, - lifetime.get_mist() - ) - } else if *mutable { - format!("{} mut&", base) - } else { - format!("{}&", base) - } - } - Self::Dyn(ty) => { - format!("dyn {}", ty.get_mist()) - } - Self::Void => "void".to_string(), - Self::Fn { - kind, - return_type, - params, - } => { - format!( - "{} {}({})", - return_type.get_mist(), - kind.get_mist(), - params - .iter() - .map(TypeExpr::get_mist) - .collect::>() - .join(", ") - ) - } - } - } -} - -impl GetMist for FnKind { - fn get_mist(&self) -> String { - match self { - Self::Fn => "fn", - Self::UnsafeFn => "unsafe fn", - Self::FnClosure => "Fn", - Self::FnMut => "FnMut", - Self::FnOnce => "FnOnce", - } - .to_string() - } -} - -impl GetMist for ExprPath { - fn get_mist(&self) -> String { - self.0 - .iter() - .map(ExprPathSegment::get_mist) - .collect::>() - .join("::") - } -} - -impl GetMist for ExprPathSegment { - fn get_mist(&self) -> String { - format!( - "{}{}", - self.ident.get_mist(), - self.generics - .as_ref() - .map(|v| format!("{}", v.get_mist())) - .unwrap_or_default() - ) - } -} - -impl GetMist for Generics { - fn get_mist(&self) -> String { - if self.0.is_empty() { - String::new() - } else { - format!( - "<{}>", - self.0 - .iter() - .map(Generic::get_mist) - .collect::>() - .join(", ") - ) - } - } -} - -impl GetMist for Generic { - fn get_mist(&self) -> String { - match self { - Self::Lifetime(name) => format!("'{}", name.get_mist()), - Self::Type(ty) => ty.get_mist(), - } - } -} - -impl GetMist for GenericsDecl { - fn get_mist(&self) -> String { - if self.0.is_empty() { - String::new() - } else { - format!( - "<{}>", - self.0 - .iter() - .map(|v| v.get_mist()) - .collect::>() - .join(", ") - ) - } - } -} - -impl GetMist for GenericDecl { - fn get_mist(&self) -> String { - match self { - GenericDecl::Lifetime(name) => format!("'{}", name.get_mist()), - GenericDecl::Type(name, requirements) => { - name.get_mist() - + &(if !requirements.is_empty() { - format!( - ": {}", - requirements - .iter() - .map(TypeExpr::get_mist) - .collect::>() - .join(" + ") - ) - } else { - String::new() - }) - } - } - } -} - -impl GenMist for T { - fn gen_mist(&self, _: &mut Context, cg: &mut MistCodegen) { - cg.add(&self.get_mist()); - } -} - -impl GenMist for Spanned { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - self.item.gen_mist(ctx, cg); - } -} - -impl GenMist for Attribute { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Self::Path(path) => cg.add(&path.get_mist()), - Self::NameValue { path, value } => { - cg.add(&format!("{} = ", path.get_mist())); - value.gen_mist(ctx, cg); - } - Self::List { path, items } => { - cg.add(&path.get_mist()); - cg.add("("); - for (i, item) in items.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - item.gen_mist(ctx, cg); - } - cg.add(")"); - } - } - } -} - -impl GenMist for Pattern { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Self::Etc => cg.add(".."), - Self::Literal(lit) => lit.gen_mist(ctx, cg), - Self::Path(mutable, path) => { - if *mutable { - cg.add("mut "); - } - cg.add(&path.get_mist()) - } - Self::Struct(path, inner) => { - cg.add(&path.get_mist()); - cg.add(" {"); - for (idx, i) in inner.iter().enumerate() { - if idx > 0 { - cg.add(", "); - } - if let Some((name, pat)) = i { - cg.add(&name.get_mist()); - if let Some(pat) = pat { - cg.add(": "); - pat.gen_mist(ctx, cg); - } - } else { - cg.add(".."); - } - } - cg.add("}"); - } - Self::NamedTuple(path, inner) => { - cg.add(&path.get_mist()); - cg.add("("); - for (i, pat) in inner.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - pat.gen_mist(ctx, cg); - } - cg.add(")"); - } - Self::Tuple(inner) => { - cg.add("("); - for (i, pat) in inner.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - pat.gen_mist(ctx, cg); - } - cg.add(")"); - } - } - } -} - -impl GenMist for Literal { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Self::Int(n) => cg.add(&n.to_string()), - Self::Float(n) => cg.add(&format!("{n:?}")), - Self::Bool(b) => cg.add(&b.to_string()), - Self::String(s) => cg.add(&format!("\"{s}\"")), - Self::Tuple(values) => { - cg.add("("); - for (i, val) in values.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - val.gen_mist(ctx, cg); - } - cg.add(")"); - } - } - } -} diff --git a/crates/codegen/src/fmt/statement.rs b/crates/codegen/src/fmt/statement.rs deleted file mode 100644 index 087c2d6..0000000 --- a/crates/codegen/src/fmt/statement.rs +++ /dev/null @@ -1,158 +0,0 @@ -use mist_parser::ast::*; - -use crate::fmt::{Context, GenMist, GetMist, MistCodegen}; - -impl GenMist for Block { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - cg.addln("{"); - cg.indent += 1; - - for stmt in &self.statements { - ctx.expr_ensure_semicolon = true; - cg.add_indented(""); - stmt.gen_mist(ctx, cg); - cg.addln(""); - } - - if let Some(soft_return) = &self.soft_return { - ctx.expr_ensure_semicolon = false; - cg.add_indented(""); - soft_return.gen_mist(ctx, cg); - cg.addln(""); - } - - cg.indent -= 1; - cg.add_indented("}"); - } -} - -impl GenMist for Statement { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Statement::UnsafeBlock(block) => { - cg.add("unsafe "); - block.gen_mist(ctx, cg); - } - Statement::TopLevel(tl) => tl.gen_mist(ctx, cg), - Statement::Block(block) => block.gen_mist(ctx, cg), - Statement::VarDecl(VarDeclStmt { decl, init }) => { - if decl.type_.is_some() { - cg.add(&decl.type_.as_ref().unwrap().get_mist()); - cg.add(" "); - decl.name.gen_mist(ctx, cg); - } else { - cg.add("let "); - decl.name.gen_mist(ctx, cg); - } - if let Some(init) = init { - cg.add(" = "); - init.gen_mist(ctx, cg); - } - } - Statement::Match(expr, match_items) => { - cg.add("match "); - expr.gen_mist(ctx, cg); - cg.add(" {"); - if !match_items.is_empty() { - cg.addln(""); - cg.indent += 1; - for match_item in match_items { - let MatchItem(pat, body) = &match_item.item; - cg.add_indented(""); - for (i, p) in pat.iter().enumerate() { - if i > 0 { - cg.add(" | "); - } - p.gen_mist(ctx, cg); - } - cg.add(" => "); - if body.is_block() { - body.gen_mist(ctx, cg); - cg.addln(""); - } else { - ctx.expr_ensure_semicolon = false; - body.gen_mist(ctx, cg); - cg.addln(","); - } - } - cg.indent -= 1; - cg.add_indented("}"); - } else { - cg.add("}"); - } - } - Statement::If { - initial, - else_if, - else_branch, - } => { - cg.add("if "); - ctx.expr_ensure_semicolon = false; - initial.condition.gen_mist(ctx, cg); - cg.add(" "); - initial.body.gen_mist(ctx, cg); - - for else_if_branch in else_if { - cg.add(" else if "); - ctx.expr_ensure_semicolon = false; - else_if_branch.condition.gen_mist(ctx, cg); - cg.add(" "); - else_if_branch.body.gen_mist(ctx, cg); - } - - if let Some(else_br) = else_branch { - cg.add(" else "); - else_br.gen_mist(ctx, cg); - } - } - Statement::While(StatementBranch { condition, body }) => { - cg.add("while "); - condition.gen_mist(ctx, cg); - cg.add(" "); - body.gen_mist(ctx, cg); - } - Statement::Loop(body) => { - cg.add("loop "); - body.gen_mist(ctx, cg); - } - Statement::CStyleFor { - init, - condition, - update, - body, - } => { - cg.add("for ("); - ctx.expr_ensure_semicolon = true; - init.gen_mist(ctx, cg); - cg.add(" "); - ctx.expr_ensure_semicolon = false; - condition.gen_mist(ctx, cg); - cg.add(" "); - update.gen_mist(ctx, cg); - cg.add(") "); - body.gen_mist(ctx, cg); - } - Statement::For { - pattern, - iterator, - body, - } => { - cg.add("for "); - pattern.gen_mist(ctx, cg); - cg.add(" in "); - iterator.gen_mist(ctx, cg); - cg.add(" "); - body.gen_mist(ctx, cg); - } - Statement::Return(expr) => { - cg.add("return"); - if let Some(expr) = expr { - cg.add(" "); - expr.gen_mist(ctx, cg); - } - } - Statement::Break => cg.add("break"), - Statement::Continue => cg.add("continue"), - } - } -} diff --git a/crates/codegen/src/fmt/top_level.rs b/crates/codegen/src/fmt/top_level.rs deleted file mode 100644 index 6d65979..0000000 --- a/crates/codegen/src/fmt/top_level.rs +++ /dev/null @@ -1,356 +0,0 @@ -use mist_parser::ast::*; - -use crate::fmt::{Context, GenMist, GetMist, MistCodegen}; - -impl GenMist for ImplDecl { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - cg.add_indented("impl "); - let generics = self.generics.get_mist(); - if !generics.is_empty() { - cg.add(&generics); - cg.add(" "); - } - if let Some(trait_) = &self.trait_ { - cg.add(&trait_.get_mist()); - cg.add(" for "); - } - - cg.add(&self.target.get_mist()); - - cg.start_bracket(); - - for method in &self.methods { - method.gen_mist(ctx, cg); - } - - cg.indent -= 1; - cg.add_indentedln("}"); - } -} - -impl GenMist for FunctionDecl { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - cg.add_indented(&self.visibility.get_mist()); - - if self.return_type.is_none() { - cg.add("void "); - } else { - cg.add(&self.return_type.as_ref().unwrap().get_mist()); - cg.add(" "); - } - - cg.add(&self.name.get_mist()); - cg.add(&self.generics.get_mist()); - cg.add("("); - - if let Some((is_ref, lifetime, is_mut)) = &self.self_param { - if *is_ref { - cg.add("&"); - } - if let Some(lifetime) = lifetime { - cg.add(&format!("'{} ", lifetime.0)); - } - if *is_mut { - cg.add("mut "); - } - cg.add("self"); - if !self.params.0.is_empty() { - cg.add(", "); - } - } - - for (i, param) in self.params.0.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - param.gen_mist(ctx, cg); - } - - cg.add(")"); - - if let Some(override_spec) = &self.is_override { - cg.add(" override"); - if let Some(path) = &override_spec.0 { - cg.add("("); - cg.add(&path.get_mist()); - cg.add(")"); - } - } - - if let Some(body) = &self.body { - cg.start_indent(); - body.gen_mist(ctx, cg); - cg.addln(""); - } else { - cg.addln(";"); - } - } -} - -impl GenMist for ParamList { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - for (i, param) in self.0.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - param.gen_mist(ctx, cg); - } - } -} - -impl GenMist for VarDecl { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - if let Some(type_) = &self.type_ { - cg.add(&type_.get_mist()); - cg.add(" "); - } - self.name.gen_mist(ctx, cg); - } -} - -impl GetMist for FieldDecl { - fn get_mist(&self) -> String { - format!( - "{}{} {}", - self.visibility.get_mist(), - self.type_.get_mist(), - self.name.get_mist(), - ) - } -} - -impl GetMist for EnumItem { - fn get_mist(&self) -> String { - match self { - Self::Named(id) => id.get_mist(), - Self::Struct(id, s) => format!( - "{} {{{}}}", - id.get_mist(), - s.iter() - .map(FieldDecl::get_mist) - .collect::>() - .join(", ") - ), - Self::Tuple(id, t) => format!( - "{}({})", - id.get_mist(), - t.iter() - .map(TypeExpr::get_mist) - .collect::>() - .join(", ") - ), - } - } -} - -impl GenMist for TopLevel { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - if let TopLevelKind::ModAttribute = self.0.item { - for attr in &self.1 { - cg.add("#!["); - attr.gen_mist(ctx, cg); - cg.addln("]"); - } - } else { - for attr in &self.1 { - cg.add("#["); - attr.gen_mist(ctx, cg); - cg.addln("]"); - } - } - - self.0.gen_mist(ctx, cg); - } -} - -impl GenMist for TopLevelKind { - fn gen_mist(&self, ctx: &mut Context, cg: &mut MistCodegen) { - match self { - Self::ModAttribute => {} - Self::StaticDecl(decl) => { - cg.add("static "); - decl.decl.gen_mist(ctx, cg); - - if let Some(init) = &decl.init { - cg.add(" = "); - init.gen_mist(ctx, cg); - } - cg.add(";"); - } - Self::ConstDecl(decl) => { - cg.add("const "); - decl.decl.gen_mist(ctx, cg); - - if let Some(init) = &decl.init { - cg.add(" = "); - init.gen_mist(ctx, cg); - } - cg.add(";"); - } - Self::Import(vis, path) => { - cg.addln(&format!("{}use {};", vis.get_mist(), path.get_mist())) - } - Self::DeclareModule(vis, name) => { - cg.addln(&format!("{}module {};", vis.get_mist(), name.get_mist())) - } - Self::FunctionDecl(decl) => decl.gen_mist(ctx, cg), - Self::ImplDecl(impl_) => impl_.gen_mist(ctx, cg), - Self::StructDecl { - visibility, - name, - generics, - fields, - } => { - cg.add(&format!( - "{}struct {}{}", - visibility.get_mist(), - name.get_mist(), - generics.get_mist() - )); - - if fields.is_empty() { - cg.add(" {}"); - } else { - cg.start_bracket(); - - for field in fields { - cg.add_indentedln(&format!("{},", field.item.get_mist())); - } - - cg.indent -= 1; - cg.add_indented("}"); - } - - cg.addln(""); - } - Self::EnumDecl { - visibility, - name, - generics, - fields, - } => { - cg.add(&format!( - "{}enum {}{}", - visibility.get_mist(), - name.get_mist(), - generics.get_mist() - )); - - if fields.is_empty() { - cg.add(" {}"); - } else { - cg.start_bracket(); - - for field in fields { - cg.add_indentedln(&format!("{},", field.item.get_mist())); - } - - cg.indent -= 1; - cg.add_indented("}"); - } - - cg.addln(""); - } - Self::TraitDecl { - visibility, - name, - generics, - requirements, - items, - } => { - cg.add(&format!( - "{}trait {}{}", - visibility.get_mist(), - name.get_mist(), - generics.get_mist() - )); - if !requirements.is_empty() { - cg.add(" : "); - cg.add( - &requirements - .iter() - .map(TypeExpr::get_mist) - .collect::>() - .join(" + "), - ); - } - cg.start_bracket(); - for item in items { - item.gen_mist(ctx, cg); - } - cg.indent -= 1; - cg.add_indentedln("}"); - } - Self::ClassDecl { - visibility, - name, - generics, - inherits, - fields, - constructor, - items, - } => { - cg.add(&format!( - "{}class {}{}", - visibility.get_mist(), - name.get_mist(), - generics.get_mist() - )); - if let Some(inherits) = inherits { - cg.add(" : "); - cg.add(&inherits.get_mist()); - } - - cg.start_bracket(); - - for field in fields { - cg.add_indented(&field.item.decl.get_mist()); - if let Some(init) = &field.item.init { - cg.add(" = "); - init.gen_mist(ctx, cg); - } - cg.addln(";"); - } - - if let Some(constructor) = constructor { - if fields.len() > 0 { - cg.addln(""); - } - - cg.add_indented(&constructor.item.visibility.get_mist()); - cg.add("constructor"); - cg.add(&constructor.item.generics.get_mist()); - cg.add("("); - for (i, param) in constructor.item.params.0.iter().enumerate() { - if i > 0 { - cg.add(", "); - } - param.gen_mist(ctx, cg); - } - cg.add(") "); - cg.start_indent(); - constructor.item.body.gen_mist(ctx, cg); - cg.addln(""); - - if items.len() > 0 { - cg.addln(""); - } - } - - for (i, item) in items.iter().enumerate() { - if i > 0 { - cg.addln(""); - } - - match item { - ClassItem::Method(method) => method.gen_mist(ctx, cg), - ClassItem::ImplDecl(impl_) => impl_.gen_mist(ctx, cg), - } - } - - cg.indent -= 1; - cg.add_indentedln("}"); - } - } - } -} diff --git a/crates/codegen/src/lib.rs b/crates/codegen/src/lib.rs index 6642487..c12c7e2 100644 --- a/crates/codegen/src/lib.rs +++ b/crates/codegen/src/lib.rs @@ -1,6 +1,5 @@ pub mod class_decl; pub mod expr; -pub mod fmt; pub mod statement; pub mod top_level; From 579d229cadca45eb4d3a5d7b404896f8d6c15c09 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Thu, 2 Jul 2026 07:05:19 +0200 Subject: [PATCH 6/6] Type aliases --- crates/codegen/src/top_level.rs | 14 ++++++++++++-- crates/parser/src/ast/top_level.rs | 5 +++++ crates/parser/src/grammar.pest | 8 +++++++- crates/parser/src/parser/items/mod.rs | 8 ++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/crates/codegen/src/top_level.rs b/crates/codegen/src/top_level.rs index 58433e7..004a42b 100644 --- a/crates/codegen/src/top_level.rs +++ b/crates/codegen/src/top_level.rs @@ -191,6 +191,16 @@ impl GenRust for TopLevelKind { fn gen_rust(&self, ctx: &mut Context, cg: &mut RustCodegen) { match self { Self::ModAttribute => {} + Self::TypeAlias { name, generics, ty } => { + cg.add("type "); + name.gen_rust(ctx, cg); + if let Some(g) = generics { + g.gen_rust(ctx, cg); + } + cg.add(" = "); + ty.gen_rust(ctx, cg); + cg.addln(";"); + } Self::ConstDecl(decl) => { cg.add("const "); decl.decl.gen_rust(ctx, cg); @@ -200,7 +210,7 @@ impl GenRust for TopLevelKind { init.gen_rust(ctx, cg); } - cg.add(";"); + cg.addln(";"); } Self::StaticDecl(decl) => { cg.add("static "); @@ -211,7 +221,7 @@ impl GenRust for TopLevelKind { init.gen_rust(ctx, cg); } - cg.add(";"); + cg.addln(";"); } Self::Import(vis, path) => { cg.addln(&format!("{}use {};", vis.get_rust(), path.get_rust())) diff --git a/crates/parser/src/ast/top_level.rs b/crates/parser/src/ast/top_level.rs index e6c4394..5e5a13d 100644 --- a/crates/parser/src/ast/top_level.rs +++ b/crates/parser/src/ast/top_level.rs @@ -32,6 +32,11 @@ pub enum TopLevelKind { ImplDecl(ImplDecl), StaticDecl(VarDeclStmt), ConstDecl(VarDeclStmt), + TypeAlias { + name: Identifier, + generics: Option, + ty: TypeExpr, + }, TraitDecl { visibility: Visibility, name: Identifier, diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index d77efac..1f3891d 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -35,6 +35,7 @@ keyword = { | "unsafe" | "override" | "const" + | "type" } identifier = @{ @@ -369,13 +370,18 @@ function_decl = { const_decl = { "const" ~ var_decl_statement ~ ";" } static_decl = { "static" ~ var_decl_statement ~ ";" } +// ====================================================== +// Type aliases +// ====================================================== +type_alias = { "type" ~ identifier ~ generics_decl? ~ "=" ~ type_expr ~ ";" } + // ====================================================== // TOP LEVEL // ====================================================== top_level = { mod_attribute - | (attributes ~ (import | impl_for_decl | impl_decl | trait_decl | struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl)) + | (attributes ~ (import | impl_for_decl | impl_decl | trait_decl | struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl | type_alias)) } // ====================================================== diff --git a/crates/parser/src/parser/items/mod.rs b/crates/parser/src/parser/items/mod.rs index b6bd1cb..05064fd 100644 --- a/crates/parser/src/parser/items/mod.rs +++ b/crates/parser/src/parser/items/mod.rs @@ -125,6 +125,14 @@ impl<'a> TryFrom> for TopLevelKind { Rule::const_decl => Ok(TopLevelKind::ConstDecl(inner.next().unwrap().try_into()?)), Rule::static_decl => Ok(TopLevelKind::StaticDecl(inner.next().unwrap().try_into()?)), + Rule::type_alias => Ok(TopLevelKind::TypeAlias { + name: inner.next().unwrap().try_into()?, + generics: consume_rule(&mut inner, Rule::generics_decl) + .map(GenericsDecl::try_from) + .transpose()?, + ty: inner.next().unwrap().try_into()?, + }), + _ => AstError::bug_unimplemented(pair), } }