use super::{
parser_util::{InternalAstError, Parser},
span::ContainedSpan,
*,
};
#[cfg(feature = "roblox")]
use super::types::*;
#[cfg(feature = "roblox")]
use crate::tokenizer_luau::InterpolatedStringKind;
#[cfg(feature = "lua52")]
use super::lua52::*;
use crate::tokenizer::{TokenKind, TokenReference, TokenType};
use std::borrow::Cow;
#[derive(Clone, Debug, PartialEq)]
struct ParseSymbol(Symbol);
define_parser!(ParseSymbol, TokenReference, |this, state| {
let expecting = TokenType::Symbol { symbol: this.0 };
let token = state.peek();
if *token.token_type() == expecting {
Ok((
state.advance().ok_or(InternalAstError::NoMatch)?,
token.clone(),
))
} else {
Err(InternalAstError::NoMatch)
}
});
#[derive(Clone, Debug, PartialEq)]
struct ParseNumber;
define_parser!(ParseNumber, TokenReference, |_, state| {
let token = state.peek();
if token.token_kind() == TokenKind::Number {
Ok((
state.advance().ok_or(InternalAstError::NoMatch)?,
token.clone(),
))
} else {
Err(InternalAstError::NoMatch)
}
});
#[derive(Clone, Debug, PartialEq)]
struct ParseStringLiteral;
define_parser!(ParseStringLiteral, TokenReference, |_, state| {
let token = state.peek();
if token.token_kind() == TokenKind::StringLiteral {
Ok((
state.advance().ok_or(InternalAstError::NoMatch)?,
token.clone(),
))
} else {
Err(InternalAstError::NoMatch)
}
});
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct ParseBlock;
define_parser!(ParseBlock, Block, |_, state| {
let mut stmts = Vec::new();
while let Ok((new_state, stmt)) = keep_going!(ParseStmt.parse(state)) {
state = new_state;
let mut semicolon = None;
if let Ok((new_state, new_semicolon)) = ParseSymbol(Symbol::Semicolon).parse(state) {
state = new_state;
semicolon = Some(new_semicolon);
}
stmts.push((stmt, semicolon));
}
if let Ok((mut state, last_stmt)) = keep_going!(ParseLastStmt.parse(state)) {
let mut semicolon = None;
if let Ok((new_state, new_semicolon)) = ParseSymbol(Symbol::Semicolon).parse(state) {
state = new_state;
semicolon = Some(new_semicolon)
}
Ok((
state,
Block {
stmts,
last_stmt: Some((last_stmt, semicolon)),
},
))
} else {
Ok((
state,
Block {
stmts,
last_stmt: None,
},
))
}
});
#[derive(Clone, Debug, PartialEq)]
struct ParseLastStmt;
define_parser!(
ParseLastStmt,
LastStmt,
|_, state| if let Ok((state, token)) = ParseSymbol(Symbol::Return).parse(state) {
let (state, returns) = expect!(
state,
ZeroOrMoreDelimited(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state),
"return values"
);
Ok((state, LastStmt::Return(Return { token, returns })))
} else if let Ok((state, token)) = ParseSymbol(Symbol::Break).parse(state) {
Ok((state, LastStmt::Break(token)))
} else {
cfg_if::cfg_if! {
if #[cfg(feature = "roblox")] {
let (state, continue_token) = ParseIdentifier.parse(state)?;
if continue_token.token().to_string() == "continue" {
Ok((state, LastStmt::Continue(continue_token)))
} else {
Err(InternalAstError::NoMatch)
}
} else {
Err(InternalAstError::NoMatch)
}
}
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseField;
define_parser!(ParseField, Field, |_, state| {
if let Ok((state, start_bracket)) = ParseSymbol(Symbol::LeftBracket).parse(state) {
let (state, key) = expect!(state, ParseExpression.parse(state), "expected key");
let (state, end_bracket) = expect!(
state,
ParseSymbol(Symbol::RightBracket).parse(state),
"expected ']'"
);
let (state, equal) = expect!(
state,
ParseSymbol(Symbol::Equal).parse(state),
"expected '='"
);
let (state, value) = expect!(state, ParseExpression.parse(state), "expected value");
return Ok((
state,
Field::ExpressionKey {
brackets: ContainedSpan::new(start_bracket, end_bracket),
key,
equal,
value,
},
));
} else if let Ok((state, key)) = keep_going!(ParseIdentifier.parse(state)) {
if let Ok((state, equal)) = ParseSymbol(Symbol::Equal).parse(state) {
let (state, value) = expect!(state, ParseExpression.parse(state), "expected value");
return Ok((state, Field::NameKey { key, equal, value }));
}
}
if let Ok((state, expr)) = keep_going!(ParseExpression.parse(state)) {
return Ok((state, Field::NoKey(expr)));
}
Err(InternalAstError::NoMatch)
});
struct ParseTableConstructor;
define_parser!(ParseTableConstructor, TableConstructor, |_, state| {
let (mut state, start_brace) = ParseSymbol(Symbol::LeftBrace).parse(state)?;
let mut fields = Punctuated::new();
while let Ok((new_state, field)) = keep_going!(ParseField.parse(state)) {
let field_sep = if let Ok((new_state, separator)) =
ParseSymbol(Symbol::Comma).parse(new_state)
{
state = new_state;
Some(separator)
} else if let Ok((new_state, separator)) = ParseSymbol(Symbol::Semicolon).parse(new_state) {
state = new_state;
Some(separator)
} else {
state = new_state;
None
};
let is_end = field_sep.is_none();
fields.push(Pair::new(field, field_sep));
if is_end {
break;
}
}
let (state, end_brace) = expect!(
state,
ParseSymbol(Symbol::RightBrace).parse(state),
"expected '}'"
);
Ok((
state,
TableConstructor {
braces: ContainedSpan::new(start_brace, end_brace),
fields,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseUnaryExpression;
define_parser!(ParseUnaryExpression, Expression, |_, state| {
let (state, unop) = keep_going!(ParseUnOp.parse(state))?;
let (state, expression) = expect!(
state,
ParseExpressionAtPrecedence(unop.precedence()).parse(state),
"expected expression"
);
let expression = Box::new(expression);
Ok((state, Expression::UnaryOperator { unop, expression }))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseParenExpression;
define_parser!(ParseParenExpression, Expression, |_, state| {
let (state, left_paren) = ParseSymbol(Symbol::LeftParen).parse(state)?;
let (state, expression) = expect!(state, ParseExpression.parse(state), "expected expression");
let (state, right_paren) = expect!(
state,
ParseSymbol(Symbol::RightParen).parse(state),
"expected ')'"
);
Ok((
state,
Expression::Parentheses {
contained: ContainedSpan::new(left_paren, right_paren),
expression: Box::new(expression),
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseValueExpression;
define_parser!(ParseValueExpression, Expression, |_, state| {
let (state, value) = keep_going!(ParseValue.parse(state))?;
#[cfg(feature = "roblox")]
let (state, type_assertion) =
if let Ok((state, type_assertion)) = keep_going!(ParseTypeAssertion.parse(state)) {
(state, Some(type_assertion))
} else {
(state, None)
};
let value = Box::new(value);
Ok((
state,
Expression::Value {
value,
#[cfg(feature = "roblox")]
type_assertion,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParsePartExpression;
define_parser!(ParsePartExpression, Expression, |_, state| {
if let Ok((state, expression)) = keep_going!(ParseUnaryExpression.parse(state)) {
Ok((state, expression))
} else if let Ok((state, expression)) = keep_going!(ParseValueExpression.parse(state)) {
Ok((state, expression))
} else {
Err(InternalAstError::NoMatch)
}
});
#[derive(Clone, Debug, PartialEq)]
struct ParseExpressionAtPrecedence(u8);
define_parser!(ParseExpressionAtPrecedence, Expression, |this, state| {
let min_precedence = this.0;
let (mut state, mut current_expr) = ParsePartExpression.parse(state)?;
while let Ok((next_state, operator)) = ParseBinOp.parse(state) {
if operator.precedence() < min_precedence {
break;
}
let next_min_precedence = if operator.is_right_associative() {
operator.precedence()
} else {
operator.precedence() + 1
};
let (next_state, rhs) = expect!(
next_state,
ParseExpressionAtPrecedence(next_min_precedence).parse(next_state),
"expected expression"
);
state = next_state;
current_expr = Expression::BinaryOperator {
lhs: Box::new(current_expr),
binop: operator,
rhs: Box::new(rhs),
};
}
Ok((state, current_expr))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseExpression;
define_parser!(ParseExpression, Expression, |_, state| {
ParseExpressionAtPrecedence(1).parse(state)
});
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeAssertion;
#[rustfmt::skip]
define_roblox_parser!(
ParseTypeAssertion,
TypeAssertion,
TokenReference,
|_, state| {
let (state, assertion_op) = ParseSymbol(Symbol::TwoColons).parse(state)?;
let (state, cast_to) = expect!(
state,
ParseTypeInfo(TypeInfoContext::None).parse(state),
"expected type in type assertion"
);
Ok((state, TypeAssertion { assertion_op, cast_to }))
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseValue;
define_parser!(ParseValue, Value, |_, state| parse_first_of!(state, {
ParseSymbol(Symbol::Nil) => Value::Symbol,
ParseSymbol(Symbol::False) => Value::Symbol,
ParseSymbol(Symbol::True) => Value::Symbol,
ParseNumber => Value::Number,
ParseStringLiteral => Value::String,
ParseSymbol(Symbol::Ellipse) => Value::Symbol,
ParseFunction => Value::Function,
ParseTableConstructor => Value::TableConstructor,
ParseFunctionCall => Value::FunctionCall,
ParseVar => Value::Var,
ParseParenExpression => Value::ParenthesesExpression,
@#[cfg(feature = "roblox")]
ParseIfExpression => Value::IfExpression,
@#[cfg(feature = "roblox")]
ParseInterpolatedString => Value::InterpolatedString,
}));
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseStmt;
define_parser!(ParseStmt, Stmt, |_, state| parse_first_of!(state, {
ParseAssignment => Stmt::Assignment,
ParseFunctionCall => Stmt::FunctionCall,
ParseDo => Stmt::Do,
ParseWhile => Stmt::While,
ParseRepeat => Stmt::Repeat,
ParseIf => Stmt::If,
ParseNumericFor => Stmt::NumericFor,
ParseGenericFor => Stmt::GenericFor,
ParseFunctionDeclaration => Stmt::FunctionDeclaration,
ParseLocalFunction => Stmt::LocalFunction,
ParseLocalAssignment => Stmt::LocalAssignment,
@#[cfg(feature = "roblox")]
ParseCompoundAssignment => Stmt::CompoundAssignment,
@#[cfg(feature = "roblox")]
ParseExportedTypeDeclaration => Stmt::ExportedTypeDeclaration,
@#[cfg(feature = "roblox")]
ParseTypeDeclaration => Stmt::TypeDeclaration,
@#[cfg(feature = "lua52")]
ParseGoto => Stmt::Goto,
@#[cfg(feature = "lua52")]
ParseLabel => Stmt::Label,
}));
#[derive(Clone, Debug, PartialEq)]
struct ParsePrefix;
define_parser!(ParsePrefix, Prefix, |_, state| parse_first_of!(state, {
ParseParenExpression => Prefix::Expression,
ParseIdentifier => Prefix::Name,
}));
struct ParseIndex;
define_parser!(
ParseIndex,
Index,
|_, state| if let Ok((state, start_bracket)) = ParseSymbol(Symbol::LeftBracket).parse(state) {
let (state, expression) =
expect!(state, ParseExpression.parse(state), "expected expression");
let (state, end_bracket) = expect!(
state,
ParseSymbol(Symbol::RightBracket).parse(state),
"expected ']'"
);
Ok((
state,
Index::Brackets {
brackets: ContainedSpan::new(start_bracket, end_bracket),
expression,
},
))
} else if let Ok((state, dot)) = ParseSymbol(Symbol::Dot).parse(state) {
let (state, name) = expect!(state, ParseIdentifier.parse(state), "expected name");
Ok((state, Index::Dot { dot, name }))
} else {
Err(InternalAstError::NoMatch)
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseFunctionArgs;
define_parser!(
ParseFunctionArgs,
FunctionArgs,
|_, state| if let Ok((state, left_paren)) =
keep_going!(ParseSymbol(Symbol::LeftParen).parse(state))
{
let (state, arguments) = expect!(
state,
ZeroOrMoreDelimited(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state),
"expected arguments"
);
let (state, right_paren) = expect!(
state,
ParseSymbol(Symbol::RightParen).parse(state),
"expected ')'"
);
Ok((
state,
FunctionArgs::Parentheses {
arguments,
parentheses: ContainedSpan::new(left_paren, right_paren),
},
))
} else if let Ok((state, table_constructor)) = keep_going!(ParseTableConstructor.parse(state)) {
Ok((state, FunctionArgs::TableConstructor(table_constructor)))
} else if let Ok((state, string)) = keep_going!(ParseStringLiteral.parse(state)) {
Ok((state, FunctionArgs::String(string)))
} else {
Err(InternalAstError::NoMatch)
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseNumericFor;
define_parser!(ParseNumericFor, NumericFor, |_, state| {
let (mut state, for_token) = ParseSymbol(Symbol::For).parse(state)?;
#[cfg(not(feature = "roblox"))]
let (state, index_variable) = expect!(state, ParseIdentifier.parse(state), "expected names");
#[cfg(feature = "roblox")]
let (state, (index_variable, type_specifier)) =
expect!(state, ParseNameWithType.parse(state), "expected names");
let (state, equal_token) = ParseSymbol(Symbol::Equal).parse(state)?; let (state, start) = expect!(
state,
ParseExpression.parse(state),
"expected start expression"
);
let (state, start_end_comma) = expect!(
state,
ParseSymbol(Symbol::Comma).parse(state),
"expected comma"
);
let (state, end) = expect!(
state,
ParseExpression.parse(state),
"expected end expression"
);
let (state, step, end_step_comma) =
if let Ok((state, comma)) = ParseSymbol(Symbol::Comma).parse(state) {
let (state, expression) = expect!(
state,
ParseExpression.parse(state),
"expected limit expression"
);
(state, Some(expression), Some(comma))
} else {
(state, None, None)
};
let (state, do_token) = expect!(state, ParseSymbol(Symbol::Do).parse(state), "expected 'do'");
let (state, block) = expect!(state, ParseBlock.parse(state), "expected block");
let (state, end_token) = expect!(
state,
ParseSymbol(Symbol::End).parse(state),
"expected 'end'"
);
Ok((
state,
NumericFor {
for_token,
index_variable,
equal_token,
start,
start_end_comma,
end,
end_step_comma,
step,
do_token,
block,
end_token,
#[cfg(feature = "roblox")]
type_specifier,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseGenericFor;
define_parser!(ParseGenericFor, GenericFor, |_, state| {
let (mut state, for_token) = ParseSymbol(Symbol::For).parse(state)?;
let mut names;
let mut type_specifiers = Vec::new();
if cfg!(feature = "roblox") {
names = Punctuated::new();
let (new_state, full_name_list) = expect!(
state,
OneOrMore(ParseNameWithType, ParseSymbol(Symbol::Comma), false).parse(state),
"expected names"
);
for mut pair in full_name_list.into_pairs() {
type_specifiers.push(pair.value_mut().1.take());
names.push(pair.map(|(name, _)| name));
}
state = new_state;
} else {
let (new_state, new_names) = expect!(
state,
OneOrMore(ParseIdentifier, ParseSymbol(Symbol::Comma), false).parse(state),
"expected names"
);
state = new_state;
names = new_names;
}
let (state, in_token) = expect!(state, ParseSymbol(Symbol::In).parse(state), "expected 'in'"); let (state, expr_list) = expect!(
state,
OneOrMore(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state),
"expected expression"
);
let (state, do_token) = expect!(state, ParseSymbol(Symbol::Do).parse(state), "expected 'do'");
let (state, block) = expect!(state, ParseBlock.parse(state), "expected block");
let (state, end_token) = expect!(
state,
ParseSymbol(Symbol::End).parse(state),
"expected 'end'"
);
Ok((
state,
GenericFor {
for_token,
names,
in_token,
expr_list,
do_token,
block,
end_token,
#[cfg(feature = "roblox")]
type_specifiers,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseIf;
define_parser!(ParseIf, If, |_, state| {
let (state, if_token) = ParseSymbol(Symbol::If).parse(state)?;
let (state, condition) = expect!(state, ParseExpression.parse(state), "expected condition");
let (state, then_token) = expect!(
state,
ParseSymbol(Symbol::Then).parse(state),
"expected 'then'"
);
let (mut state, block) = expect!(state, ParseBlock.parse(state), "expected block");
let mut else_ifs = Vec::new();
while let Ok((new_state, else_if_token)) = ParseSymbol(Symbol::ElseIf).parse(state) {
let (new_state, condition) = expect!(
state,
ParseExpression.parse(new_state),
"expected condition"
);
let (new_state, then_token) = expect!(
state,
ParseSymbol(Symbol::Then).parse(new_state),
"expected 'then'"
);
let (new_state, block) = expect!(state, ParseBlock.parse(new_state), "expected block");
state = new_state;
else_ifs.push(ElseIf {
else_if_token,
condition,
then_token,
block,
});
}
let (state, else_token, r#else) =
if let Ok((state, else_token)) = ParseSymbol(Symbol::Else).parse(state) {
let (state, block) = expect!(state, ParseBlock.parse(state), "expected block");
(state, Some(else_token), Some(block))
} else {
(state, None, None)
};
let (state, end_token) = expect!(
state,
ParseSymbol(Symbol::End).parse(state),
"expected 'end'"
);
Ok((
state,
If {
if_token,
condition,
then_token,
block,
else_token,
r#else,
else_if: if else_ifs.is_empty() {
None
} else {
Some(else_ifs)
},
end_token,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseWhile;
define_parser!(ParseWhile, While, |_, state| {
let (state, while_token) = ParseSymbol(Symbol::While).parse(state)?;
let (state, condition) = expect!(state, ParseExpression.parse(state), "expected condition");
let (state, do_token) = expect!(state, ParseSymbol(Symbol::Do).parse(state), "expected 'do'");
let (state, block) = expect!(state, ParseBlock.parse(state), "expected block");
let (state, end_token) = expect!(
state,
ParseSymbol(Symbol::End).parse(state),
"expected 'end'"
);
Ok((
state,
While {
while_token,
condition,
do_token,
block,
end_token,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseRepeat;
define_parser!(ParseRepeat, Repeat, |_, state| {
let (state, repeat_token) = ParseSymbol(Symbol::Repeat).parse(state)?;
let (state, block) = expect!(state, ParseBlock.parse(state), "expected block");
let (state, until_token) = expect!(
state,
ParseSymbol(Symbol::Until).parse(state),
"expected 'until'"
);
let (state, until) = expect!(state, ParseExpression.parse(state), "expected condition");
Ok((
state,
Repeat {
repeat_token,
block,
until_token,
until,
},
))
});
struct ParseMethodCall;
define_parser!(ParseMethodCall, MethodCall, |_, state| {
let (state, colon_token) = ParseSymbol(Symbol::Colon).parse(state)?;
let (state, name) = expect!(state, ParseIdentifier.parse(state), "expected method");
let (state, args) = expect!(state, ParseFunctionArgs.parse(state), "expected args");
Ok((
state,
MethodCall {
colon_token,
name,
args,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseCall;
define_parser!(ParseCall, Call, |_, state| parse_first_of!(state, {
ParseFunctionArgs => Call::AnonymousCall,
ParseMethodCall => Call::MethodCall,
}));
#[derive(Clone, Debug, PartialEq)]
struct ParseFunctionBody;
#[rustfmt::skip]
define_parser!(ParseFunctionBody, FunctionBody, |_, state| {
#[cfg(feature = "roblox")]
let (state, generics) =
if let Ok((state, generics)) = keep_going!(ParseGenericDeclaration.parse(state)) {
(state, Some(generics))
} else {
(state, None)
};
let (mut state, start_parenthese) = expect!(
state,
ParseSymbol(Symbol::LeftParen).parse(state),
"expected '('"
);
let mut parameters = Punctuated::new();
let mut name_list = None;
let mut type_specifiers = Vec::new();
if cfg!(feature = "roblox") {
if let Ok((new_state, full_name_list)) = keep_going!(
OneOrMore(ParseNameWithType, ParseSymbol(Symbol::Comma), false).parse(state)
) {
let mut new_name_list = Punctuated::new();
for mut pair in full_name_list.into_pairs() {
type_specifiers.push(pair.value_mut().1.take());
new_name_list.push(pair.map(|(name, _)| name));
}
state = new_state;
name_list = Some(new_name_list);
}
} else if let Ok((new_state, new_name_list)) = keep_going!(
OneOrMore(ParseIdentifier, ParseSymbol(Symbol::Comma), false).parse(state)
) {
state = new_state;
name_list = Some(new_name_list);
}
if let Some(names) = name_list {
parameters.extend(names.into_pairs().map(|pair| {
let tuple = pair.into_tuple();
Pair::new(Parameter::Name(tuple.0), tuple.1)
}));
if let Ok((new_state, comma)) = ParseSymbol(Symbol::Comma).parse(state) {
if let Ok((new_state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(new_state) {
state = new_state;
let mut last_parameter = parameters.pop().expect("comma parsed and accepted, but no arguments before it?");
last_parameter = Pair::new(last_parameter.into_value(), Some(comma));
parameters.push(last_parameter);
parameters.push(Pair::new(Parameter::Ellipse(ellipse), None));
if cfg!(feature = "roblox") {
if let Ok((new_state, type_specifier)) = ParseTypeSpecifier(TypeInfoContext::VarArgSpecifier).parse(state) {
state = new_state;
type_specifiers.push(Some(type_specifier));
} else {
type_specifiers.push(None);
}
}
}
}
} else if let Ok((new_state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) {
state = new_state;
parameters.push(Pair::new(Parameter::Ellipse(ellipse), None));
if cfg!(feature = "roblox") {
if let Ok((new_state, type_specifier)) = ParseTypeSpecifier(TypeInfoContext::VarArgSpecifier).parse(state) {
state = new_state;
type_specifiers.push(Some(type_specifier));
} else {
type_specifiers.push(None);
}
}
}
let (state, end_parenthese) = expect!(
state,
ParseSymbol(Symbol::RightParen).parse(state),
"expected ')'"
);
#[cfg_attr(not(feature = "roblox"), allow(unused_variables))]
let (state, return_type) = if let Ok((state, return_type)) = ParseTypeSpecifier(TypeInfoContext::ReturnType).parse(state) {
(state, Some(return_type))
} else {
(state, None)
};
let (state, block) = expect!(state, ParseBlock.parse(state), "expected block");
let (state, end_token) = expect!(
state,
ParseSymbol(Symbol::End).parse(state),
"expected 'end'"
);
Ok((
state,
FunctionBody {
#[cfg(feature = "roblox")]
generics,
parameters_parentheses: ContainedSpan::new(start_parenthese, end_parenthese),
parameters,
block,
end_token,
#[cfg(feature = "roblox")]
type_specifiers,
#[cfg(feature = "roblox")]
return_type,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseFunction;
define_parser!(ParseFunction, (TokenReference, FunctionBody), |_, state| {
let (state, token) = ParseSymbol(Symbol::Function).parse(state)?;
let (state, body) = expect!(
state,
ParseFunctionBody.parse(state),
"expected function body"
);
Ok((state, (token, body)))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseSuffix;
define_parser!(ParseSuffix, Suffix, |_, state| parse_first_of!(state, {
ParseCall => Suffix::Call,
ParseIndex => Suffix::Index,
}));
#[derive(Clone, Debug, PartialEq)]
struct ParseVarExpression;
define_parser!(ParseVarExpression, VarExpression, |_, state| {
let (state, prefix) = ParsePrefix.parse(state)?;
let (state, suffixes) = ZeroOrMore(ParseSuffix).parse(state)?;
if let Some(Suffix::Index(_)) = suffixes.last() {
Ok((state, VarExpression { prefix, suffixes }))
} else {
Err(InternalAstError::NoMatch)
}
});
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseVar;
define_parser!(ParseVar, Var, |_, state| parse_first_of!(state, {
ParseVarExpression => Var::Expression,
ParseIdentifier => Var::Name,
}));
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseAssignment;
define_parser!(ParseAssignment, Assignment, |_, state| {
let (state, var_list) = OneOrMore(ParseVar, ParseSymbol(Symbol::Comma), false).parse(state)?;
let (state, equal_token) = ParseSymbol(Symbol::Equal).parse(state)?;
let (state, expr_list) = expect!(
state,
OneOrMore(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state),
"expected values"
);
Ok((
state,
Assignment {
var_list,
equal_token,
expr_list,
},
))
});
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseLocalFunction;
define_parser!(ParseLocalFunction, LocalFunction, |_, state| {
let (state, local_token) = ParseSymbol(Symbol::Local).parse(state)?;
let (state, function_token) = ParseSymbol(Symbol::Function).parse(state)?;
let (state, name) = expect!(state, ParseIdentifier.parse(state), "expected name");
let (state, body) = ParseFunctionBody.parse(state)?;
Ok((
state,
LocalFunction {
local_token,
function_token,
name,
body,
},
))
});
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseLocalAssignment;
define_parser!(ParseLocalAssignment, LocalAssignment, |_, state| {
let (mut state, local_token) = ParseSymbol(Symbol::Local).parse(state)?;
let mut name_list = Punctuated::new();
#[cfg(feature = "lua54")]
let mut attributes = Vec::new();
#[cfg(feature = "roblox")]
let mut type_specifiers = Vec::new();
loop {
let (new_state, name) = expect!(state, ParseIdentifier.parse(state), "expected name");
state = new_state;
#[cfg(feature = "lua54")]
if let Ok((new_state, attribute)) = keep_going!(ParseAttribute.parse(state)) {
attributes.push(Some(attribute));
state = new_state;
} else {
attributes.push(None);
}
#[cfg(feature = "roblox")]
if let Ok((new_state, type_specifier)) =
keep_going!(ParseTypeSpecifier(TypeInfoContext::None).parse(state))
{
type_specifiers.push(Some(type_specifier));
state = new_state;
} else {
type_specifiers.push(None);
}
if let Ok((new_state, comma)) = ParseSymbol(Symbol::Comma).parse(state) {
name_list.push(Pair::Punctuated(name, comma));
state = new_state;
} else {
name_list.push(Pair::End(name));
break;
}
}
let ((state, expr_list), equal_token) = match ParseSymbol(Symbol::Equal).parse(state) {
Ok((state, equal_token)) => (
OneOrMore(ParseExpression, ParseSymbol(Symbol::Comma), false)
.parse(state)
.map_err(|_| InternalAstError::UnexpectedToken {
token: (*state.peek()).to_owned(),
additional: Some(Cow::from("expected expression")),
})?,
Some(equal_token),
),
Err(InternalAstError::NoMatch) => ((state, Punctuated::new()), None),
Err(other) => return Err(other),
};
Ok((
state,
LocalAssignment {
local_token,
#[cfg(feature = "roblox")]
type_specifiers,
name_list,
#[cfg(feature = "lua54")]
attributes,
equal_token,
expr_list,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseDo;
define_parser!(ParseDo, Do, |_, state| {
let (state, do_token) = ParseSymbol(Symbol::Do).parse(state)?;
let (state, block) = expect!(state, ParseBlock.parse(state), "expected block");
let (state, end_token) = expect!(
state,
ParseSymbol(Symbol::End).parse(state),
"expected 'end'"
);
Ok((
state,
Do {
do_token,
block,
end_token,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseFunctionCall;
define_parser!(ParseFunctionCall, FunctionCall, |_, state| {
let (state, prefix) = ParsePrefix.parse(state)?;
let (state, suffixes) = ZeroOrMore(ParseSuffix).parse(state)?;
if let Some(Suffix::Call(_)) = suffixes.last() {
Ok((state, FunctionCall { prefix, suffixes }))
} else {
Err(InternalAstError::NoMatch)
}
});
#[derive(Clone, Debug, PartialEq)]
struct ParseFunctionName;
define_parser!(ParseFunctionName, FunctionName, |_, state| {
let (state, names) =
OneOrMore(ParseIdentifier, ParseSymbol(Symbol::Dot), false).parse(state)?;
let (state, colon_name) = if let Ok((state, colon)) = ParseSymbol(Symbol::Colon).parse(state) {
let (state, colon_name) =
expect!(state, ParseIdentifier.parse(state), "expected method name");
(state, Some((colon, colon_name)))
} else {
(state, None)
};
Ok((state, FunctionName { names, colon_name }))
});
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseFunctionDeclaration;
define_parser!(ParseFunctionDeclaration, FunctionDeclaration, |_, state| {
let (state, function_token) = ParseSymbol(Symbol::Function).parse(state)?;
let (state, name) = expect!(
state,
ParseFunctionName.parse(state),
"expected function name"
);
let (state, body) = expect!(
state,
ParseFunctionBody.parse(state),
"expected function body"
);
Ok((
state,
FunctionDeclaration {
function_token,
name,
body,
},
))
});
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseIdentifier;
#[rustfmt::skip]
define_parser!(ParseIdentifier, TokenReference, |_, state| {
let next_token = state.peek();
match next_token.token_kind() {
TokenKind::Identifier => Ok((
state.advance().ok_or(InternalAstError::NoMatch)?,
next_token.clone(),
)),
_ => Err(InternalAstError::NoMatch),
}
});
#[derive(Clone, Copy, Debug, PartialEq)]
enum TypeInfoContext {
#[cfg(feature = "roblox")]
None,
#[cfg(feature = "roblox")]
ParenthesesType,
ReturnType,
VarArgSpecifier,
#[cfg(feature = "roblox")]
GenericArgument,
}
#[derive(Clone, Debug, PartialEq)]
struct ParseNameWithType;
define_roblox_parser!(
ParseNameWithType,
(TokenReference, Option<TypeSpecifier>),
(TokenReference, Option<TokenReference>),
|_, state| {
let (state, name) = ParseIdentifier.parse(state)?;
let (state, type_specifier) = if let Ok((state, type_specifier)) =
keep_going!(ParseTypeSpecifier(TypeInfoContext::None).parse(state))
{
(state, Some(type_specifier))
} else {
(state, None)
};
Ok((state, (name, type_specifier)))
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeSpecifier(TypeInfoContext);
define_roblox_parser!(
ParseTypeSpecifier,
TypeSpecifier,
TokenReference,
|this, state| {
let (state, punctuation) = ParseSymbol(Symbol::Colon).parse(state)?;
let (state, type_info) = expect!(
state,
ParseTypeInfo(this.0).parse(state),
"expected type after colon"
);
Ok((
state,
TypeSpecifier {
punctuation,
type_info,
},
))
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseGenericDeclaration;
define_roblox_parser!(
ParseGenericDeclaration,
GenericDeclaration,
TokenReference,
|_, state| {
let (state, start_arrow) = ParseSymbol(Symbol::LessThan).parse(state)?;
let mut generics: Punctuated<GenericDeclarationParameter> = Punctuated::new();
let mut have_seen_pack = false; let mut have_seen_default = false;
let mut loop_state = state;
loop {
let (state, name) = expect!(
loop_state,
ParseIdentifier.parse(loop_state),
"expected name"
);
let (state, ellipse) = if let Ok((state, ellipse)) =
keep_going!(ParseSymbol(Symbol::Ellipse).parse(state))
{
have_seen_pack = true;
(state, Some(ellipse))
} else {
if have_seen_pack {
return Err(InternalAstError::UnexpectedToken {
token: state.peek().clone(),
additional: Some("generic types come before generic type packs".into()),
});
};
(state, None)
};
let (state, default) =
if let Ok((state, equals)) = keep_going!(ParseSymbol(Symbol::Equal).parse(state)) {
have_seen_default = true;
let parse_context = if ellipse.is_some() {
TypeInfoContext::GenericArgument
} else {
TypeInfoContext::None
};
let (state, type_info) = expect!(
state,
ParseTypeInfo(parse_context).parse(state),
"expected type after `=`"
);
(state, Some((equals, type_info)))
} else {
if have_seen_default {
return Err(InternalAstError::UnexpectedToken {
token: state.peek().clone(),
additional: Some("expected default type after type name".into()),
});
}
(state, None)
};
let parameter = match ellipse {
Some(ellipse) => GenericParameterInfo::Variadic { name, ellipse },
None => GenericParameterInfo::Name(name),
};
let declaration_parameter = GenericDeclarationParameter { parameter, default };
if let Ok((state, punctuation)) = keep_going!(ParseSymbol(Symbol::Comma).parse(state)) {
generics.push(Pair::Punctuated(declaration_parameter, punctuation));
loop_state = state;
} else {
generics.push(Pair::End(declaration_parameter));
loop_state = state;
break;
}
}
let (state, end_arrow) = expect!(
loop_state,
ParseSymbol(Symbol::GreaterThan).parse(loop_state),
"expected `>` to match `<`"
);
Ok((
state,
GenericDeclaration {
arrows: ContainedSpan::new(start_arrow, end_arrow),
generics,
},
))
}
);
#[cfg(feature = "roblox")]
#[allow(clippy::result_large_err)]
fn parse_interpolated_string(
state: ParserState<'_>,
) -> Result<(ParserState<'_>, InterpolatedString), InternalAstError> {
let mut current = state.peek().clone();
let (mut state, kind) = match ¤t.token_type {
TokenType::InterpolatedString { kind, .. } => (
state.advance().expect(
"we just peeked an interpolated string literal, and now can't advance to it",
),
kind,
),
_ => return Err(InternalAstError::NoMatch),
};
match kind {
InterpolatedStringKind::Simple => Ok((
state,
InterpolatedString {
segments: Vec::new(),
last_string: current,
},
)),
InterpolatedStringKind::Begin => {
let mut segments = Vec::new();
let last_string;
loop {
if matches!(
state.peek().token_type,
TokenType::Symbol {
symbol: Symbol::LeftBrace
}
) {
return Err(InternalAstError::UnexpectedToken {
token: state.peek().clone(),
additional: Some("unexpected double brace for interpolated string. try \\{ if you meant to escape".into()),
});
}
let expression;
(state, expression) = expect!(
state,
ParseExpression.parse(state),
"expected expression in interpolated string"
);
segments.push(InterpolatedStringSegment {
expression,
literal: current.clone(),
});
current = state.peek().clone();
if matches!(
current.token_type,
TokenType::InterpolatedString {
kind: InterpolatedStringKind::End,
..
}
) {
last_string = current;
return Ok((
state.advance().expect(
"we just peeked an interpolated string literal to end the formatted string, and now can't advance to it",
),
InterpolatedString {
segments,
last_string,
},
));
}
if current.token_kind() != TokenKind::InterpolatedString {
return Err(InternalAstError::UnexpectedToken {
additional: Some(
"interpolated string parameter can only contain an expression".into(),
),
token: current.clone(),
});
}
state = match state.advance() {
Some(state) => state,
None => {
return Err(InternalAstError::UnexpectedToken {
token: current,
additional: Some("expected `}` to end interpolated string".into()),
})
}
};
}
}
other => {
unreachable!("unexpected interpolated string kind: {other:?} ({current:#?})")
}
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "roblox")] {
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseCompoundAssignment;
define_parser!(
ParseCompoundAssignment,
CompoundAssignment,
|_, state| {
let (state, lhs) = ParseVar.parse(state)?;
let (state, compound_operator) = ParseCompoundOp.parse(state)?;
let (state, rhs) = expect!(
state,
ParseExpression.parse(state),
"expected value"
);
Ok((
state,
CompoundAssignment {
lhs,
compound_operator,
rhs,
},
))
}
);
#[derive(Clone, Debug, Default, PartialEq)]
struct ParseIfExpression;
define_parser!(
ParseIfExpression,
IfExpression,
|_, state| {
let (state, if_token) = ParseSymbol(Symbol::If).parse(state)?;
let (state, condition) = expect!(state, ParseExpression.parse(state), "expected condition");
let (state, then_token) = expect!(state, ParseSymbol(Symbol::Then).parse(state), "expected `then`");
let (mut state, if_expression) = expect!(state, ParseExpression.parse(state), "expected expression");
let mut else_if_expressions = Vec::new();
while let Ok((new_state, else_if_token)) = ParseSymbol(Symbol::ElseIf).parse(state) {
let (new_state, condition) = expect!(
state,
ParseExpression.parse(new_state),
"expected condition"
);
let (new_state, then_token) = expect!(
state,
ParseSymbol(Symbol::Then).parse(new_state),
"expected 'then'"
);
let (new_state, expression) = expect!(state, ParseExpression.parse(new_state), "expected expression");
state = new_state;
else_if_expressions.push(ElseIfExpression {
else_if_token,
condition,
then_token,
expression,
});
}
let (state, else_token) = expect!(state, ParseSymbol(Symbol::Else).parse(state), "expected `else` in if expression");
let (state, else_expression) = expect!(state, ParseExpression.parse(state), "expected expression");
Ok((
state,
IfExpression {
if_token,
condition,
then_token,
if_expression,
else_if_expressions: if else_if_expressions.is_empty() { None } else { Some(else_if_expressions) },
else_token,
else_expression,
},
))
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseInterpolatedString;
define_parser!(
ParseInterpolatedString,
InterpolatedString,
|_, state| {
parse_interpolated_string(state)
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeDeclaration;
define_parser!(
ParseTypeDeclaration,
TypeDeclaration,
|_, state| {
let (state, type_token) = ParseIdentifier.parse(state)?;
if type_token.token().to_string() != "type" {
return Err(InternalAstError::NoMatch);
}
let (state, base) = ParseIdentifier.parse(state)?;
let (state, generics) = if let Ok((state, generics)) =
keep_going!(ParseGenericDeclaration.parse(state))
{
(state, Some(generics))
} else {
(state, None)
};
let (state, equal_token) = expect!(
state,
ParseSymbol(Symbol::Equal).parse(state),
"expected `=` while parsing type alias"
);
let (state, declare_as) =
expect!(state, ParseTypeInfo(TypeInfoContext::None).parse(state), "expected type");
Ok((
state,
TypeDeclaration {
type_token,
base,
generics,
equal_token,
declare_as,
},
))
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseExportedTypeDeclaration;
define_parser!(
ParseExportedTypeDeclaration,
ExportedTypeDeclaration,
|_, state| {
let (state, export_token) = ParseIdentifier.parse(state)?;
if export_token.token().to_string() != "export" {
return Err(InternalAstError::NoMatch);
}
let (state, type_declaration) =
expect!(state, ParseTypeDeclaration.parse(state), "expected type declaration");
Ok((
state,
ExportedTypeDeclaration {
export_token,
type_declaration
},
))
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseIndexedTypeInfo;
define_parser!(ParseIndexedTypeInfo, IndexedTypeInfo, |_, state| {
let (state, base_type) = if let Ok((state, identifier)) = {
ParseIdentifier.parse(state)
} {
if let Ok((state, start_arrow)) = ParseSymbol(Symbol::LessThan).parse(state)
{
let (state, generics) = expect!(
state,
OneOrMore(ParseTypeInfo(TypeInfoContext::GenericArgument), ParseSymbol(Symbol::Comma), false).parse(state),
"expected type parameters"
);
let (state, end_arrow) = expect!(
state,
ParseSymbol(Symbol::GreaterThan).parse(state),
"expected `>` to close `<`"
);
(
state,
IndexedTypeInfo::Generic {
base: identifier,
arrows: ContainedSpan::new(start_arrow, end_arrow),
generics,
},
)
} else {
(state, IndexedTypeInfo::Basic(identifier))
}
} else {
return Err(InternalAstError::NoMatch);
};
Ok((state, base_type))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseParenthesesTypeInfo(TokenReference);
define_parser!(ParseParenthesesTypeInfo, TypeInfo, |this, state| {
let (state, type_info) = expect!(state, ParseTypeInfo(TypeInfoContext::None).parse(state), "expected type within parentheses");
let (state, end_parenthese) = expect!(state, ParseSymbol(Symbol::RightParen).parse(state), "expected `)`");
let mut types = Punctuated::new();
types.push(Pair::new(type_info, None));
Ok((state, TypeInfo::Tuple {
parentheses: ContainedSpan::new(this.0.clone(), end_parenthese),
types,
}))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseTupleTypeInfo(TokenReference);
define_parser!(ParseTupleTypeInfo, TypeInfo, |this, state| {
let (state, types) = expect!(
state,
ZeroOrMoreDelimited(ParseTypeInfo(TypeInfoContext::ParenthesesType), ParseSymbol(Symbol::Comma), false)
.parse(state),
"expected types within parentheses"
);
let (state, end_parenthese) = expect!(state, ParseSymbol(Symbol::RightParen).parse(state), "expected `)`");
Ok((state, TypeInfo::Tuple {
parentheses: ContainedSpan::new(this.0.clone(), end_parenthese),
types,
}))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeArray(TokenReference);
define_parser!(ParseTypeArray, TypeInfo, |this, state| {
let (state, type_info) = expect!(
state,
ParseTypeInfo(TypeInfoContext::None).parse(state),
"expected type in array"
);
let (state, end_brace) = expect!(
state,
ParseSymbol(Symbol::RightBrace).parse(state),
"expected `}` to match `{`"
);
Ok((
state,
TypeInfo::Array {
braces: ContainedSpan::new(this.0.clone(), end_brace),
type_info: Box::new(type_info)
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeArgument;
define_parser!(ParseTypeArgument, TypeArgument, |_, state| {
if let Ok((new_state, identifier)) = ParseIdentifier.parse(state) {
if let Ok((state, colon)) = ParseSymbol(Symbol::Colon).parse(new_state) {
let (state, type_info) = expect!(state, ParseTypeInfo(TypeInfoContext::None).parse(state), "expected type");
return Ok((
state,
TypeArgument {
name: Some((identifier, colon)),
type_info
}
))
}
};
let (state, type_info) = ParseTypeInfo(TypeInfoContext::ParenthesesType).parse(state)?;
Ok((
state,
TypeArgument {
name: None,
type_info,
}
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseCallbackTypeInfo(TokenReference, Option<GenericDeclaration>);
define_parser!(ParseCallbackTypeInfo, TypeInfo, |this, state| {
let (state, types) = expect!(
state,
ZeroOrMoreDelimited(ParseTypeArgument, ParseSymbol(Symbol::Comma), false)
.parse(state),
"expected types within parentheses"
);
let (state, end_parenthese) = expect!(
state,
ParseSymbol(Symbol::RightParen).parse(state),
"expected `)` to match `(`"
);
let (state, arrow) = expect!(state, ParseSymbol(Symbol::ThinArrow).parse(state), "expected `->` after `()` when parsing function type");
let (state, return_value) = expect!(
state,
ParseTypeInfo(TypeInfoContext::ReturnType).parse(state),
"expected return type after `->`"
);
Ok((
state,
TypeInfo::Callback {
generics: this.1.clone(),
arguments: types,
parentheses: ContainedSpan::new(this.0.clone(), end_parenthese),
arrow,
return_type: Box::new(return_value),
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeTable(TokenReference);
define_parser!(ParseTypeTable, TypeInfo, |this, state| {
let mut state = state;
let mut fields = Punctuated::new();
while let Ok((new_state, field)) = keep_going!(ParseTypeField.parse(state)) {
let field_sep = if let Ok((new_state, separator)) =
ParseSymbol(Symbol::Comma).parse(new_state)
{
state = new_state;
Some(separator)
} else if let Ok((new_state, separator)) = ParseSymbol(Symbol::Semicolon).parse(new_state) {
state = new_state;
Some(separator)
} else {
state = new_state;
None
};
let is_end = field_sep.is_none();
fields.push(Pair::new(field, field_sep));
if is_end {
break;
}
}
let (state, end_brace) = expect!(
state,
ParseSymbol(Symbol::RightBrace).parse(state),
"expected `}` to match `{`"
);
Ok((state, TypeInfo::Table {
braces: ContainedSpan::new(this.0.clone(), end_brace),
fields,
}))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseSingleTypeInfo(TypeInfoContext);
define_parser!(ParseSingleTypeInfo, TypeInfo, |this, state| {
let (state, base_type) = if let Ok((state, string_singleton)) = ParseStringLiteral.parse(state) {
(state, TypeInfo::String(string_singleton))
} else if let Ok((state, true_singleton)) = ParseSymbol(Symbol::True).parse(state) {
(state, TypeInfo::Boolean(true_singleton))
} else if let Ok((state, false_singleton)) = ParseSymbol(Symbol::False).parse(state) {
(state, TypeInfo::Boolean(false_singleton))
} else if let Ok((state, nil_singleton)) = ParseSymbol(Symbol::Nil).parse(state) {
(state, TypeInfo::Basic(nil_singleton))
} else if let Ok((state, identifier)) = ParseIdentifier
.parse(state)
{
if identifier.token().to_string() == "typeof" {
let (state, start_parenthese) = expect!(
state,
ParseSymbol(Symbol::LeftParen).parse(state),
"expected '(' when parsing typeof type"
);
let (state, expression) = expect!(
state,
ParseExpression.parse(state),
"expected expression when parsing typeof type"
);
let (state, end_parenthese) = expect!(
state,
ParseSymbol(Symbol::RightParen).parse(state),
"expected ')' when parsing typeof type"
);
(
state,
TypeInfo::Typeof {
typeof_token: identifier,
parentheses: ContainedSpan::new(start_parenthese, end_parenthese),
inner: Box::new(expression),
},
)
} else if let Ok((state, punctuation)) = ParseSymbol(Symbol::Dot).parse(state)
{
let (state, type_info) = expect!(
state,
ParseIndexedTypeInfo.parse(state),
"expected type when parsing type index"
);
(
state,
TypeInfo::Module {
module: identifier,
punctuation,
type_info: Box::new(type_info),
},
)
} else if let Ok((state, start_arrow)) = ParseSymbol(Symbol::LessThan).parse(state)
{
let (state, generics) = expect!(
state,
ZeroOrMoreDelimited(ParseTypeInfo(TypeInfoContext::GenericArgument), ParseSymbol(Symbol::Comma), false).parse(state),
"expected type parameters"
);
let (state, end_arrow) = expect!(
state,
ParseSymbol(Symbol::GreaterThan).parse(state),
"expected `>` to close `<`"
);
(
state,
TypeInfo::Generic {
base: identifier,
arrows: ContainedSpan::new(start_arrow, end_arrow),
generics,
},
)
} else if matches!(this.0, TypeInfoContext::ParenthesesType | TypeInfoContext::ReturnType | TypeInfoContext::VarArgSpecifier | TypeInfoContext::GenericArgument) {
if let Ok((state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) {
(state, TypeInfo::GenericPack {
name: identifier,
ellipse
})
} else {
(state, TypeInfo::Basic(identifier))
}
} else {
(state, TypeInfo::Basic(identifier))
}
} else if let Ok((state, generics)) = ParseGenericDeclaration.parse(state) {
let (state, start_parenthese) = ParseSymbol(Symbol::LeftParen).parse(state)?;
ParseCallbackTypeInfo(start_parenthese, Some(generics)).parse(state)?
} else if let Ok((state, start_parenthese)) =
ParseSymbol(Symbol::LeftParen).parse(state)
{
let atom =
if matches!(this.0, TypeInfoContext::ReturnType | TypeInfoContext::GenericArgument) {
ParseTupleTypeInfo(start_parenthese.clone()).parse(state)
} else {
ParseParenthesesTypeInfo(start_parenthese.clone()).parse(state)
};
if let Ok((state, parentheses_type)) = atom {
if let Ok((state, arrow)) = ParseSymbol(Symbol::ThinArrow).parse(state) {
let (parentheses, arguments) = match parentheses_type {
TypeInfo::Tuple { parentheses, types } => {
let arguments = types.into_pairs().map(|pair| pair.map(|type_info| TypeArgument {
name: None,
type_info
})).collect::<Punctuated<_>>();
(parentheses, arguments)
},
_ => unreachable!("parsed a non-tuple as a parentheses type"),
};
let (state, return_value) = expect!(
state,
ParseTypeInfo(TypeInfoContext::ReturnType).parse(state),
"expected return type after `->`"
);
(
state,
TypeInfo::Callback {
generics: None,
arguments,
parentheses,
arrow,
return_type: Box::new(return_value),
},
)
} else {
(state, parentheses_type)
}
} else {
ParseCallbackTypeInfo(start_parenthese, None).parse(state)?
}
} else if let Ok((state, start_brace)) = ParseSymbol(Symbol::LeftBrace).parse(state) {
if let Ok((state, type_array)) = ParseTypeArray(start_brace.clone()).parse(state) {
(state, type_array)
} else {
ParseTypeTable(start_brace).parse(state)?
}
} else if matches!(this.0, TypeInfoContext::GenericArgument) {
if let Ok((state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) {
let (state, name) = expect!(
state,
ParseIdentifier.parse(state),
"expected name after `...`"
);
(state, TypeInfo::VariadicPack { ellipse, name })
} else {
return Err(InternalAstError::NoMatch);
}
} else if matches!(this.0, TypeInfoContext::ParenthesesType | TypeInfoContext::ReturnType) {
if let Ok((state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) {
let (state, type_info) = expect!(
state,
ParseSingleTypeInfo(TypeInfoContext::None).parse(state),
"expected type info after `...`"
);
(
state,
TypeInfo::Variadic {
ellipse,
type_info: Box::new(type_info),
}
)
} else {
return Err(InternalAstError::NoMatch);
}
} else {
return Err(InternalAstError::NoMatch);
};
Ok((state, base_type))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseSingleTypeInfoAtom(TypeInfoContext);
define_parser!(ParseSingleTypeInfoAtom, TypeInfo, |this, state| {
let (mut state, mut base_type) = ParseSingleTypeInfo(this.0).parse(state)?;
if let Ok((new_state, question_mark)) = ParseSymbol(Symbol::QuestionMark).parse(state) {
base_type = TypeInfo::Optional {
base: Box::new(base_type),
question_mark,
};
state = new_state;
}
Ok((state, base_type))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeInfo(TypeInfoContext);
define_parser!(ParseTypeInfo, TypeInfo, |this, state| {
let (state, base_type) = ParseSingleTypeInfoAtom(this.0).parse(state)?;
if let Ok((state, pipe)) = ParseSymbol(Symbol::Pipe).parse(state) {
let (state, right) = expect!(
state,
ParseTypeInfo(this.0).parse(state),
"expected type after `|` for union type"
);
Ok((
state,
TypeInfo::Union {
left: Box::new(base_type),
right: Box::new(right),
pipe,
},
))
} else if let Ok((state, ampersand)) = ParseSymbol(Symbol::Ampersand).parse(state) {
let (state, right) = expect!(
state,
ParseTypeInfo(this.0).parse(state),
"expected type after `&` for intersection type"
);
Ok((
state,
TypeInfo::Intersection {
left: Box::new(base_type),
right: Box::new(right),
ampersand,
},
))
} else {
Ok((state, base_type))
}
});
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeField;
define_parser!(
ParseTypeField,
TypeField,
|_, state| {
let (state, key) = ParseTypeFieldKey.parse(state)?;
let (state, colon) = expect!(
state,
ParseSymbol(Symbol::Colon).parse(state),
"expected `:` after key"
);
let (state, value) = expect!(
state,
ParseTypeInfo(TypeInfoContext::None).parse(state),
"expected value type for key"
);
Ok((state, TypeField { key, colon, value }))
}
);
#[derive(Clone, Debug, PartialEq)]
struct ParseTypeFieldKey;
#[rustfmt::skip]
define_parser!(ParseTypeFieldKey, TypeFieldKey, |_, state| {
if let Ok((state, identifier)) = ParseIdentifier.parse(state) {
Ok((state, TypeFieldKey::Name(identifier)))
} else if let Ok((state, start_bracket)) = ParseSymbol(Symbol::LeftBracket).parse(state)
{
let (state, inner) = expect!(
state,
ParseTypeInfo(TypeInfoContext::None).parse(state),
"expected type within brackets for index signature"
);
let (state, end_bracket) = expect!(
state,
ParseSymbol(Symbol::RightBracket).parse(state),
"expected `]` to match `[`"
);
Ok((
state,
TypeFieldKey::IndexSignature {
brackets: ContainedSpan::new(start_bracket, end_bracket),
inner,
},
))
} else {
Err(InternalAstError::NoMatch)
}
});
}
}
#[derive(Clone, Debug, PartialEq)]
struct ParseGoto;
define_lua52_parser!(ParseGoto, Goto, TokenReference, |_, state| {
let (state, goto_token) = ParseSymbol(Symbol::Goto).parse(state)?;
let (state, label_name) = expect!(
state,
ParseIdentifier.parse(state),
"expected identifier after `goto`"
);
Ok((
state,
Goto {
goto_token,
label_name,
},
))
});
#[derive(Clone, Debug, PartialEq)]
struct ParseLabel;
define_lua52_parser!(ParseLabel, Label, TokenReference, |_, state| {
let (state, left_colons) = ParseSymbol(Symbol::TwoColons).parse(state)?;
let (state, name) = expect!(
state,
ParseIdentifier.parse(state),
"expected identifier after `::`"
);
let (state, right_colons) = expect!(
state,
ParseSymbol(Symbol::TwoColons).parse(state),
"expected `::`"
);
Ok((
state,
Label {
left_colons,
name,
right_colons,
},
))
});
cfg_if::cfg_if! {
if #[cfg(feature = "lua54")] {
#[derive(Clone, Debug, PartialEq)]
struct ParseAttribute;
define_parser!(ParseAttribute, Attribute, |_, state| {
let (state, left_angle_bracket) = ParseSymbol(Symbol::LessThan).parse(state)?;
let (state, name) = expect!(
state,
ParseIdentifier.parse(state),
"expected identifier after `<`"
);
let (state, right_angle_bracket) = expect!(
state,
ParseSymbol(Symbol::GreaterThan).parse(state),
"expected `>`"
);
Ok((
state,
Attribute {
brackets: ContainedSpan::new(left_angle_bracket, right_angle_bracket),
name,
},
))
});
}
}
macro_rules! make_op_parser {
($enum:ident, $parser:ident, { $($(#[$inner:meta])* $operator:ident,)+ }) => {
#[derive(Clone, Debug, PartialEq)]
struct $parser;
define_parser!($parser, $enum, |_, state| {
$(
$(#[$inner])*
if let Ok((state, operator)) = ParseSymbol(Symbol::$operator).parse(state) {
return Ok((state, $enum::$operator(operator)));
}
)+
if let Some(x) = None {
match x {
$(
$(#[$inner])*
$enum::$operator(_) => {},
)+
}
}
Err(InternalAstError::NoMatch)
});
};
}
#[derive(Clone, Debug, PartialEq)]
struct ParseBinOp;
define_parser!(ParseBinOp, BinOp, |_, state| {
if let Ok((state, operator)) = ParseSymbol(Symbol::And).parse(state) {
Ok((state, BinOp::And(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Caret).parse(state) {
Ok((state, BinOp::Caret(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::GreaterThan).parse(state) {
#[cfg(feature = "lua53")]
if operator.trailing_trivia().next().is_none() {
if let Ok((state, operator2)) = ParseSymbol(Symbol::GreaterThan).parse(state) {
let merged_token = Token {
start_position: operator.start_position,
end_position: operator2.end_position,
token_type: TokenType::Symbol {
symbol: Symbol::DoubleGreaterThan,
},
};
let merged_operator = TokenReference::new(
operator.leading_trivia,
merged_token,
operator2.trailing_trivia,
);
return Ok((state, BinOp::DoubleGreaterThan(merged_operator)));
}
}
Ok((state, BinOp::GreaterThan(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::GreaterThanEqual).parse(state) {
Ok((state, BinOp::GreaterThanEqual(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::LessThan).parse(state) {
Ok((state, BinOp::LessThan(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::LessThanEqual).parse(state) {
Ok((state, BinOp::LessThanEqual(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Minus).parse(state) {
Ok((state, BinOp::Minus(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Or).parse(state) {
Ok((state, BinOp::Or(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Percent).parse(state) {
Ok((state, BinOp::Percent(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Plus).parse(state) {
Ok((state, BinOp::Plus(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Slash).parse(state) {
Ok((state, BinOp::Slash(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Star).parse(state) {
Ok((state, BinOp::Star(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::TildeEqual).parse(state) {
Ok((state, BinOp::TildeEqual(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::TwoDots).parse(state) {
Ok((state, BinOp::TwoDots(operator)))
} else if let Ok((state, operator)) = ParseSymbol(Symbol::TwoEqual).parse(state) {
Ok((state, BinOp::TwoEqual(operator)))
} else {
#[cfg(feature = "lua53")]
if let Ok((state, operator)) = ParseSymbol(Symbol::Ampersand).parse(state) {
return Ok((state, BinOp::Ampersand(operator)));
} else if let Ok((state, operator)) = ParseSymbol(Symbol::DoubleSlash).parse(state) {
return Ok((state, BinOp::DoubleSlash(operator)));
} else if let Ok((state, operator)) = ParseSymbol(Symbol::DoubleLessThan).parse(state) {
return Ok((state, BinOp::DoubleLessThan(operator)));
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Pipe).parse(state) {
return Ok((state, BinOp::Pipe(operator)));
} else if let Ok((state, operator)) = ParseSymbol(Symbol::Tilde).parse(state) {
return Ok((state, BinOp::Tilde(operator)));
}
Err(InternalAstError::NoMatch)
}
});
make_op_parser!(UnOp, ParseUnOp,
{
Minus,
Not,
Hash,
#[cfg(feature = "lua53")]
Tilde,
}
);
#[cfg(feature = "roblox")]
make_op_parser!(CompoundOp, ParseCompoundOp,
{
PlusEqual,
MinusEqual,
StarEqual,
SlashEqual,
PercentEqual,
CaretEqual,
TwoDotsEqual,
}
);