use crate::parser::{
parse_function_expression,
parse_unary_expression,
try_parse_table_expression,
OptionParsingResult,
};
use crate::parser::token_utils::{
skip_first_token,
LuaKeyword,
LuaSymbol,
};
use crate::parser::node_types::NodeTypes;
use crate::parser::node_types::builders::{
Expression,
UnaryOperator,
};
use lualexer::{Token, TokenType};
use std::convert::TryFrom;
pub fn try_parse_primary_expression<'a, T: NodeTypes>(
tokens: &'a [Token<'a>],
) -> OptionParsingResult<'a, T::Expression> {
if let Some(token) = tokens.first() {
let expression_and_tokens = if let Ok(keyword) = LuaKeyword::try_from(token.get_content()) {
match keyword {
LuaKeyword::True => {
let expression = T::Expression::true_expression();
(expression, skip_first_token(tokens))
}
LuaKeyword::False => {
let expression = T::Expression::false_expression();
(expression, skip_first_token(tokens))
}
LuaKeyword::Nil => {
let expression = T::Expression::nil_expression();
(expression, skip_first_token(tokens))
}
LuaKeyword::Function => {
return parse_function_expression::<T>(tokens)
.map(|(function, next_tokens)| Some((function.into(), next_tokens)))
}
LuaKeyword::Not => {
let (expression, tokens) = parse_unary_expression::<T>(
T::UnaryOperator::not(),
skip_first_token(tokens)
)?;
(expression.into(), tokens)
}
_ => return Ok(None),
}
} else if let Ok(symbol) = LuaSymbol::try_from(token.get_content()) {
match symbol {
LuaSymbol::OpenBrace => {
return Ok(try_parse_table_expression::<T>(tokens)?
.map(|(table, next_tokens)| (table.into(), next_tokens)))
}
LuaSymbol::Length => {
let (expression, tokens) = parse_unary_expression::<T>(
T::UnaryOperator::length(),
skip_first_token(tokens)
)?;
(expression.into(), tokens)
}
LuaSymbol::Minus => {
let (expression, tokens) = parse_unary_expression::<T>(
T::UnaryOperator::minus(),
skip_first_token(tokens)
)?;
(expression.into(), tokens)
}
LuaSymbol::VariableArguments => {
(T::Expression::variable_arguments(), skip_first_token(tokens))
}
_ => return Ok(None),
}
} else {
match (token.get_type(), token.get_content()) {
(TokenType::Number, number) => {
let expression = T::NumberExpression::from(number.to_owned());
(expression.into(), skip_first_token(tokens))
}
(TokenType::String, string) => {
let expression = T::StringExpression::from(string.to_owned());
(expression.into(), skip_first_token(tokens))
}
_ => return Ok(None),
}
};
Ok(Some(expression_and_tokens))
} else {
Ok(None)
}
}