diff --git a/Cargo.lock b/Cargo.lock index d08efc2..b134b8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,6 +77,15 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "mist" version = "0.1.0" +dependencies = [ + "parser", + "serde", + "serde_json", +] + +[[package]] +name = "parser" +version = "0.1.0" dependencies = [ "pest", "pest_derive", diff --git a/Cargo.toml b/Cargo.toml index 3f1f1f9..9afc151 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] -pest = "2.8.6" -pest_derive = "2.8.6" serde = { version = "1.0.228", features = ["serde_derive"] } serde_json = "1.0.149" +parser = { path = "./parser" } diff --git a/parser/Cargo.toml b/parser/Cargo.toml new file mode 100644 index 0000000..fcd7fd0 --- /dev/null +++ b/parser/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "parser" +version = "0.1.0" +edition = "2024" + +[dependencies] +pest = "2.8.6" +pest_derive = "2.8.6" +serde = { version = "1.0.228", features = ["serde_derive"] } +serde_json = "1.0.149" diff --git a/src/parser/ast.rs b/parser/src/ast.rs similarity index 100% rename from src/parser/ast.rs rename to parser/src/ast.rs diff --git a/src/parser/grammar.pest b/parser/src/grammar.pest similarity index 100% rename from src/parser/grammar.pest rename to parser/src/grammar.pest diff --git a/src/parser/mod.rs b/parser/src/lib.rs similarity index 99% rename from src/parser/mod.rs rename to parser/src/lib.rs index 152f95c..7b1a67a 100644 --- a/src/parser/mod.rs +++ b/parser/src/lib.rs @@ -5,7 +5,7 @@ pub mod ast; use ast::*; #[derive(Parser)] -#[grammar = "./src/parser/grammar.pest"] +#[grammar = "./src/grammar.pest"] pub struct MistParser; // convenience alias for pest errors diff --git a/semantic/Cargo.toml b/semantic/Cargo.toml new file mode 100644 index 0000000..c290a2c --- /dev/null +++ b/semantic/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "semantic" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/semantic/src/lib.rs b/semantic/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/semantic/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); + } +} diff --git a/src/compiler.rs b/src/compiler.rs deleted file mode 100644 index 136aed5..0000000 --- a/src/compiler.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::{fs, path::PathBuf, process, time::Instant}; - -use crate::{gogen, parser}; - -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 ast = match parser::parse(&source) { - Ok(ast) => { - println!(" ✓ parsed {} items", ast.len()); - ast - } - Err(e) => { - eprintln!("error: parse failed\n{}", e); - process::exit(1); - } - }; - - println!(" → generating Go code..."); - - // let output = gogen::generate(&ast); - let output = String::from("// TODO: implement code generation\n"); - - // 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/errors.rs b/src/errors.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/gogen/mod.rs b/src/gogen/mod.rs deleted file mode 100644 index d41f710..0000000 --- a/src/gogen/mod.rs +++ /dev/null @@ -1,283 +0,0 @@ -// use crate::parser::ast::{ -// BinOperator, Class, Expression, Function, Statement, Struct, TopLevel, TopLevel, TypeExpr, -// }; - -// pub fn generate(program: &TopLevel) -> String { -// let mut out = String::new(); - -// out.push_str("package main\n\n"); - -// // imports -// let mut imports = vec![]; -// for item in &program.statements { -// if let TopLevel::Import(i) = item { -// imports.push(i.path.clone()); -// } -// } - -// if !imports.is_empty() { -// out.push_str("import (\n"); -// for imp in imports { -// out.push_str(&format!(" {}\n", imp)); -// } -// out.push_str(")\n\n"); -// } - -// // rest -// for item in &program.statements { -// match item { -// TopLevel::Function(f) => out.push_str(&gen_function(f)), -// TopLevel::Struct(s) => out.push_str(&gen_struct(s)), -// TopLevel::Class(c) => out.push_str(&gen_class(c)), -// TopLevel::Import(_) => {} -// } -// out.push('\n'); -// } - -// out -// } - -// fn gen_struct(s: &Struct) -> String { -// let mut out = format!("type {} struct {{\n", s.name); - -// for field in &s.fields { -// out.push_str(&format!( -// " {} {}\n", -// capitalize(&field.name), -// gen_type(&field.type_expr) -// )); -// } - -// out.push_str("}\n"); -// out -// } - -// fn gen_class(c: &Class) -> String { -// let mut out = String::new(); - -// // struct -// out.push_str(&format!("type {} struct {{\n", c.name)); -// for field in &c.fields { -// out.push_str(&format!( -// " {} {}\n", -// capitalize(&field.name), -// gen_type(&field.type_expr) -// )); -// } -// out.push_str("}\n\n"); - -// // methods -// for method in &c.methods { -// out.push_str(&gen_method(c, method)); -// out.push('\n'); -// } - -// out -// } - -// fn gen_function(f: &Function) -> String { -// let mut out = format!("func {}(", f.name); - -// // params -// for (i, p) in f.params.iter().enumerate() { -// if i > 0 { -// out.push_str(", "); -// } -// out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); -// } - -// out.push(')'); - -// // return -// if let Some(ret) = &f.return_type { -// out.push_str(&format!(" {}", gen_type(ret))); -// } - -// out.push_str(" {\n"); - -// for stmt in &f.body { -// out.push_str(&gen_statement(stmt)); -// } - -// out.push_str("}\n"); -// out -// } - -// fn gen_method(class: &Class, f: &Function) -> String { -// let mut out = format!("func (self *{}) {}(", class.name, f.name); - -// for (i, p) in f.params.iter().enumerate() { -// if i > 0 { -// out.push_str(", "); -// } -// out.push_str(&format!("{} {}", p.name, gen_type(&p.type_expr))); -// } - -// out.push(')'); - -// if let Some(ret) = &f.return_type { -// out.push_str(&format!(" {}", gen_type(ret))); -// } - -// out.push_str(" {\n"); - -// for stmt in &f.body { -// out.push_str(&gen_statement(stmt)); -// } - -// out.push_str("}\n"); - -// out -// } - -// fn gen_statement(stmt: &Statement) -> String { -// match stmt { -// Statement::Let(s) => { -// let mut out = format!(" {} := {}", s.name, gen_expr(&s.value)); - -// out.push_str(";\n"); -// out -// } - -// Statement::Return(r) => match &r.value { -// Some(v) => format!(" return {};\n", gen_expr(v)), -// None => " return;\n".to_string(), -// }, - -// Statement::Expression(e) => { -// format!(" {};\n", gen_expr(e)) -// } - -// Statement::If(i) => { -// let mut out = format!(" if {} {{\n", gen_expr(&i.condition)); - -// for stmt in &i.body { -// out.push_str(&gen_statement(stmt)); -// } - -// out.push_str(" }"); - -// if let Some(else_body) = &i.else_body { -// out.push_str(" else {\n"); -// for stmt in else_body { -// out.push_str(&gen_statement(stmt)); -// } -// out.push_str(" }"); -// } - -// out.push('\n'); -// out -// } - -// Statement::For(f) => { -// let mut out = format!( -// " for _, {} := range {} {{\n", -// f.var, -// gen_expr(&f.iterator) -// ); - -// for stmt in &f.body { -// out.push_str(&gen_statement(stmt)); -// } - -// out.push_str(" }\n"); -// out -// } -// } -// } - -// fn gen_expr(expr: &Expression) -> String { -// match expr { -// Expression::Identifier(name, _) => name.clone(), -// Expression::Integer(v, _) => v.to_string(), -// Expression::Float(v, _) => v.to_string(), -// Expression::StringLit(s, _) => format!("\"{}\"", s), -// Expression::Bool(b, _) => b.to_string(), - -// Expression::BinaryOp(b) => format!( -// "{} {} {}", -// gen_expr(&b.left), -// op_to_str(&b.op), -// gen_expr(&b.right) -// ), - -// Expression::Call(c) => { -// let args = c.args.iter().map(gen_expr).collect::>().join(", "); -// format!("{}({})", gen_expr(&c.callee), args) -// } - -// Expression::FieldAccess(f) => { -// format!("{}.{}", gen_expr(&f.object), capitalize(&f.field)) -// } - -// Expression::StructInit(s) => { -// let mut out = format!("{}{{", s.name); - -// for (i, (name, val)) in s.fields.iter().enumerate() { -// if i > 0 { -// out.push_str(", "); -// } -// out.push_str(&format!("{}: {}", capitalize(name), gen_expr(val))); -// } - -// out.push('}'); -// out -// } - -// Expression::ArrayLiteral(arr) => { -// let elems = arr -// .elements -// .iter() -// .map(gen_expr) -// .collect::>() -// .join(", "); -// format!("[]any{{{}}}", elems) // simple version -// } - -// _ => todo!(), -// } -// } - -// fn gen_type(t: &TypeExpr) -> String { -// match t { -// TypeExpr::Named(n) => match n.as_str() { -// "int" => "int".into(), -// "float" => "float64".into(), -// "string" => "string".into(), -// _ => n.clone(), -// }, - -// TypeExpr::Array(inner) => { -// format!("[]{}", gen_type(inner)) -// } - -// TypeExpr::Optional(inner) => { -// format!("*{}", gen_type(inner)) // pointer for optional -// } -// } -// } - -// fn capitalize(s: &str) -> String { -// let mut chars = s.chars(); -// match chars.next() { -// Some(c) => c.to_uppercase().collect::() + chars.as_str(), -// None => String::new(), -// } -// } - -// fn op_to_str(op: &BinOperator) -> &'static str { -// match op { -// BinOperator::Add => "+", -// BinOperator::Sub => "-", -// BinOperator::Mul => "*", -// BinOperator::Div => "/", -// BinOperator::Eq => "==", -// BinOperator::NotEq => "!=", -// BinOperator::Lt => "<", -// BinOperator::Gt => ">", -// BinOperator::LtEq => "<=", -// BinOperator::GtEq => ">=", -// BinOperator::And => "&&", -// BinOperator::Or => "||", -// } -// } diff --git a/src/gogen/sourcemap.rs b/src/gogen/sourcemap.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/main.rs b/src/main.rs index d2d17ea..ad40e2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,3 @@ -pub mod compiler; -pub mod errors; -pub mod gogen; -pub mod parser; - use std::fs; use std::path::PathBuf; use std::process; @@ -52,7 +47,7 @@ fn main() { } pub fn cmd_build() { - compiler::build(); + unimplemented!("build command is not implemented yet"); } fn cmd_check(path: &str) {