mod parse_bracket;
mod parse_field;
mod parse_function;
mod parse_method;
mod parse_parenthese;
mod parse_prefix;
mod parse_primary;
mod parse_right;
mod parse_single;
mod parse_table;
mod parse_unary;
pub use parse_bracket::*;
pub use parse_field::*;
pub use parse_function::*;
pub use parse_method::*;
pub use parse_parenthese::*;
pub use parse_prefix::*;
pub use parse_primary::*;
pub use parse_right::*;
pub use parse_single::*;
pub use parse_table::*;
pub use parse_unary::*;
use crate::parser::{
OptionParsingResult,
ParsingResult,
};
use crate::parser::token_utils::{
skip_first_token_if_is_symbol,
LuaSymbol,
};
use crate::parser::node_types::NodeTypes;
use lualexer::{Token};
pub fn try_parse_expression<'a, T: NodeTypes>(
tokens: &'a [Token<'a>]
) -> OptionParsingResult<'a, T::Expression> {
if let Some((left, tokens)) = try_parse_single_expression::<T>(tokens)? {
let (final_expression, next_tokens) = parse_right_expression::<T>(left, tokens, 0)?;
Ok(Some((final_expression, next_tokens)))
} else {
Ok(None)
}
}
pub fn parse_expression_list<'a, T: NodeTypes>(
mut tokens: &'a [Token<'a>]
) -> ParsingResult<'a, Vec<T::Expression>> {
let mut expressions = Vec::new();
if let Some((first_expression, mut next_tokens)) = try_parse_expression::<T>(tokens)? {
expressions.push(first_expression);
while let Some(next_expression_tokens) = skip_first_token_if_is_symbol(next_tokens, LuaSymbol::Comma) {
if let Some((expression, next_expression_tokens)) = try_parse_expression::<T>(next_expression_tokens)? {
expressions.push(expression);
next_tokens = next_expression_tokens;
} else {
break
}
}
tokens = next_tokens;
}
Ok((expressions, tokens))
}
#[cfg(test)]
mod test {
use super::try_parse_expression;
use crate::nodes::*;
use crate::parser_impl::FastParserNodes;
use lualexer::FastLexer;
macro_rules! test_expressions {
($($name:ident($input:literal) => $expect:expr),+) => {
$(
#[test]
fn $name() {
let tokens = FastLexer::new()
.parse($input)
.unwrap();
let (expression, tokens) = try_parse_expression::<FastParserNodes>(&tokens)
.unwrap()
.unwrap();
assert_eq!(expression, $expect.into());
assert_eq!(tokens, &[]);
}
)+
};
}
test_expressions!(
parse_true("true") => Expression::True,
parse_false("false") => Expression::False,
parse_nil("nil") => Expression::Nil,
parse_variable_arguments("...") => Expression::VariableArguments,
parse_string("'hello'") => StringExpression { value: "'hello'".to_string() },
parse_number("123") => NumberExpression { value: "123".to_string() },
parse_empty_function("function() end") => FunctionExpression {
block: Block::from((Vec::new(), None)),
parameters: Vec::new(),
is_variadic: false,
},
parse_single_parameter_function("function(a) end") => FunctionExpression {
block: Block::from((Vec::new(), None)),
parameters: vec!["a".to_owned()],
is_variadic: false,
},
parse_multiple_parameters_function("function(a, b,c) end") => FunctionExpression {
block: Block::from((Vec::new(), None)),
parameters: vec!["a".to_owned(), "b".to_owned(), "c".to_owned()],
is_variadic: false,
},
parse_empty_variadic_function("function(...) end") => FunctionExpression {
block: Block::from((Vec::new(), None)),
parameters: Vec::new(),
is_variadic: true,
},
parse_single_parameter_variadic_function("function(a, ...) end") => FunctionExpression {
block: Block::from((Vec::new(), None)),
parameters: vec!["a".to_owned()],
is_variadic: true,
},
parse_multiple_parameters_variadic_function("function(a, b,c,...) end") => FunctionExpression {
block: Block::from((Vec::new(), None)),
parameters: vec!["a".to_owned(), "b".to_owned(), "c".to_owned()],
is_variadic: true,
},
parse_binary_true_and_false("true and false") => BinaryExpression {
left: Expression::True,
right: Expression::False,
operator: BinaryOperator::And,
},
parse_binary_true_or_false("true or false") => BinaryExpression {
left: Expression::True,
right: Expression::False,
operator: BinaryOperator::Or,
},
parse_with_precedence_binary_or_and("true or true and false") => BinaryExpression {
left: Expression::True,
operator: BinaryOperator::Or,
right: BinaryExpression {
left: Expression::True,
operator: BinaryOperator::And,
right: Expression::False,
}.into(),
},
parse_with_precedence_binary_and_or("false and true or true") => BinaryExpression {
left: BinaryExpression {
left: Expression::False,
operator: BinaryOperator::And,
right: Expression::True,
}.into(),
operator: BinaryOperator::Or,
right: Expression::True,
},
parse_with_precedence_concat_plus("'1' .. 4 + 6") => BinaryExpression {
left: StringExpression { value: "'1'".to_owned() }.into(),
operator: BinaryOperator::Concat,
right: BinaryExpression {
left: NumberExpression::from("4".to_owned()).into(),
operator: BinaryOperator::Plus,
right: NumberExpression::from("6".to_owned()).into(),
}.into(),
},
parse_with_precedence_exponent_plus("1 ^ 4 + 6") => BinaryExpression {
left: BinaryExpression {
left: NumberExpression::from("1".to_owned()).into(),
operator: BinaryOperator::Caret,
right: NumberExpression::from("4".to_owned()).into(),
}.into(),
operator: BinaryOperator::Plus,
right: NumberExpression::from("6".to_owned()).into(),
},
parse_exponent_right_associativity("2^3^2") => BinaryExpression {
left: NumberExpression::from("2".to_owned()).into(),
operator: BinaryOperator::Caret,
right: BinaryExpression {
left: NumberExpression::from("3".to_owned()).into(),
operator: BinaryOperator::Caret,
right: NumberExpression::from("2".to_owned()).into(),
}.into(),
},
parse_unary_not_true("not true") => UnaryExpression {
operator: UnaryOperator::Not,
expression: Expression::True,
},
parse_unary_length("#foo") => UnaryExpression {
operator: UnaryOperator::Length,
expression: Expression::Identifier("foo".to_owned()),
},
parse_exponent_precedence_over_unary_minus("- 2 ^ 4") => UnaryExpression {
operator: UnaryOperator::Minus,
expression: BinaryExpression {
left: NumberExpression::from("2".to_owned()).into(),
operator: BinaryOperator::Caret,
right: NumberExpression::from("4".to_owned()).into(),
}.into(),
},
parse_unary_precedence_over_addition("- 2+3") => BinaryExpression {
left: UnaryExpression {
operator: UnaryOperator::Minus,
expression: NumberExpression::from("2".to_owned()).into(),
}.into(),
operator: BinaryOperator::Plus,
right: NumberExpression::from("3".to_owned()).into(),
},
parse_empty_table("{}") => TableExpression::from(Vec::new()),
parse_table_with_one_value("{true}") => TableExpression::from(vec![
TableEntry::Value(Expression::True),
]),
parse_table_with_one_value_ending_with_comma("{true,}") => TableExpression::from(vec![
TableEntry::Value(Expression::True),
]),
parse_table_with_one_value_ending_with_semicolon("{true;}") => TableExpression::from(vec![
TableEntry::Value(Expression::True),
]),
parse_table_with_two_values_separated_with_comma("{true, false}") => TableExpression::from(vec![
TableEntry::Value(Expression::True),
TableEntry::Value(Expression::False),
]),
parse_table_with_two_values_separated_with_semicolon("{true; false}") => TableExpression::from(vec![
TableEntry::Value(Expression::True),
TableEntry::Value(Expression::False),
]),
parse_table_with_field("{key = true}") => TableExpression::from(vec![
TableEntry::Field("key".to_owned(), Expression::True),
]),
parse_table_with_index("{[true] = false}") => TableExpression::from(vec![
TableEntry::Index(Expression::True, Expression::False),
]),
parse_identifier("id") => Expression::Identifier("id".to_owned()),
parse_field_index("foo.bar") => FieldExpression {
prefix: Prefix::Identifier("foo".to_owned()),
field: "bar".to_owned(),
},
parse_multiple_field_index("foo.bar.baz") => FieldExpression {
prefix: Prefix::Field(Box::new(FieldExpression {
prefix: Prefix::Identifier("foo".to_owned()),
field: "bar".to_owned(),
})),
field: "baz".to_owned(),
},
parse_bracket_index("foo[1]") => IndexExpression {
prefix: Prefix::Identifier("foo".to_owned()),
index: NumberExpression { value: "1".to_owned() }.into(),
},
parse_function_call("foo()") => FunctionCall {
prefix: Box::new(Prefix::Identifier("foo".to_owned())),
arguments: Arguments::Tuple(Vec::new()),
method: None,
},
parse_function_call_with_index("foo.bar()") => FunctionCall {
prefix: Box::new(Prefix::Field(Box::new(FieldExpression {
prefix: Prefix::Identifier("foo".to_owned()),
field: "bar".to_owned(),
}))),
arguments: Arguments::Tuple(Vec::new()),
method: None,
},
parse_function_call_with_string_argument("foo''") => FunctionCall {
prefix: Box::new(Prefix::Identifier("foo".to_owned())),
arguments: Arguments::String(StringExpression::from("''".to_owned())),
method: None,
},
parse_function_call_with_table_argument("foo{}") => FunctionCall {
prefix: Box::new(Prefix::Identifier("foo".to_owned())),
arguments: Arguments::Table(TableExpression::from(Vec::new())),
method: None,
},
parse_method_call("foo:bar()") => FunctionCall {
prefix: Box::new(Prefix::Identifier("foo".to_owned())),
arguments: Arguments::Tuple(Vec::new()),
method: Some("bar".to_owned()),
},
parse_method_call_with_index("foo.bar:baz()") => FunctionCall {
prefix: Box::new(Prefix::Field(Box::new(FieldExpression {
prefix: Prefix::Identifier("foo".to_owned()),
field: "bar".to_owned(),
}))),
arguments: Arguments::Tuple(Vec::new()),
method: Some("baz".to_owned()),
},
parse_function_call_with_single_argument("foo(true)") => FunctionCall {
prefix: Box::new(Prefix::Identifier("foo".to_owned())),
arguments: Arguments::Tuple(vec![Expression::True]),
method: None,
},
parse_function_call_with_two_arguments("foo(true, false)") => FunctionCall {
prefix: Box::new(Prefix::Identifier("foo".to_owned())),
arguments: Arguments::Tuple(vec![
Expression::True,
Expression::False,
]),
method: None,
},
parse_method_call_with_two_arguments("foo:bar(true, false)") => FunctionCall {
prefix: Box::new(Prefix::Identifier("foo".to_owned())),
arguments: Arguments::Tuple(vec![
Expression::True,
Expression::False,
]),
method: Some("bar".to_owned()),
},
parse_parenthese_expression("(true)") => Expression::Parenthese(Box::new(Expression::True))
);
}