Skip to content

Commit

Permalink
feat(parser): add types to support binary operators.
Browse files Browse the repository at this point in the history
  • Loading branch information
rzvxa committed Mar 5, 2024
1 parent 4dfa7e2 commit cf51393
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 18 deletions.
29 changes: 29 additions & 0 deletions crates/fuse-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
2 changes: 2 additions & 0 deletions crates/fuse-ast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod ast;
mod ast_factory;
mod precedence;

pub use ast::*;
pub use ast_factory::*;
pub use precedence::*;
17 changes: 17 additions & 0 deletions crates/fuse-ast/src/precedence.rs
Original file line number Diff line number Diff line change
@@ -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,
}
28 changes: 20 additions & 8 deletions crates/fuse-parser/src/lexer/token_kind.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use fuse_ast::Precedence;
use fuse_common_proc::serializable;

#[serializable]
Expand Down Expand Up @@ -93,6 +94,10 @@ pub enum TokenKind {
LAngle,
/// >
RAngle,
/// <=
LtEq,
/// >=
GtEq,
/// =
Eq,
/// ==
Expand All @@ -115,6 +120,8 @@ pub enum TokenKind {
Slash,
/// //
Slash2,
/// %
Percent,
/// =>
Arrow,
/// ->
Expand Down Expand Up @@ -188,15 +195,20 @@ impl TokenKind {
}
}

pub fn is_binary_operator(&self) -> bool {
pub fn to_precedence(self) -> Option<Precedence> {
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,
}
}
}
12 changes: 8 additions & 4 deletions crates/fuse-parser/src/parsers/expressions.rs
Original file line number Diff line number Diff line change
@@ -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<Expression> {
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<Expression> {
match self.cur_kind() {
TokenKind::True => {
let token = self.consume();
Ok(self.ast.boolean_expression(BooleanLiteral {
Expand Down Expand Up @@ -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<Identifier> {
Expand Down
63 changes: 57 additions & 6 deletions crates/fuse-parser/src/parsers/operators.rs
Original file line number Diff line number Diff line change
@@ -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<UnaryOperator> {
Expand All @@ -12,8 +17,12 @@ impl<'a> Parser<'a> {
}
}

pub(crate) fn parse_proceding_operator(&mut self, lhs: Expression) -> ParserResult<Expression> {
self.parse_proceding_operator_recursive(lhs)
pub(crate) fn parse_with_precedence(
&mut self,
lhs: Expression,
precedence: Precedence,
) -> ParserResult<Expression> {
self.parse_proceding_operator_recursive(lhs, precedence)
}

fn parse_unary_not_operator(&mut self) -> ParserResult<UnaryOperator> {
Expand Down Expand Up @@ -46,11 +55,53 @@ impl<'a> Parser<'a> {
})
}

fn parse_proceding_operator_recursive(&mut self, lhs: Expression) -> ParserResult<Expression> {
fn parse_proceding_operator_recursive(
&mut self,
lhs: Expression,
precedence: Precedence,
) -> ParserResult<Expression> {
// 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<BinaryOperatorKind> {
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
}
}
}

0 comments on commit cf51393

Please sign in to comment.