diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 03a5bd1..fb72ea9 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -1,9 +1,7 @@ -use std::collections::HashMap; - use serde::Serialize; #[derive(Debug, Clone, Serialize)] -pub struct FieldList(pub HashMap); +pub struct FieldList(pub Vec<(String, bool, TypeExpr)>); #[derive(Debug, Clone, Serialize)] pub struct ParamList(pub Vec); @@ -83,7 +81,7 @@ pub enum Postfix { FieldAccess(String), Call(Vec), MacroCall(String), - StructCall(HashMap), + StructCall(Vec<(String, Expression)>), Index(Expression), Binary(BinaryOp, Expression), } @@ -102,9 +100,23 @@ pub enum Statement { VarDecl(VarDeclStmt), VarAssign(VarAssignStmt), - If(IfStmt), - While(WhileStmt), - For(ForStmt), + If { + initial: StatementBranch, + else_if: Vec, + else_branch: Option>, + }, + While(StatementBranch), + CStyleFor { + init: Box, + condition: Expression, + update: Box, + body: Box, + }, + For { + pattern: String, + iterator: Expression, + body: Box, + }, Return(Option), Break, @@ -131,23 +143,8 @@ pub struct VarAssignStmt { } #[derive(Debug, Clone, Serialize)] -pub struct IfStmt { +pub struct StatementBranch { pub condition: Expression, - pub then_branch: Box, - pub else_branch: Option>, -} - -#[derive(Debug, Clone, Serialize)] -pub struct WhileStmt { - pub condition: Expression, - pub body: Box, -} - -#[derive(Debug, Clone, Serialize)] -pub struct ForStmt { - pub init: (bool, String, Option), - pub condition: Option, - pub update: Option>, pub body: Box, } diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 59d1490..56e45ad 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -12,10 +12,12 @@ string_lit = { "\"" ~ inner_str ~ "\"" } inner_str = @{ (!"\"" ~ ("\\\"" | ANY))* } static_path = { identifier ~ ("::" ~ identifier)* } -export = { "public" } -mutable = { "mut" } -sharp = _{ "#" } -var_decl = { type_expr ~ mutable? ~ identifier } +export = { "public" } +mutable = { "mut" } +sharp = _{ "#" } +var = { "var" } +var_decl = { (var | type_expr) ~ mutable? ~ identifier } +semicolon = _{ ";" } // ================= TOP LEVEL ================= @@ -66,6 +68,8 @@ statement = _{ | assign_statement | if_stmt | while_stmt + | c_for_stmt + | for_stmt | return_stmt | break_stmt | continue_stmt @@ -74,26 +78,38 @@ statement = _{ // --- basic statements --- -expr_stmt = { expr ~ ";" } +expr_stmt = { expr ~ semicolon } -return_stmt = { "return" ~ expr? ~ ";" } +return_stmt = { "return" ~ expr? ~ semicolon } -break_stmt = { "break" ~ ";" } +break_stmt = { "break" ~ semicolon } -continue_stmt = { "continue" ~ ";" } +continue_stmt = { "continue" ~ semicolon } -var_decl_statement = { var_decl ~ ("=" ~ expr)? ~ ";" } +var_decl_statement = { var_decl ~ ("=" ~ expr)? ~ semicolon } -assign_statement = { expr ~ "=" ~ expr ~ ";" } +assign_statement = { expr ~ "=" ~ expr ~ semicolon } + +else_if = { "else" ~ "if" ~ "(" ~ expr ~ ")" ~ statement } + +else_if_list = { else_if* } if_stmt = { - "if" ~ "(" ~ expr ~ ")" ~ statement ~ ("else" ~ statement)? + "if" ~ "(" ~ expr ~ ")" ~ statement ~ else_if_list ~ ("else" ~ statement)? } while_stmt = { "while" ~ "(" ~ expr ~ ")" ~ statement } +c_for_stmt = { + "for" ~ "(" ~ statement ~ expr ~ semicolon ~ statement ~ ")" ~ statement +} + +for_stmt = { + "for" ~ "(" ~ identifier ~ "in" ~ expr ~ ")" ~ statement +} + // ================= EXPRESSIONS ================= tuple_type = { "(" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ")" } path_type = { static_path ~ ("<" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ">")? } @@ -131,7 +147,7 @@ macro_call_px = { "!" ~ "(" ~ macro_inner_v* ~ ")" } struct_px = { "{" ~ (struct_field_decl ~ ("," ~ struct_field_decl)*)? ~ ","? ~ "}" } index_px = { "[" ~ expr ~ "]" } binary_px = { bin_op ~ expr } -bin_op = { "+" | "-" | "*" | "/" | "%" | "==" | "!=" | "<" | ">" | "<=" | ">=" } +bin_op = { "<=" | ">=" | "==" | "!=" | "+" | "-" | "*" | "/" | "%" | "<" | ">" } struct_field_decl = { identifier ~ ":" ~ expr } prefix = { diff --git a/parser/src/lib.rs b/parser/src/lib.rs index e2014f4..ce1dd56 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -104,7 +104,7 @@ impl From> for FieldList { }; let param_type = TypeExpr::from(param_inner.next().unwrap()); let param_name = param_inner.next().unwrap().as_str().to_string(); - (param_name, (export, param_type)) + (param_name, export, param_type) }) .collect(); @@ -196,6 +196,20 @@ impl From> for TopLevel { } } +impl From> for StatementBranch { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + let mut inner = pair.into_inner(); + + let condition = Expression::from(inner.next().unwrap()); + let body = Statement::from(inner.next().unwrap()); + + StatementBranch { + condition, + body: Box::new(body), + } + } +} + impl From> for TopLevelKind { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { let rule = pair.as_rule(); @@ -303,27 +317,34 @@ impl From> for Statement { Rule::continue_stmt => Statement::Continue, Rule::if_stmt => { - let condition = Expression::from(inner.next().unwrap()); - let then_branch = Statement::from(inner.next().unwrap()); + let mut inner = inner.skip(2); - let else_branch = inner.next().map(Statement::from); - - Statement::If(IfStmt { - condition, - then_branch: Box::new(then_branch), - else_branch: else_branch.map(Box::new), - }) + Statement::If { + initial: pair.into(), + else_if: inner + .next() + .unwrap() + .into_inner() + .map(StatementBranch::from) + .collect(), + else_branch: inner.next().map(Statement::from).map(Box::new), + } } - Rule::while_stmt => { - let condition = Expression::from(inner.next().unwrap()); - let body = Statement::from(inner.next().unwrap()); + Rule::while_stmt => Statement::While(pair.into()), - Statement::While(WhileStmt { - condition, - body: Box::new(body), - }) - } + Rule::c_for_stmt => Statement::CStyleFor { + init: Box::new(Statement::from(inner.next().unwrap())), + condition: inner.next().unwrap().into(), + update: Box::new(Statement::from(inner.next().unwrap())), + body: Box::new(Statement::from(inner.next().unwrap())), + }, + + Rule::for_stmt => Statement::For { + pattern: inner.next().unwrap().as_str().to_string(), + iterator: inner.next().unwrap().into(), + body: Box::new(Statement::from(inner.next().unwrap())), + }, Rule::assign_statement => Statement::VarAssign(VarAssignStmt { target: Expression::from(inner.next().unwrap()), @@ -495,7 +516,13 @@ impl From> for VarDecl { Rule::var_decl => { let mut inner = pair.into_inner(); - let type_ = Some(inner.next().map(TypeExpr::from).unwrap()); + let type_ = inner.next().and_then(|pair| { + if pair.as_str().trim() == "var" { + None + } else { + Some(TypeExpr::from(pair)) + } + }); let mutable = if inner.peek().unwrap().as_rule() == Rule::mutable { inner.next(); true diff --git a/src/codegen.rs b/src/codegen.rs index b4c4a35..3440a77 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,7 +1,7 @@ use parser::ast::{ - Attribute, BinaryOp, Block, Expression, IfStmt, Literal, Path, Postfix, Prefix, Statement, - TopLevel, TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, - VarDeclStmt, WhileStmt, + Attribute, BinaryOp, Block, Expression, Literal, Path, Postfix, Prefix, Statement, + StatementBranch, TopLevel, TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt, + VarDecl, VarDeclStmt, }; // --------------------------------------------------------------------------- @@ -61,6 +61,19 @@ impl RustCodegen { } self.output.clone() } + + pub fn ensure_brackets(&mut self, stmt: &Statement) { + match stmt { + Statement::Block(_) => stmt.to_rust(self), + _ => { + self.add_indentedln("{"); + self.indent += 1; + stmt.to_rust(self); + self.indent -= 1; + self.add_indentedln("}"); + } + } + } } impl Default for RustCodegen { @@ -202,7 +215,7 @@ impl GetRust for Postfix { BinaryOp::LessThanOrEqual => "<=", BinaryOp::GreaterThanOrEqual => ">=", }; - format!("{} {}", op_str, rhs.get_rust()) + format!(" {} {}", op_str, rhs.get_rust()) } } } @@ -284,7 +297,7 @@ impl ToRust for TopLevelKind { cg.addln(&format!("{}struct {} {{", vis, name)); cg.indent += 1; - for (field_name, (_, ty)) in &fields.0 { + for (field_name, _, ty) in &fields.0 { let ty = ty.get_rust(); cg.add_indentedln(&format!("pub {}: {},", field_name, ty)); } @@ -353,36 +366,64 @@ impl ToRust for Statement { cg.add_indentedln(&format!("{} = {};", target.get_rust(), value.get_rust(),)); } - Statement::If(IfStmt { - condition, - then_branch, + Statement::If { + initial, + else_if, else_branch, - }) => { - cg.add_indentedln(&format!("if {} {{", condition.get_rust())); - cg.indent += 1; - then_branch.to_rust(cg); - cg.indent -= 1; - cg.add_indentedln("}"); + } => { + cg.add_indentedln(&format!("if {}", initial.condition.get_rust())); + cg.ensure_brackets(&initial.body); + + for else_if_branch in else_if { + cg.add_indentedln(&format!("else if {}", else_if_branch.condition.get_rust())); + cg.ensure_brackets(&else_if_branch.body); + } if let Some(else_br) = else_branch { - cg.add_indentedln("else {"); - cg.indent += 1; - else_br.to_rust(cg); - cg.indent -= 1; - cg.add_indentedln("}"); + cg.add_indentedln("else"); + cg.ensure_brackets(else_br); } } - Statement::While(WhileStmt { condition, body }) => { - cg.add_indentedln(&format!("while {} {{", condition.get_rust())); + Statement::While(StatementBranch { condition, body }) => { + cg.add_indentedln(&format!("while {}", condition.get_rust())); + cg.ensure_brackets(body); + } + + Statement::CStyleFor { + init, + condition, + update, + body, + } => { + cg.add_indentedln("{"); cg.indent += 1; - body.to_rust(cg); + + init.to_rust(cg); + + cg.add_indentedln(&format!("while {}", condition.get_rust())); + + cg.add_indentedln("{"); + cg.indent += 1; + + cg.ensure_brackets(body); + + update.to_rust(cg); + + cg.indent -= 1; + cg.add_indentedln("}"); + cg.indent -= 1; cg.add_indentedln("}"); } - Statement::For { .. } => { - cg.add_indentedln("// TODO: transform into iterator-based loop"); + Statement::For { + pattern, + iterator, + body, + } => { + cg.add_indentedln(&format!("for {} in {}", pattern, iterator.get_rust())); + cg.ensure_brackets(body); } Statement::Return(expr) => { diff --git a/test/src/main.mist b/test/src/main.mist index 40ba951..fe1d604 100644 --- a/test/src/main.mist +++ b/test/src/main.mist @@ -1,13 +1,7 @@ -#![allow(unused_mut)] - -#[derive(Debug)] -public struct ApiCall { - i32 x, - i32 y, -} - void main() { - ApiCall call = ApiCall { x: 10, y: 12 }; + var iter = vec!(1, 2, 3, 4, 5); - println!("{call:?}"); + for (i in iter) { + println!("{i}"); + } }