diff --git a/codegen/src/expr.rs b/codegen/src/expr.rs index 1729525..2b51f26 100644 --- a/codegen/src/expr.rs +++ b/codegen/src/expr.rs @@ -102,7 +102,10 @@ impl GenRust for Expression { if ensure_semicolon { ctx.expr_ensure_semicolon = true; - cg.add(";"); + + if !self.is_block() { + cg.add(";"); + } } } } @@ -166,9 +169,12 @@ impl GenRust for Postfix { Postfix::Call(args) => { cg.add("("); - for arg in args { + for (i, arg) in args.iter().enumerate() { + if i > 0 { + cg.add(", "); + } + arg.gen_rust(ctx, cg); - cg.add(", "); } cg.add(")"); diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index a2513fc..220cde2 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -81,6 +81,19 @@ impl RustCodegen { } } } + + pub fn ensure_brackets_expr(&mut self, ctx: &mut Context, expr: &Expression) { + match expr { + Expression::Statement(stmt) => self.ensure_brackets(ctx, stmt), + _ => { + self.add("{"); + self.indent += 1; + expr.gen_rust(ctx, self); + self.indent -= 1; + self.add("}"); + } + } + } } impl GenRust for Attribute { diff --git a/codegen/src/statement.rs b/codegen/src/statement.rs index 2274f5c..8f16fcb 100644 --- a/codegen/src/statement.rs +++ b/codegen/src/statement.rs @@ -18,10 +18,11 @@ impl GenRust for Block { if let Some(soft_return) = &self.1 { ctx.expr_ensure_semicolon = false; soft_return.gen_rust(ctx, cg); + cg.addln(""); } cg.indent -= 1; - cg.add_indentedln("}"); + cg.add_indented("}"); } } @@ -57,17 +58,14 @@ impl GenRust for Statement { p.gen_rust(ctx, cg); } - cg.add(" => {"); - cg.indent += 1; + cg.add(" => "); - body.gen_rust(ctx, cg); - - cg.indent -= 1; - cg.add_indentedln("}"); + cg.ensure_brackets_expr(ctx, body); } cg.indent -= 1; - cg.add_indentedln("}"); + cg.addln(""); + cg.add_indented("}"); } Statement::If { @@ -77,24 +75,32 @@ impl GenRust for Statement { } => { cg.add("if "); initial.condition.gen_rust(ctx, cg); - cg.ensure_brackets(ctx, &initial.body); + cg.add(" "); + cg.ensure_brackets_expr(ctx, &initial.body); for else_if_branch in else_if { cg.add("else if"); else_if_branch.condition.gen_rust(ctx, cg); - cg.ensure_brackets(ctx, &else_if_branch.body); + cg.add(" "); + cg.ensure_brackets_expr(ctx, &else_if_branch.body); } if let Some(else_br) = else_branch { - cg.add("else"); - cg.ensure_brackets(ctx, else_br); + cg.add(" else "); + cg.ensure_brackets_expr(ctx, else_br); } } Statement::While(StatementBranch { condition, body }) => { cg.add("while "); condition.gen_rust(ctx, cg); - cg.ensure_brackets(ctx, body); + cg.add(" "); + cg.ensure_brackets_expr(ctx, body); + } + + Statement::Loop(body) => { + cg.add("loop "); + cg.ensure_brackets_expr(ctx, body); } Statement::CStyleFor { @@ -103,28 +109,40 @@ impl GenRust for Statement { update, body, } => { - cg.add_indentedln("{"); + cg.addln("{"); cg.indent += 1; + ctx.expr_ensure_semicolon = true; + + cg.add_indented(""); + init.gen_rust(ctx, cg); - cg.add("while "); + cg.addln(""); + cg.add_indented("while "); + + ctx.expr_ensure_semicolon = false; condition.gen_rust(ctx, cg); - cg.add("{"); + cg.add(" "); + cg.add("{"); cg.indent += 1; - cg.ensure_brackets(ctx, body); + ctx.expr_ensure_semicolon = true; + + body.gen_rust(ctx, cg); update.gen_rust(ctx, cg); + cg.addln(""); + cg.indent -= 1; cg.add_indentedln("}"); cg.indent -= 1; - cg.add_indentedln("}"); + cg.add_indented("}"); } Statement::For { @@ -138,7 +156,7 @@ impl GenRust for Statement { pattern.gen_rust(ctx, cg); cg.add(" in "); iterator.gen_rust(ctx, cg); - cg.ensure_brackets(ctx, body); + cg.ensure_brackets_expr(ctx, body); } Statement::Return(expr) => { diff --git a/mist-test/src/app.mist b/mist-test/src/app.mist index 5c09745..9e68eb4 100644 --- a/mist-test/src/app.mist +++ b/mist-test/src/app.mist @@ -91,4 +91,33 @@ pub class Application { } } } -} \ No newline at end of file +} + +i32 test_stmt() { + if (0 == 0) { + 0 + } + else { + 1 + } +} + +void loops_test() { + for (x : 0..10) { + println!("{x}"); + } + + for (var mut i = 0; i < 10; i++) { + println!("{i}"); + } + + var i = 0; + + while (i == 1) { + println!("hi"); + } + + loop { + println!("loop!"); + } +} diff --git a/mist-test/src/logger.mist b/mist-test/src/logger.mist index e8ee98a..fab6cea 100644 --- a/mist-test/src/logger.mist +++ b/mist-test/src/logger.mist @@ -13,7 +13,7 @@ pub enum LogLevel { impl fmt::Display for LogLevel { fmt::Result fmt(self*, Formatter<'_> mut* f) { - return match (self) { + match (self) { LogLevel::Info => write!(f, "[INFO]"); LogLevel::Warning => write!(f, "[WARN]"); @@ -66,7 +66,7 @@ pub class Logger { impl fmt::Display { fmt::Result fmt(self*, Formatter<'_> mut* f) { - return write!(f, "logger ({})", self.prefix); + write!(f, "logger ({})", self.prefix) } } } \ No newline at end of file diff --git a/parser/src/ast/expr.rs b/parser/src/ast/expr.rs index 77962cb..75583e0 100644 --- a/parser/src/ast/expr.rs +++ b/parser/src/ast/expr.rs @@ -81,3 +81,13 @@ pub enum Generic { Lifetime(Identifier), Type(TypeExpr), } + +impl Expression { + pub fn is_block(&self) -> bool { + if let Expression::Statement(stmt) = self { + stmt.is_block() + } else { + false + } + } +} diff --git a/parser/src/ast/statement.rs b/parser/src/ast/statement.rs index a95429c..f0682c5 100644 --- a/parser/src/ast/statement.rs +++ b/parser/src/ast/statement.rs @@ -11,27 +11,28 @@ pub struct Block( #[derive(Debug, Clone, Serialize)] pub enum Statement { Block(Block), - VarDecl(VarDeclStmt), If { initial: StatementBranch, else_if: Vec, - else_branch: Option>, + else_branch: Option>, }, + Loop(Expression), While(StatementBranch), CStyleFor { - init: Box, + init: Expression, condition: Expression, - update: Box, - body: Box, + update: Expression, + body: Expression, }, For { mutable: bool, pattern: Pattern, iterator: Expression, - body: Box, + body: Box, }, Match(Expression, Vec<(Vec, Expression)>), + VarDecl(VarDeclStmt), Return(Option), Break, Continue, @@ -53,5 +54,29 @@ pub struct VarDeclStmt { #[derive(Debug, Clone, Serialize)] pub struct StatementBranch { pub condition: Expression, - pub body: Box, + pub body: Box, +} + +impl Statement { + pub fn is_block(&self) -> bool { + match self { + Self::Block(_) => true, + Self::If { + initial, + else_if, + else_branch, + } => { + else_branch + .as_ref() + .map(|v| v.is_block()) + .unwrap_or_default() + || else_if + .last() + .map(|b| b.body.is_block()) + .unwrap_or_default() + || initial.body.is_block() + } + _ => false, + } + } } diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 8e03ebc..5a87ca1 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -29,6 +29,7 @@ keyword = { | "true" | "false" | "dyn" + | "loop" } identifier = @{ @@ -379,6 +380,7 @@ control_flow = { | c_for_stmt | for_stmt | match_stmt + | loop_stmt | block } @@ -405,11 +407,15 @@ while_stmt = { } c_for_stmt = { - "for" ~ "(" ~ statement ~ expr ~ semicolon ~ statement ~ ")" ~ statement + "for" ~ "(" ~ statement ~ statement ~ expr ~ ")" ~ statement } for_stmt = { - "for" ~ "(" ~ mutable? ~ pattern ~ "in" ~ expr ~ ")" ~ statement + "for" ~ "(" ~ mutable? ~ pattern ~ ":" ~ expr ~ ")" ~ statement +} + +loop_stmt = { + "loop" ~ statement } // ------------------------------------------------------ diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 6c8bfa2..7ed8227 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -65,7 +65,7 @@ impl<'a> TryFrom> for Statement { else_if: collect_recovered(inner.next().unwrap().into_inner()), else_branch: inner .next() - .map(Statement::try_from) + .map(Expression::try_from) .transpose() .map(|v| v.map(Box::new)) .get_map(|v| { Some(Box::new(v)) }), @@ -74,11 +74,13 @@ impl<'a> TryFrom> for Statement { Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())), + Rule::loop_stmt => ast_expr!(Statement::Loop(inner.next().unwrap().try_into())), + Rule::c_for_stmt => ast_expr!(Statement::CStyleFor { - init: inner.next().unwrap().try_into().map(Box::new), + init: inner.next().unwrap().try_into(), condition: inner.next().unwrap().try_into(), - update: inner.next().unwrap().try_into().map(Box::new), - body: inner.next().unwrap().try_into().map(Box::new), + update: inner.next().unwrap().try_into(), + body: inner.next().unwrap().try_into(), }), Rule::for_stmt => ast_expr!(Statement::For { diff --git a/src/builder.rs b/src/builder.rs index 34afc8a..f59da2d 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,7 +1,7 @@ use std::{ collections::HashMap, env, fs, - path::PathBuf, + path::{MAIN_SEPARATOR, PathBuf}, process::{Command, Stdio}, }; @@ -44,6 +44,8 @@ pub fn build(mut args: Vec, root: PathBuf) -> bool { let mut mapping = HashMap::new(); + let mist_src = format!(".mist{MAIN_SEPARATOR}src"); + for message in cargo_metadata::Message::parse_stream(&mut reader) { match message { Ok(Message::CompilerMessage(msg)) => { @@ -53,8 +55,10 @@ pub fn build(mut args: Vec, root: PathBuf) -> bool { let mist_file = span .file_name - .replacen(".mist/src", "src", 1) - .replace(".rs", ".mist"); + .replacen(&mist_src, "src", 1) + .trim_end_matches(".rs") + .to_string() + + ".mist"; let mist_path = root.join(&mist_file); diff --git a/src/main.mist b/src/main.mist index 05af30c..70447ac 100644 --- a/src/main.mist +++ b/src/main.mist @@ -15,7 +15,7 @@ void main() { match (args[1].as_str()) { "run" | "build" | "check" | "r" | "b" | "c" => { - var root = transpiler::build(); + var root = transpiler::build(false); println!(""); @@ -26,7 +26,7 @@ void main() { } } "transpile" | "t" => { - transpiler::build(); + transpiler::build(args.get(2).is_some()); } "init" => { init_project(args); diff --git a/src/transpiler.rs b/src/transpiler.rs index 77b2522..8c2a6ea 100644 --- a/src/transpiler.rs +++ b/src/transpiler.rs @@ -7,7 +7,7 @@ use std::{ use mist_parser::error::ParseError; -pub fn build() -> PathBuf { +pub fn build(force: bool) -> PathBuf { let start = Instant::now(); let root = std::env::current_dir() @@ -17,7 +17,7 @@ pub fn build() -> PathBuf { let src_dir = root.join("src"); let out_dir = root.join(".mist/src"); - build_dir(&root, &src_dir, &src_dir, &out_dir); + build_dir(&root, &src_dir, &src_dir, &out_dir, force); let elapsed = start.elapsed(); @@ -29,7 +29,7 @@ pub fn build() -> PathBuf { root } -fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { +fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path, force: bool) { let entries = match fs::read_dir(current_dir) { Ok(entries) => entries, Err(e) => { @@ -57,7 +57,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { // recurse into nested directories if path.is_dir() { - build_dir(root, base_src, &path, out_dir); + build_dir(root, base_src, &path, out_dir, force); continue; } @@ -72,7 +72,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { let _ = fs::create_dir_all(parent); } - if should_skip(&path, &dest_path) { + if !force && should_skip(&path, &dest_path) { continue; } @@ -83,7 +83,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) { let output_path = out_dir.join(relative).with_extension("rs"); // Cache layer: Skip if the generated .rs file is newer than the .mist source - if should_skip(&path, &output_path) { + if !force && should_skip(&path, &output_path) { continue; }