Skip to content

Commit faad477

Browse files
committed
fix(parser): member and call expressions precedence.
1 parent ca41a45 commit faad477

File tree

15 files changed

+550
-46
lines changed

15 files changed

+550
-46
lines changed

crates/fuse-ast/src/ast.rs

+125-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use fuse_common::{ReferenceType, Span};
22
use fuse_common_proc::serializable;
33
use std::{cell::Cell, rc::Rc};
44

5+
use crate::GetSpan;
6+
57
#[serializable]
68
#[derive(Debug)]
79
pub struct Chunk {
@@ -117,11 +119,35 @@ pub enum Expression {
117119
ArrayExpression(Box<ArrayExpression>),
118120
TupleExpression(Box<TupleExpression>),
119121
ParenthesizedExpression(Box<ParenthesizedExpression>),
122+
MemberExpression(Box<MemberExpression>),
120123
CallExpression(Box<CallExpression>),
121124
TableConstructionExpression(Box<ConstructionExpression>),
122125
StructConstructionExpression(Box<StructConstructionExpression>),
123126
}
124127

128+
impl Expression {
129+
pub fn span(&self) -> Span {
130+
use Expression::*;
131+
match self {
132+
NumberLiteral(expr) => expr.span,
133+
StringLiteral(expr) => expr.span,
134+
BooleanLiteral(expr) => expr.span,
135+
Identifier(expr) => expr.span,
136+
Function(expr) => expr.span,
137+
If(expr) => expr.span,
138+
UnaryOperator(expr) => expr.span(),
139+
BinaryOperator(expr) => expr.span(),
140+
ArrayExpression(expr) => expr.span,
141+
TupleExpression(expr) => expr.span,
142+
ParenthesizedExpression(expr) => expr.span,
143+
MemberExpression(expr) => expr.span,
144+
CallExpression(expr) => expr.span,
145+
TableConstructionExpression(expr) => expr.span,
146+
StructConstructionExpression(expr) => expr.span(),
147+
}
148+
}
149+
}
150+
125151
#[serializable]
126152
#[derive(Debug, PartialEq)]
127153
pub struct BooleanLiteral {
@@ -264,12 +290,29 @@ pub struct UnaryOperator {
264290
pub expression: Expression,
265291
}
266292

293+
impl GetSpan for UnaryOperator {
294+
#[inline]
295+
fn span(&self) -> Span {
296+
Span::with_spans(vec![self.kind.span(), self.expression.span()])
297+
}
298+
}
299+
267300
#[serializable]
268301
#[derive(Debug, PartialEq)]
269302
pub enum UnaryOperatorKind {
270303
Not(Span),
271-
Minus(Span),
272304
Plus(Span),
305+
Minus(Span),
306+
}
307+
308+
impl GetSpan for UnaryOperatorKind {
309+
fn span(&self) -> Span {
310+
match self {
311+
Self::Not(span) => *span,
312+
Self::Plus(span) => *span,
313+
Self::Minus(span) => *span,
314+
}
315+
}
273316
}
274317

275318
#[serializable]
@@ -280,6 +323,12 @@ pub struct BinaryOperator {
280323
pub rhs: Expression,
281324
}
282325

326+
impl GetSpan for BinaryOperator {
327+
fn span(&self) -> Span {
328+
Span::with_spans(vec![self.kind.span(), self.lhs.span(), self.rhs.span()])
329+
}
330+
}
331+
283332
#[serializable]
284333
#[derive(Debug, PartialEq)]
285334
pub enum BinaryOperatorKind {
@@ -307,6 +356,36 @@ pub enum BinaryOperatorKind {
307356
Member(Span),
308357
}
309358

359+
impl GetSpan for BinaryOperatorKind {
360+
fn span(&self) -> Span {
361+
let span = match self {
362+
Self::Assignment(span) => span,
363+
Self::LogicalOr(span) => span,
364+
Self::LogicalAnd(span) => span,
365+
Self::BitwiseOr(span) => span,
366+
Self::BitwiseXor(span) => span,
367+
Self::BitwiseAnd(span) => span,
368+
Self::Equality(span) => span,
369+
Self::NonEquality(span) => span,
370+
Self::LessThanEqual(span) => span,
371+
Self::LessThan(span) => span,
372+
Self::GreaterThanEqual(span) => span,
373+
Self::GreaterThan(span) => span,
374+
Self::Plus(span) => span,
375+
Self::Minus(span) => span,
376+
Self::Multiply(span) => span,
377+
Self::Exponential(span) => span,
378+
Self::Division(span) => span,
379+
Self::FloorDivision(span) => span,
380+
Self::Modulo(span) => span,
381+
Self::ShiftLeft(span) => span,
382+
Self::ShiftRight(span) => span,
383+
Self::Member(span) => span,
384+
};
385+
*span
386+
}
387+
}
388+
310389
#[serializable]
311390
#[derive(Debug, PartialEq)]
312391
pub struct ArrayExpression {
@@ -403,13 +482,58 @@ pub struct CallExpression {
403482
pub arguments: Vec<Expression>,
404483
}
405484

485+
#[serializable]
486+
#[derive(Debug, PartialEq)]
487+
pub struct MemberExpression {
488+
pub span: Span,
489+
pub lhs: Box<MemberExpressionLHS>,
490+
pub rhs: Box<MemberExpressionRHS>,
491+
}
492+
493+
#[serializable]
494+
#[derive(Debug, PartialEq)]
495+
pub enum MemberExpressionLHS {
496+
Identifier(Identifier),
497+
Expression(Expression),
498+
Member(MemberExpression),
499+
Call(CallExpression),
500+
}
501+
502+
impl From<MemberExpressionRHS> for MemberExpressionLHS {
503+
fn from(value: MemberExpressionRHS) -> Self {
504+
match value {
505+
MemberExpressionRHS::Number(num) => {
506+
Self::Expression(Expression::NumberLiteral(Box::from(num)))
507+
}
508+
MemberExpressionRHS::Identifier(ident) => Self::Identifier(ident),
509+
MemberExpressionRHS::Member(member) => Self::Member(member),
510+
MemberExpressionRHS::Call(call) => Self::Call(call),
511+
}
512+
}
513+
}
514+
515+
#[serializable]
516+
#[derive(Debug, PartialEq)]
517+
pub enum MemberExpressionRHS {
518+
Identifier(Identifier),
519+
Number(NumberLiteral),
520+
Member(MemberExpression),
521+
Call(CallExpression),
522+
}
523+
406524
#[serializable]
407525
#[derive(Debug, PartialEq)]
408526
pub struct StructConstructionExpression {
409527
pub target: Expression,
410528
pub construction: ConstructionExpression,
411529
}
412530

531+
impl GetSpan for StructConstructionExpression {
532+
fn span(&self) -> Span {
533+
Span::with_spans(vec![self.target.span(), self.construction.span])
534+
}
535+
}
536+
413537
#[serializable]
414538
#[derive(Debug, PartialEq)]
415539
pub struct ConstructionExpression {

crates/fuse-ast/src/ast_factory.rs

+13
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,19 @@ impl AstFactory {
182182
}))
183183
}
184184

185+
pub fn member_expression(
186+
&self,
187+
span: Span,
188+
lhs: MemberExpressionLHS,
189+
rhs: MemberExpressionRHS,
190+
) -> Expression {
191+
Expression::MemberExpression(Box::from(MemberExpression {
192+
span,
193+
lhs: Box::from(lhs),
194+
rhs: Box::from(rhs),
195+
}))
196+
}
197+
185198
pub fn struct_construction_expression(
186199
&self,
187200
target: Expression,

crates/fuse-ast/src/get_span.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use fuse_common::Span;
2+
3+
pub trait GetSpan {
4+
fn span(&self) -> Span;
5+
}

crates/fuse-ast/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
mod ast_factory;
2+
mod get_span;
23
mod precedence;
34

45
pub mod ast;
56

67
pub use ast::*;
78
pub use ast_factory::*;
9+
pub use get_span::*;
810
pub use precedence::*;

crates/fuse-common/src/span.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::cmp;
2+
13
use fuse_common_proc::serializable;
24

35
#[serializable]
@@ -12,4 +14,12 @@ impl Span {
1214
pub const fn new(start: u32, end: u32) -> Self {
1315
Self { start, end }
1416
}
17+
18+
#[inline]
19+
pub fn with_spans(spans: Vec<Self>) -> Self {
20+
spans
21+
.into_iter()
22+
.reduce(|acc, e| Span::new(cmp::min(acc.start, e.start), cmp::max(acc.end, e.end)))
23+
.expect("Attempt to construct a `Span` using `with_spans` with an empty list of spans.")
24+
}
1525
}

crates/fuse-parser/src/parsers/expressions.rs

+46-8
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::cell::Cell;
33
use crate::{lexer::TokenKind, Parser, ParserResult};
44
use fuse_ast::{
55
ArrayExpressionElement, BinaryOperator, BooleanLiteral, ConstructionExpression,
6-
ConstructionField, Else, Expression, Identifier, If, KeyValueArgument, Precedence,
7-
SpreadArgument, TupleExpressionElement,
6+
ConstructionField, Else, Expression, Identifier, If, KeyValueArgument, MemberExpression,
7+
MemberExpressionLHS, MemberExpressionRHS, Precedence, SpreadArgument, TupleExpressionElement,
88
};
99

1010
impl<'a> Parser<'a> {
@@ -22,6 +22,11 @@ impl<'a> Parser<'a> {
2222
}
2323

2424
pub(crate) fn try_parse_primary_expression(&mut self) -> Option<ParserResult<Expression>> {
25+
let expr = self.try_parse_primary_expression_base()?;
26+
Some(expr.and_then(|expr| self.parse_expression_with_suffix(expr)))
27+
}
28+
29+
pub(crate) fn try_parse_primary_expression_base(&mut self) -> Option<ParserResult<Expression>> {
2530
use TokenKind::*;
2631
let expr = match self.cur_kind() {
2732
True => {
@@ -59,11 +64,7 @@ impl<'a> Parser<'a> {
5964
_ => return None,
6065
};
6166

62-
let Ok(expr) = expr else {
63-
return Some(expr);
64-
};
65-
66-
Some(self.parse_expression_with_suffix(expr))
67+
Some(expr)
6768
}
6869

6970
pub(crate) fn parse_identifier(&mut self) -> ParserResult<Identifier> {
@@ -250,6 +251,7 @@ impl<'a> Parser<'a> {
250251
match self.cur_kind() {
251252
TokenKind::LCurly => self.parse_struct_construction_expression(expr),
252253
TokenKind::LParen => self.parse_call_expression(expr),
254+
TokenKind::Dot => self.parse_member_chain_expression_recursive(expr),
253255
_ => Ok(expr),
254256
}
255257
}
@@ -320,7 +322,7 @@ impl<'a> Parser<'a> {
320322
}
321323

322324
fn parse_call_expression(&mut self, expr: Expression) -> ParserResult<Expression> {
323-
let start = self.start_span();
325+
let start = expr.span();
324326
// consume the open parentheses
325327
self.consume();
326328

@@ -341,6 +343,42 @@ impl<'a> Parser<'a> {
341343
.call_expression(self.end_span(start), expr, arguments))
342344
}
343345

346+
fn parse_member_chain_expression_recursive(
347+
&mut self,
348+
expr: Expression,
349+
) -> ParserResult<Expression> {
350+
let start = expr.span();
351+
if self.consume_if(TokenKind::Dot).is_none() {
352+
return Ok(expr);
353+
}
354+
355+
let lhs = {
356+
match expr {
357+
Expression::Identifier(lhs) => MemberExpressionLHS::Identifier(*lhs),
358+
Expression::CallExpression(call) => MemberExpressionLHS::Call(*call),
359+
Expression::MemberExpression(member) => MemberExpressionLHS::Member(*member),
360+
_ => MemberExpressionLHS::Expression(expr),
361+
}
362+
};
363+
364+
// TODO: better error messages here, no panic, we should recover.
365+
let rhs = match self.try_parse_primary_expression_base().expect("Expected a primary expression")? {
366+
Expression::Identifier(ident) => MemberExpressionRHS::Identifier(*ident),
367+
Expression::NumberLiteral(num) => MemberExpressionRHS::Number(*num),
368+
Expression::CallExpression(call) => MemberExpressionRHS::Call(*call),
369+
Expression::MemberExpression(member) => MemberExpressionRHS::Member(*member),
370+
rhs => panic!("write error, member rhs should be identifier or number(only for tuple types). {rhs:?}"),
371+
};
372+
373+
let expr = self.ast.member_expression(self.end_span(start), lhs, rhs);
374+
let expr = match self.cur_kind() {
375+
TokenKind::LParen => self.parse_call_expression(expr)?,
376+
_ => expr,
377+
};
378+
379+
self.parse_member_chain_expression_recursive(expr)
380+
}
381+
344382
fn parse_expression_with_precedence(
345383
&mut self,
346384
expr: Expression,

crates/fuse-parser/tests/cases/pass/call-expression-01/ast.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Some(Chunk(
1313
statements: [
1414
Expression(CallExpression(CallExpression(
1515
span: Span(
16-
start: 4,
16+
start: 0,
1717
end: 6,
1818
),
1919
callee: Identifier(Identifier(

crates/fuse-parser/tests/cases/pass/call-expression-02/ast.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Some(Chunk(
1313
statements: [
1414
Expression(CallExpression(CallExpression(
1515
span: Span(
16-
start: 4,
16+
start: 0,
1717
end: 13,
1818
),
1919
callee: Identifier(Identifier(

0 commit comments

Comments
 (0)