Generated
+9
@@ -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",
|
||||
|
||||
+1
-2
@@ -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" }
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "semantic"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<PathBuf> {
|
||||
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")
|
||||
}
|
||||
@@ -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::<Vec<_>>().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::<Vec<_>>()
|
||||
// .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::<String>() + 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 => "||",
|
||||
// }
|
||||
// }
|
||||
+1
-6
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user