use super::*;
impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
'name: 'ast,
{
pub(in crate::parser) fn parse_expression_node(
self,
) -> std::result::Result<ParseNodeResult<'ast, Expression<'ast>>, ParseErrors> {
self.parse_node(|parser| parser.parse_expression())
}
pub(in crate::parser) fn parse_expression(&mut self) -> Result<Expression<'ast>> {
self.parse_expression_mut()
}
pub(in crate::parser) fn parse_expression_mut(&mut self) -> Result<Expression<'ast>> {
self.parse_expression_with_limit(0)
}
pub(in crate::parser) fn parse_expression_with_limit(
&mut self,
limit: u8,
) -> Result<Expression<'ast>> {
let old_recursion_counter = self.enter_recursion("expression")?;
let result = self.parse_expression_with_limit_inner(limit);
self.contexts.recursion_counter = old_recursion_counter;
result
}
pub(in crate::parser) fn parse_expression_with_limit_inner(
&mut self,
limit: u8,
) -> Result<Expression<'ast>> {
let lhs = match self.current {
Token::Hash => Some(UnaryOp::Length),
Token::Reserved(R::Not) => Some(UnaryOp::Not),
Token::Minus => Some(UnaryOp::Negate),
Token::Bang => {
self.report_parse_error(self.located("Unexpected '!'; did you mean 'not'?"));
Some(UnaryOp::Not)
}
_ => None,
};
let lhs = if let Some(op) = lhs {
let op_position = self.current_position();
self.advance();
let rhs = self.parse_expression_with_limit(8)?;
let location = Location::new(op_position, rhs.location().end);
let cst = if self.cst.enabled() {
Some(CstNode::ExprOp(CstExprOp { op: op_position }))
} else {
None
};
let expression = self.arena.alloc_expression_unary_direct(location, op, rhs);
self.attach_expression_cst(expression, cst)
} else {
self.parse_assertion_expression()?
};
self.parse_expression_after_lhs(lhs, limit)
}
pub(in crate::parser) fn parse_expression_after_lhs(
&mut self,
mut lhs: Expression<'ast>,
limit: u8,
) -> Result<Expression<'ast>> {
loop {
let Some(priority) = self
.current
.binary_priority()
.or_else(|| self.check_binary_confusables(limit))
else {
return Ok(lhs);
};
if priority.left <= limit {
return Ok(lhs);
}
let op_position = priority
.op_position
.unwrap_or_else(|| self.current_position());
self.advance();
let rhs = self.parse_expression_with_limit(priority.right)?;
let lhs_ref: Expression<'ast> = lhs;
let location = Location::new(lhs_ref.location().begin, rhs.location().end);
let cst = if self.cst.enabled() {
Some(CstNode::ExprOp(CstExprOp { op: op_position }))
} else {
None
};
let expression =
self.arena
.alloc_expression_binary_direct(location, lhs_ref, priority.op, rhs);
lhs = self.attach_expression_cst(expression, cst);
self.enter_recursion("expression")?;
}
}
pub(in crate::parser) fn parse_name_expression(
&mut self,
_context: &'static str,
) -> Result<Expression<'ast>> {
let location = self.current_token_location();
let name = if let Token::Ident(name) = self.current {
name
} else {
let message_index = self.report_parse_error(self.identifier_error(Some(_context)));
return Ok(self.arena.alloc_expression_error_direct(
location,
self.empty_expression_slice(),
message_index,
));
};
self.advance();
if let Some(local) = self.visible_local(name) {
if self.local_is_type_function_capture(local) {
let error_location = self.current_location();
let message_index = self.report_parse_error(self.error_at(
error_location,
self.name_message(
b"Type function cannot reference outer local '",
local.name,
b"'",
),
));
return Ok(self.arena.alloc_expression_error_direct(
error_location,
self.empty_expression_slice(),
message_index,
));
}
return Ok(self.arena.alloc_expression_local_direct(
location,
local,
local.function_depth != self.contexts.functions.len(),
));
}
Ok(self.arena.alloc_expression_global_direct(location, name))
}
pub(in crate::parser) fn parse_prefix_expression(&mut self) -> Result<Expression<'ast>> {
if self.current.kind() == TokenKind::LeftParen {
let location = self.current_location();
self.advance();
let expression = self.parse_expression()?;
let (end, close_position) = if self.current.kind() == TokenKind::RightParen {
self.advance();
(
self.previous_token_end_position(),
self.previous_token_location().begin,
)
} else {
self.report_parse_error(self.unmatched_group_error(location));
(self.previous_token_end_position(), Position::missing())
};
let cst = if self.cst.enabled() {
Some(CstNode::ExprGroup(CstExprGroup { close_position }))
} else {
None
};
let expression = self
.arena
.alloc_expression_grouped_direct(Location::new(location.begin, end), expression);
return Ok(self.attach_expression_cst(expression, cst));
}
self.parse_name_expression("expression")
}
pub(in crate::parser) fn parse_primary_expression(
&mut self,
as_statement: bool,
) -> Result<Expression<'ast>> {
let mut expression_line = self.current_line();
let expression = self.parse_prefix_expression()?;
if matches!(expression.kind(), ExpressionKind::Grouped(_)) {
expression_line = self.previous_line();
}
self.parse_primary_expression_after_prefix(expression, expression_line, as_statement)
}
pub(in crate::parser) fn parse_simple_expression(&mut self) -> Result<Expression<'ast>> {
match self.current {
Token::Number(source) => self.parse_number_expression(source),
Token::InterpStringSimple(value) => {
let location = self.current_token_location();
let cst = if self.cst.enabled() {
Some(CstNode::ExprConstantString(CstExprConstantString {
source_string: self.current_source_string(),
quote_style: CstStringQuoteStyle::QuotedInterp,
block_depth: 0,
}))
} else {
None
};
let expression =
self.parse_quoted_string(value, location, StringQuoteStyle::QuotedSimple);
self.advance();
Ok(self.attach_expression_cst(expression, cst))
}
Token::InterpStringBegin(value) => self.parse_interpolated_string(value),
Token::Reserved(R::False) => {
let location = self.current_token_location();
self.advance();
Ok(self.arena.alloc_expression_boolean_direct(location, false))
}
Token::Reserved(R::Nil) => {
let location = self.current_token_location();
self.advance();
Ok(self.arena.alloc_expression_nil_direct(location))
}
Token::Attribute(_) | Token::AttributeOpen => {
let location = self.current_location();
let attributes = self.parse_attributes()?;
let Token::Reserved(R::Function) = self.current else {
let message_index =
self.report_parse_error(self.attribute_expression_error(location));
return Ok(self.arena.alloc_expression_error_direct(
location,
self.empty_expression_slice(),
message_index,
));
};
self.parse_function_literal_with_attributes(attributes, location)
}
Token::Reserved(R::Function) => self.parse_function_literal(),
Token::Reserved(R::If) => self.parse_if_expression(),
Token::Reserved(R::True) => {
let location = self.current_token_location();
self.advance();
Ok(self.arena.alloc_expression_boolean_direct(location, true))
}
Token::QuotedString { value, quote_style } => {
let ast_quote_style = StringQuoteStyle::from(quote_style);
let location = self.current_token_location();
let cst = if self.cst.enabled() {
Some(CstNode::ExprConstantString(CstExprConstantString {
source_string: self.current_source_string(),
quote_style: CstStringQuoteStyle::from(quote_style),
block_depth: 0,
}))
} else {
None
};
self.advance();
let expression = self.parse_quoted_string(value, location, ast_quote_style);
Ok(self.attach_expression_cst(expression, cst))
}
Token::RawString { value, block_depth } => {
let location = self.current_token_location();
let cst = if self.cst.enabled() {
Some(CstNode::ExprConstantString(CstExprConstantString {
source_string: self.current_source_string(),
quote_style: CstStringQuoteStyle::QuotedRaw,
block_depth: block_depth as u32,
}))
} else {
None
};
self.advance();
let expression = self.arena.alloc_expression_string_direct(
location,
self.ast_string(&multiline_string_bytes(value)),
StringQuoteStyle::QuotedRaw,
);
Ok(self.attach_expression_cst(expression, cst))
}
Token::LeftBrace => {
let location = self.current_location();
self.advance();
self.parse_table_constructor(location)
}
Token::Ellipsis => {
if !self.in_vararg_function() {
let error = self.varargs_error();
let location = error.location;
let message_index = self.report_parse_error(error);
self.advance();
return Ok(self.alloc_expression(ExpressionInit::new(
location,
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)));
}
let location = self.current_token_location();
self.advance();
Ok(self.alloc_expression(ExpressionInit::new(location, ExpressionKind::Varargs)))
}
Token::BrokenString => {
let error = self.malformed_string_error();
let location = error.location;
let message_index = self.report_parse_error(error);
self.advance();
Ok(self.alloc_expression(ExpressionInit::new(
location,
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)))
}
Token::BrokenInterpDoubleBrace(_) => {
let error = self.interpolated_double_brace_error();
let location = error.location;
let message_index = self.report_parse_error(error);
self.advance();
Ok(self.alloc_expression(ExpressionInit::new(
location,
ExpressionKind::Error {
expressions: self.empty_expression_slice(),
message_index,
},
)))
}
_ => self.parse_primary_expression(false),
}
}
pub(in crate::parser) fn parse_assertion_expression(&mut self) -> Result<Expression<'ast>> {
let expression = self.parse_simple_expression()?;
if self.current.kind() != TokenKind::DoubleColon {
return Ok(expression);
}
let op = self.current_position();
self.advance();
let annotation = self.parse_type_annotation()?;
let begin = expression.location().begin;
Ok(self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(begin, annotation.location.end),
ExpressionKind::TypeAssertion {
expr: expression,
annotation,
},
),
if self.cst.enabled() {
Some(CstNode::ExprTypeAssertion(CstExprTypeAssertion { op }))
} else {
None
},
))
}
pub(in crate::parser) fn parse_if_expression(&mut self) -> Result<Expression<'ast>> {
let begin = self.current_position();
if matches!(self.current, Token::Reserved(R::If | R::Elseif)) {
self.advance();
} else {
self.report_parse_error(self.unexpected("if"));
}
let condition = self.parse_expression()?;
let has_then = self.expect_and_consume_keyword(R::Then, "if then else expression");
let then_position = if has_then {
self.previous_token_location().begin
} else {
Position::missing()
};
let then_expression = self.parse_expression()?;
let else_position = self.current_position();
let is_else_if = matches!(self.current, Token::Reserved(R::Elseif));
let (else_expression, has_else) = if is_else_if {
let old_recursion_counter = self.enter_recursion("expression")?;
let expression = self.parse_if_expression()?;
self.contexts.recursion_counter = old_recursion_counter;
(expression, true)
} else {
let has_else = self.expect_and_consume_keyword(R::Else, "if then else expression");
(self.parse_expression()?, has_else)
};
let result = self.alloc_expression_with_cst(
ExpressionInit::new(
Location::new(begin, else_expression.location().end),
ExpressionKind::If {
condition,
has_then,
then_expression,
has_else,
else_expression,
},
),
if self.cst.enabled() {
Some(CstNode::ExprIfElse(CstExprIfElse {
then_position,
else_position,
is_else_if,
}))
} else {
None
},
);
Ok(result)
}
}
mod call;
mod strings;
mod table;