Skip to content

Commit

Permalink
new: parse short match correctly (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
KennedyTedesco committed Jan 16, 2023
1 parent 3f56fd4 commit 4766736
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 92 deletions.
53 changes: 20 additions & 33 deletions src/parser/internal/expression/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,37 @@ use crate::tree::expression::control_flow::MatchExpression;
use crate::tree::utils::CommaSeparated;

pub fn match_expression(state: &mut State) -> ParseResult<MatchExpression> {
let r#match = utils::skip_keyword(state, TokenKind::Match)?;

let expression = if state.iterator.current().kind == TokenKind::LeftBrace {
None
} else {
Some(Box::new(expression::create(state)?))
};

Ok(MatchExpression {
comments: state.iterator.comments(),
r#match: utils::skip_keyword(state, TokenKind::Match)?,
expression: Box::new(expression::create(state)?),
r#match,
expression,
body: MatchBodyExpression {
left_brace: utils::skip_left_brace(state)?,
arms: {
let mut items = Vec::new();
let mut commas = Vec::new();
let mut default_arm = None;

while state.iterator.current().kind != TokenKind::RightBrace {
let current = state.iterator.current();
let (condition, default) = if current.kind == TokenKind::Default {
(
MatchArmConditionExpression::Default(utils::skip_keyword(
state,
TokenKind::Default,
)?),
true,
)
let condition = if current.kind == TokenKind::Default {
MatchArmConditionExpression::Default(utils::skip_keyword(
state,
TokenKind::Default,
)?)
} else {
(
MatchArmConditionExpression::Expressions(utils::comma_separated(
state,
&expression::create,
TokenKind::DoubleArrow,
)?),
false,
)
MatchArmConditionExpression::Expressions(utils::comma_separated(
state,
&expression::create,
TokenKind::DoubleArrow,
)?)
};

let arm = MatchArmExpression {
Expand All @@ -48,20 +49,6 @@ pub fn match_expression(state: &mut State) -> ParseResult<MatchExpression> {
expression: expression::create(state)?,
};

if default {
if let Some(default_arm) = &default_arm {
crate::parser_report!(
state,
match_expression_cannot_have_multiple_default_arms(
default_arm,
&arm,
)
);
} else {
default_arm = Some(arm.clone());
}
}

items.push(arm);

let current = state.iterator.current();
Expand Down
39 changes: 0 additions & 39 deletions src/parser/issue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,25 +347,6 @@ pub enum ParserIssueCode {
/// - Remove the modifier
ModifierCannotBeUsedOnInterfaceConstant = 22,

/// Match expression cannot have multiple default arms ( code = 23 )
///
/// Example:
///
/// ```ara
/// function foo(string $input): string {
/// match $input {
/// "foo" => "bar",
/// default => "baz",
/// default => "qux",
/// }
/// }
/// ```
///
/// Possible solution(s):
///
/// - Remove one of the default arms
MatchExpressionCannotHaveMultipleDefaultArms = 23,

/// Promoted property cannot be variadic ( code = 24 )
///
/// Example:
Expand Down Expand Up @@ -919,26 +900,6 @@ pub(crate) fn modifier_cannot_be_used_on_interface_constant(
.with_note("only the `final`, and `public` modifiers can be used on an interface constant.")
}

pub(crate) fn match_expression_cannot_have_multiple_default_arms(
state: &ParserState,
first: &dyn Node,
second: &dyn Node,
) -> Issue {
let origin = state.source.name();

Issue::error(
ParserIssueCode::MatchExpressionCannotHaveMultipleDefaultArms,
"match expression cannot have multiple default arms",
)
.with_source(origin, second.initial_position(), second.final_position())
.with_annotation(Annotation::primary(
origin,
first.initial_position(),
first.final_position(),
))
.with_note("a match expression can only have one default arm")
}

pub(crate) fn promoted_property_cannot_be_variadic(
state: &ParserState,
class_name: Option<&Identifier>,
Expand Down
8 changes: 6 additions & 2 deletions src/tree/expression/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::tree::Node;
pub struct MatchExpression {
pub comments: CommentGroup,
pub r#match: Keyword,
pub expression: Box<Expression>,
pub expression: Option<Box<Expression>>,
pub body: MatchBodyExpression,
}

Expand Down Expand Up @@ -54,7 +54,11 @@ impl Node for MatchExpression {
}

fn children(&self) -> Vec<&dyn Node> {
vec![&self.r#match, self.expression.as_ref(), &self.body]
let mut children: Vec<&dyn Node> = vec![&self.r#match, &self.body];
if let Some(expression) = &self.expression {
children.push(expression.as_ref());
}
children
}

fn get_description(&self) -> String {
Expand Down
40 changes: 22 additions & 18 deletions tests/samples/0070/tree.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1388,11 +1388,13 @@ DefinitionTree {
value: "match",
position: 669,
},
expression: Variable(
Variable {
position: 675,
name: "$a",
},
expression: Some(
Variable(
Variable {
position: 675,
name: "$a",
},
),
),
body: MatchBodyExpression {
left_brace: 678,
Expand Down Expand Up @@ -1524,20 +1526,22 @@ DefinitionTree {
value: "match",
position: 751,
},
expression: Parenthesized(
ParenthesizedExpression {
comments: CommentGroup {
comments: [],
},
left_parenthesis: 757,
expression: Variable(
Variable {
position: 758,
name: "$a",
expression: Some(
Parenthesized(
ParenthesizedExpression {
comments: CommentGroup {
comments: [],
},
),
right_parenthesis: 760,
},
left_parenthesis: 757,
expression: Variable(
Variable {
position: 758,
name: "$a",
},
),
right_parenthesis: 760,
},
),
),
body: MatchBodyExpression {
left_brace: 762,
Expand Down
9 changes: 9 additions & 0 deletions tests/samples/0106/code.ara
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function bar(): void {
$c = match {
$a == $b => 'a is equal to b',
$a > $b => 'a is greater than b',
$a < $b => 'a is less than b',
default => 'a and b are not comparable',
default => 'a and b are not comparable', // The analyzer should warn about this
};
}
Loading

0 comments on commit 4766736

Please sign in to comment.