From 4d6e74986631aa96860163b1a79934f1a9d59b5f Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 20 Apr 2026 19:20:56 +0200 Subject: [PATCH 01/16] Added codegen lib --- codegen/Cargo.toml | 6 ++++++ codegen/src/lib.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 codegen/Cargo.toml create mode 100644 codegen/src/lib.rs diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml new file mode 100644 index 0000000..80c03ee --- /dev/null +++ b/codegen/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "codegen" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/codegen/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} From a28d431a0360a3dcf9fb621bf779425c08a7e7a4 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 20 Apr 2026 19:54:17 +0200 Subject: [PATCH 02/16] Go codegen --- codegen/Cargo.toml | 3 +- codegen/src/lib.rs | 362 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 358 insertions(+), 7 deletions(-) diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 80c03ee..c64ec89 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "codegen" version = "0.1.0" -edition = "2024" +edition = "2024" [dependencies] +parser = { path = "../parser" } diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index b93cf3f..306c744 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -1,14 +1,364 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +use parser::ast::{ + BinaryOp, Block, Expression, Postfix, Statement, TopLevel, TypeExpr, VarKind, +}; + +pub struct GoCodegen { + output: String, + indent: usize, +} + +impl GoCodegen { + pub fn new() -> Self { + Self { + output: String::new(), + indent: 0, + } + } + + fn indent_str(&self) -> String { + " ".repeat(self.indent) + } + + fn add_indented(&mut self, s: &str) { + self.output.push_str(&format!("{}{}", self.indent_str(), s)); + } + + fn add(&mut self, s: &str) { + self.output.push_str(s); + } + + fn addln(&mut self, s: &str) { + self.add(s); + self.add("\n"); + } + + fn add_indentedln(&mut self, s: &str) { + self.add_indented(s); + self.add("\n"); + } + + pub fn generate(&mut self, toplevels: &[TopLevel]) -> String { + for tl in toplevels { + self.generate_toplevel(tl); + } + self.output.clone() + } + + fn generate_toplevel(&mut self, tl: &TopLevel) { + match tl { + TopLevel::Import(path) => { + let import_path = path.replace("\"", ""); + if import_path.starts_with("./") || import_path.starts_with("/") { + self.addln(&format!("import \"{}\"", import_path)); + } else { + self.addln(&format!("import \"{}\"", import_path)); + } + self.addln(""); + } + TopLevel::StructDecl { export, name, fields } => { + let name = if *export { name } else { name }; + self.addln(&format!("type {} struct {{", name)); + self.indent += 1; + for (field_name, (_, ty)) in &fields.0 { + let go_ty = self.translate_type(ty); + self.addln(&format!("{} {}", field_name, go_ty)); + } + self.indent -= 1; + self.addln("}\n"); + } + TopLevel::FunctionDecl { + export, + name, + params, + return_type, + body, + } => { + let name = if *export { format!("{}", name) } else { name.clone() }; + let params_str = params + .0 + .iter() + .map(|(n, (_, t))| format!("{} {}", n, self.translate_type(t))) + .collect::>() + .join(", "); + + let ret_ty = return_type + .as_ref() + .map(|t| self.translate_type(t)) + .unwrap_or_else(|| "".to_string()); + + if ret_ty.is_empty() { + self.addln(&format!("func {}({}) {{", name, params_str)); + } else { + self.addln(&format!("func {}({}) {} {{", name, params_str, ret_ty)); + } + self.indent += 1; + self.generate_block(body); + self.indent -= 1; + self.addln("}\n"); + } + } + } + + fn translate_type(&self, ty: &TypeExpr) -> String { + match ty { + TypeExpr::Identifier(name) => match name.as_str() { + "int" => "int".to_string(), + "float" | "float64" => "float64".to_string(), + "float32" => "float32".to_string(), + "bool" => "bool".to_string(), + "string" => "string".to_string(), + "byte" => "byte".to_string(), + "rune" => "rune".to_string(), + _ => 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 { + Statement::Expression(expr) => { + self.add_indentedln(&format!("{};", self.generate_expression(expr))); + } + Statement::Block(block) => { + self.add_indentedln("{"); + self.indent += 1; + self.generate_block(block); + self.indent -= 1; + self.add_indentedln("}\n"); + } + Statement::VarDecl { kind, name, init } => { + let go_kind = match kind { + VarKind::Let | VarKind::Const => "var", + VarKind::Var => "var", + }; + let init_expr = init + .as_ref() + .map(|e| format!(" = {}", self.generate_expression(e))) + .unwrap_or_else(|| "".to_string()); + self.add_indentedln(&format!("{} {}{};\n", go_kind, name, init_expr)); + } + Statement::VarAssign { target, value } => { + self.add_indentedln(&format!( + "{} = {};\n", + self.generate_expression(target), + self.generate_expression(value) + )); + } + Statement::If { + condition, + then_branch, + else_branch, + } => { + self.add_indented(&format!( + "if {} ", + self.generate_expression(condition) + )); + self.generate_statement(then_branch); + if let Some(else_br) = else_branch { + self.add_indented("else "); + self.generate_statement(else_br); + } + } + Statement::While { + condition, + body, + } => { + self.add_indented(&format!( + "for {} ", + self.generate_expression(condition) + )); + self.generate_statement(body); + } + Statement::For { + init, + condition, + update, + body, + } => { + let (kind, init_name, init_val) = init; + let init_expr = init_val + .as_ref() + .map(|e| format!(" = {}", self.generate_expression(e))) + .unwrap_or_else(|| "".to_string()); + let init_str = format!("{} {}{}", self.var_kind_to_go(kind), init_name, init_expr); + + let cond_str = condition + .as_ref() + .map(|e| self.generate_expression(e)) + .unwrap_or_else(|| "true".to_string()); + + let update_str = update + .as_ref() + .map(|s| self.generate_expression(&self.stmt_to_expr(s))) + .unwrap_or_else(|| "".to_string()); + + self.add_indented(&format!("for {}; {}; {} ", init_str, cond_str, update_str)); + self.generate_statement(body); + } + Statement::Return(expr) => { + let ret_val = expr + .as_ref() + .map(|e| self.generate_expression(e)) + .unwrap_or_else(|| "".to_string()); + self.add_indentedln(&format!("return {};\n", ret_val)); + } + Statement::Break => { + self.add_indentedln("break;\n"); + } + Statement::Continue => { + self.add_indentedln("continue;\n"); + } + } + } + + fn stmt_to_expr(&self, stmt: &Statement) -> Expression { + match stmt { + Statement::Expression(e) => e.clone(), + _ => Expression::Identifier(String::new()), + } + } + + fn var_kind_to_go(&self, kind: &VarKind) -> String { + match kind { + VarKind::Let | VarKind::Const => "var".to_string(), + VarKind::Var => "var".to_string(), + } + } + + 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!("\"{}\"", 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_str = args + .iter() + .map(|a| self.generate_expression(a)) + .collect::>() + .join(", "); + format!("{}({})", result, args_str) + } + Postfix::Index(idx) => format!( + "{}[{}]", + result, + self.generate_expression(idx) + ), + 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, + self.generate_expression(rhs) + ) + } + }; + } + result + } +} + +impl Default for GoCodegen { + fn default() -> Self { + Self::new() + } } #[cfg(test)] mod tests { use super::*; + use std::collections::HashMap; + use parser::ast::{ParamList, TypeExpr, Block, Statement, Expression, TopLevel}; #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + fn test_int_literal() { + let cg = GoCodegen::new(); + let expr = Expression::IntLiteral(42); + let result = cg.generate_expression(&expr); + assert_eq!(result, "42"); } -} + + #[test] + fn test_string_literal() { + let cg = GoCodegen::new(); + let expr = Expression::StringLiteral("hello".to_string()); + let result = cg.generate_expression(&expr); + assert_eq!(result, "\"hello\""); + } + + #[test] + fn test_function_decl() { + let mut cg = GoCodegen::new(); + let toplevel = TopLevel::FunctionDecl { + export: true, + name: "main".to_string(), + params: ParamList(HashMap::new()), + return_type: None, + body: Block(vec![Statement::Return(None)]), + }; + cg.generate_toplevel(&toplevel); + let output = cg.output.clone(); + assert!(output.contains("func main()")); + } + + #[test] + fn test_struct_decl() { + let mut cg = GoCodegen::new(); + let mut fields = HashMap::new(); + fields.insert("x".to_string(), (true, TypeExpr::Identifier("int".to_string()))); + let toplevel = TopLevel::StructDecl { + export: true, + name: "Point".to_string(), + fields: ParamList(fields), + }; + cg.generate_toplevel(&toplevel); + let output = cg.output.clone(); + assert!(output.contains("type Point struct")); + assert!(output.contains("x int")); + } + + #[test] + fn test_if_statement() { + let mut cg = GoCodegen::new(); + let stmt = Statement::If { + condition: Expression::Identifier("x".to_string()), + then_branch: Box::new(Statement::Return(Some(Expression::IntLiteral(1)))), + else_branch: None, + }; + cg.generate_statement(&stmt); + let output = cg.output.clone(); + assert!(output.contains("if x")); + } +} \ No newline at end of file From 1822ce7bfb76afc7d25e5865baf3eff845088381 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Mon, 20 Apr 2026 22:15:37 +0200 Subject: [PATCH 03/16] Working golang codegen --- Cargo.lock | 8 ++ Cargo.toml | 1 + codegen/Cargo.lock | 248 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 codegen/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index d1e4cb8..1e65460 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,13 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "codegen" +version = "0.1.0" +dependencies = [ + "parser", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -78,6 +85,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" name = "mist" version = "0.1.0" dependencies = [ + "codegen", "parser", "semantic", "serde", diff --git a/Cargo.toml b/Cargo.toml index 2a9e8f2..178909d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ serde = { version = "1.0.228", features = ["serde_derive"] } serde_json = "1.0.149" parser = { path = "./parser" } semantic = { path = "./semantic" } +codegen = { path = "./codegen" } diff --git a/codegen/Cargo.lock b/codegen/Cargo.lock new file mode 100644 index 0000000..e2dce17 --- /dev/null +++ b/codegen/Cargo.lock @@ -0,0 +1,248 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "codegen" +version = "0.1.0" +dependencies = [ + "parser", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "parser" +version = "0.1.0" +dependencies = [ + "pest", + "pest_derive", + "serde", + "serde_json", +] + +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +dependencies = [ + "pest", + "sha2", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" From 508b180d6384ea45f94083d89d25071c5061fc94 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 21 Apr 2026 11:20:20 +0200 Subject: [PATCH 04/16] Compiler --- src/compiler.rs | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 8 ++--- 2 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 src/compiler.rs diff --git a/src/compiler.rs b/src/compiler.rs new file mode 100644 index 0000000..385b950 --- /dev/null +++ b/src/compiler.rs @@ -0,0 +1,95 @@ +use std::{fs, path::PathBuf, process, time::Instant}; + +use serde::Deserialize; + +#[derive(Deserialize)] +struct Config { + entry: String, + out_dir: String, +} + +pub fn build() { + let start = Instant::now(); + + // 1. find project root + let root = find_project_root().unwrap_or_else(|| { + panic!("error: could not find project root (mist.json)"); + }); + + println!("mistc build ({})", root.display()); + + // 2. load config + let config = load_config(&root); + + let entry_path = root.join(&config.entry); + let out_dir = root.join(&config.out_dir); + + println!(" → entry: {}", entry_path.display()); + + // 3. read entry file + let source = match fs::read_to_string(&entry_path) { + Ok(s) => s, + Err(e) => { + eprintln!("error: failed to read entry file\n {}", e); + process::exit(1); + } + }; + + println!(" → parsing..."); + + let mut ast = match parser::parse(&source) { + Ok(ast) => ast, + Err(e) => { + eprintln!("error: parse failed\n{}", e); + process::exit(1); + } + }; + + println!(" → type checking..."); + + semantic::walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); + + println!(" → generating Go code..."); + + let mut gc = codegen::GoCodegen::new(); + let output = gc.generate(&ast); + + // 4. ensure build dir + if let Err(e) = fs::create_dir_all(&out_dir) { + eprintln!("error: failed to create build dir\n {}", e); + process::exit(1); + } + + let out_file = out_dir.join("main.go"); + + if let Err(e) = fs::write(&out_file, output) { + eprintln!("error: failed to write output\n {}", e); + process::exit(1); + } + + let elapsed = start.elapsed(); + + println!(" ✓ built {}", out_file.display()); + println!("build finished in {:.2?}", elapsed); +} + +pub fn find_project_root() -> Option { + let mut dir = std::env::current_dir().ok()?; + + loop { + if dir.join("mist.json").exists() { + return Some(dir); + } + + if !dir.pop() { + return None; + } + } +} + +fn load_config(root: &std::path::Path) -> Config { + let content = + std::fs::read_to_string(root.join("mist.json")).expect("failed to read mist.json"); + + serde_json::from_str(&content).expect("invalid mist.json format") +} diff --git a/src/main.rs b/src/main.rs index a9e6d3a..e2db46a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +pub mod compiler; + use std::fs; use std::path::PathBuf; use std::process; @@ -18,7 +20,7 @@ fn main() { eprintln!("error: expected a file path\n usage: mist build"); process::exit(1); } - cmd_build(); + compiler::build(); } "check" => { if args.len() < 3 { @@ -48,10 +50,6 @@ fn main() { } } -pub fn cmd_build() { - unimplemented!("build command is not implemented yet"); -} - fn cmd_check(path: &str) { let source = read_ms_file(path); match parser::parse(&source) { From 18fedba1192692af70d065c67ab9d25d3f52b359 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 21 Apr 2026 11:28:26 +0200 Subject: [PATCH 05/16] Package --- codegen/src/lib.rs | 57 ++++++++++++++++++--------------------- parser/src/ast.rs | 1 + parser/src/grammar.pest | 4 ++- parser/src/lib.rs | 4 +++ semantic/src/lib.rs | 1 + semantic/src/top_level.rs | 1 + test/src/main.ms | 2 ++ 7 files changed, 38 insertions(+), 32 deletions(-) diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 306c744..4b01aef 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -1,6 +1,4 @@ -use parser::ast::{ - BinaryOp, Block, Expression, Postfix, Statement, TopLevel, TypeExpr, VarKind, -}; +use parser::ast::{BinaryOp, Block, Expression, Postfix, Statement, TopLevel, TypeExpr, VarKind}; pub struct GoCodegen { output: String, @@ -55,7 +53,11 @@ impl GoCodegen { } self.addln(""); } - TopLevel::StructDecl { export, name, fields } => { + TopLevel::StructDecl { + export, + name, + fields, + } => { let name = if *export { name } else { name }; self.addln(&format!("type {} struct {{", name)); self.indent += 1; @@ -73,7 +75,11 @@ impl GoCodegen { return_type, body, } => { - let name = if *export { format!("{}", name) } else { name.clone() }; + let name = if *export { + format!("{}", name) + } else { + name.clone() + }; let params_str = params .0 .iter() @@ -96,6 +102,10 @@ impl GoCodegen { self.indent -= 1; self.addln("}\n"); } + TopLevel::Package(pkg) => { + self.addln(&format!("package {}", pkg)); + self.addln(""); + } } } @@ -155,24 +165,15 @@ impl GoCodegen { then_branch, else_branch, } => { - self.add_indented(&format!( - "if {} ", - self.generate_expression(condition) - )); + self.add_indented(&format!("if {} ", self.generate_expression(condition))); self.generate_statement(then_branch); if let Some(else_br) = else_branch { self.add_indented("else "); self.generate_statement(else_br); } } - Statement::While { - condition, - body, - } => { - self.add_indented(&format!( - "for {} ", - self.generate_expression(condition) - )); + Statement::While { condition, body } => { + self.add_indented(&format!("for {} ", self.generate_expression(condition))); self.generate_statement(body); } Statement::For { @@ -258,11 +259,7 @@ impl GoCodegen { .join(", "); format!("{}({})", result, args_str) } - Postfix::Index(idx) => format!( - "{}[{}]", - result, - self.generate_expression(idx) - ), + Postfix::Index(idx) => format!("{}[{}]", result, self.generate_expression(idx)), Postfix::Binary(op, rhs) => { let op_str = match op { BinaryOp::Plus => "+", @@ -277,12 +274,7 @@ impl GoCodegen { BinaryOp::LessThanOrEqual => "<=", BinaryOp::GreaterThanOrEqual => ">=", }; - format!( - "{} {} {}", - result, - op_str, - self.generate_expression(rhs) - ) + format!("{} {} {}", result, op_str, self.generate_expression(rhs)) } }; } @@ -299,8 +291,8 @@ impl Default for GoCodegen { #[cfg(test)] mod tests { use super::*; + use parser::ast::{Block, Expression, ParamList, Statement, TopLevel, TypeExpr}; use std::collections::HashMap; - use parser::ast::{ParamList, TypeExpr, Block, Statement, Expression, TopLevel}; #[test] fn test_int_literal() { @@ -337,7 +329,10 @@ mod tests { fn test_struct_decl() { let mut cg = GoCodegen::new(); let mut fields = HashMap::new(); - fields.insert("x".to_string(), (true, TypeExpr::Identifier("int".to_string()))); + fields.insert( + "x".to_string(), + (true, TypeExpr::Identifier("int".to_string())), + ); let toplevel = TopLevel::StructDecl { export: true, name: "Point".to_string(), @@ -361,4 +356,4 @@ mod tests { let output = cg.output.clone(); assert!(output.contains("if x")); } -} \ No newline at end of file +} diff --git a/parser/src/ast.rs b/parser/src/ast.rs index a84e4a9..0313478 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -31,6 +31,7 @@ pub enum BinaryOp { #[derive(Debug, Clone, Serialize)] pub enum TopLevel { Import(String), + Package(String), StructDecl { export: bool, name: String, diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index ec4c62e..4cc1a94 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -13,7 +13,9 @@ inner_str = @{ (!"\"" ~ ANY)* } // ================= TOP LEVEL ================= -top_level = _{ import | function_decl | struct_decl } +top_level = _{ import | function_decl | struct_decl | package } + +package = { "package" ~ identifier ~ ";" } export = { "export" } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 7e48fab..2dbe131 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -70,6 +70,10 @@ impl TopLevel { let path = pair.into_inner().next().unwrap().as_str().to_string(); Some(TopLevel::Import(path)) } + Rule::package => { + let name = pair.into_inner().next().unwrap().as_str().to_string(); + Some(TopLevel::Package(name)) + } Rule::function_decl => { let mut inner = pair.into_inner(); diff --git a/semantic/src/lib.rs b/semantic/src/lib.rs index 24057de..40735a5 100644 --- a/semantic/src/lib.rs +++ b/semantic/src/lib.rs @@ -15,6 +15,7 @@ pub fn walk_ast(top_scope: Arc, tl: &mut Vec) { for tl in tl { match tl { parser::ast::TopLevel::Import(_) => unimplemented!(), + parser::ast::TopLevel::Package(_) => {} parser::ast::TopLevel::FunctionDecl { params, body, name, .. diff --git a/semantic/src/top_level.rs b/semantic/src/top_level.rs index f58fa96..b1e85cb 100644 --- a/semantic/src/top_level.rs +++ b/semantic/src/top_level.rs @@ -112,6 +112,7 @@ impl TopLevelSymbolScope { for top in top_level { match top { TopLevel::Import(_) => unimplemented!(), + TopLevel::Package(_) => {} TopLevel::FunctionDecl { export, diff --git a/test/src/main.ms b/test/src/main.ms index 59ea0e1..c183302 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -1,3 +1,5 @@ +package main; + export struct MyType { export x: int, } From e45546ad2e18609e7816ecf995e2bb6315f8e710 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 21 Apr 2026 12:29:06 +0200 Subject: [PATCH 06/16] Main function --- semantic/src/lib.rs | 5 ++++- test/src/main.ms | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/semantic/src/lib.rs b/semantic/src/lib.rs index 40735a5..3d1128b 100644 --- a/semantic/src/lib.rs +++ b/semantic/src/lib.rs @@ -21,7 +21,10 @@ pub fn walk_ast(top_scope: Arc, tl: &mut Vec) { params, body, name, .. } => { let rf = top_scope.get_reference(name).unwrap(); - *name = rf.name.clone(); + + if name != "main" { + *name = rf.name.clone(); + } match &*rf.var_type { hir::TypeRef::Function(f) => walk_param_list(&f.params, params), diff --git a/test/src/main.ms b/test/src/main.ms index c183302..44279da 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -1,7 +1,5 @@ package main; -export struct MyType { - export x: int, +function main() { + let a = 10; } - -export function test(a: MyType) { } From 5b5b6aa795ab00df23ce4ed8bd2c6cb04d4b3328 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 21 Apr 2026 12:39:55 +0200 Subject: [PATCH 07/16] Fixed types --- semantic/src/scope.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index dff29cf..9c1fd22 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -52,12 +52,34 @@ impl LocalScope { } pub fn get_reference(&self, name: &String) -> Option> { - self.variables + let rf = self + .variables .lock() .unwrap() .get(name) .cloned() - .or_else(|| self.parent.get_reference(name)) + .or_else(|| self.parent.get_reference(name)); + + match rf { + Some(v) => Some(v), + None => match name.as_str() { + "int" => { + let var_ref = Arc::new(VarRef { + export: false, + name: name.clone(), + var_type: Arc::new(TypeRef::Int), + }); + + self.variables + .lock() + .unwrap() + .insert(name.clone(), var_ref.clone()); + + Some(var_ref) + } + _ => None, + }, + } } pub fn with_block(self: &Arc, block: &mut parser::ast::Block) { @@ -120,22 +142,18 @@ impl LocalScope { ) -> Option> { match expr { ast::Expression::IntLiteral(_) => self - .parent .get_reference(&"int".to_string()) .map(|r| r.var_type.clone()), ast::Expression::FloatLiteral(_) => self - .parent .get_reference(&"float".to_string()) .map(|r| r.var_type.clone()), ast::Expression::BoolLiteral(_) => self - .parent .get_reference(&"bool".to_string()) .map(|r| r.var_type.clone()), ast::Expression::StringLiteral(_) => self - .parent .get_reference(&"string".to_string()) .map(|r| r.var_type.clone()), From f5126ad37c9247edad8d88c38ac4db399e8a11ad Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 21 Apr 2026 18:19:42 +0200 Subject: [PATCH 08/16] mapgen --- mapgen/go.mod | 9 +++++++++ mapgen/go.sum | 6 ++++++ mapgen/main.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 mapgen/go.mod create mode 100644 mapgen/go.sum create mode 100644 mapgen/main.go diff --git a/mapgen/go.mod b/mapgen/go.mod new file mode 100644 index 0000000..787464e --- /dev/null +++ b/mapgen/go.mod @@ -0,0 +1,9 @@ +module mapgen + +go 1.25.5 + +require ( + golang.org/x/mod v0.35.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/tools v0.44.0 // indirect +) diff --git a/mapgen/go.sum b/mapgen/go.sum new file mode 100644 index 0000000..d570929 --- /dev/null +++ b/mapgen/go.sum @@ -0,0 +1,6 @@ +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= diff --git a/mapgen/main.go b/mapgen/main.go new file mode 100644 index 0000000..b335654 --- /dev/null +++ b/mapgen/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + "go/token" + + "golang.org/x/tools/go/packages" +) + +func main() { + cfg := &packages.Config{ + Mode: packages.NeedTypes, + } + + pkgs, err := packages.Load(cfg, "fmt") + if err != nil { + panic(err) + } + + for _, pkg := range pkgs { + scope := pkg.Types.Scope() + + for _, name := range scope.Names() { + if !token.IsExported(name) { + continue + } + + obj := scope.Lookup(name) + fmt.Println(name, obj.Type()) + } + } +} From 664e8aba74e62084dfb15145568fc11dfc8b38d5 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 08:43:34 +0200 Subject: [PATCH 09/16] Working mapgen --- mapgen/main.go | 131 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) diff --git a/mapgen/main.go b/mapgen/main.go index b335654..6c78f7b 100644 --- a/mapgen/main.go +++ b/mapgen/main.go @@ -1,15 +1,45 @@ package main import ( + "encoding/json" "fmt" "go/token" + "go/types" + "os" "golang.org/x/tools/go/packages" ) +type TypeSymbol string + +type VarSymbol struct { + Export bool `json:"export"` + VarType TypeSymbol `json:"var_type"` + Name string `json:"name"` +} + +type FunctionSymbol struct { + Export bool `json:"export"` + Name string `json:"name"` + Params map[string]VarSymbol `json:"params"` + ReturnTypes []TypeSymbol `json:"return_types"` +} + +type StructSymbol struct { + Export bool `json:"export"` + Name string `json:"name"` + Fields map[string]VarSymbol `json:"fields"` + Methods map[string]FunctionSymbol `json:"methods"` +} + +type TopLevelSymbolScope struct { + Structs map[string]StructSymbol `json:"structs"` + Functions map[string]FunctionSymbol `json:"functions"` +} + func main() { cfg := &packages.Config{ - Mode: packages.NeedTypes, + Mode: packages.NeedTypes | packages.NeedTypesInfo, } pkgs, err := packages.Load(cfg, "fmt") @@ -17,6 +47,15 @@ func main() { panic(err) } + if packages.PrintErrors(pkgs) > 0 { + os.Exit(1) + } + + result := TopLevelSymbolScope{ + Structs: make(map[string]StructSymbol), + Functions: make(map[string]FunctionSymbol), + } + for _, pkg := range pkgs { scope := pkg.Types.Scope() @@ -26,7 +65,95 @@ func main() { } obj := scope.Lookup(name) - fmt.Println(name, obj.Type()) + + switch obj := obj.(type) { + + case *types.Func: + fn := buildFunction(obj) + result.Functions[name] = fn + + case *types.TypeName: + if strct, ok := buildStruct(obj); ok { + result.Structs[name] = strct + } + } } } + + out, err := json.MarshalIndent(result, "", " ") + if err != nil { + panic(err) + } + + fmt.Println(string(out)) +} + +func buildFunction(fn *types.Func) FunctionSymbol { + sig := fn.Type().(*types.Signature) + + params := make(map[string]VarSymbol) + for i := 0; i < sig.Params().Len(); i++ { + p := sig.Params().At(i) + + name := p.Name() + if name == "" { + name = fmt.Sprintf("param%d", i) + } + + params[name] = VarSymbol{ + Export: true, + Name: name, + VarType: TypeSymbol(p.Type().String()), + } + } + + var returnTypes []TypeSymbol + for i := 0; i < sig.Results().Len(); i++ { + r := sig.Results().At(i) + returnTypes = append(returnTypes, TypeSymbol(r.Type().String())) + } + + return FunctionSymbol{ + Export: token.IsExported(fn.Name()), + Name: fn.Name(), + Params: params, + ReturnTypes: returnTypes, + } +} + +func buildStruct(tn *types.TypeName) (StructSymbol, bool) { + underlying := tn.Type().Underlying() + + strct, ok := underlying.(*types.Struct) + if !ok { + return StructSymbol{}, false + } + + fields := make(map[string]VarSymbol) + + for i := 0; i < strct.NumFields(); i++ { + f := strct.Field(i) + + fields[f.Name()] = VarSymbol{ + Export: token.IsExported(f.Name()), + Name: f.Name(), + VarType: TypeSymbol(f.Type().String()), + } + } + + methods := make(map[string]FunctionSymbol) + methodSet := types.NewMethodSet(tn.Type()) + + for i := 0; i < methodSet.Len(); i++ { + m := methodSet.At(i).Obj().(*types.Func) + + methods[m.Name()] = buildFunction(m) + } + + return StructSymbol{ + Export: token.IsExported(tn.Name()), + Name: tn.Name(), + Fields: fields, + Methods: methods, + }, true } From 842383ba6e4bb6bbbc353af0f01e08ac6e1e36cb Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 08:56:44 +0200 Subject: [PATCH 10/16] Testing scope importing --- Cargo.lock | 2 ++ semantic/Cargo.toml | 2 ++ semantic/src/scope.rs | 7 +++++-- semantic/src/top_level.rs | 34 ++++++++++++++++++++++++++++------ src/compiler.rs | 2 +- src/main.rs | 4 ++-- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e65460..57bae6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,6 +168,8 @@ name = "semantic" version = "0.1.0" dependencies = [ "parser", + "serde", + "serde_json", ] [[package]] diff --git a/semantic/Cargo.toml b/semantic/Cargo.toml index 69caf32..cbebdd1 100644 --- a/semantic/Cargo.toml +++ b/semantic/Cargo.toml @@ -5,3 +5,5 @@ edition = "2024" [dependencies] parser = { path = "../parser" } +serde = { version = "1.0.228", features = ["serde_derive"] } +serde_json = "1.0.149" diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 9c1fd22..64a727f 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -17,8 +17,11 @@ pub enum Scope { } impl Scope { - pub fn from_top(top_level: &Vec) -> Arc { - let tl = TopLevelSymbolScope::from(top_level); + pub fn from_top( + path: &std::path::PathBuf, + top_level: &Vec, + ) -> Arc { + let tl = TopLevelSymbolScope::from(path, top_level); Arc::new(Self::TopLevel(TopLevelHirScope::from_tlss(&tl))) } diff --git a/semantic/src/top_level.rs b/semantic/src/top_level.rs index b1e85cb..c467fe3 100644 --- a/semantic/src/top_level.rs +++ b/semantic/src/top_level.rs @@ -1,20 +1,23 @@ use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; use parser::ast::TopLevel; use parser::ast::{ParamList, TypeExpr}; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct TypeSymbol(pub String); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct VarSymbol { pub export: bool, pub var_type: TypeSymbol, pub name: String, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct FunctionSymbol { pub export: bool, pub name: String, @@ -22,7 +25,7 @@ pub struct FunctionSymbol { pub return_type: Option, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct StructSymbol { pub export: bool, pub name: String, @@ -96,22 +99,41 @@ impl StructSymbol { } } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct JSONScope { + pub structs: HashMap, + pub functions: HashMap, + pub package_name: String, +} + +type JsonScopeMap = HashMap; + #[derive(Clone, Debug)] pub struct TopLevelSymbolScope { + pub imports: HashMap, pub structs: HashMap, pub functions: HashMap, } impl TopLevelSymbolScope { - pub fn from(top_level: &Vec) -> Self { + pub fn from(path: &PathBuf, top_level: &Vec) -> Self { let mut scope = TopLevelSymbolScope { + imports: HashMap::new(), structs: HashMap::new(), functions: HashMap::new(), }; for top in top_level { match top { - TopLevel::Import(_) => unimplemented!(), + TopLevel::Import(package) => { + let json = fs::read(path.join("mist.map.json")).unwrap(); + let json_scope_map: JsonScopeMap = serde_json::from_slice(&json).unwrap(); + let json_scope = json_scope_map.get(package).unwrap().clone(); + + scope + .imports + .insert(json_scope.package_name.clone(), json_scope); + } TopLevel::Package(_) => {} TopLevel::FunctionDecl { diff --git a/src/compiler.rs b/src/compiler.rs index 385b950..c7cbbe9 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -47,7 +47,7 @@ pub fn build() { println!(" → type checking..."); - semantic::walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); + semantic::walk_ast(semantic::scope::Scope::from_top(&root, &ast), &mut ast); println!(" → generating Go code..."); diff --git a/src/main.rs b/src/main.rs index e2db46a..6331f9c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,7 +56,7 @@ fn cmd_check(path: &str) { Ok(mut ast) => { println!("parse: ok"); - walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); + // walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); println!("{:#?}", ast) } @@ -71,7 +71,7 @@ fn cmd_parse(path: &str) { let source = read_ms_file(path); match parser::parse(&source) { Ok(mut ast) => { - walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); + // walk_ast(semantic::scope::Scope::from_top(&ast), &mut ast); fs::write("output.json", serde_json::to_string_pretty(&ast).unwrap()).unwrap_or_else( |e| { From 10a304bfe44eb34f2cf98b321b0c5c611b7a48d1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 09:05:32 +0200 Subject: [PATCH 11/16] Mist mapping --- mapgen/main.go | 45 +++-- test/mist.map.json | 450 +++++++++++++++++++++++++++++++++++++++++++++ test/src/main.ms | 2 + 3 files changed, 484 insertions(+), 13 deletions(-) create mode 100644 test/mist.map.json diff --git a/mapgen/main.go b/mapgen/main.go index 6c78f7b..e1f644e 100644 --- a/mapgen/main.go +++ b/mapgen/main.go @@ -33,15 +33,20 @@ type StructSymbol struct { } type TopLevelSymbolScope struct { - Structs map[string]StructSymbol `json:"structs"` - Functions map[string]FunctionSymbol `json:"functions"` + PackageName string `json:"package_name"` + Structs map[string]StructSymbol `json:"structs"` + Functions map[string]FunctionSymbol `json:"functions"` } func main() { cfg := &packages.Config{ - Mode: packages.NeedTypes | packages.NeedTypesInfo, + Mode: packages.NeedName | + packages.NeedTypes | + packages.NeedTypesInfo | + packages.NeedModule, } + // you can expand this to multiple packages later pkgs, err := packages.Load(cfg, "fmt") if err != nil { panic(err) @@ -51,12 +56,16 @@ func main() { os.Exit(1) } - result := TopLevelSymbolScope{ - Structs: make(map[string]StructSymbol), - Functions: make(map[string]FunctionSymbol), - } + // 🔑 FINAL RESULT: map[import_path]scope + result := make(map[string]TopLevelSymbolScope) for _, pkg := range pkgs { + scopeData := TopLevelSymbolScope{ + PackageName: pkg.Name, // e.g. "http" + Structs: make(map[string]StructSymbol), + Functions: make(map[string]FunctionSymbol), + } + scope := pkg.Types.Scope() for _, name := range scope.Names() { @@ -69,15 +78,17 @@ func main() { switch obj := obj.(type) { case *types.Func: - fn := buildFunction(obj) - result.Functions[name] = fn + scopeData.Functions[name] = buildFunction(obj) case *types.TypeName: if strct, ok := buildStruct(obj); ok { - result.Structs[name] = strct + scopeData.Structs[name] = strct } } } + + // 🔑 key = import path (e.g. "net/http") + result[pkg.PkgPath] = scopeData } out, err := json.MarshalIndent(result, "", " ") @@ -114,7 +125,7 @@ func buildFunction(fn *types.Func) FunctionSymbol { } return FunctionSymbol{ - Export: token.IsExported(fn.Name()), + Export: true, // already filtered before calling Name: fn.Name(), Params: params, ReturnTypes: returnTypes, @@ -134,8 +145,12 @@ func buildStruct(tn *types.TypeName) (StructSymbol, bool) { for i := 0; i < strct.NumFields(); i++ { f := strct.Field(i) + if !token.IsExported(f.Name()) { + continue + } + fields[f.Name()] = VarSymbol{ - Export: token.IsExported(f.Name()), + Export: true, Name: f.Name(), VarType: TypeSymbol(f.Type().String()), } @@ -147,11 +162,15 @@ func buildStruct(tn *types.TypeName) (StructSymbol, bool) { for i := 0; i < methodSet.Len(); i++ { m := methodSet.At(i).Obj().(*types.Func) + if !token.IsExported(m.Name()) { + continue + } + methods[m.Name()] = buildFunction(m) } return StructSymbol{ - Export: token.IsExported(tn.Name()), + Export: true, Name: tn.Name(), Fields: fields, Methods: methods, diff --git a/test/mist.map.json b/test/mist.map.json new file mode 100644 index 0000000..cf63929 --- /dev/null +++ b/test/mist.map.json @@ -0,0 +1,450 @@ +{ + "fmt": { + "package_name": "fmt", + "structs": {}, + "functions": { + "Append": { + "export": true, + "name": "Append", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "b": { + "export": true, + "var_type": "[]byte", + "name": "b" + } + }, + "return_types": [ + "[]byte" + ] + }, + "Appendf": { + "export": true, + "name": "Appendf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "b": { + "export": true, + "var_type": "[]byte", + "name": "b" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + } + }, + "return_types": [ + "[]byte" + ] + }, + "Appendln": { + "export": true, + "name": "Appendln", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "b": { + "export": true, + "var_type": "[]byte", + "name": "b" + } + }, + "return_types": [ + "[]byte" + ] + }, + "Errorf": { + "export": true, + "name": "Errorf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + } + }, + "return_types": [ + "error" + ] + }, + "FormatString": { + "export": true, + "name": "FormatString", + "params": { + "state": { + "export": true, + "var_type": "fmt.State", + "name": "state" + }, + "verb": { + "export": true, + "var_type": "rune", + "name": "verb" + } + }, + "return_types": [ + "string" + ] + }, + "Fprint": { + "export": true, + "name": "Fprint", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "w": { + "export": true, + "var_type": "io.Writer", + "name": "w" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Fprintf": { + "export": true, + "name": "Fprintf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + }, + "w": { + "export": true, + "var_type": "io.Writer", + "name": "w" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Fprintln": { + "export": true, + "name": "Fprintln", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "w": { + "export": true, + "var_type": "io.Writer", + "name": "w" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Fscan": { + "export": true, + "name": "Fscan", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "r": { + "export": true, + "var_type": "io.Reader", + "name": "r" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Fscanf": { + "export": true, + "name": "Fscanf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + }, + "r": { + "export": true, + "var_type": "io.Reader", + "name": "r" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Fscanln": { + "export": true, + "name": "Fscanln", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "r": { + "export": true, + "var_type": "io.Reader", + "name": "r" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Print": { + "export": true, + "name": "Print", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Printf": { + "export": true, + "name": "Printf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Println": { + "export": true, + "name": "Println", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Scan": { + "export": true, + "name": "Scan", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Scanf": { + "export": true, + "name": "Scanf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Scanln": { + "export": true, + "name": "Scanln", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Sprint": { + "export": true, + "name": "Sprint", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + } + }, + "return_types": [ + "string" + ] + }, + "Sprintf": { + "export": true, + "name": "Sprintf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + } + }, + "return_types": [ + "string" + ] + }, + "Sprintln": { + "export": true, + "name": "Sprintln", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + } + }, + "return_types": [ + "string" + ] + }, + "Sscan": { + "export": true, + "name": "Sscan", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "str": { + "export": true, + "var_type": "string", + "name": "str" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Sscanf": { + "export": true, + "name": "Sscanf", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "format": { + "export": true, + "var_type": "string", + "name": "format" + }, + "str": { + "export": true, + "var_type": "string", + "name": "str" + } + }, + "return_types": [ + "int", + "error" + ] + }, + "Sscanln": { + "export": true, + "name": "Sscanln", + "params": { + "a": { + "export": true, + "var_type": "[]any", + "name": "a" + }, + "str": { + "export": true, + "var_type": "string", + "name": "str" + } + }, + "return_types": [ + "int", + "error" + ] + } + } + } +} \ No newline at end of file diff --git a/test/src/main.ms b/test/src/main.ms index 44279da..4346ab5 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -1,5 +1,7 @@ package main; +import "fmt"; + function main() { let a = 10; } From 797eed173c6ef83123cba5fdaa249b2f4f335ebd Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 09:23:37 +0200 Subject: [PATCH 12/16] HIR package importing --- semantic/src/hir.rs | 145 +++++++++++++++++++++++++++++++++++++- semantic/src/lib.rs | 2 +- semantic/src/top_level.rs | 5 +- test/src/main.ms | 2 +- 4 files changed, 150 insertions(+), 4 deletions(-) diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs index ed5129f..9f390b3 100644 --- a/semantic/src/hir.rs +++ b/semantic/src/hir.rs @@ -6,15 +6,24 @@ use std::{ }, }; -use crate::top_level::{FunctionSymbol, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol}; +use crate::top_level::{ + FunctionSymbol, JSONScope, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol, +}; #[derive(Clone, Debug)] pub enum TypeRef { Struct(StructRef), Function(FunctionRef), + Package(PackageRef), Int, } +#[derive(Clone, Debug)] +pub struct PackageRef { + pub name: String, + pub variables: HashMap>, +} + #[derive(Clone, Debug)] pub struct VarRef { pub export: bool, @@ -58,6 +67,17 @@ impl TopLevelHirScope { scope.struct_ref(tlss, symbol); } + for (_, symbol) in &tlss.imports { + scope.variables.insert( + symbol.package_name.clone(), + Arc::new(VarRef { + export: false, + name: symbol.package_name.clone(), + var_type: Arc::new(TypeRef::Package(PackageRef::from_tlss(symbol))), + }), + ); + } + scope } @@ -181,7 +201,130 @@ impl TypeRef { match self { TypeRef::Function(f) => f.name.clone(), TypeRef::Struct(s) => s.name.clone(), + TypeRef::Package(p) => p.name.clone(), TypeRef::Int => "int".to_string(), } } } + +impl PackageRef { + pub fn from_tlss(json_scope: &JSONScope) -> Self { + let mut scope = Self { + name: json_scope.package_name.clone(), + variables: HashMap::new(), + }; + + for (_, symbol) in &json_scope.functions { + scope.function_ref(json_scope, symbol); + } + + for (_, symbol) in &json_scope.structs { + scope.struct_ref(json_scope, symbol); + } + + scope + } + + pub fn function_ref(&mut self, json_scope: &JSONScope, symbol: &FunctionSymbol) { + if self.variables.get(&symbol.name).is_none() { + let name = symbol.name.clone(); + + if let Some(_) = json_scope.functions.get(&symbol.name) { + let rf = FunctionRef { + export: symbol.export, + name: name.clone(), + params: symbol + .params + .iter() + .map(|(name, v)| (name.clone(), self.var_ref(json_scope, v))) + .collect(), + return_type: symbol + .return_type + .clone() + .map(|rt| self.type_ref(json_scope, &rt)), + }; + + self.variables.insert( + symbol.name.clone(), + Arc::new(VarRef { + export: false, + name: name.clone(), + var_type: Arc::new(TypeRef::Function(rf)), + }), + ); + } else { + unimplemented!() + } + } + } + + pub fn struct_ref(&mut self, json_scope: &JSONScope, symbol: &StructSymbol) -> Arc { + if let Some(rf) = self.variables.get(&symbol.name) { + rf.var_type.clone() + } else { + let name = symbol.name.clone(); + + let rf = Arc::new(TypeRef::Struct(StructRef { + export: symbol.export, + name: name.clone(), + fields: symbol + .fields + .iter() + .map(|(name, v)| (name.clone(), self.var_ref(json_scope, v))) + .collect(), + })); + + self.variables.insert( + symbol.name.clone(), + Arc::new(VarRef { + export: symbol.export, + name: name.clone(), + var_type: rf.clone(), + }), + ); + + rf + } + } + + pub fn var_ref(&mut self, json_scope: &JSONScope, symbol: &VarSymbol) -> Arc { + Arc::new(VarRef { + export: symbol.export, + var_type: self.type_ref(json_scope, &symbol.var_type), + name: symbol.name.clone(), + }) + } + + pub fn type_ref(&mut self, json_scope: &JSONScope, symbol: &TypeSymbol) -> Arc { + if let Some(var_ref) = self.variables.get(&symbol.0) { + var_ref.var_type.clone() + } else { + if let Some(json_scope_rf) = json_scope.structs.get(&symbol.0) { + self.struct_ref(json_scope, json_scope_rf) + } else { + match symbol.0.as_str() { + // TODO: This is a hack, we should have a better way to handle built-in types + "int" | "[]any" => { + let var_ref = Arc::new(VarRef { + export: false, + name: symbol.0.clone(), + var_type: Arc::new(TypeRef::Int), + }); + + self.variables.insert(symbol.0.clone(), var_ref.clone()); + + var_ref.var_type.clone() + } + + _ => { + unimplemented!("{:?}", symbol) + } + } + } + } + } + + pub fn get_reference(&self, name: &String) -> Option> { + self.variables.get(name).cloned() + } +} diff --git a/semantic/src/lib.rs b/semantic/src/lib.rs index 3d1128b..80dcc83 100644 --- a/semantic/src/lib.rs +++ b/semantic/src/lib.rs @@ -14,7 +14,7 @@ pub mod top_level; pub fn walk_ast(top_scope: Arc, tl: &mut Vec) { for tl in tl { match tl { - parser::ast::TopLevel::Import(_) => unimplemented!(), + parser::ast::TopLevel::Import(package) => {} parser::ast::TopLevel::Package(_) => {} parser::ast::TopLevel::FunctionDecl { diff --git a/semantic/src/top_level.rs b/semantic/src/top_level.rs index c467fe3..9be616f 100644 --- a/semantic/src/top_level.rs +++ b/semantic/src/top_level.rs @@ -128,7 +128,10 @@ impl TopLevelSymbolScope { TopLevel::Import(package) => { let json = fs::read(path.join("mist.map.json")).unwrap(); let json_scope_map: JsonScopeMap = serde_json::from_slice(&json).unwrap(); - let json_scope = json_scope_map.get(package).unwrap().clone(); + let json_scope = json_scope_map + .get(&package.replace("\"", "")) + .unwrap() + .clone(); scope .imports diff --git a/test/src/main.ms b/test/src/main.ms index 4346ab5..99646a0 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -3,5 +3,5 @@ package main; import "fmt"; function main() { - let a = 10; + fmt.Println("hello"); } From 53b87eb02ece36710e1e5f421f7e1ec54e8903df Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 09:27:29 +0200 Subject: [PATCH 13/16] More flexible types --- semantic/src/hir.rs | 49 ++++++++++++++----------------------------- semantic/src/scope.rs | 27 +++++++++++------------- 2 files changed, 28 insertions(+), 48 deletions(-) diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs index 9f390b3..7b37dae 100644 --- a/semantic/src/hir.rs +++ b/semantic/src/hir.rs @@ -15,7 +15,7 @@ pub enum TypeRef { Struct(StructRef), Function(FunctionRef), Package(PackageRef), - Int, + Name(String), } #[derive(Clone, Debug)] @@ -162,23 +162,15 @@ impl TopLevelHirScope { if let Some(tlss_rf) = tlss.structs.get(&symbol.0) { self.struct_ref(tlss, tlss_rf) } else { - match symbol.0.as_str() { - "int" => { - let var_ref = Arc::new(VarRef { - export: false, - name: symbol.0.clone(), - var_type: Arc::new(TypeRef::Int), - }); + let var_ref = Arc::new(VarRef { + export: false, + name: symbol.0.clone(), + var_type: Arc::new(TypeRef::Name(symbol.0.clone())), + }); - self.variables.insert(symbol.0.clone(), var_ref.clone()); + self.variables.insert(symbol.0.clone(), var_ref.clone()); - var_ref.var_type.clone() - } - - _ => { - unimplemented!("{:?}", symbol) - } - } + var_ref.var_type.clone() } } } @@ -202,7 +194,7 @@ impl TypeRef { TypeRef::Function(f) => f.name.clone(), TypeRef::Struct(s) => s.name.clone(), TypeRef::Package(p) => p.name.clone(), - TypeRef::Int => "int".to_string(), + TypeRef::Name(n) => n.clone(), } } } @@ -302,24 +294,15 @@ impl PackageRef { if let Some(json_scope_rf) = json_scope.structs.get(&symbol.0) { self.struct_ref(json_scope, json_scope_rf) } else { - match symbol.0.as_str() { - // TODO: This is a hack, we should have a better way to handle built-in types - "int" | "[]any" => { - let var_ref = Arc::new(VarRef { - export: false, - name: symbol.0.clone(), - var_type: Arc::new(TypeRef::Int), - }); + let var_ref = Arc::new(VarRef { + export: false, + name: symbol.0.clone(), + var_type: Arc::new(TypeRef::Name(symbol.0.clone())), + }); - self.variables.insert(symbol.0.clone(), var_ref.clone()); + self.variables.insert(symbol.0.clone(), var_ref.clone()); - var_ref.var_type.clone() - } - - _ => { - unimplemented!("{:?}", symbol) - } - } + var_ref.var_type.clone() } } } diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 64a727f..403224e 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -65,23 +65,20 @@ impl LocalScope { match rf { Some(v) => Some(v), - None => match name.as_str() { - "int" => { - let var_ref = Arc::new(VarRef { - export: false, - name: name.clone(), - var_type: Arc::new(TypeRef::Int), - }); + None => { + let var_ref = Arc::new(VarRef { + export: false, + name: name.clone(), + var_type: Arc::new(TypeRef::Name(name.clone())), + }); - self.variables - .lock() - .unwrap() - .insert(name.clone(), var_ref.clone()); + self.variables + .lock() + .unwrap() + .insert(name.clone(), var_ref.clone()); - Some(var_ref) - } - _ => None, - }, + Some(var_ref) + } } } From ea6aabd89601fb26893849be594188d88c40144a Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 09:34:23 +0200 Subject: [PATCH 14/16] Working imports --- mapgen/main.go | 14 +++++++++++-- semantic/src/lib.rs | 2 +- semantic/src/scope.rs | 5 +++++ test/mist.map.json | 46 +++++++++++++++++++++---------------------- test/src/main.ms | 2 +- 5 files changed, 42 insertions(+), 27 deletions(-) diff --git a/mapgen/main.go b/mapgen/main.go index e1f644e..b51fad5 100644 --- a/mapgen/main.go +++ b/mapgen/main.go @@ -6,6 +6,7 @@ import ( "go/token" "go/types" "os" + "unicode" "golang.org/x/tools/go/packages" ) @@ -78,7 +79,7 @@ func main() { switch obj := obj.(type) { case *types.Func: - scopeData.Functions[name] = buildFunction(obj) + scopeData.Functions[LowerFirst(name)] = buildFunction(obj) case *types.TypeName: if strct, ok := buildStruct(obj); ok { @@ -99,6 +100,15 @@ func main() { fmt.Println(string(out)) } +func LowerFirst(s string) string { + if s == "" { + return "" + } + r := []rune(s) + r[0] = unicode.ToLower(r[0]) + return string(r) +} + func buildFunction(fn *types.Func) FunctionSymbol { sig := fn.Type().(*types.Signature) @@ -166,7 +176,7 @@ func buildStruct(tn *types.TypeName) (StructSymbol, bool) { continue } - methods[m.Name()] = buildFunction(m) + methods[LowerFirst(m.Name())] = buildFunction(m) } return StructSymbol{ diff --git a/semantic/src/lib.rs b/semantic/src/lib.rs index 80dcc83..9af6dfa 100644 --- a/semantic/src/lib.rs +++ b/semantic/src/lib.rs @@ -14,7 +14,7 @@ pub mod top_level; pub fn walk_ast(top_scope: Arc, tl: &mut Vec) { for tl in tl { match tl { - parser::ast::TopLevel::Import(package) => {} + parser::ast::TopLevel::Import(_) => {} parser::ast::TopLevel::Package(_) => {} parser::ast::TopLevel::FunctionDecl { diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 403224e..6cd3f5c 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -120,6 +120,11 @@ impl LocalScope { *id = field.name.clone(); current_type = field.var_type.clone(); } + TypeRef::Package(p) => { + let var_ref = p.variables.get(id)?; + *id = var_ref.name.clone(); + current_type = var_ref.var_type.clone(); + } _ => unimplemented!(), }, Postfix::Call(_args) => match &*current_type { diff --git a/test/mist.map.json b/test/mist.map.json index cf63929..529a5df 100644 --- a/test/mist.map.json +++ b/test/mist.map.json @@ -3,7 +3,7 @@ "package_name": "fmt", "structs": {}, "functions": { - "Append": { + "append": { "export": true, "name": "Append", "params": { @@ -22,7 +22,7 @@ "[]byte" ] }, - "Appendf": { + "appendf": { "export": true, "name": "Appendf", "params": { @@ -46,7 +46,7 @@ "[]byte" ] }, - "Appendln": { + "appendln": { "export": true, "name": "Appendln", "params": { @@ -65,7 +65,7 @@ "[]byte" ] }, - "Errorf": { + "errorf": { "export": true, "name": "Errorf", "params": { @@ -84,7 +84,7 @@ "error" ] }, - "FormatString": { + "formatString": { "export": true, "name": "FormatString", "params": { @@ -103,7 +103,7 @@ "string" ] }, - "Fprint": { + "fprint": { "export": true, "name": "Fprint", "params": { @@ -123,7 +123,7 @@ "error" ] }, - "Fprintf": { + "fprintf": { "export": true, "name": "Fprintf", "params": { @@ -148,7 +148,7 @@ "error" ] }, - "Fprintln": { + "fprintln": { "export": true, "name": "Fprintln", "params": { @@ -168,7 +168,7 @@ "error" ] }, - "Fscan": { + "fscan": { "export": true, "name": "Fscan", "params": { @@ -188,7 +188,7 @@ "error" ] }, - "Fscanf": { + "fscanf": { "export": true, "name": "Fscanf", "params": { @@ -213,7 +213,7 @@ "error" ] }, - "Fscanln": { + "fscanln": { "export": true, "name": "Fscanln", "params": { @@ -233,7 +233,7 @@ "error" ] }, - "Print": { + "print": { "export": true, "name": "Print", "params": { @@ -248,7 +248,7 @@ "error" ] }, - "Printf": { + "printf": { "export": true, "name": "Printf", "params": { @@ -268,7 +268,7 @@ "error" ] }, - "Println": { + "println": { "export": true, "name": "Println", "params": { @@ -283,7 +283,7 @@ "error" ] }, - "Scan": { + "scan": { "export": true, "name": "Scan", "params": { @@ -298,7 +298,7 @@ "error" ] }, - "Scanf": { + "scanf": { "export": true, "name": "Scanf", "params": { @@ -318,7 +318,7 @@ "error" ] }, - "Scanln": { + "scanln": { "export": true, "name": "Scanln", "params": { @@ -333,7 +333,7 @@ "error" ] }, - "Sprint": { + "sprint": { "export": true, "name": "Sprint", "params": { @@ -347,7 +347,7 @@ "string" ] }, - "Sprintf": { + "sprintf": { "export": true, "name": "Sprintf", "params": { @@ -366,7 +366,7 @@ "string" ] }, - "Sprintln": { + "sprintln": { "export": true, "name": "Sprintln", "params": { @@ -380,7 +380,7 @@ "string" ] }, - "Sscan": { + "sscan": { "export": true, "name": "Sscan", "params": { @@ -400,7 +400,7 @@ "error" ] }, - "Sscanf": { + "sscanf": { "export": true, "name": "Sscanf", "params": { @@ -425,7 +425,7 @@ "error" ] }, - "Sscanln": { + "sscanln": { "export": true, "name": "Sscanln", "params": { diff --git a/test/src/main.ms b/test/src/main.ms index 99646a0..d994a44 100644 --- a/test/src/main.ms +++ b/test/src/main.ms @@ -3,5 +3,5 @@ package main; import "fmt"; function main() { - fmt.Println("hello"); + fmt.println("hello"); } From 141d2ab7b050cb8213a923ca08edb7956574212c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 09:42:55 +0200 Subject: [PATCH 15/16] Token naming fix --- semantic/src/hir.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs index 7b37dae..c5640d5 100644 --- a/semantic/src/hir.rs +++ b/semantic/src/hir.rs @@ -206,8 +206,8 @@ impl PackageRef { variables: HashMap::new(), }; - for (_, symbol) in &json_scope.functions { - scope.function_ref(json_scope, symbol); + for (token_name, symbol) in &json_scope.functions { + scope.function_ref(json_scope, token_name, symbol); } for (_, symbol) in &json_scope.structs { @@ -217,11 +217,16 @@ impl PackageRef { scope } - pub fn function_ref(&mut self, json_scope: &JSONScope, symbol: &FunctionSymbol) { + pub fn function_ref( + &mut self, + json_scope: &JSONScope, + token_name: &String, + symbol: &FunctionSymbol, + ) { if self.variables.get(&symbol.name).is_none() { let name = symbol.name.clone(); - if let Some(_) = json_scope.functions.get(&symbol.name) { + if let Some(_) = json_scope.functions.get(token_name) { let rf = FunctionRef { export: symbol.export, name: name.clone(), @@ -237,7 +242,7 @@ impl PackageRef { }; self.variables.insert( - symbol.name.clone(), + token_name.clone(), Arc::new(VarRef { export: false, name: name.clone(), From d514fa9efca9ac9ed0e8ed31bd89c2d7c27c03fc Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Wed, 22 Apr 2026 09:49:09 +0200 Subject: [PATCH 16/16] Fix expression statement --- semantic/src/scope.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs index 6cd3f5c..4ad0655 100644 --- a/semantic/src/scope.rs +++ b/semantic/src/scope.rs @@ -100,6 +100,9 @@ impl LocalScope { ); } } + Statement::Expression(e) => { + self.get_type_from_expr(e); + } _ => {} } }