Merge pull request #44 from mist-go/statement-patches-and-errors

Statement patches and errors
This commit is contained in:
2026-05-22 03:48:17 +02:00
committed by GitHub
12 changed files with 162 additions and 49 deletions
+9 -3
View File
@@ -102,7 +102,10 @@ impl GenRust for Expression {
if ensure_semicolon { if ensure_semicolon {
ctx.expr_ensure_semicolon = true; ctx.expr_ensure_semicolon = true;
cg.add(";");
if !self.is_block() {
cg.add(";");
}
} }
} }
} }
@@ -166,9 +169,12 @@ impl GenRust for Postfix {
Postfix::Call(args) => { Postfix::Call(args) => {
cg.add("("); cg.add("(");
for arg in args { for (i, arg) in args.iter().enumerate() {
if i > 0 {
cg.add(", ");
}
arg.gen_rust(ctx, cg); arg.gen_rust(ctx, cg);
cg.add(", ");
} }
cg.add(")"); cg.add(")");
+13
View File
@@ -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 { impl GenRust for Attribute {
+37 -19
View File
@@ -18,10 +18,11 @@ impl GenRust for Block {
if let Some(soft_return) = &self.1 { if let Some(soft_return) = &self.1 {
ctx.expr_ensure_semicolon = false; ctx.expr_ensure_semicolon = false;
soft_return.gen_rust(ctx, cg); soft_return.gen_rust(ctx, cg);
cg.addln("");
} }
cg.indent -= 1; cg.indent -= 1;
cg.add_indentedln("}"); cg.add_indented("}");
} }
} }
@@ -57,17 +58,14 @@ impl GenRust for Statement {
p.gen_rust(ctx, cg); p.gen_rust(ctx, cg);
} }
cg.add(" => {"); cg.add(" => ");
cg.indent += 1;
body.gen_rust(ctx, cg); cg.ensure_brackets_expr(ctx, body);
cg.indent -= 1;
cg.add_indentedln("}");
} }
cg.indent -= 1; cg.indent -= 1;
cg.add_indentedln("}"); cg.addln("");
cg.add_indented("}");
} }
Statement::If { Statement::If {
@@ -77,24 +75,32 @@ impl GenRust for Statement {
} => { } => {
cg.add("if "); cg.add("if ");
initial.condition.gen_rust(ctx, cg); 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 { for else_if_branch in else_if {
cg.add("else if"); cg.add("else if");
else_if_branch.condition.gen_rust(ctx, cg); 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 { if let Some(else_br) = else_branch {
cg.add("else"); cg.add(" else ");
cg.ensure_brackets(ctx, else_br); cg.ensure_brackets_expr(ctx, else_br);
} }
} }
Statement::While(StatementBranch { condition, body }) => { Statement::While(StatementBranch { condition, body }) => {
cg.add("while "); cg.add("while ");
condition.gen_rust(ctx, cg); 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 { Statement::CStyleFor {
@@ -103,28 +109,40 @@ impl GenRust for Statement {
update, update,
body, body,
} => { } => {
cg.add_indentedln("{"); cg.addln("{");
cg.indent += 1; cg.indent += 1;
ctx.expr_ensure_semicolon = true;
cg.add_indented("");
init.gen_rust(ctx, cg); init.gen_rust(ctx, cg);
cg.add("while "); cg.addln("");
cg.add_indented("while ");
ctx.expr_ensure_semicolon = false;
condition.gen_rust(ctx, cg); condition.gen_rust(ctx, cg);
cg.add("{"); cg.add(" ");
cg.add("{");
cg.indent += 1; cg.indent += 1;
cg.ensure_brackets(ctx, body); ctx.expr_ensure_semicolon = true;
body.gen_rust(ctx, cg);
update.gen_rust(ctx, cg); update.gen_rust(ctx, cg);
cg.addln("");
cg.indent -= 1; cg.indent -= 1;
cg.add_indentedln("}"); cg.add_indentedln("}");
cg.indent -= 1; cg.indent -= 1;
cg.add_indentedln("}"); cg.add_indented("}");
} }
Statement::For { Statement::For {
@@ -138,7 +156,7 @@ impl GenRust for Statement {
pattern.gen_rust(ctx, cg); pattern.gen_rust(ctx, cg);
cg.add(" in "); cg.add(" in ");
iterator.gen_rust(ctx, cg); iterator.gen_rust(ctx, cg);
cg.ensure_brackets(ctx, body); cg.ensure_brackets_expr(ctx, body);
} }
Statement::Return(expr) => { Statement::Return(expr) => {
+30 -1
View File
@@ -91,4 +91,33 @@ pub class Application {
} }
} }
} }
} }
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!");
}
}
+2 -2
View File
@@ -13,7 +13,7 @@ pub enum LogLevel {
impl fmt::Display for LogLevel { impl fmt::Display for LogLevel {
fmt::Result fmt(self*, Formatter<'_> mut* f) { fmt::Result fmt(self*, Formatter<'_> mut* f) {
return match (self) { match (self) {
LogLevel::Info => write!(f, "[INFO]"); LogLevel::Info => write!(f, "[INFO]");
LogLevel::Warning => write!(f, "[WARN]"); LogLevel::Warning => write!(f, "[WARN]");
@@ -66,7 +66,7 @@ pub class Logger {
impl fmt::Display { impl fmt::Display {
fmt::Result fmt(self*, Formatter<'_> mut* f) { fmt::Result fmt(self*, Formatter<'_> mut* f) {
return write!(f, "logger ({})", self.prefix); write!(f, "logger ({})", self.prefix)
} }
} }
} }
+10
View File
@@ -81,3 +81,13 @@ pub enum Generic {
Lifetime(Identifier), Lifetime(Identifier),
Type(TypeExpr), Type(TypeExpr),
} }
impl Expression {
pub fn is_block(&self) -> bool {
if let Expression::Statement(stmt) = self {
stmt.is_block()
} else {
false
}
}
}
+32 -7
View File
@@ -11,27 +11,28 @@ pub struct Block(
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub enum Statement { pub enum Statement {
Block(Block), Block(Block),
VarDecl(VarDeclStmt),
If { If {
initial: StatementBranch, initial: StatementBranch,
else_if: Vec<StatementBranch>, else_if: Vec<StatementBranch>,
else_branch: Option<Box<Statement>>, else_branch: Option<Box<Expression>>,
}, },
Loop(Expression),
While(StatementBranch), While(StatementBranch),
CStyleFor { CStyleFor {
init: Box<Statement>, init: Expression,
condition: Expression, condition: Expression,
update: Box<Statement>, update: Expression,
body: Box<Statement>, body: Expression,
}, },
For { For {
mutable: bool, mutable: bool,
pattern: Pattern, pattern: Pattern,
iterator: Expression, iterator: Expression,
body: Box<Statement>, body: Box<Expression>,
}, },
Match(Expression, Vec<(Vec<Pattern>, Expression)>), Match(Expression, Vec<(Vec<Pattern>, Expression)>),
VarDecl(VarDeclStmt),
Return(Option<Expression>), Return(Option<Expression>),
Break, Break,
Continue, Continue,
@@ -53,5 +54,29 @@ pub struct VarDeclStmt {
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct StatementBranch { pub struct StatementBranch {
pub condition: Expression, pub condition: Expression,
pub body: Box<Statement>, pub body: Box<Expression>,
}
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,
}
}
} }
+8 -2
View File
@@ -29,6 +29,7 @@ keyword = {
| "true" | "true"
| "false" | "false"
| "dyn" | "dyn"
| "loop"
} }
identifier = @{ identifier = @{
@@ -379,6 +380,7 @@ control_flow = {
| c_for_stmt | c_for_stmt
| for_stmt | for_stmt
| match_stmt | match_stmt
| loop_stmt
| block | block
} }
@@ -405,11 +407,15 @@ while_stmt = {
} }
c_for_stmt = { c_for_stmt = {
"for" ~ "(" ~ statement ~ expr ~ semicolon ~ statement ~ ")" ~ statement "for" ~ "(" ~ statement ~ statement ~ expr ~ ")" ~ statement
} }
for_stmt = { for_stmt = {
"for" ~ "(" ~ mutable? ~ pattern ~ "in" ~ expr ~ ")" ~ statement "for" ~ "(" ~ mutable? ~ pattern ~ ":" ~ expr ~ ")" ~ statement
}
loop_stmt = {
"loop" ~ statement
} }
// ------------------------------------------------------ // ------------------------------------------------------
+6 -4
View File
@@ -65,7 +65,7 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
else_if: collect_recovered(inner.next().unwrap().into_inner()), else_if: collect_recovered(inner.next().unwrap().into_inner()),
else_branch: inner else_branch: inner
.next() .next()
.map(Statement::try_from) .map(Expression::try_from)
.transpose() .transpose()
.map(|v| v.map(Box::new)) .map(|v| v.map(Box::new))
.get_map(|v| { Some(Box::new(v)) }), .get_map(|v| { Some(Box::new(v)) }),
@@ -74,11 +74,13 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())), 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 { 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(), condition: inner.next().unwrap().try_into(),
update: inner.next().unwrap().try_into().map(Box::new), update: inner.next().unwrap().try_into(),
body: inner.next().unwrap().try_into().map(Box::new), body: inner.next().unwrap().try_into(),
}), }),
Rule::for_stmt => ast_expr!(Statement::For { Rule::for_stmt => ast_expr!(Statement::For {
+7 -3
View File
@@ -1,7 +1,7 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
env, fs, env, fs,
path::PathBuf, path::{MAIN_SEPARATOR, PathBuf},
process::{Command, Stdio}, process::{Command, Stdio},
}; };
@@ -44,6 +44,8 @@ pub fn build(mut args: Vec<String>, root: PathBuf) -> bool {
let mut mapping = HashMap::new(); let mut mapping = HashMap::new();
let mist_src = format!(".mist{MAIN_SEPARATOR}src");
for message in cargo_metadata::Message::parse_stream(&mut reader) { for message in cargo_metadata::Message::parse_stream(&mut reader) {
match message { match message {
Ok(Message::CompilerMessage(msg)) => { Ok(Message::CompilerMessage(msg)) => {
@@ -53,8 +55,10 @@ pub fn build(mut args: Vec<String>, root: PathBuf) -> bool {
let mist_file = span let mist_file = span
.file_name .file_name
.replacen(".mist/src", "src", 1) .replacen(&mist_src, "src", 1)
.replace(".rs", ".mist"); .trim_end_matches(".rs")
.to_string()
+ ".mist";
let mist_path = root.join(&mist_file); let mist_path = root.join(&mist_file);
+2 -2
View File
@@ -15,7 +15,7 @@ void main() {
match (args[1].as_str()) { match (args[1].as_str()) {
"run" | "build" | "check" | "r" | "b" | "c" => { "run" | "build" | "check" | "r" | "b" | "c" => {
var root = transpiler::build(); var root = transpiler::build(false);
println!(""); println!("");
@@ -26,7 +26,7 @@ void main() {
} }
} }
"transpile" | "t" => { "transpile" | "t" => {
transpiler::build(); transpiler::build(args.get(2).is_some());
} }
"init" => { "init" => {
init_project(args); init_project(args);
+6 -6
View File
@@ -7,7 +7,7 @@ use std::{
use mist_parser::error::ParseError; use mist_parser::error::ParseError;
pub fn build() -> PathBuf { pub fn build(force: bool) -> PathBuf {
let start = Instant::now(); let start = Instant::now();
let root = std::env::current_dir() let root = std::env::current_dir()
@@ -17,7 +17,7 @@ pub fn build() -> PathBuf {
let src_dir = root.join("src"); let src_dir = root.join("src");
let out_dir = root.join(".mist/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(); let elapsed = start.elapsed();
@@ -29,7 +29,7 @@ pub fn build() -> PathBuf {
root 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) { let entries = match fs::read_dir(current_dir) {
Ok(entries) => entries, Ok(entries) => entries,
Err(e) => { Err(e) => {
@@ -57,7 +57,7 @@ fn build_dir(root: &Path, base_src: &Path, current_dir: &Path, out_dir: &Path) {
// recurse into nested directories // recurse into nested directories
if path.is_dir() { if path.is_dir() {
build_dir(root, base_src, &path, out_dir); build_dir(root, base_src, &path, out_dir, force);
continue; 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); let _ = fs::create_dir_all(parent);
} }
if should_skip(&path, &dest_path) { if !force && should_skip(&path, &dest_path) {
continue; 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"); let output_path = out_dir.join(relative).with_extension("rs");
// Cache layer: Skip if the generated .rs file is newer than the .mist source // 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; continue;
} }