Skip to content

Commit

Permalink
chore: implement reverse spread arguments
Browse files Browse the repository at this point in the history
closes #17
  • Loading branch information
azjezz committed Jan 5, 2023
1 parent 12a97e0 commit 4a781f3
Show file tree
Hide file tree
Showing 28 changed files with 383 additions and 305 deletions.
26 changes: 16 additions & 10 deletions src/parser/internal/definition/attribute.rs
Expand Up @@ -24,16 +24,22 @@ pub fn gather(state: &mut State) -> ParseResult<bool> {
let arguments = argument::argument_list_expression(state)?;

for argument in &arguments.arguments.inner {
let value = match argument {
ArgumentExpression::Positional { value, .. } => value,
ArgumentExpression::Named { value, .. } => value,
};

if !value.is_constant(true) {
crate::parser_report!(
state,
invalid_constant_initialization_expression(value)
);
match argument {
ArgumentExpression::Value { value, .. }
| ArgumentExpression::Named { value, .. } => {
if !value.is_constant(true) {
crate::parser_report!(
state,
invalid_constant_initialization_expression(value)
);
}
}
expression => {
crate::parser_report!(
state,
invalid_constant_initialization_expression(expression)
);
}
}
}

Expand Down
47 changes: 29 additions & 18 deletions src/parser/internal/expression/argument.rs
Expand Up @@ -17,38 +17,49 @@ pub fn argument_list_expression(state: &mut State) -> ParseResult<ArgumentListEx
}

fn argument_expression(state: &mut State) -> ParseResult<ArgumentExpression> {
if identifier::is_identifier_maybe_reserved(&state.iterator.current().kind)
let current = state.iterator.current();
let comments = state.iterator.comments();

if identifier::is_identifier_maybe_reserved(&current.kind)
&& state.iterator.lookahead(1).kind == TokenKind::Colon
{
let name = identifier::identifier_maybe_reserved(state)?;
let colon = utils::skip(state, TokenKind::Colon)?;
let ellipsis = if state.iterator.current().kind == TokenKind::Ellipsis {
Some(utils::skip(state, TokenKind::Ellipsis)?)
} else {
None
};
let value = expression::create(state)?;

return Ok(ArgumentExpression::Named {
comments: state.iterator.comments(),
comments,
name,
colon,
ellipsis,
value,
});
}

let ellipsis = if state.iterator.current().kind == TokenKind::Ellipsis {
Some(utils::skip(state, TokenKind::Ellipsis)?)
if current.kind == TokenKind::Ellipsis {
let ellipsis = current.position;
state.iterator.next();
let value = expression::create(state)?;

Ok(ArgumentExpression::Spread {
comments,
ellipsis,
value,
})
} else {
None
};
let value = expression::create(state)?;
let current = state.iterator.current();

let value = expression::create(state)?;
if current.kind == TokenKind::Ellipsis {
let ellipsis = current.position;
state.iterator.next();

Ok(ArgumentExpression::Positional {
comments: state.iterator.comments(),
ellipsis,
value,
})
Ok(ArgumentExpression::ReverseSpread {
comments,
value,
ellipsis,
})
} else {
Ok(ArgumentExpression::Value { comments, value })
}
}
}
2 changes: 1 addition & 1 deletion src/parser/issue.rs
Expand Up @@ -1720,7 +1720,7 @@ pub(crate) fn invalid_constant_expression(state: &ParserState, expression: &Expr

pub(crate) fn invalid_constant_initialization_expression(
state: &ParserState,
expression: &Expression,
expression: &dyn Node,
) -> Issue {
let origin = state.source.name();

Expand Down
33 changes: 24 additions & 9 deletions src/tree/expression/argument.rs
Expand Up @@ -11,16 +11,24 @@ use crate::tree::Node;
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "snake_case", tag = "type", content = "value")]
pub enum ArgumentExpression {
Positional {
Value {
comments: CommentGroup,
ellipsis: Option<usize>,
value: Expression,
},
Spread {
comments: CommentGroup,
ellipsis: usize,
value: Expression,
},
ReverseSpread {
comments: CommentGroup,
value: Expression,
ellipsis: usize,
},
Named {
comments: CommentGroup,
name: Identifier,
colon: usize,
ellipsis: Option<usize>,
value: Expression,
},
}
Expand All @@ -46,30 +54,37 @@ pub struct ArgumentPlaceholderExpression {
impl Node for ArgumentExpression {
fn comments(&self) -> Option<&CommentGroup> {
match &self {
ArgumentExpression::Positional { comments, .. }
ArgumentExpression::Value { comments, .. }
| ArgumentExpression::Spread { comments, .. }
| ArgumentExpression::ReverseSpread { comments, .. }
| ArgumentExpression::Named { comments, .. } => Some(comments),
}
}

fn initial_position(&self) -> usize {
match self {
ArgumentExpression::Positional {
ellipsis, value, ..
} => ellipsis.unwrap_or_else(|| value.initial_position()),
ArgumentExpression::Value { value, .. }
| ArgumentExpression::ReverseSpread { value, .. } => value.initial_position(),
ArgumentExpression::Spread { ellipsis, .. } => *ellipsis,
ArgumentExpression::Named { name, .. } => name.initial_position(),
}
}

fn final_position(&self) -> usize {
match self {
ArgumentExpression::Positional { value, .. } => value.final_position(),
ArgumentExpression::Value { value, .. } | ArgumentExpression::Spread { value, .. } => {
value.final_position()
}
ArgumentExpression::ReverseSpread { ellipsis, .. } => *ellipsis,
ArgumentExpression::Named { value, .. } => value.final_position(),
}
}

fn children(&self) -> Vec<&dyn Node> {
match self {
ArgumentExpression::Positional { value, .. } => vec![value],
ArgumentExpression::Value { value, .. }
| ArgumentExpression::Spread { value, .. }
| ArgumentExpression::ReverseSpread { value, .. } => vec![value],
ArgumentExpression::Named { name, value, .. } => vec![name, value],
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/tree/expression/mod.rs
Expand Up @@ -160,12 +160,14 @@ impl Expression {
.inner
.iter()
.all(|argument| match argument {
ArgumentExpression::Positional { value, .. } => {
ArgumentExpression::Value { value, .. } => {
value.is_constant(initilization)
}
ArgumentExpression::Named { value, .. } => {
value.is_constant(initilization)
}
// spreading arguments cannot be used in constant expressions
_ => false,
})
}
},
Expand Down

0 comments on commit 4a781f3

Please sign in to comment.