diff --git a/mist-test/src/app.mist b/mist-test/src/app.mist index 01fbd87..42072ac 100644 --- a/mist-test/src/app.mist +++ b/mist-test/src/app.mist @@ -46,7 +46,7 @@ pub class Application { void tick(self mut*) { self.logger.info("tick"); - self.ticks = self.ticks + 1; + self.ticks++; var task = task::create_task("background-job"); diff --git a/parser/src/ast.rs b/parser/src/ast.rs deleted file mode 100644 index d2acb95..0000000 --- a/parser/src/ast.rs +++ /dev/null @@ -1,280 +0,0 @@ -use serde::Serialize; - -#[derive(Debug, Clone, Serialize)] -pub struct Identifier(pub String); - -#[derive(Debug, Clone, Serialize, Default)] -pub struct ParamList(pub Vec); - -#[derive(Debug, Clone, Serialize, Default)] -pub struct Block(pub Vec); - -#[derive(Debug, Clone, Serialize)] -pub enum TypePostfix { - Ref, - RefMut, - RefLifetime(Identifier), - RefMutLifetime(Identifier), -} - -#[derive(Debug, Clone, Serialize)] -pub enum Visibility { - Public, - PublicTarget(Path), - Private, -} - -#[derive(Debug, Clone, Serialize)] -pub enum Attribute { - /// #[test] - Path(Path), - - /// #[name = "value"] - NameValue { path: Path, value: Literal }, - - /// #[derive(Clone, Copy)] - List { path: Path, items: Vec }, -} - -#[derive(Debug, Clone, Serialize)] -pub enum TypeExprKind { - Path(Path), - PathParams(Path, Vec), - Tuple(Vec), - Lifetime(Identifier), -} - -#[derive(Debug, Clone, Serialize)] -pub struct TypeExpr(pub TypeExprKind, pub Vec); - -#[derive(Debug, Clone, Serialize)] -pub struct Path(pub Vec); - -#[derive(Debug, Clone, Serialize)] -pub enum BinaryOp { - Plus, - Minus, - Multiply, - Divide, - Modulo, - Equal, - NotEqual, - LessThan, - GreaterThan, - LessThanOrEqual, - GreaterThanOrEqual, - And, - Or, -} - -#[derive(Debug, Clone, Serialize)] -pub struct TopLevel(pub TopLevelKind, pub Vec); - -#[derive(Debug, Clone, Serialize)] -pub enum TopLevelKind { - ModAttribute, - Import(Visibility, Path), - Mod(Visibility, Identifier), - ImplDecl(ImplDecl), - TraitDecl { - visibility: Visibility, - name: Identifier, - generics: Generics, - requirements: Vec, - items: Vec, - }, - EnumDecl { - visibility: Visibility, - name: Identifier, - generics: Generics, - fields: Vec, - }, - StructDecl { - visibility: Visibility, - name: Identifier, - generics: Generics, - fields: Vec, - }, - FunctionDecl(FunctionDecl), - ClassDecl { - visibility: Visibility, - name: Identifier, - generics: Generics, - fields: Vec, - constructor: ClassConstructor, - items: Vec, - }, -} - -#[derive(Debug, Clone, Serialize)] -pub enum ClassItem { - Method(FunctionDecl), - ImplDecl(ImplDecl), -} - -#[derive(Debug, Clone, Serialize, Default)] -pub struct Generics(pub Vec); - -#[derive(Debug, Clone, Serialize)] -pub enum Generic { - Lifetime(Identifier), - Type(Identifier, 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, Vec), -} - -#[derive(Debug, Clone, Serialize)] -pub struct ClassConstructor { - pub visibility: Visibility, - pub generics: Generics, - pub params: ParamList, - pub body: Block, -} - -#[derive(Debug, Clone, Serialize)] -pub struct FunctionDecl { - pub visibility: Visibility, - pub name: Identifier, - pub generics: Generics, - pub params: ParamList, - pub return_type: TypeExpr, - pub body: Option, -} - -#[derive(Debug, Clone, Serialize)] -pub enum Postfix { - FieldAccess(Identifier), - Call(Vec), - MacroCall(String), - StructCall(Vec<(Identifier, Expression)>), - Index(Expression), - Binary(BinaryOp, Expression), -} - -#[derive(Debug, Clone, Serialize)] -pub enum Prefix { - Ref, - RefMut, - Deref, - New, - Not, -} - -#[derive(Debug, Clone, Serialize)] -pub enum Statement { - Expression(Expression), - Block(Block), - - VarDecl(VarDeclStmt), - VarAssign(VarAssignStmt), - If { - initial: StatementBranch, - else_if: Vec, - else_branch: Option>, - }, - While(StatementBranch), - CStyleFor { - init: Box, - condition: Expression, - update: Box, - body: Box, - }, - For { - mutable: bool, - pattern: Pattern, - iterator: Expression, - body: Box, - }, - Match(Expression, Vec<(Pattern, Block)>), - - Return(Option), - Break, - Continue, -} - -#[derive(Debug, Clone, Serialize)] -pub struct ImplDecl { - pub generics: Generics, - pub target: TypeExpr, - pub trait_: Option, - pub methods: Vec, -} - -#[derive(Debug, Clone, Serialize)] -pub struct VarDecl { - pub mutable: bool, - pub name: Pattern, - pub type_: Option, -} - -#[derive(Debug, Clone, Serialize)] -pub struct VarDeclStmt { - pub decl: VarDecl, - pub init: Option, -} - -#[derive(Debug, Clone, Serialize)] -pub struct FieldDecl { - pub visibility: Visibility, - pub type_: TypeExpr, - pub name: Identifier, -} - -#[derive(Debug, Clone, Serialize)] -pub struct FieldDeclStmt { - pub decl: FieldDecl, - pub init: Option, -} - -#[derive(Debug, Clone, Serialize)] -pub struct VarAssignStmt { - pub target: Expression, - pub value: Expression, -} - -#[derive(Debug, Clone, Serialize)] -pub struct StatementBranch { - pub condition: Expression, - pub body: Box, -} - -#[derive(Debug, Clone, Serialize)] -pub enum Expression { - Literal(Literal), - Path(Path), - Fix { - initial: Box, - prefixes: Vec, - postfixes: Vec, - }, -} - -#[derive(Debug, Clone, Serialize)] -pub enum Literal { - String(String), - Int(i64), - Float(f64), - Bool(bool), - Tuple(Vec), -} - -impl TypeExpr { - pub fn no_px(kind: TypeExprKind) -> Self { - Self(kind, Vec::new()) - } -} diff --git a/parser/src/ast/expr.rs b/parser/src/ast/expr.rs new file mode 100644 index 0000000..9680af9 --- /dev/null +++ b/parser/src/ast/expr.rs @@ -0,0 +1,93 @@ +use serde::Serialize; + +use super::*; + +#[derive(Debug, Clone, Serialize)] +pub enum BinaryOp { + Plus, + Minus, + Multiply, + Divide, + Modulo, + Equal, + NotEqual, + LessThan, + GreaterThan, + LessThanOrEqual, + GreaterThanOrEqual, + And, + Or, + ShiftLeft, + ShiftRight, + RangeInclusive, + RangeExclusive, + BitAnd, + BitOr, + BitXor, +} + +#[derive(Debug, Clone, Serialize)] +pub enum Expression { + Literal(Literal), + Path(ExprPath), + Fix { + initial: Box, + prefixes: Vec, + postfixes: Vec, + }, + Binary { + lhs: Box, + op: BinaryOp, + rhs: Box, + }, +} + +#[derive(Debug, Clone, Serialize)] +pub enum Literal { + String(String), + Int(i64), + Float(f64), + Bool(bool), + Tuple(Vec), + Array(Vec), + ArrayRepeat(Box, Box), +} + +#[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 Postfix { + FieldAccess(Identifier, Option), + Call(Vec), + MacroCall(String), + StructCall(Vec<(Identifier, Expression)>), + Index(Expression), + As(TypeExpr), +} + +#[derive(Debug, Clone, Serialize)] +pub enum Prefix { + Ref, + RefMut, + Deref, + New(Option), + Not, + Neg, +} + +#[derive(Debug, Clone, Serialize)] +pub struct ExprPathSegment { + pub ident: Identifier, + pub generics: Option, +} + +#[derive(Debug, Clone, Serialize)] +pub struct ExprPath(pub Vec); diff --git a/parser/src/ast/mod.rs b/parser/src/ast/mod.rs new file mode 100644 index 0000000..1dd636d --- /dev/null +++ b/parser/src/ast/mod.rs @@ -0,0 +1,43 @@ +use serde::Serialize; + +pub mod expr; +pub mod statement; +pub mod top_level; + +pub use expr::*; +pub use statement::*; +pub use top_level::*; + +#[derive(Debug, Clone, Serialize)] +pub struct Path(pub Vec); + +#[derive(Debug, Clone, Serialize)] +pub struct Identifier(pub String); + +#[derive(Debug, Clone, Serialize, Default)] +pub struct ParamList(pub Vec); + +#[derive(Debug, Clone, Serialize)] +pub enum TypePostfix { + Ref, + RefMut, + RefLifetime(Identifier), + RefMutLifetime(Identifier), +} + +#[derive(Debug, Clone, Serialize)] +pub enum TypeExprKind { + Path(Path), + PathParams(Path, Vec), + Tuple(Vec), + Lifetime(Identifier), +} + +#[derive(Debug, Clone, Serialize)] +pub struct TypeExpr(pub TypeExprKind, pub Vec); + +impl TypeExpr { + pub fn no_px(kind: TypeExprKind) -> Self { + Self(kind, Vec::new()) + } +} diff --git a/parser/src/ast/statement.rs b/parser/src/ast/statement.rs new file mode 100644 index 0000000..8ae23e9 --- /dev/null +++ b/parser/src/ast/statement.rs @@ -0,0 +1,64 @@ +use serde::Serialize; + +use super::*; + +#[derive(Debug, Clone, Serialize, Default)] +pub struct Block(pub Vec); + +#[derive(Debug, Clone, Serialize)] +pub enum Statement { + Expression(Expression), + Block(Block), + + VarDecl(VarDeclStmt), + Assign { + target: Expression, + compound: String, + value: Expression, + }, + If { + initial: StatementBranch, + else_if: Vec, + else_branch: Option>, + }, + While(StatementBranch), + CStyleFor { + init: Box, + condition: Expression, + update: Box, + body: Box, + }, + For { + mutable: bool, + pattern: Pattern, + iterator: Expression, + body: Box, + }, + Match(Expression, Vec<(Pattern, Block)>), + + Return(Option), + Break, + Continue, + + Increment(Expression), + Decrement(Expression), +} + +#[derive(Debug, Clone, Serialize)] +pub struct VarDecl { + pub mutable: bool, + pub name: Pattern, + pub type_: Option, +} + +#[derive(Debug, Clone, Serialize)] +pub struct VarDeclStmt { + pub decl: VarDecl, + pub init: Option, +} + +#[derive(Debug, Clone, Serialize)] +pub struct StatementBranch { + pub condition: Expression, + pub body: Box, +} diff --git a/parser/src/ast/top_level.rs b/parser/src/ast/top_level.rs new file mode 100644 index 0000000..30021ea --- /dev/null +++ b/parser/src/ast/top_level.rs @@ -0,0 +1,121 @@ +use serde::Serialize; + +use super::*; + +#[derive(Debug, Clone, Serialize)] +pub enum Visibility { + Public, + PublicTarget(Path), + Private, +} + +#[derive(Debug, Clone, Serialize)] +pub enum Attribute { + /// #[test] + Path(Path), + + /// #[name = "value"] + NameValue { path: Path, value: Literal }, + + /// #[derive(Clone, Copy)] + List { path: Path, items: Vec }, +} + +#[derive(Debug, Clone, Serialize)] +pub struct TopLevel(pub TopLevelKind, pub Vec); + +#[derive(Debug, Clone, Serialize)] +pub enum TopLevelKind { + ModAttribute, + Import(Visibility, Path), + Mod(Visibility, Identifier), + ImplDecl(ImplDecl), + TraitDecl { + visibility: Visibility, + name: Identifier, + generics: Generics, + requirements: Vec, + items: Vec, + }, + EnumDecl { + visibility: Visibility, + name: Identifier, + generics: Generics, + fields: Vec, + }, + StructDecl { + visibility: Visibility, + name: Identifier, + generics: Generics, + fields: Vec, + }, + FunctionDecl(FunctionDecl), + ClassDecl { + visibility: Visibility, + name: Identifier, + generics: Generics, + fields: Vec, + constructor: ClassConstructor, + items: Vec, + }, +} + +#[derive(Debug, Clone, Serialize)] +pub enum ClassItem { + Method(FunctionDecl), + ImplDecl(ImplDecl), +} + +#[derive(Debug, Clone, Serialize, Default)] +pub struct Generics(pub Vec); + +#[derive(Debug, Clone, Serialize)] +pub enum Generic { + Lifetime(Identifier), + Type(Identifier, Vec), +} +#[derive(Debug, Clone, Serialize)] +pub enum EnumItem { + Named(Identifier), + Tuple(Identifier, Vec), + Struct(Identifier, Vec), +} + +#[derive(Debug, Clone, Serialize)] +pub struct ClassConstructor { + pub visibility: Visibility, + pub generics: Generics, + pub params: ParamList, + pub body: Block, +} + +#[derive(Debug, Clone, Serialize)] +pub struct FunctionDecl { + pub visibility: Visibility, + pub name: Identifier, + pub generics: Generics, + pub params: ParamList, + pub return_type: TypeExpr, + pub body: Option, +} + +#[derive(Debug, Clone, Serialize)] +pub struct ImplDecl { + pub generics: Generics, + pub target: TypeExpr, + pub trait_: Option, + pub methods: Vec, +} + +#[derive(Debug, Clone, Serialize)] +pub struct FieldDecl { + pub visibility: Visibility, + pub type_: TypeExpr, + pub name: Identifier, +} + +#[derive(Debug, Clone, Serialize)] +pub struct FieldDeclStmt { + pub decl: FieldDecl, + pub init: Option, +} diff --git a/parser/src/error.rs b/parser/src/error.rs index ebec476..1ad1b05 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -48,11 +48,19 @@ impl<'a, F> AstError<'a, F> { } } + #[track_caller] pub fn bug_unimplemented(pair: Pair<'a, Rule>) -> AstResult<'a, T, F> { + let loc = std::panic::Location::caller(); + Err(Self { span: pair.as_span(), error_code: ErrorCode::AstGenBug, - error_message: format!("Possible bug, unimplemented: {:#?}", pair.as_rule()), + error_message: format!( + "Possible bug, unimplemented: {:#?}, at {}:{}", + pair.as_rule(), + loc.file(), + loc.line(), + ), recovered: None, }) } diff --git a/parser/src/grammar.pest b/parser/src/grammar.pest index 945c825..056511f 100644 --- a/parser/src/grammar.pest +++ b/parser/src/grammar.pest @@ -323,6 +323,8 @@ statement = _{ | continue_stmt | block | var_decl_statement + | increment_statement + | decrement_statement } // ------------------------------------------------------ @@ -349,8 +351,29 @@ var_decl_statement = { var_decl ~ ("=" ~ expr)? ~ semicolon } +increment_statement = { + expr ~ "++" ~ semicolon +} + +decrement_statement = { + expr ~ "--" ~ semicolon +} + +compound_assign = { + "=" + | "+=" + | "-=" + | "/=" + | "%=" + | "&=" + | "|=" + | "^=" + | "<<=" + | ">>=" +} + assign_statement = { - expr ~ "=" ~ expr ~ semicolon + expr ~ compound_assign ~ expr ~ semicolon } // ------------------------------------------------------ @@ -404,13 +427,19 @@ match_stmt = { // ====================================================== // ------------------------------------------------------ -// TUPLES +// TUPLES & ARRAYS // ------------------------------------------------------ tuple = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" } +array = { + "[" ~ expr ~ ";" ~ expr ~ "]" // Repeat notation: [0; 10] + + | "[" ~ (expr ~ ("," ~ expr)* ~ ","?)? ~ "]" // Standard elements initialization +} + // ------------------------------------------------------ // MACROS // ------------------------------------------------------ @@ -424,10 +453,19 @@ macro_inner_v = { // PRIMARY EXPRESSIONS // ------------------------------------------------------ +expr_path_segment = { + identifier ~ ("::" ~ generics)? +} + +expr_path = { + expr_path_segment ~ ("::" ~ expr_path_segment)* +} + primary = { literal - | static_path + | expr_path | tuple + | array } // ------------------------------------------------------ @@ -435,7 +473,7 @@ primary = { // ------------------------------------------------------ field_px = { - "." ~ identifier + "." ~ identifier ~ ("::" ~ generics)? } call_px = { @@ -458,8 +496,8 @@ index_px = { "[" ~ expr ~ "]" } -binary_px = { - bin_op ~ expr +as_px = { + "as" ~ type_expr } postfix = { @@ -468,32 +506,19 @@ postfix = { | macro_call_px | struct_px | index_px - | binary_px + | as_px } // ------------------------------------------------------ // PREFIX EXPRESSIONS // ------------------------------------------------------ -deref_px = { - "*" -} - -mut_ref_px = { - "&" ~ mutable -} - -ref_px = { - "&" -} - -new_px = { - "new" -} - -not_px = { - "!" -} +deref_px = { "*" } +mut_ref_px = { "&" ~ mutable } +ref_px = { "&" } +new_px = { "new" ~ generics? } +not_px = { "!" } +neg_px = { "-" } prefix = { deref_px @@ -501,36 +526,61 @@ prefix = { | ref_px | new_px | not_px -} - -prefix_list = { - prefix* + | neg_px } // ------------------------------------------------------ -// OPERATORS +// OPERATORS (Arranged carefully for PEG priority matching) // ------------------------------------------------------ -bin_op = { - "<=" - | ">=" - | "==" - | "!=" - | "&&" - | "||" - | "+" - | "-" - | "*" - | "/" - | "%" - | "<" - | ">" +shl = { "<<" } +shr = { ">>" } +range_inc = { "..=" } +range_exc = { ".." } +lte = { "<=" } +gte = { ">=" } +eq = { "==" } +neq = { "!=" } +and = { "&&" } +or = { "||" } +add = { "+" } +sub = { "-" } +mul = { "*" } +div = { "/" } +rem = { "%" } +lt = { "<" } +gt = { ">" } +bitand = { "&" } +bitor = { "|" } +bitxor = { "^" } + +bin_op = _{ + shl + | shr + | range_inc + | range_exc + | lte + | gte + | eq + | neq + | and + | or + | lt + | gt + | add + | sub + | mul + | div + | rem + | bitand + | bitor + | bitxor } // ------------------------------------------------------ // EXPRESSIONS // ------------------------------------------------------ -expr = { - prefix_list ~ primary ~ postfix* -} +expr = { term ~ (bin_op ~ term)* } + +term = { prefix* ~ primary ~ postfix* } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index df5cbf5..245fd9f 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -41,7 +41,7 @@ macro_rules! ast_ensure { Err(AstError { span: $pair.as_span(), error_code: crate::error::ErrorCode::AstGenBug, - error_message: format!("Possible bug: expected {:?}, got {}", $rule, $pair), + error_message: format!("Possible bug: expected {:?}, got {:?}", $rule, $pair.as_rule()), recovered: None, }) } @@ -50,6 +50,16 @@ macro_rules! ast_ensure { #[macro_export] macro_rules! ast_expr { + (use $r:expr, $($v:expr),* $(,)?) => {{ + let mut analyzer = $crate::error::AstErrorAnalyzer(None); + + $( + analyzer.get($v).get()?; + )* + + analyzer.build($r) + }}; + ($($item:ident)::+ { $($k:ident: $v:expr),* $(,)? }) => {{ let mut analyzer = $crate::error::AstErrorAnalyzer(None); diff --git a/parser/src/parser/common/expr.rs b/parser/src/parser/common/expr.rs index e49680d..94baab8 100644 --- a/parser/src/parser/common/expr.rs +++ b/parser/src/parser/common/expr.rs @@ -1,40 +1,122 @@ use crate::{ Rule, ast::*, - ast_expr, - error::{AstError, GetLength, IntoErr, collect_recovered, collect_recovered_map}, + ast_ensure, ast_expr, + error::{AstError, AstResult, GetLength, IntoErr, collect_recovered, collect_recovered_map}, }; +use pest::pratt_parser::PrattParser; +use std::sync::OnceLock; impl<'a> TryFrom> for Expression { type Error = AstError<'a, Self>; fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { let rule = pair.as_rule(); - let mut inner = pair.clone().into_inner(); + let inner = pair.clone().into_inner(); match rule { Rule::expr => { - let prefixes = inner - .next() - .map(|p| collect_recovered::(p.into_inner())) - .unwrap_or_else(|| Ok(Vec::new())); + static PRATT_PARSER: OnceLock> = OnceLock::new(); + let pratt = PRATT_PARSER.get_or_init(|| { + use Rule::*; + use pest::pratt_parser::{Assoc::*, Op}; - let exp = Expression::try_from(inner.next().unwrap()); + PrattParser::new() + .op(Op::infix(range_inc, Left) | Op::infix(range_exc, Left)) + .op(Op::infix(or, Left)) + .op(Op::infix(and, Left)) + .op(Op::infix(bitor, Left)) + .op(Op::infix(bitxor, Left)) + .op(Op::infix(bitand, Left)) + .op(Op::infix(eq, Left) | Op::infix(neq, Left)) + .op(Op::infix(lt, Left) + | Op::infix(lte, Left) + | Op::infix(gt, Left) + | Op::infix(gte, Left)) + .op(Op::infix(shl, Left) | Op::infix(shr, Left)) + .op(Op::infix(add, Left) | Op::infix(sub, Left)) + .op(Op::infix(mul, Left) | Op::infix(div, Left) | Op::infix(rem, Left)) + }); - if inner.len() > 0 || prefixes.len() > 0 { + pratt + .map_primary(|primary_pair| Expression::try_from(primary_pair)) + .map_infix(|lhs, op, rhs| { + let bin_op = match op.as_rule() { + Rule::shl => BinaryOp::ShiftLeft, + Rule::shr => BinaryOp::ShiftRight, + Rule::range_inc => BinaryOp::RangeInclusive, + Rule::range_exc => BinaryOp::RangeExclusive, + Rule::lte => BinaryOp::LessThanOrEqual, + Rule::gte => BinaryOp::GreaterThanOrEqual, + Rule::eq => BinaryOp::Equal, + Rule::neq => BinaryOp::NotEqual, + Rule::and => BinaryOp::And, + Rule::or => BinaryOp::Or, + Rule::add => BinaryOp::Plus, + Rule::sub => BinaryOp::Minus, + Rule::mul => BinaryOp::Multiply, + Rule::div => BinaryOp::Divide, + Rule::rem => BinaryOp::Modulo, + Rule::lt => BinaryOp::LessThan, + Rule::gt => BinaryOp::GreaterThan, + Rule::bitand => BinaryOp::BitAnd, + Rule::bitor => BinaryOp::BitOr, + Rule::bitxor => BinaryOp::BitXor, + _ => return AstError::bug_unimplemented(op), + }; + + ast_expr!(Expression::Binary { + lhs: lhs.map(Box::new), + op: Ok(bin_op) as AstResult<'_, BinaryOp>, + rhs: rhs.map(Box::new), + }) + }) + .parse(inner) + } + + Rule::term => { + let mut prefix_pairs = Vec::new(); + let mut primary_pair = None; + let mut postfix_pairs = Vec::new(); + + for p in inner { + match p.as_rule() { + Rule::prefix => prefix_pairs.push(p), + Rule::primary => primary_pair = Some(p), + Rule::postfix => postfix_pairs.push(p), + _ => {} + } + } + + let prefixes = collect_recovered::(prefix_pairs.into_iter()); + let exp = Expression::try_from( + primary_pair.expect("Term must contain a primary expression"), + ); + let postfixes = collect_recovered::(postfix_pairs.into_iter()); + + if postfixes.len() > 0 || prefixes.len() > 0 { ast_expr!(Expression::Fix { initial: exp.map(Box::new), prefixes: prefixes, - postfixes: collect_recovered(inner), + postfixes: postfixes, }) } else { - exp + ast_expr!(use exp?, prefixes, postfixes) } } - Rule::primary => inner.next().unwrap().try_into(), + Rule::tuple => { + ast_expr!(Expression::Literal( + collect_recovered(pair.into_inner()) + .map(Literal::Tuple) + .get_map(Literal::Tuple) + )) + } + + Rule::primary => pair.into_inner().next().unwrap().try_into(), Rule::static_path => ast_expr!(Expression::Path(pair.try_into())), Rule::literal => ast_expr!(Expression::Literal(pair.try_into())), + Rule::expr_path => ast_expr!(Expression::Path(pair.try_into())), _ => AstError::bug_unimplemented(pair), } @@ -50,8 +132,14 @@ impl<'a> TryFrom> for Prefix { Rule::deref_px => Self::Deref, Rule::mut_ref_px => Self::RefMut, Rule::ref_px => Self::Ref, - Rule::new_px => Self::New, + Rule::new_px => Self::New( + pair.into_inner() + .next() + .map(|v| v.try_into().get()) + .transpose()?, + ), Rule::not_px => Self::Not, + Rule::neg_px => Self::Neg, _ => return AstError::bug_unimplemented(pair), }) @@ -69,7 +157,10 @@ impl<'a> TryFrom> for Postfix { Rule::postfix => Postfix::try_from(inner.next().unwrap()), Rule::field_px => { - ast_expr!(Postfix::FieldAccess(inner.next().unwrap().try_into())) + ast_expr!(Postfix::FieldAccess( + inner.next().unwrap().try_into(), + inner.next().map(Generics::try_from).transpose() + )) } Rule::call_px => ast_expr!(Postfix::Call(collect_recovered(inner))), @@ -86,32 +177,38 @@ impl<'a> TryFrom> for Postfix { ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap()))) } - Rule::binary_px => { - let op_pair = inner.next().unwrap(); - let op = match op_pair.as_str() { - "+" => BinaryOp::Plus, - "-" => BinaryOp::Minus, - "*" => BinaryOp::Multiply, - "/" => BinaryOp::Divide, - "%" => BinaryOp::Modulo, - "==" => BinaryOp::Equal, - "!=" => BinaryOp::NotEqual, - "<" => BinaryOp::LessThan, - ">" => BinaryOp::GreaterThan, - "<=" => BinaryOp::LessThanOrEqual, - ">=" => BinaryOp::GreaterThanOrEqual, - "&&" => BinaryOp::And, - "||" => BinaryOp::Or, - - _ => return AstError::bug_unimplemented(op_pair), - }; - - Ok(Postfix::Binary(op, inner.next().unwrap().try_into().get()?)) - } - Rule::macro_call_px => Ok(Postfix::MacroCall(inner.as_str().to_string())), + Rule::as_px => { + ast_expr!(Postfix::As(inner.next().unwrap().try_into())) + } + _ => AstError::bug_unimplemented(pair), } } } + +impl<'a> TryFrom> for ExprPath { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + ast_ensure!(pair, Rule::expr_path => { + ast_expr!(ExprPath(collect_recovered(pair.into_inner()))) + }) + } +} + +impl<'a> TryFrom> for ExprPathSegment { + type Error = AstError<'a, Self>; + + fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result { + let mut inner = pair.clone().into_inner(); + + ast_ensure!(pair, Rule::expr_path_segment => { + ast_expr!(ExprPathSegment { + ident: Identifier::try_from(inner.next().unwrap()), + generics: inner.next().map(Generics::try_from).transpose(), + }) + }) + } +} diff --git a/parser/src/parser/common/statement.rs b/parser/src/parser/common/statement.rs index 243e6a3..860ec61 100644 --- a/parser/src/parser/common/statement.rs +++ b/parser/src/parser/common/statement.rs @@ -88,13 +88,12 @@ impl<'a> TryFrom> for Statement { body: inner.next().unwrap().try_into().map(Box::new), }), - Rule::assign_statement => ast_expr!(VarAssignStmt { + Rule::assign_statement => ast_expr!(Statement::Assign { target: inner.next().unwrap().try_into(), + compound: Ok(inner.next().unwrap().as_str().trim().to_string()) + as AstResult<'_, String>, value: inner.next().unwrap().try_into(), - }) - .map(Statement::VarAssign) - .get_map(Statement::VarAssign), - + }), Rule::match_stmt => ast_expr!(Statement::Match( inner.next().unwrap().try_into(), inner @@ -108,6 +107,14 @@ impl<'a> TryFrom> for Statement { .collect::>>(), )), + Rule::increment_statement => { + ast_expr!(Statement::Increment(inner.next().unwrap().try_into())) + } + + Rule::decrement_statement => { + ast_expr!(Statement::Decrement(inner.next().unwrap().try_into())) + } + Rule::unexpected_statement => { return Err(AstError { span: pair.as_span(), diff --git a/src/codegen.rs b/src/codegen.rs index f60d37e..8ba285b 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,8 +1,8 @@ use mist_parser::ast::{ - Attribute, BinaryOp, Block, ClassItem, EnumItem, Expression, FieldDecl, FunctionDecl, Generic, - Generics, Identifier, ImplDecl, Literal, Path, Pattern, Postfix, Prefix, Statement, - StatementBranch, TopLevel, TopLevelKind, TypeExpr, TypeExprKind, TypePostfix, VarAssignStmt, - VarDecl, VarDeclStmt, Visibility, + Attribute, BinaryOp, Block, ClassItem, EnumItem, ExprPath, ExprPathSegment, Expression, + FieldDecl, FunctionDecl, Generic, Generics, Identifier, ImplDecl, Literal, Path, Pattern, + Postfix, Prefix, Statement, StatementBranch, TopLevel, TopLevelKind, TypeExpr, TypeExprKind, + TypePostfix, VarDecl, VarDeclStmt, Visibility, }; // --------------------------------------------------------------------------- @@ -137,6 +137,17 @@ impl GetRust for Literal { .join(", ") ) } + Self::Array(values) => format!( + "[{}]", + values + .iter() + .map(Expression::get_rust) + .collect::>() + .join(", ") + ), + Self::ArrayRepeat(value, repeat) => { + format!("[{}; {}]", value.get_rust(), repeat.get_rust()) + } } } } @@ -156,6 +167,32 @@ impl GetRust for Expression { + &Some(prefixes).get_rust() + &postfixes.get_rust() } + // Safely integrated to handle the tree structure built by the Pratt Parser + Expression::Binary { lhs, 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 => ">=", + BinaryOp::And => "&&", + BinaryOp::Or => "||", + BinaryOp::ShiftLeft => "<<", + BinaryOp::ShiftRight => ">>", + BinaryOp::RangeInclusive => "..=", + BinaryOp::RangeExclusive => "..", + BinaryOp::BitAnd => "&", + BinaryOp::BitOr => "|", + BinaryOp::BitXor => "^", + }; + format!("{} {} {}", lhs.get_rust(), op_str, rhs.get_rust()) + } } } } @@ -167,7 +204,8 @@ impl GetRust for Prefix { Self::Ref => "&", Self::RefMut => "&mut ", Self::Not => "!", - Self::New => "", + Self::New(_) => "", + Self::Neg => "-", } .to_string() } @@ -179,6 +217,29 @@ impl GetRust for [Prefix] { } } +impl GetRust for ExprPath { + fn get_rust(&self) -> String { + self.0 + .iter() + .map(ExprPathSegment::get_rust) + .collect::>() + .join("::") + } +} + +impl GetRust for ExprPathSegment { + fn get_rust(&self) -> String { + format!( + "{}{}", + self.ident.get_rust(), + self.generics + .as_ref() + .map(|v| format!("::{}", v.get_rust())) + .unwrap_or_default() + ) + } +} + impl GetRust for Option<&Vec> { fn get_rust(&self) -> String { self.map(|prefixes| { @@ -186,8 +247,14 @@ impl GetRust for Option<&Vec> { .iter() .last() .map(|p| match p { - Prefix::New => "::new", - _ => "", + Prefix::New(generics) => format!( + "::new{}", + generics + .as_ref() + .map(|v| format!("::{}", v.get_rust())) + .unwrap_or_default(), + ), + _ => String::new(), }) .unwrap_or_default() .to_string() @@ -199,7 +266,14 @@ impl GetRust for Option<&Vec> { impl GetRust for Postfix { fn get_rust(&self) -> String { match self { - Postfix::FieldAccess(field) => format!(".{}", field.get_rust()), + Postfix::FieldAccess(field, generics) => format!( + ".{}{}", + field.get_rust(), + generics + .as_ref() + .map(|v| format!("::{}", v.get_rust())) + .unwrap_or_default() + ), Postfix::Call(args) => { let args = args @@ -227,24 +301,7 @@ impl GetRust for Postfix { 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 => ">=", - BinaryOp::And => "&&", - BinaryOp::Or => "||", - }; - format!(" {} {}", op_str, rhs.get_rust()) - } + Postfix::As(ty) => format!(" as {}", ty.get_rust()), } } } @@ -254,7 +311,6 @@ impl GetRust for [Postfix] { self.iter().map(Postfix::get_rust).collect() } } - // --------------------------------------------------------------------------- // ToRust — output-writing (top-level, statements, blocks) // --------------------------------------------------------------------------- @@ -545,8 +601,17 @@ impl ToRust for Statement { cg.add_indentedln(&format!("let {}{};", decl.get_rust(), init)); } - Statement::VarAssign(VarAssignStmt { target, value }) => { - cg.add_indentedln(&format!("{} = {};", target.get_rust(), value.get_rust(),)); + Statement::Assign { + target, + compound, + value, + } => { + cg.add_indentedln(&format!( + "{} {} {};", + target.get_rust(), + compound, + value.get_rust(), + )); } Statement::Match(expr, match_items) => { @@ -639,6 +704,9 @@ impl ToRust for Statement { Statement::Break => cg.add_indentedln("break;"), Statement::Continue => cg.add_indentedln("continue;"), + + Statement::Increment(e) => cg.add_indentedln(&format!("{}+=1;", e.get_rust())), + Statement::Decrement(e) => cg.add_indentedln(&format!("{}-=1;", e.get_rust())), } } } @@ -822,7 +890,7 @@ impl GetRust for Generics { "<{}>", self.0 .iter() - .map(|v| (true, v).get_rust()) + .map(|v| (false, v).get_rust()) .collect::>() .join(", ") ) @@ -836,9 +904,7 @@ impl GetRust for (bool, &Generic) { Generic::Lifetime(name) => format!("'{}", name.get_rust()), Generic::Type(name, requirements) => { name.get_rust() - + &(if !self.0 && requirements.len() == 0 { - String::new() - } else { + + &(if self.0 && requirements.len() != 0 { format!( ": {}", requirements @@ -847,6 +913,8 @@ impl GetRust for (bool, &Generic) { .collect::>() .join("+") ) + } else { + String::new() }) } }