diff --git a/parser/src/ast.rs b/parser/src/ast.rs index 05bca76..7ff1df8 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -1,7 +1,10 @@ use serde::Serialize; #[derive(Debug, Clone, Serialize)] -pub struct FieldList(pub Vec<(String, Visibility, TypeExpr)>); +pub struct Identifier(pub String); + +#[derive(Debug, Clone, Serialize)] +pub struct FieldList(pub Vec<(Identifier, Visibility, TypeExpr)>); #[derive(Debug, Clone, Serialize)] pub struct ParamList(pub Vec); @@ -44,7 +47,7 @@ pub enum TypeExprKind { pub struct TypeExpr(pub TypeExprKind, pub Vec); #[derive(Debug, Clone, Serialize)] -pub struct Path(pub Vec); +pub struct Path(pub Vec); #[derive(Debug, Clone, Serialize)] pub enum BinaryOp { @@ -67,22 +70,45 @@ pub struct TopLevel(pub TopLevelKind, pub Vec); #[derive(Debug, Clone, Serialize)] pub enum TopLevelKind { ModAttribute, - Include(Path), + Import(Path), + Mod(Identifier), + EnumDecl { + visibility: Visibility, + name: Identifier, + fields: Vec, + }, StructDecl { visibility: Visibility, - name: String, + name: Identifier, fields: FieldList, }, FunctionDecl(FunctionDecl), ClassDecl { visibility: Visibility, - name: String, + name: Identifier, fields: Vec, constructor: ClassConstructor, methods: Vec, }, } +#[derive(Debug, Clone, Serialize)] +pub enum Pattern { + NamedTuple(Path, Vec), + Struct(Path, Vec), + Tuple(Vec), + Literal(Literal), + Path(Path), + Id(Identifier), +} + +#[derive(Debug, Clone, Serialize)] +pub enum EnumItem { + Named(Identifier), + Tuple(Identifier, Vec), + Struct(Identifier, FieldList), +} + #[derive(Debug, Clone, Serialize)] pub struct ClassConstructor { pub visibility: Visibility, @@ -93,7 +119,7 @@ pub struct ClassConstructor { #[derive(Debug, Clone, Serialize)] pub struct FunctionDecl { pub visibility: Visibility, - pub name: String, + pub name: Identifier, pub params: ParamList, pub return_type: TypeExpr, pub body: Block, @@ -101,10 +127,10 @@ pub struct FunctionDecl { #[derive(Debug, Clone, Serialize)] pub enum Postfix { - FieldAccess(String), + FieldAccess(Identifier), Call(Vec), MacroCall(String), - StructCall(Vec<(String, Expression)>), + StructCall(Vec<(Identifier, Expression)>), Index(Expression), Binary(BinaryOp, Expression), } @@ -138,10 +164,12 @@ pub enum Statement { body: Box, }, For { - pattern: String, + mutable: bool, + pattern: Pattern, iterator: Expression, body: Box, }, + Match(Expression, Vec<(Pattern, Block)>), Return(Option), Break, @@ -151,7 +179,7 @@ pub enum Statement { #[derive(Debug, Clone, Serialize)] pub struct VarDecl { pub mutable: bool, - pub name: String, + pub name: Pattern, pub type_: Option, } diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 9913b8c..7c207f5 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -12,11 +12,16 @@ string_lit = { "\"" ~ inner_str ~ "\"" } inner_str = @{ (!"\"" ~ ("\\\"" | ANY))* } static_path = { identifier ~ ("::" ~ identifier)* } +// pattern +tuple_pattern = { "(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")" } +named_tuple_pattern = { static_path ~ "(" ~ (identifier ~ ("," ~ identifier)*)? ~ ")" } +struct_pattern = { static_path ~ "{" ~ (identifier ~ ("," ~ identifier)*)? ~ "}" } +pattern = _{ named_tuple_pattern | tuple_pattern | struct_pattern | literal | static_path } + export = { "public" } mutable = { "mut" } -sharp = _{ "#" } var = { "var" } -var_decl = { (var | type_expr) ~ mutable? ~ identifier } +var_decl = { (var | type_expr) ~ mutable? ~ pattern } semicolon = _{ ";" } // ================= CLASS ================= @@ -33,12 +38,22 @@ method = { } class_decl = { - "class" ~ identifier ~ "{" ~ class_fields ~ class_constructor ~ method* ~ "}" + export? ~ "class" ~ identifier ~ "{" ~ class_fields ~ class_constructor ~ method* ~ "}" } // ================= TOP LEVEL ================= -top_level = { (attributes ~ (import | function_decl | struct_decl | class_decl)) | mod_attribute } +enum_named = { identifier } +enum_tuple = { identifier ~ tuple_type } +enum_struct = { identifier ~ "{" ~ field_list ~ "}" } + +enum_field = _{ enum_tuple | enum_struct | enum_named } + +enum_fields = _{ enum_field ~ ("," ~ enum_field)* ~ ","? } + +enum_decl = { export? ~ "enum" ~ identifier ~ "{" ~ enum_fields ~ "}" } + +top_level = { (attributes ~ (import | function_decl | struct_decl | enum_decl | class_decl | mod_package)) | mod_attribute } attribute = { "#" ~ "[" ~ meta ~ "]" @@ -49,7 +64,7 @@ mod_attribute = { } meta = { - static_path ~ ("=" ~ primary | "(" ~ meta_list? ~ ")")? + static_path ~ ("=" ~ literal | "(" ~ meta_list? ~ ")")? } meta_list = { @@ -58,7 +73,9 @@ meta_list = { attributes = { attribute* } -import = { sharp ~ "include" ~ "<" ~ static_path ~ ">" } +import = { "use" ~ "<" ~ static_path ~ ">" ~ semicolon } + +mod_package = { "mod" ~ identifier ~ semicolon } field_list = { field ~ ("," ~ field)* ~ ","? } field = { export? ~ type_expr ~ identifier } @@ -81,6 +98,7 @@ statement_list = { statement* } statement = _{ expr_stmt + | match_stmt | var_decl_statement | assign_statement | if_stmt @@ -124,7 +142,13 @@ c_for_stmt = { } for_stmt = { - "for" ~ "(" ~ identifier ~ "in" ~ expr ~ ")" ~ statement + "for" ~ "(" ~ mutable? ~ pattern ~ "in" ~ expr ~ ")" ~ statement +} + +match_item = { pattern ~ "=>" ~ block } + +match_stmt = { + "match" ~ "(" ~ expr ~ ")" ~ "{" ~ match_item* ~ "}" } // ================= EXPRESSIONS ================= @@ -140,11 +164,15 @@ macro_inner_v = { tuple = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" } -primary = { +literal = { float | integer | boolean | string_lit +} + +primary = { + literal | static_path | tuple } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index bb3f16d..636223a 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -84,7 +84,7 @@ impl From> for TypeExprKind { impl From> for Path { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { match pair.as_rule() { - Rule::static_path => Path(pair.into_inner().map(|i| i.as_str().to_string()).collect()), + Rule::static_path => Path(pair.into_inner().map(Identifier::from).collect()), _ => unimplemented!("{pair:#?}"), } } @@ -98,7 +98,7 @@ impl From> for FieldList { let mut param_inner = p.into_inner(); let visibility = Visibility::from(&mut param_inner); let param_type = TypeExpr::from(param_inner.next().unwrap()); - let param_name = param_inner.next().unwrap().as_str().to_string(); + let param_name = Identifier::from(param_inner.next().unwrap()); (param_name, visibility, param_type) }) .collect(); @@ -229,13 +229,13 @@ impl From> for TopLevelKind { let mut inner = pair.clone().into_inner(); match rule { - Rule::import => TopLevelKind::Include(Path::from(inner.next().unwrap())), + Rule::import => TopLevelKind::Import(Path::from(inner.next().unwrap())), Rule::function_decl => TopLevelKind::FunctionDecl(FunctionDecl::from(pair)), Rule::struct_decl => { let visibility = Visibility::from(&mut inner); - let name = inner.next().unwrap().as_str().to_string(); + let name = Identifier::from(inner.next().unwrap()); let fields_pair = inner.next().unwrap(); let fields = FieldList::from(fields_pair); @@ -248,7 +248,7 @@ impl From> for TopLevelKind { Rule::class_decl => TopLevelKind::ClassDecl { visibility: Visibility::from(&mut inner), - name: inner.next().unwrap().as_str().to_string(), + name: Identifier::from(inner.next().unwrap()), fields: inner .next() .unwrap() @@ -259,6 +259,42 @@ impl From> for TopLevelKind { methods: inner.into_iter().map(FunctionDecl::from).collect(), }, + Rule::enum_decl => TopLevelKind::EnumDecl { + visibility: Visibility::from(&mut inner), + name: Identifier::from(inner.next().unwrap()), + fields: inner.map(EnumItem::from).collect(), + }, + + Rule::mod_package => TopLevelKind::Mod(Identifier::from(inner.next().unwrap())), + + _ => unimplemented!("{rule:#?}"), + } + } +} + +impl From> for EnumItem { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::enum_named => EnumItem::Named(Identifier::from(inner.next().unwrap())), + + Rule::enum_tuple => EnumItem::Tuple( + Identifier::from(inner.next().unwrap()), + inner + .next() + .unwrap() + .into_inner() + .map(TypeExpr::from) + .collect(), + ), + + Rule::enum_struct => EnumItem::Struct( + Identifier::from(inner.next().unwrap()), + FieldList::from(inner.next().unwrap()), + ), + _ => unimplemented!("{rule:#?}"), } } @@ -329,7 +365,8 @@ impl From> for Statement { }, Rule::for_stmt => Statement::For { - pattern: inner.next().unwrap().as_str().to_string(), + mutable: listen_rule(&mut inner, Rule::mutable), + pattern: Pattern::from(inner.next().unwrap()), iterator: inner.next().unwrap().into(), body: Box::new(Statement::from(inner.next().unwrap())), }, @@ -339,6 +376,19 @@ impl From> for Statement { value: Expression::from(inner.next().unwrap()), }), + Rule::match_stmt => Statement::Match( + Expression::from(inner.next().unwrap()), + inner + .map(|match_itms| { + let mut match_inner = match_itms.into_inner(); + ( + Pattern::from(match_inner.next().unwrap()), + Block::from(match_inner.next().unwrap()), + ) + }) + .collect(), + ), + _ => unimplemented!("{rule:#?}"), } } @@ -351,6 +401,7 @@ impl From> for Literal { match rule { Rule::primary => Self::from(inner.next().unwrap()), + Rule::literal => Self::from(inner.next().unwrap()), Rule::integer => Literal::Int(pair.as_str().parse::().unwrap()), Rule::float => Literal::Float(pair.as_str().parse::().unwrap()), Rule::boolean => Literal::Bool(pair.as_str().parse::().unwrap()), @@ -387,9 +438,7 @@ impl From> for Expression { } Rule::primary => Expression::from(inner.next().unwrap()), Rule::static_path => Expression::Path(Path::from(pair)), - Rule::integer | Rule::float | Rule::boolean | Rule::string_lit | Rule::tuple => { - Expression::Literal(Literal::from(pair)) - } + Rule::literal => Expression::Literal(Literal::from(pair)), _ => unimplemented!("{rule:#?}"), } } @@ -417,10 +466,7 @@ impl From> for Postfix { match rule { Rule::postfix => Postfix::from(inner.next().unwrap()), - Rule::field_px => { - let field_name = inner.next().unwrap().as_str().to_string(); - Postfix::FieldAccess(field_name) - } + Rule::field_px => Postfix::FieldAccess(Identifier::from(inner.next().unwrap())), Rule::call_px => Postfix::Call(inner.map(Expression::from).collect()), @@ -429,7 +475,7 @@ impl From> for Postfix { .map(|p| { let mut pi = p.into_inner(); ( - pi.next().unwrap().as_str().to_string(), + Identifier::from(pi.next().unwrap()), Expression::from(pi.next().unwrap()), ) }) @@ -485,6 +531,35 @@ impl From> for VarDeclStmt { } } +impl From> for Pattern { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + let rule = pair.as_rule(); + let mut inner = pair.clone().into_inner(); + + match rule { + Rule::tuple_pattern => Pattern::Tuple(inner.map(Identifier::from).collect()), + + Rule::named_tuple_pattern => Pattern::NamedTuple( + Path::from(inner.next().unwrap()), + inner.map(Identifier::from).collect(), + ), + + Rule::struct_pattern => Pattern::Struct( + Path::from(inner.next().unwrap()), + inner.map(Identifier::from).collect(), + ), + + Rule::literal => Pattern::Literal(Literal::from(pair)), + + Rule::identifier => Pattern::Id(Identifier::from(pair)), + + Rule::static_path => Pattern::Path(Path::from(pair)), + + _ => unimplemented!("{rule:?}"), + } + } +} + impl From> for VarDecl { fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { match pair.as_rule() { @@ -500,7 +575,7 @@ impl From> for VarDecl { }); let mutable = listen_rule(&mut inner, Rule::mutable); - let name = inner.next().unwrap().as_str().to_string(); + let name = Pattern::from(inner.next().unwrap()); VarDecl { mutable, @@ -522,10 +597,10 @@ impl From> for FunctionDecl { let return_type = TypeExpr::from(inner.next().unwrap()); - let name = inner.next().unwrap().as_str().to_string(); + let name = Identifier::from(inner.next().unwrap()); let self_param = consume_rule(&mut inner, Rule::self_param).map(|param| { let mut param_inner = param.into_inner(); - let name = format!("self"); + let name = Pattern::Id(Identifier(String::from("self"))); let mutable = listen_rule(&mut param_inner, Rule::mutable); @@ -533,9 +608,9 @@ impl From> for FunctionDecl { VarDecl { mutable: mutable && !is_ref, - name, + name: name.clone(), type_: Some(TypeExpr( - TypeExprKind::Path(Path(vec![format!("Self")])), + TypeExprKind::Path(Path(vec![Identifier("Self".to_string())])), if is_ref { vec![if mutable { TypePostfix::RefMut @@ -608,3 +683,9 @@ pub fn consume_rule<'a>( if consumed { pairs.next() } else { None } } + +impl From> for Identifier { + fn from(pair: pest::iterators::Pair<'_, Rule>) -> Self { + Identifier(pair.as_str().to_string()) + } +} diff --git a/src/codegen.rs b/src/codegen.rs index 6bfa172..6558d35 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,7 +1,7 @@ use parser::ast::{ - Attribute, BinaryOp, Block, Expression, FunctionDecl, Literal, Path, Postfix, Prefix, - Statement, StatementBranch, TopLevel, TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, - VarAssignStmt, VarDecl, VarDeclStmt, Visibility, + Attribute, BinaryOp, Block, EnumItem, Expression, FunctionDecl, Identifier, Literal, Path, + Pattern, Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind, TypeExpr, + TypeExprKind, TypePostfix, VarAssignStmt, VarDecl, VarDeclStmt, Visibility, }; // --------------------------------------------------------------------------- @@ -197,7 +197,7 @@ impl GetRust for Option<&Vec> { impl GetRust for Postfix { fn get_rust(&self) -> String { match self { - Postfix::FieldAccess(field) => format!(".{}", field), + Postfix::FieldAccess(field) => format!(".{}", field.get_rust()), Postfix::Call(args) => { let args = args @@ -215,7 +215,7 @@ impl GetRust for Postfix { Postfix::StructCall(fields) => { let fields = fields .iter() - .map(|(k, v)| format!("{}: {}", k, v.get_rust())) + .map(|(k, v)| format!("{}: {}", k.get_rust(), v.get_rust())) .collect::>() .join(", "); format!("{{ {} }}", fields) @@ -308,21 +308,43 @@ impl ToRust for TopLevelKind { fn to_rust(&self, cg: &mut RustCodegen) { match self { Self::ModAttribute => {} - Self::Include(path) => { - cg.addln(&format!("use {};", path.get_rust())); - } + Self::Import(path) => cg.addln(&format!("use {};", path.get_rust())), + Self::Mod(id) => cg.addln(&format!("mod {};", id.get_rust())), Self::FunctionDecl(decl) => decl.to_rust(cg), Self::StructDecl { visibility, name, fields, } => { - cg.addln(&format!("{}struct {} {{", visibility.get_rust(), name)); + cg.addln(&format!( + "{}struct {} {{", + visibility.get_rust(), + name.get_rust() + )); cg.indent += 1; for (field_name, _, ty) in &fields.0 { let ty = ty.get_rust(); - cg.add_indentedln(&format!("pub {}: {},", field_name, ty)); + cg.add_indentedln(&format!("pub {}: {},", field_name.get_rust(), ty)); + } + + cg.indent -= 1; + cg.addln("}\n"); + } + Self::EnumDecl { + visibility, + name, + fields, + } => { + cg.addln(&format!( + "{}enum {} {{", + visibility.get_rust(), + name.get_rust() + )); + cg.indent += 1; + + for field in fields { + cg.add_indentedln(&(format!("{}", field.get_rust()) + ",")); } cg.indent -= 1; @@ -336,19 +358,23 @@ impl ToRust for TopLevelKind { methods, } => { // Struct decl - cg.addln(&format!("{}struct {} {{", visibility.get_rust(), name)); + cg.addln(&format!( + "{}struct {} {{", + visibility.get_rust(), + name.get_rust() + )); cg.indent += 1; for field in fields { let ty = field.decl.type_.clone().unwrap().get_rust(); - cg.add_indentedln(&format!("pub {}: {},", field.decl.name, ty)); + cg.add_indentedln(&format!("pub {}: {},", field.decl.name.get_rust(), ty)); } cg.indent -= 1; cg.addln("}\n"); // Constructor - cg.addln(&format!("impl {} {{", name)); + cg.addln(&format!("impl {} {{", name.get_rust())); cg.indent += 1; let params_str = constructor @@ -372,7 +398,7 @@ impl ToRust for TopLevelKind { if let Some(init) = &field.init { cg.add_indentedln(&format!( "this.{} = {};", - field.decl.name, + field.decl.name.get_rust(), init.get_rust() )); } @@ -384,7 +410,7 @@ impl ToRust for TopLevelKind { .params .0 .iter() - .map(|e| e.name.to_string()) + .map(|e| e.name.get_rust()) .collect::>() .join(", ") )); @@ -446,6 +472,23 @@ impl ToRust for Statement { cg.add_indentedln(&format!("{} = {};", target.get_rust(), value.get_rust(),)); } + Statement::Match(expr, match_items) => { + cg.add_indentedln(&format!("match {} {{", expr.get_rust())); + cg.indent += 1; + + for itm in match_items { + cg.add_indentedln(&format!("{} =>", itm.0.get_rust())); + cg.add_indentedln("{"); + cg.indent += 1; + itm.1.to_rust(cg); + cg.indent -= 1; + cg.add_indentedln("}"); + } + + cg.indent -= 1; + cg.add_indentedln("}"); + } + Statement::If { initial, else_if, @@ -498,11 +541,17 @@ impl ToRust for Statement { } Statement::For { + mutable, pattern, iterator, body, } => { - cg.add_indentedln(&format!("for {} in {}", pattern, iterator.get_rust())); + cg.add_indentedln(&format!( + "for {}{} in {}", + get_mutable(*mutable), + pattern.get_rust(), + iterator.get_rust() + )); cg.ensure_brackets(body); } @@ -530,7 +579,7 @@ impl ToRust for FunctionDecl { cg.add_indentedln(&format!( "{}fn {}({}) -> {} {{", self.visibility.get_rust(), - self.name, + self.name.get_rust(), params_str, self.return_type.get_rust() )); @@ -543,21 +592,28 @@ impl ToRust for FunctionDecl { impl GetRust for VarDecl { fn get_rust(&self) -> String { - let mutability = if self.mutable { "mut " } else { "" }; - let ty = self .type_ .as_ref() .map(|t| format!(": {}", t.get_rust())) .unwrap_or_default(); - format!("{}{}{}", mutability, self.name, ty) + format!( + "{}{}{}", + get_mutable(self.mutable), + self.name.get_rust(), + ty + ) } } impl GetRust for Path { fn get_rust(&self) -> String { - self.0.join("::") + self.0 + .iter() + .map(Identifier::get_rust) + .collect::>() + .join("::") } } @@ -580,6 +636,71 @@ impl GetRust for Visibility { } } +impl GetRust for Identifier { + fn get_rust(&self) -> String { + self.0.clone() + } +} + +impl GetRust for EnumItem { + fn get_rust(&self) -> String { + match self { + Self::Named(id) => id.get_rust(), + Self::Struct(id, s) => format!( + "{} {{{}}}", + id.get_rust(), + s.0.iter() + .map(|(id, _, ty)| format!("{}: {}", id.get_rust(), ty.get_rust())) + .collect::>() + .join(", ") + ), + Self::Tuple(id, t) => format!( + "{} ({})", + id.get_rust(), + t.iter() + .map(TypeExpr::get_rust) + .collect::>() + .join(", ") + ), + } + } +} + +impl GetRust for Pattern { + fn get_rust(&self) -> String { + match self { + Self::Id(id) => id.get_rust(), + Self::Path(path) => path.get_rust(), + Self::Literal(lit) => lit.get_rust(), + Self::Struct(path, ids) => format!( + "{} {{{}}}", + path.get_rust(), + ids.iter() + .map(Identifier::get_rust) + .collect::>() + .join(", ") + ), + Self::Tuple(ids) => format!( + "({})", + ids.iter() + .map(Identifier::get_rust) + .collect::>() + .join(", ") + ), + Self::NamedTuple(path, ids) => { + format!( + "{} ({})", + path.get_rust(), + ids.iter() + .map(Identifier::get_rust) + .collect::>() + .join(", ") + ) + } + } + } +} + pub fn get_static_type_path(path: &Path) -> String { let rust_path = path.get_rust(); @@ -593,3 +714,7 @@ pub fn get_static_type_path(path: &Path) -> String { pub fn get_type_postfixes(postfixes: &[TypePostfix]) -> String { postfixes.iter().map(TypePostfix::get_rust).collect() } + +pub fn get_mutable(mutable: bool) -> String { + if mutable { "mut " } else { "" }.to_string() +} diff --git a/test/src/main.mist b/test/src/main.mist index 811a162..602dd59 100644 --- a/test/src/main.mist +++ b/test/src/main.mist @@ -1,17 +1,18 @@ -class MyClass { - String message; - - public constructor(str* name) { - self.message = format!("Hello {}!", name); - } - - public void greet(self*) { - println!("{}", self.message); - } -} +mod my_class; +use ; +use ; void main() { var my_class = new MyClass("World"); my_class.greet(); - var x = 1 + 2 + 3; + + match (MyEnum::Tuple(10, String::new())) { + MyEnum::Tuple(i, _) => { + println!("{i}"); + } + MyEnum::Named => { + + } + _ => {} + } } diff --git a/test/src/my_class.mist b/test/src/my_class.mist new file mode 100644 index 0000000..7cc321d --- /dev/null +++ b/test/src/my_class.mist @@ -0,0 +1,17 @@ +public class MyClass { + String message; + + public constructor(str* name) { + self.message = format!("Hello {}!", name); + } + + public void greet(self*) { + println!("{}", self.message); + } +} + +public enum MyEnum { + Named, + Tuple(i32, String), + Struct { i32 x } +}