diff --git a/Cargo.lock b/Cargo.lock index bd912aa..b134b8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,6 @@ name = "mist" version = "0.1.0" dependencies = [ "parser", - "semantic", "serde", "serde_json", ] @@ -155,15 +154,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "semantic" -version = "0.1.0" -dependencies = [ - "parser", - "serde", - "serde_json", -] - [[package]] name = "serde" version = "1.0.228" diff --git a/Cargo.toml b/Cargo.toml index 2a9e8f2..9afc151 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,3 @@ edition = "2024" serde = { version = "1.0.228", features = ["serde_derive"] } serde_json = "1.0.149" parser = { path = "./parser" } -semantic = { path = "./semantic" } diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 5028788..7478c7a 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -64,7 +64,7 @@ pub enum Statement { // let/const/var x = ... VarDecl { - kind: VarKind, + mutable: bool, name: String, init: Option, type_: Option, @@ -90,7 +90,7 @@ pub enum Statement { // for (...) stmt For { - init: (VarKind, String, Option), + init: (bool, String, Option), condition: Option, update: Option>, body: Box, @@ -115,10 +115,3 @@ pub enum Expression { postfixes: Vec, }, } - -#[derive(Debug, Clone, Serialize)] -pub enum VarKind { - Let, - Const, - Var, -} diff --git a/parser/src/lib.rs b/parser/src/lib.rs index f71ad03..e9e15b8 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -188,7 +188,7 @@ impl From> for Statement { let init = inner.next().map(Expression::from); Statement::VarDecl { - kind: VarKind::Var, + mutable: false, name: name.as_str().to_string(), init, type_, @@ -243,19 +243,12 @@ impl From> for Statement { Rule::var_decl => { let mut it = p.into_inner(); - let kind = match it.next().unwrap().as_str() { - "let" => VarKind::Let, - "const" => VarKind::Const, - "var" => VarKind::Var, - _ => unreachable!(), - }; - let name = it.next().unwrap().as_str().to_string(); let init_expr = it .next() .map(|e| Expression::from(e.into_inner().next().unwrap())); - (kind, name, init_expr) + (false, name, init_expr) } _ => unimplemented!( "For loop init parsing not implemented yet: {:?}", diff --git a/semantic/Cargo.toml b/semantic/Cargo.toml deleted file mode 100644 index cbebdd1..0000000 --- a/semantic/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "semantic" -version = "0.1.0" -edition = "2024" - -[dependencies] -parser = { path = "../parser" } -serde = { version = "1.0.228", features = ["serde_derive"] } -serde_json = "1.0.149" diff --git a/semantic/src/hir.rs b/semantic/src/hir.rs deleted file mode 100644 index c5640d5..0000000 --- a/semantic/src/hir.rs +++ /dev/null @@ -1,318 +0,0 @@ -use std::{ - collections::HashMap, - sync::{ - Arc, - atomic::{AtomicUsize, Ordering}, - }, -}; - -use crate::top_level::{ - FunctionSymbol, JSONScope, StructSymbol, TopLevelSymbolScope, TypeSymbol, VarSymbol, -}; - -#[derive(Clone, Debug)] -pub enum TypeRef { - Struct(StructRef), - Function(FunctionRef), - Package(PackageRef), - Name(String), -} - -#[derive(Clone, Debug)] -pub struct PackageRef { - pub name: String, - pub variables: HashMap>, -} - -#[derive(Clone, Debug)] -pub struct VarRef { - pub export: bool, - pub var_type: Arc, - pub name: String, -} - -#[derive(Clone, Debug)] -pub struct FunctionRef { - pub export: bool, - pub name: String, - pub params: HashMap>, - pub return_type: Option>, -} - -#[derive(Clone, Debug)] -pub struct StructRef { - pub export: bool, - pub name: String, - pub fields: HashMap>, -} - -#[derive(Debug)] -pub struct TopLevelHirScope { - pub variables: HashMap>, - pub var_idx: AtomicUsize, -} - -impl TopLevelHirScope { - pub fn from_tlss(tlss: &TopLevelSymbolScope) -> Self { - let mut scope = Self { - variables: HashMap::new(), - var_idx: AtomicUsize::new(0), - }; - - for (_, symbol) in &tlss.functions { - scope.function_ref(tlss, symbol); - } - - for (_, symbol) in &tlss.structs { - 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 - } - - pub fn function_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &FunctionSymbol) { - if self.variables.get(&symbol.name).is_none() { - let name = self.get_name(symbol.export); - - if let Some(_) = tlss.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(tlss, v))) - .collect(), - return_type: symbol - .return_type - .clone() - .map(|rt| self.type_ref(tlss, &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, - tlss: &TopLevelSymbolScope, - symbol: &StructSymbol, - ) -> Arc { - if let Some(rf) = self.variables.get(&symbol.name) { - rf.var_type.clone() - } else { - let name = self.get_name(symbol.export); - - 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(tlss, 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, tlss: &TopLevelSymbolScope, symbol: &VarSymbol) -> Arc { - Arc::new(VarRef { - export: symbol.export, - var_type: self.type_ref(tlss, &symbol.var_type), - name: self.get_name(symbol.export), - }) - } - - pub fn type_ref(&mut self, tlss: &TopLevelSymbolScope, symbol: &TypeSymbol) -> Arc { - if let Some(var_ref) = self.variables.get(&symbol.0) { - var_ref.var_type.clone() - } else { - if let Some(tlss_rf) = tlss.structs.get(&symbol.0) { - self.struct_ref(tlss, tlss_rf) - } else { - 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()); - - var_ref.var_type.clone() - } - } - } - - pub fn get_reference(&self, name: &String) -> Option> { - self.variables.get(name).cloned() - } - - pub fn next_var_idx(&self) -> usize { - self.var_idx.fetch_add(1, Ordering::Relaxed) - } - - pub fn get_name(&self, export: bool) -> String { - format!("{}{}", if export { 'V' } else { 'v' }, self.next_var_idx()) - } -} - -impl TypeRef { - pub fn get_name(&self) -> String { - match self { - TypeRef::Function(f) => f.name.clone(), - TypeRef::Struct(s) => s.name.clone(), - TypeRef::Package(p) => p.name.clone(), - TypeRef::Name(n) => n.clone(), - } - } -} - -impl PackageRef { - pub fn from_tlss(json_scope: &JSONScope) -> Self { - let mut scope = Self { - name: json_scope.package_name.clone(), - variables: HashMap::new(), - }; - - for (token_name, symbol) in &json_scope.functions { - scope.function_ref(json_scope, token_name, symbol); - } - - for (_, symbol) in &json_scope.structs { - scope.struct_ref(json_scope, symbol); - } - - scope - } - - 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(token_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( - token_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 { - 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()); - - var_ref.var_type.clone() - } - } - } - - 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 deleted file mode 100644 index aa5ba6d..0000000 --- a/semantic/src/lib.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::{collections::HashMap, sync::Arc}; - -use parser::ast::{ParamList, TypeExpr}; - -use crate::{ - hir::VarRef, - scope::{LocalScope, Scope}, -}; - -pub mod hir; -pub mod scope; -pub mod top_level; - -pub fn walk_ast(top_scope: Arc, tl: &mut Vec) { - for tl in tl { - match tl { - parser::ast::TopLevel::Import(_) => {} - - parser::ast::TopLevel::FunctionDecl { - params, body, name, .. - } => { - let rf = top_scope.get_reference(name).unwrap(); - - if name != "main" { - *name = rf.name.clone(); - } - - let scope = LocalScope::new(top_scope.clone()); - - scope.with_params(params); - - scope.with_block(body); - } - - parser::ast::TopLevel::StructDecl { name, fields, .. } => { - let rf = top_scope.get_reference(name).unwrap(); - *name = rf.name.clone(); - - match &*rf.var_type { - hir::TypeRef::Struct(s) => walk_param_list(&s.fields, fields), - _ => unimplemented!(), - } - } - } - } -} - -pub fn walk_param_list(fields: &HashMap>, param_list: &mut ParamList) { - let old_param_list = param_list.clone(); - param_list.0.clear(); - - for (name, param) in fields { - param_list.0.insert( - param.name.clone(), - ( - old_param_list.0.get(name).map(|a| a.0).unwrap_or_default(), - TypeExpr::Identifier(param.var_type.get_name()), - ), - ); - } -} diff --git a/semantic/src/scope.rs b/semantic/src/scope.rs deleted file mode 100644 index a80a0de..0000000 --- a/semantic/src/scope.rs +++ /dev/null @@ -1,294 +0,0 @@ -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; - -use parser::ast::{self, ParamList, Postfix, Statement}; - -use crate::{ - hir::{TopLevelHirScope, TypeRef, VarRef}, - top_level::TopLevelSymbolScope, -}; - -#[derive(Debug)] -pub enum Scope { - TopLevel(TopLevelHirScope), - Local(LocalScope), -} - -impl Scope { - 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))) - } - - pub fn get_reference(&self, name: &String) -> Option> { - match self { - Scope::TopLevel(tl) => tl.get_reference(name), - Scope::Local(l) => l.get_reference(name), - } - } - - pub fn next_var_idx(&self) -> usize { - match self { - Scope::TopLevel(tl) => tl.next_var_idx(), - Scope::Local(l) => l.parent.next_var_idx(), - } - } - - pub fn get_name(&self, export: bool) -> String { - format!("{}{}", if export { 'V' } else { 'v' }, self.next_var_idx()) - } -} - -#[derive(Debug)] -pub struct LocalScope { - pub parent: Arc, - pub variables: Mutex>>, -} - -impl LocalScope { - pub fn new(parent: Arc) -> Arc { - Arc::new(LocalScope { - parent, - variables: Mutex::new(HashMap::new()), - }) - } - - pub fn get_reference(&self, name: &String) -> Option> { - self.variables - .lock() - .unwrap() - .get(name) - .cloned() - .or_else(|| self.parent.get_reference(name)) - } - - pub fn get_type_reference(&self, name: &String) -> Option> { - match self.get_reference(name) { - Some(v) => Some(v), - 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()); - - Some(var_ref) - } - } - } - - pub fn with_statement(self: &Arc, statement: &mut Statement) { - match statement { - Statement::Block(b) => self.clone().with_block(b), - Statement::VarDecl { - name, init, type_, .. - } => { - if let Some(init) = init { - let init_type = self.get_type_from_expr(init); - let var_type = type_ - .as_mut() - .map(|t| self.get_type_from_type_expr(t)) - .or_else(|| Some(init_type)) - .unwrap() - .unwrap(); - - let var_name = name.clone(); - - *name = self.parent.get_name(false); - - self.variables.lock().unwrap().insert( - var_name, - Arc::new(VarRef { - export: false, - name: name.clone(), - var_type, - }), - ); - } - } - Statement::Expression(e) => { - self.get_type_from_expr(e); - } - Statement::If { - condition, - then_branch, - else_branch, - } => { - self.get_type_from_expr(condition); - self.clone().with_statement(then_branch); - if let Some(else_branch) = else_branch { - self.clone().with_statement(else_branch); - } - } - Statement::Return(expr) => { - if let Some(expr) = expr { - self.get_type_from_expr(expr); - } - } - _ => {} - } - } - - pub fn with_block(self: &Arc, block: &mut parser::ast::Block) { - for statement in &mut block.0 { - self.with_statement(statement); - } - } - - pub fn walk_postfixes( - self: &Arc, - initial: &mut Box, - postfixes: &mut Vec, - ) -> Option> { - let mut current_type = self.get_type_from_expr(initial)?; - - for postfix in postfixes { - match postfix { - Postfix::FieldAccess(id) => match &*current_type { - TypeRef::Struct(s) => { - let field = s.fields.get(id)?; - *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 { - TypeRef::Function(s) => { - for arg in args { - self.get_type_from_expr(arg); - } - current_type = s.return_type.clone()?; - } - _ => unimplemented!(), - }, - Postfix::StructCall(fields) => match &*current_type { - TypeRef::Struct(s) => { - let mut old_fields = fields.clone(); - - fields.clear(); - - for (name, mut expr) in old_fields.drain() { - self.get_type_from_expr(&mut expr); - fields.insert(s.fields.get(&name).unwrap().name.clone(), expr); - } - } - _ => unimplemented!(), - }, - Postfix::Binary(op, right) => match op { - parser::ast::BinaryOp::Equal - | parser::ast::BinaryOp::NotEqual - | parser::ast::BinaryOp::GreaterThan - | parser::ast::BinaryOp::LessThan - | parser::ast::BinaryOp::GreaterThanOrEqual - | parser::ast::BinaryOp::LessThanOrEqual => { - self.get_type_from_expr(right)?; - current_type = Arc::new(TypeRef::Name("bool".to_string())); - } - parser::ast::BinaryOp::Plus - | parser::ast::BinaryOp::Minus - | parser::ast::BinaryOp::Multiply - | parser::ast::BinaryOp::Divide - | parser::ast::BinaryOp::Modulo => { - self.get_type_from_expr(right)?; - } - }, - _ => unimplemented!(), - } - } - - Some(current_type) - } - - pub fn get_type_from_type_expr( - self: &Arc, - expr: &mut ast::TypeExpr, - ) -> Option> { - match expr { - ast::TypeExpr::Identifier(id) => { - if let Some(v) = self.get_type_reference(id).map(|r| r.var_type.clone()) { - *id = v.get_name(); - Some(v) - } else { - None - } - } - } - } - - pub fn get_type_from_expr( - self: &Arc, - expr: &mut ast::Expression, - ) -> Option> { - match expr { - ast::Expression::IntLiteral(_) => self - .get_type_reference(&"int".to_string()) - .map(|r| r.var_type.clone()), - - ast::Expression::FloatLiteral(_) => self - .get_type_reference(&"float".to_string()) - .map(|r| r.var_type.clone()), - - ast::Expression::BoolLiteral(_) => self - .get_type_reference(&"bool".to_string()) - .map(|r| r.var_type.clone()), - - ast::Expression::StringLiteral(_) => self - .get_type_reference(&"string".to_string()) - .map(|r| r.var_type.clone()), - - ast::Expression::Identifier(id) => { - let rf = self.get_reference(id)?; - *id = rf.name.clone(); - Some(rf.var_type.clone()) - } - - ast::Expression::Postfix { initial, postfixes } => { - self.walk_postfixes(initial, postfixes) - } - } - } - - pub fn with_params(self: &Arc, param_list: &mut ParamList) { - let mut new_param_list = HashMap::new(); - - for (param_name, (export, type_expr)) in param_list.0.drain() { - match &type_expr { - parser::ast::TypeExpr::Identifier(id) => { - let new_name = self.parent.get_name(export); - - self.variables.lock().unwrap().insert( - param_name.clone(), - Arc::new(VarRef { - export: export, - var_type: self - .parent - .get_reference(id) - .map(|r| r.var_type.clone()) - .unwrap(), - name: new_name.clone(), - }), - ); - - new_param_list.insert(new_name, (export, type_expr)); - } - } - } - - param_list.0 = new_param_list; - } -} diff --git a/semantic/src/top_level.rs b/semantic/src/top_level.rs deleted file mode 100644 index 1f8543e..0000000 --- a/semantic/src/top_level.rs +++ /dev/null @@ -1,174 +0,0 @@ -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, Serialize, Deserialize)] -pub struct TypeSymbol(pub String); - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct VarSymbol { - pub export: bool, - pub var_type: TypeSymbol, - pub name: String, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FunctionSymbol { - pub export: bool, - pub name: String, - pub params: HashMap, - pub return_type: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct StructSymbol { - pub export: bool, - pub name: String, - pub fields: HashMap, - pub methods: HashMap, -} - -impl TypeSymbol { - pub fn from_ast(expr: TypeExpr) -> Self { - TypeSymbol(match expr { - TypeExpr::Identifier(i) => i.to_string(), - }) - } -} - -impl FunctionSymbol { - pub fn from_ast( - export: bool, - name: String, - params: ParamList, - return_type: Option, - ) -> Self { - Self { - export: export, - name: name.clone(), - params: params - .0 - .iter() - .map(|(name, (export, v))| { - ( - name.clone(), - VarSymbol { - export: *export, - name: name.clone(), - var_type: TypeSymbol(match v { - TypeExpr::Identifier(i) => i.to_string(), - }), - }, - ) - }) - .collect(), - return_type: return_type.map(TypeSymbol::from_ast), - } - } -} - -impl StructSymbol { - pub fn from_ast(export: bool, name: String, fields: ParamList) -> Self { - Self { - export, - name, - fields: fields - .0 - .iter() - .map(|(name, (export, v))| { - ( - name.clone(), - VarSymbol { - export: *export, - name: name.clone(), - var_type: TypeSymbol(match v { - TypeExpr::Identifier(i) => i.to_string(), - }), - }, - ) - }) - .collect(), - // TODO - parse struct methods - methods: HashMap::new(), - } - } -} - -#[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(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(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.replace("\"", "")) - .unwrap() - .clone(); - - scope - .imports - .insert(json_scope.package_name.clone(), json_scope); - } - - TopLevel::FunctionDecl { - export, - name, - params, - return_type, - .. - } => { - scope.functions.insert( - name.clone(), - FunctionSymbol::from_ast( - *export, - name.clone(), - params.clone(), - return_type.clone(), - ), - ); - } - - TopLevel::StructDecl { - export, - name, - fields, - } => { - scope.structs.insert( - name.clone(), - StructSymbol::from_ast(*export, name.clone(), fields.clone()), - ); - } - } - } - - scope - } -} diff --git a/src/codegen.rs b/src/codegen.rs index 29d6eb6..04dcfce 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,11 +1,11 @@ -use parser::ast::{BinaryOp, Block, Expression, Postfix, Statement, TopLevel, TypeExpr, VarKind}; +use parser::ast::{BinaryOp, Block, Expression, Postfix, Statement, TopLevel, TypeExpr}; -pub struct GoCodegen { +pub struct RustCodegen { output: String, indent: usize, } -impl GoCodegen { +impl RustCodegen { pub fn new() -> Self { Self { output: String::new(), @@ -17,10 +17,6 @@ impl GoCodegen { " ".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); } @@ -31,8 +27,7 @@ impl GoCodegen { } fn add_indentedln(&mut self, s: &str) { - self.add_indented(s); - self.add("\n"); + self.add(&format!("{}{}\n", self.indent_str(), s)); } pub fn generate(&mut self, toplevels: &[TopLevel]) -> String { @@ -45,29 +40,29 @@ impl GoCodegen { 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(""); + let path = path.replace("\"", ""); + self.addln(&format!("use {};", path)); } + TopLevel::StructDecl { export, name, fields, } => { - let name = if *export { name } else { name }; - self.addln(&format!("type {} struct {{", name)); + let vis = if *export { "pub " } else { "" }; + + self.addln(&format!("{}struct {} {{", vis, 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)); + let ty = self.translate_type(ty); + self.add_indentedln(&format!("pub {}: {},", field_name, ty)); } + self.indent -= 1; self.addln("}\n"); } + TopLevel::FunctionDecl { export, name, @@ -75,31 +70,26 @@ impl GoCodegen { return_type, body, } => { - let name = if *export { - format!("{}", name) - } else { - name.clone() - }; + let vis = if *export { "pub " } else { "" }; + let params_str = params .0 .iter() - .map(|(n, (_, t))| format!("{} {}", n, self.translate_type(t))) + .map(|(n, (_, t))| format!("{}: {}", n, self.translate_type(t))) .collect::>() .join(", "); - let ret_ty = return_type + let ret = return_type .as_ref() - .map(|t| self.translate_type(t)) - .unwrap_or_else(|| "".to_string()); + .map(|t| format!(" -> {}", self.translate_type(t))) + .unwrap_or_default(); + + self.addln(&format!("{}fn {}({}){} {{", vis, name, params_str, ret)); - 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"); } } @@ -108,13 +98,11 @@ impl GoCodegen { 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(), + "int" => "i32".into(), + "float" | "float64" => "f64".into(), + "float32" => "f32".into(), + "bool" => "bool".into(), + "string" => "String".into(), _ => name.clone(), }, } @@ -131,112 +119,92 @@ impl GoCodegen { 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"); + self.add_indentedln("}"); } + Statement::VarDecl { - kind, + mutable, name, init, type_, } => { - let go_kind = match kind { - VarKind::Let | VarKind::Const => "var", - VarKind::Var => "var", - }; - let init_expr = init + let mutability = if *mutable { "mut " } else { "" }; + + let ty = type_ + .as_ref() + .map(|t| format!(": {}", self.translate_type(t))) + .unwrap_or_default(); + + let init = init .as_ref() .map(|e| format!(" = {}", self.generate_expression(e))) - .unwrap_or_else(|| "".to_string()); - let type_expr = type_ - .clone() - .map(|t| self.translate_type(&t)) .unwrap_or_default(); - self.add_indentedln(&format!( - "{} {} {}{};\n", - go_kind, name, type_expr, init_expr - )); + + self.add_indentedln(&format!("let {}{}{}{};", mutability, name, ty, init)); } + 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.add_indentedln(&format!("if {} {{", self.generate_expression(condition))); + + self.indent += 1; self.generate_statement(then_branch); + self.indent -= 1; + + self.add_indentedln("}"); + if let Some(else_br) = else_branch { - self.add_indented("else "); + self.add_indentedln("else {"); + self.indent += 1; self.generate_statement(else_br); + self.indent -= 1; + self.add_indentedln("}"); } } + Statement::While { condition, body } => { - self.add_indented(&format!("for {} ", self.generate_expression(condition))); + self.add_indentedln(&format!("while {} {{", self.generate_expression(condition))); + + self.indent += 1; self.generate_statement(body); + self.indent -= 1; + + self.add_indentedln("}"); } - 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::For { .. } => { + // Rust doesn't support C-style for loops + self.add_indentedln("// TODO: transform into iterator-based loop"); } + Statement::Return(expr) => { - let ret_val = expr + let 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"); - } - } - } + .unwrap_or_default(); - fn stmt_to_expr(&self, stmt: &Statement) -> Expression { - match stmt { - Statement::Expression(e) => e.clone(), - _ => Expression::Identifier(String::new()), - } - } + self.add_indentedln(&format!("return {};", val)); + } - fn var_kind_to_go(&self, kind: &VarKind) -> String { - match kind { - VarKind::Let | VarKind::Const => "var".to_string(), - VarKind::Var => "var".to_string(), + Statement::Break => self.add_indentedln("break;"), + Statement::Continue => self.add_indentedln("continue;"), } } @@ -246,7 +214,8 @@ impl GoCodegen { Expression::IntLiteral(n) => n.to_string(), Expression::FloatLiteral(n) => n.to_string(), Expression::BoolLiteral(b) => b.to_string(), - Expression::StringLiteral(s) => format!("\"{}\"", s), + Expression::StringLiteral(s) => format!("\"{}\".to_string()", s), + Expression::Postfix { initial, postfixes } => { let base = self.generate_expression(initial); self.apply_postfixes(&base, postfixes) @@ -256,28 +225,35 @@ impl GoCodegen { 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 + let args = args .iter() .map(|a| self.generate_expression(a)) .collect::>() .join(", "); - format!("{}({})", result, args_str) + format!("{}({})", result, args) } + Postfix::StructCall(fields) => { - let args_str = fields + let fields = fields .iter() - .map(|(a, b)| format!("{a}: {}", self.generate_expression(b))) + .map(|(k, v)| format!("{}: {}", k, self.generate_expression(v))) .collect::>() .join(", "); - format!("{}{{{}}}", result, args_str) + format!("{} {{ {} }}", result, fields) } - 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 { + let op = match op { BinaryOp::Plus => "+", BinaryOp::Minus => "-", BinaryOp::Multiply => "*", @@ -290,86 +266,18 @@ impl GoCodegen { BinaryOp::LessThanOrEqual => "<=", BinaryOp::GreaterThanOrEqual => ">=", }; - format!("{} {} {}", result, op_str, self.generate_expression(rhs)) + + format!("{} {} {}", result, op, self.generate_expression(rhs)) } }; } + result } } -impl Default for GoCodegen { +impl Default for RustCodegen { fn default() -> Self { Self::new() } } - -#[cfg(test)] -mod tests { - use super::*; - use parser::ast::{Block, Expression, ParamList, Statement, TopLevel, TypeExpr}; - use std::collections::HashMap; - - #[test] - 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")); - } -} diff --git a/src/compiler.rs b/src/compiler.rs index 01e0074..db5d31c 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -30,14 +30,6 @@ pub fn build() { let file_name = entry.file_name(); let file_name = file_name.to_string_lossy(); - let script = if file_name.ends_with(".ms") { - true - } else if file_name.ends_with(".mist") { - false - } else { - continue; - }; - // 3. read entry file let source = match fs::read_to_string(&entry_path) { Ok(s) => s, @@ -49,7 +41,7 @@ pub fn build() { let parser_result = parser::parse(&source).map_err(|e| e.to_string()); - let mut ast = match parser_result { + let ast = match parser_result { Ok(ast) => ast, Err(e) => { eprintln!("error: parse failed\n{}", e); @@ -57,9 +49,9 @@ pub fn build() { } }; - semantic::walk_ast(semantic::scope::Scope::from_top(&root, &ast), &mut ast); + // semantic::walk_ast(semantic::scope::Scope::from_top(&root, &ast), &mut ast); - let mut gc = crate::codegen::GoCodegen::new(); + let mut gc = crate::codegen::RustCodegen::new(); let output = gc.generate(&ast); if let Err(e) = fs::create_dir_all(&out_dir) { @@ -67,8 +59,7 @@ pub fn build() { process::exit(1); } - let out_file = - out_dir.join(file_name.replace(if script { ".ms" } else { ".mist" }, ".go")); + let out_file = out_dir.join(file_name.replace(".mist", ".rs")); if let Err(e) = fs::write(&out_file, output) { eprintln!("error: failed to write output\n {}", e); diff --git a/test/src/main.mist b/test/src/main.mist index e217fc6..8df4404 100644 --- a/test/src/main.mist +++ b/test/src/main.mist @@ -1,5 +1,3 @@ -package main; - public struct Idk { int a, int b,