diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 8ba217a..5051a1d 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -47,7 +47,7 @@ pub enum BinaryOp { #[derive(Debug, Clone, Serialize)] pub enum TopLevel { - Import(String), + Include(StaticPath), StructDecl { export: bool, name: String, @@ -66,11 +66,19 @@ pub enum TopLevel { pub enum Postfix { FieldAccess(String), Call(Vec), + MacroCall(String), StructCall(HashMap), Index(Expression), Binary(BinaryOp, Expression), } +#[derive(Debug, Clone, Serialize)] +pub enum Prefix { + Ref, + RefMut, + Deref, +} + #[derive(Debug, Clone, Serialize)] pub enum Statement { Expression(Expression), @@ -134,8 +142,10 @@ pub enum Expression { FloatLiteral(f64), BoolLiteral(bool), StringLiteral(String), - Postfix { + TupleLiteral(Vec), + Fix { initial: Box, + prefixes: Vec, postfixes: Vec, }, } diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index e60b11b..406001c 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -9,18 +9,19 @@ integer = @{ ASCII_DIGIT+ } float = @{ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ } boolean = { "true" | "false" } string_lit = { "\"" ~ inner_str ~ "\"" } -inner_str = @{ (!"\"" ~ ANY)* } +inner_str = @{ (!"\"" ~ ("\\\"" | ANY))* } static_path = { identifier ~ ("::" ~ identifier)* } -export = { "public" } -mutable = { "mut" } -var_decl = { type_expr ~ mutable? ~ identifier } +export = { "public" } +mutable = { "mut" } +sharp = _{ "#" } +var_decl = { type_expr ~ mutable? ~ identifier } // ================= TOP LEVEL ================= top_level = _{ import | function_decl | struct_decl } -import = { "import" ~ string_lit ~ ";" } +import = { sharp ~ "include" ~ "<" ~ static_path ~ ">" } field_list = { field ~ ("," ~ field)* ~ ","? } field = { export? ~ type_expr ~ identifier } @@ -44,6 +45,7 @@ statement_list = { statement* } statement = _{ expr_stmt | var_decl_statement + | assign_statement | if_stmt | while_stmt | return_stmt @@ -64,6 +66,8 @@ continue_stmt = { "continue" ~ ";" } var_decl_statement = { var_decl ~ ("=" ~ expr)? ~ ";" } +assign_statement = { expr ~ "=" ~ expr ~ ";" } + if_stmt = { "if" ~ "(" ~ expr ~ ")" ~ statement ~ ("else" ~ statement)? } @@ -78,17 +82,26 @@ path_type = { static_path ~ ("<" ~ (type_expr ~ ("," ~ type_expr)*)? ~ ">")? } ref_type = { mutable? ~ "*" } type_expr = { (path_type | tuple_type) ~ ref_type* } +macro_inner_v = { + "(" ~ macro_inner_v* ~ ")" + | (!("(" | ")") ~ ANY) +} + +tuple = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" } + primary = { integer | float | boolean | string_lit | static_path + | tuple } postfix = { field_px | call_px + | macro_call_px | struct_px | index_px | binary_px @@ -96,12 +109,23 @@ postfix = { field_px = { "." ~ identifier } call_px = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" } +macro_call_px = { "!" ~ "(" ~ macro_inner_v* ~ ")" } struct_px = { "{" ~ (struct_field_decl ~ ("," ~ struct_field_decl)*)? ~ "}" } index_px = { "[" ~ expr ~ "]" } binary_px = { bin_op ~ expr } bin_op = { "+" | "-" | "*" | "/" | "%" | "==" | "!=" | "<" | ">" | "<=" | ">=" } struct_field_decl = { identifier ~ ":" ~ expr } +prefix = { + deref_px + | mut_ref_px + | ref_px +} + +deref_px = { "*" } +mut_ref_px = { "&" ~ mutable } +ref_px = { "&" } + expr = { - primary ~ postfix* + prefix* ~ primary ~ postfix* } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 584c832..036e8cc 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -28,42 +28,45 @@ pub fn parse(source: &str) -> Result, ParseError> { impl From> for TypeExpr { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - Rule::type_expr => { - let mut inner = pair.into_inner(); - TypeExpr( - TypeExprKind::from(inner.next().unwrap()), - inner.map(TypePostfix::from).collect(), - ) - } - _ => unimplemented!("{pair:#?}"), + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::type_expr => TypeExpr( + TypeExprKind::from(inner.next().unwrap()), + inner.map(TypePostfix::from).collect(), + ), + _ => unimplemented!("{rule:#?}"), } } } impl From> for TypePostfix { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { + let rule = pair.as_rule(); + let inner = pair.into_inner(); + + match rule { Rule::ref_type => { - if pair.into_inner().peek().is_some() { + if inner.peek().is_some() { TypePostfix::RefMut } else { TypePostfix::Ref } } - _ => unimplemented!("{pair:#?}"), + _ => unimplemented!("{rule:#?}"), } } } impl From> for TypeExprKind { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { - match pair.as_rule() { - Rule::tuple_type => { - TypeExprKind::Tuple(pair.into_inner().map(TypeExpr::from).collect()) - } + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::tuple_type => TypeExprKind::Tuple(inner.map(TypeExpr::from).collect()), Rule::path_type => { - let mut inner = pair.into_inner(); let path = StaticPath::from(inner.next().unwrap()); let params = inner.map(TypeExpr::from).collect::>(); @@ -73,7 +76,7 @@ impl From> for TypeExprKind { TypeExprKind::PathParams(path, params) } } - _ => unimplemented!("{pair:#?}"), + _ => unimplemented!("{rule:#?}"), } } } @@ -113,23 +116,20 @@ impl From> for FieldList { impl From> for ParamList { fn from(pair: pest::iterators::Pair) -> Self { - let params = pair.into_inner().map(VarDecl::from).collect(); - - ParamList(params) + ParamList(pair.into_inner().map(VarDecl::from).collect()) } } impl TryFrom> for TopLevel { type Error = (); fn try_from(pair: pest::iterators::Pair) -> Result { - match pair.as_rule() { - Rule::import => { - let path = pair.into_inner().next().unwrap().as_str().to_string(); - Ok(TopLevel::Import(path)) - } - Rule::function_decl => { - let mut inner = pair.into_inner(); + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + match rule { + Rule::import => Ok(TopLevel::Include(StaticPath::from(inner.next().unwrap()))), + + Rule::function_decl => { let export = if let Some(first) = inner.peek() { if first.as_rule() == Rule::export { inner.next(); @@ -162,7 +162,6 @@ impl TryFrom> for TopLevel { } Rule::struct_decl => { - let mut inner = pair.into_inner(); let export = if let Some(first) = inner.peek() { if first.as_rule() == Rule::export { inner.next(); @@ -185,7 +184,7 @@ impl TryFrom> for TopLevel { } Rule::EOI => Err(()), - _ => unimplemented!("TopLevel parsing not implemented yet {:?}", pair.as_rule()), + _ => unimplemented!("{rule:#?}"), } } } @@ -208,24 +207,19 @@ impl From> for Block { impl From> for Statement { fn from(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::statement => { - let inner = pair.into_inner().next().unwrap(); - Statement::from(inner) - } + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); - Rule::expr_stmt => { - let expr_pair = pair.into_inner().next().unwrap(); - Statement::Expression(Expression::from(expr_pair)) - } + match rule { + Rule::statement => Statement::from(inner.next().unwrap()), - Rule::block => Statement::Block(Block::from(pair.into_inner().next().unwrap())), + Rule::expr_stmt => Statement::Expression(Expression::from(inner.next().unwrap())), + + Rule::block => Statement::Block(Block::from(inner.next().unwrap())), Rule::var_decl_statement => Statement::VarDecl(VarDeclStmt::from(pair)), Rule::return_stmt => { - let mut inner = pair.into_inner(); - let expr = inner.next().map(Expression::from); Statement::Return(expr) @@ -236,8 +230,6 @@ impl From> for Statement { Rule::continue_stmt => Statement::Continue, Rule::if_stmt => { - let mut inner = pair.into_inner(); - let condition = Expression::from(inner.next().unwrap()); let then_branch = Statement::from(inner.next().unwrap()); @@ -251,8 +243,6 @@ impl From> for Statement { } Rule::while_stmt => { - let mut inner = pair.into_inner(); - let condition = Expression::from(inner.next().unwrap()); let body = Statement::from(inner.next().unwrap()); @@ -262,71 +252,86 @@ impl From> for Statement { }) } - _ => unimplemented!( - "Statement parsing not implemented yet: {:?}", - pair.as_rule() - ), + Rule::assign_statement => Statement::VarAssign(VarAssignStmt { + target: Expression::from(inner.next().unwrap()), + value: Expression::from(inner.next().unwrap()), + }), + + _ => unimplemented!("{rule:#?}"), } } } impl From> for Expression { fn from(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { Rule::expr => { - let mut inner = pair.into_inner(); + let mut prefixes = Vec::new(); + + while inner + .peek() + .map(|v| v.as_rule() == Rule::prefix) + .unwrap_or_default() + { + prefixes.push(Prefix::from(inner.next().unwrap())); + } + let exp = Expression::from(inner.next().unwrap()); - if inner.len() > 0 { - Expression::Postfix { + if inner.len() > 0 || prefixes.len() > 0 { + Expression::Fix { initial: Box::new(exp), + prefixes, postfixes: inner.map(|p| Postfix::from(p)).collect(), } } else { exp } } - Rule::primary => Expression::from(pair.into_inner().next().unwrap()), + Rule::primary => Expression::from(inner.next().unwrap()), Rule::static_path => Expression::Path(StaticPath::from(pair)), - Rule::integer => { - let value = pair.as_str().parse::().unwrap(); - Expression::IntLiteral(value) - } - Rule::float => { - let value = pair.as_str().parse::().unwrap(); - Expression::FloatLiteral(value) - } - Rule::boolean => { - let value = pair.as_str().parse::().unwrap(); - Expression::BoolLiteral(value) - } - Rule::string_lit => { - let inner_str = pair.into_inner().next().unwrap().as_str(); - Expression::StringLiteral(inner_str.to_string()) - } + Rule::integer => Expression::IntLiteral(pair.as_str().parse::().unwrap()), + Rule::float => Expression::FloatLiteral(pair.as_str().parse::().unwrap()), + Rule::boolean => Expression::BoolLiteral(pair.as_str().parse::().unwrap()), + Rule::string_lit => Expression::StringLiteral(inner.as_str().to_string()), + Rule::tuple => Expression::TupleLiteral(inner.map(Expression::from).collect()), + _ => unimplemented!("{rule:#?}"), + } + } +} - _ => unimplemented!( - "Expression parsing not implemented yet {:?}", - pair.as_rule() - ), +impl From> for Prefix { + fn from(pair: pest::iterators::Pair) -> Self { + match pair.as_rule() { + Rule::prefix => Self::from(pair.into_inner().next().unwrap()), + Rule::deref_px => Self::Deref, + Rule::mut_ref_px => Self::RefMut, + Rule::ref_px => Self::Ref, + _ => unimplemented!("{pair:#?}"), } } } impl From> for Postfix { fn from(pair: pest::iterators::Pair) -> Self { - match pair.as_rule() { - Rule::postfix => Postfix::from(pair.into_inner().next().unwrap()), + let rule = pair.as_rule(); + let mut inner = pair.into_inner(); + + match rule { + Rule::postfix => Postfix::from(inner.next().unwrap()), Rule::field_px => { - let field_name = pair.into_inner().next().unwrap().as_str().to_string(); + let field_name = inner.next().unwrap().as_str().to_string(); Postfix::FieldAccess(field_name) } - Rule::call_px => Postfix::Call(pair.into_inner().map(Expression::from).collect()), + Rule::call_px => Postfix::Call(inner.map(Expression::from).collect()), Rule::struct_px => Postfix::StructCall( - pair.into_inner() + inner .map(|p| { let mut pi = p.into_inner(); ( @@ -337,10 +342,9 @@ impl From> for Postfix { .collect(), ), - Rule::index_px => Postfix::Index(Expression::from(pair.into_inner().next().unwrap())), + Rule::index_px => Postfix::Index(Expression::from(inner.next().unwrap())), Rule::binary_px => { - let mut inner = pair.into_inner(); let op_pair = inner.next().unwrap(); let op = match op_pair.as_str() { "+" => BinaryOp::Plus, @@ -362,7 +366,9 @@ impl From> for Postfix { Postfix::Binary(op, Expression::from(inner.next().unwrap())) } - _ => unimplemented!("Postfix parsing not implemented yet {:?}", pair.as_rule()), + Rule::macro_call_px => Postfix::MacroCall(inner.as_str().to_string()), + + _ => unimplemented!("{rule:#?}"), } } } diff --git a/src/codegen.rs b/src/codegen.rs index 0830a5f..db79b79 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,6 +1,6 @@ use parser::ast::{ - BinaryOp, Block, Expression, IfStmt, Postfix, Statement, StaticPath, TopLevel, TypeExpr, - TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, WhileStmt, + BinaryOp, Block, Expression, IfStmt, Postfix, Prefix, Statement, StaticPath, TopLevel, + TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, WhileStmt, }; // --------------------------------------------------------------------------- @@ -112,71 +112,96 @@ impl GetRust for Expression { Expression::IntLiteral(n) => n.to_string(), Expression::FloatLiteral(n) => n.to_string(), Expression::BoolLiteral(b) => b.to_string(), - Expression::StringLiteral(s) => format!("\"{}\".to_string()", s), + Expression::StringLiteral(s) => format!("\"{s}\""), + Expression::TupleLiteral(t) => { + format!( + "({})", + t.iter() + .map(Expression::get_rust) + .collect::>() + .join(", ") + ) + } + Expression::Fix { + initial, + prefixes, + postfixes, + } => prefixes.get_rust() + &initial.get_rust() + &postfixes.get_rust(), + } + } +} - Expression::Postfix { initial, postfixes } => { - let base = initial.get_rust(); - postfixes.get_rust_with_base(&base) +impl GetRust for Prefix { + fn get_rust(&self) -> String { + match self { + Self::Deref => "*", + Self::Ref => "&", + Self::RefMut => "&mut ", + } + .to_string() + } +} + +impl GetRust for [Prefix] { + fn get_rust(&self) -> String { + self.iter().map(Prefix::get_rust).collect() + } +} + +impl GetRust for Postfix { + fn get_rust(&self) -> String { + match self { + Postfix::FieldAccess(field) => format!(".{}", field), + + Postfix::Call(args) => { + let args = args + .iter() + .map(|a| a.get_rust()) + .collect::>() + .join(", "); + format!("({})", args) + } + + Postfix::MacroCall(inner) => { + format!("!({})", inner) + } + + Postfix::StructCall(fields) => { + let fields = fields + .iter() + .map(|(k, v)| format!("{}: {}", k, v.get_rust())) + .collect::>() + .join(", "); + format!("{{ {} }}", fields) + } + + Postfix::Index(idx) => { + format!("[{}]", idx.get_rust()) + } + + Postfix::Binary(op, rhs) => { + let op_str = match op { + BinaryOp::Plus => "+", + BinaryOp::Minus => "-", + BinaryOp::Multiply => "*", + BinaryOp::Divide => "/", + BinaryOp::Modulo => "%", + BinaryOp::Equal => "==", + BinaryOp::NotEqual => "!=", + BinaryOp::LessThan => "<", + BinaryOp::GreaterThan => ">", + BinaryOp::LessThanOrEqual => "<=", + BinaryOp::GreaterThanOrEqual => ">=", + }; + format!("{} {}", op_str, rhs.get_rust()) } } } } -/// Helper — applies a slice of postfixes onto an already-rendered base string. -trait PostfixChain { - fn get_rust_with_base(&self, base: &str) -> String; -} - -impl PostfixChain for [Postfix] { - fn get_rust_with_base(&self, base: &str) -> String { - let mut result = base.to_string(); - - for postfix in self { - result = match postfix { - Postfix::FieldAccess(field) => format!("{}.{}", result, field), - - Postfix::Call(args) => { - let args = args - .iter() - .map(|a| a.get_rust()) - .collect::>() - .join(", "); - format!("{}({})", result, args) - } - - Postfix::StructCall(fields) => { - let fields = fields - .iter() - .map(|(k, v)| format!("{}: {}", k, v.get_rust())) - .collect::>() - .join(", "); - format!("{} {{ {} }}", result, fields) - } - - Postfix::Index(idx) => { - format!("{}[{}]", result, idx.get_rust()) - } - - Postfix::Binary(op, rhs) => { - let op_str = match op { - BinaryOp::Plus => "+", - BinaryOp::Minus => "-", - BinaryOp::Multiply => "*", - BinaryOp::Divide => "/", - BinaryOp::Modulo => "%", - BinaryOp::Equal => "==", - BinaryOp::NotEqual => "!=", - BinaryOp::LessThan => "<", - BinaryOp::GreaterThan => ">", - BinaryOp::LessThanOrEqual => "<=", - BinaryOp::GreaterThanOrEqual => ">=", - }; - format!("{} {} {}", result, op_str, rhs.get_rust()) - } - }; - } - - result +impl GetRust for [Postfix] { + fn get_rust(&self) -> String { + self.iter().map(Postfix::get_rust).collect() } } @@ -195,9 +220,8 @@ impl ToRust for Block { impl ToRust for TopLevel { fn to_rust(&self, cg: &mut RustCodegen) { match self { - TopLevel::Import(path) => { - let path = path.replace('"', ""); - cg.addln(&format!("use {};", path)); + TopLevel::Include(path) => { + cg.addln(&format!("use {};", path.get_rust())); } TopLevel::StructDecl { diff --git a/test/src/main.mist b/test/src/main.mist index 9f2489e..f5c3828 100644 --- a/test/src/main.mist +++ b/test/src/main.mist @@ -1 +1,3 @@ -i32 add(i32* a, i32* b) {} \ No newline at end of file +void main() { + (i32, i32, str*) my_tuple = (10, 20, "hello, world"); +} \ No newline at end of file