diff --git a/crates/fuse-ast/src/ast.rs b/crates/fuse-ast/src/ast.rs index fa58b32..52e8cdf 100644 --- a/crates/fuse-ast/src/ast.rs +++ b/crates/fuse-ast/src/ast.rs @@ -240,3 +240,32 @@ pub enum UnaryOperatorKind { Minus(Span), Plus(Span), } + +#[serializable] +#[derive(Debug, PartialEq)] +pub struct BinaryOperator { + pub kind: BinaryOperatorKind, + pub lhs: Expression, + pub rhs: Expression, +} + +#[serializable] +#[derive(Debug, PartialEq)] +pub enum BinaryOperatorKind { + LogicalOr(Span), + LogicalAnd(Span), + BitwiseOr(Span), + BitwiseAnd(Span), + Equality(Span), + NonEquality(Span), + LessThanEqual(Span), + LessThan(Span), + GreaterThanEqual(Span), + GreaterThan(Span), + Plus(Span), + Minus(Span), + Multiply(Span), + Division(Span), + FloorDivision(Span), + Modulo(Span), +} diff --git a/crates/fuse-ast/src/lib.rs b/crates/fuse-ast/src/lib.rs index 5059798..a565999 100644 --- a/crates/fuse-ast/src/lib.rs +++ b/crates/fuse-ast/src/lib.rs @@ -1,5 +1,7 @@ mod ast; mod ast_factory; +mod precedence; pub use ast::*; pub use ast_factory::*; +pub use precedence::*; diff --git a/crates/fuse-ast/src/precedence.rs b/crates/fuse-ast/src/precedence.rs new file mode 100644 index 0000000..b737316 --- /dev/null +++ b/crates/fuse-ast/src/precedence.rs @@ -0,0 +1,17 @@ +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u8)] +pub enum Precedence { + /// Default precedence of any expression + /// used as 0 value of enum. + Expression, + LogicalOr, + LogicalAnd, + BitwiseOr, + BitwiseXor, + BitwiseAnd, + Equality, + Relational, + Shift, + Add, + Multiply, +} diff --git a/crates/fuse-parser/src/lexer/token_kind.rs b/crates/fuse-parser/src/lexer/token_kind.rs index e22b80f..ce13f1a 100644 --- a/crates/fuse-parser/src/lexer/token_kind.rs +++ b/crates/fuse-parser/src/lexer/token_kind.rs @@ -1,3 +1,4 @@ +use fuse_ast::Precedence; use fuse_common_proc::serializable; #[serializable] @@ -93,6 +94,10 @@ pub enum TokenKind { LAngle, /// > RAngle, + /// <= + LtEq, + /// >= + GtEq, /// = Eq, /// == @@ -115,6 +120,8 @@ pub enum TokenKind { Slash, /// // Slash2, + /// % + Percent, /// => Arrow, /// -> @@ -188,15 +195,20 @@ impl TokenKind { } } - pub fn is_binary_operator(&self) -> bool { + pub fn to_precedence(self) -> Option { + use Precedence::*; use TokenKind::*; - matches! { - self, - | Plus - | Minus - | Star - | Slash - | Slash2 + match self { + Or => Some(LogicalOr), + And => Some(LogicalAnd), + Pipe => Some(BitwiseOr), + Caret => Some(BitwiseXor), + Amp => Some(BitwiseAnd), + Eq2 | Neq => Some(Equality), + LAngle | RAngle | LtEq | GtEq | As | In => Some(Relational), + Plus | Minus => Some(Add), + Star | Slash | Slash2 | Percent => Some(Multiply), + _ => None, } } } diff --git a/crates/fuse-parser/src/parsers/expressions.rs b/crates/fuse-parser/src/parsers/expressions.rs index c92470c..bfdd486 100644 --- a/crates/fuse-parser/src/parsers/expressions.rs +++ b/crates/fuse-parser/src/parsers/expressions.rs @@ -1,9 +1,14 @@ use crate::{lexer::TokenKind, Parser, ParserResult}; -use fuse_ast::{BooleanLiteral, Else, Expression, Identifier, If}; +use fuse_ast::{BooleanLiteral, Else, Expression, Identifier, If, Precedence}; impl<'a> Parser<'a> { pub(crate) fn parse_expression(&mut self) -> ParserResult { - let expression = match self.cur_kind() { + let expr = self.parse_primary_expression()?; + self.parse_with_precedence(expr, Precedence::Expression) + } + + pub(crate) fn parse_primary_expression(&mut self) -> ParserResult { + match self.cur_kind() { TokenKind::True => { let token = self.consume(); Ok(self.ast.boolean_expression(BooleanLiteral { @@ -37,8 +42,7 @@ impl<'a> Parser<'a> { } _ => Err(Self::unexpected_error(self.cur_token())), - }; - self.parse_proceding_operator(expression?) + } } pub(crate) fn parse_identifier(&mut self) -> ParserResult { diff --git a/crates/fuse-parser/src/parsers/operators.rs b/crates/fuse-parser/src/parsers/operators.rs index c2e9c3f..c2eb4d3 100644 --- a/crates/fuse-parser/src/parsers/operators.rs +++ b/crates/fuse-parser/src/parsers/operators.rs @@ -1,6 +1,11 @@ -use fuse_ast::{Expression, UnaryOperator, UnaryOperatorKind}; +use fuse_ast::{ + BinaryOperator, BinaryOperatorKind, Expression, Precedence, UnaryOperator, UnaryOperatorKind, +}; -use crate::{lexer::TokenKind, Parser, ParserResult}; +use crate::{ + lexer::{Token, TokenKind}, + Parser, ParserResult, +}; impl<'a> Parser<'a> { pub(crate) fn parse_unary_operator(&mut self) -> ParserResult { @@ -12,8 +17,12 @@ impl<'a> Parser<'a> { } } - pub(crate) fn parse_proceding_operator(&mut self, lhs: Expression) -> ParserResult { - self.parse_proceding_operator_recursive(lhs) + pub(crate) fn parse_with_precedence( + &mut self, + lhs: Expression, + precedence: Precedence, + ) -> ParserResult { + self.parse_proceding_operator_recursive(lhs, precedence) } fn parse_unary_not_operator(&mut self) -> ParserResult { @@ -46,11 +55,53 @@ impl<'a> Parser<'a> { }) } - fn parse_proceding_operator_recursive(&mut self, lhs: Expression) -> ParserResult { + fn parse_proceding_operator_recursive( + &mut self, + lhs: Expression, + precedence: Precedence, + ) -> ParserResult { // early return if there is no proceding binary operator. - if !self.cur_kind().is_binary_operator() { + let Some(op_precedence) = self.cur_kind().to_precedence() else { + return Ok(lhs); + }; + + if op_precedence < precedence { return Ok(lhs); } + + let op = self.parse_binary_operator_kind()?; + todo!() } + + fn parse_binary_operator_kind(&mut self) -> ParserResult { + use TokenKind::*; + let token = self.consume(); + macro_rules! match_op { + { $($kind:ident => $op:ident)+ } => ( + match *token { + $(Token { kind: $kind, span } => Ok(BinaryOperatorKind::$op(span)),)+ + _ => Err(Self::unexpected_error(&token)), + } + ) + } + match_op!{ + Or => LogicalOr + And => LogicalAnd + Pipe => BitwiseOr + Amp => BitwiseAnd + Eq2 => Equality + Neq => NonEquality + LAngle => LessThan + RAngle => GreaterThan + LtEq => LessThanEqual + GtEq => GreaterThanEqual + Plus => Plus + Minus => Minus + Star => Multiply + Slash => Division + Slash2 => FloorDivision + Percent => Modulo + } + } }