mod dense;
mod readable;
mod token_based;
mod utils;
pub use dense::DenseLuaGenerator;
pub use readable::ReadableLuaGenerator;
pub use token_based::TokenBasedLuaGenerator;
use crate::nodes;
pub trait LuaGenerator {
fn into_string(self) -> String;
fn write_block(&mut self, block: &nodes::Block);
fn write_statement(&mut self, statement: &nodes::Statement) {
use nodes::Statement::*;
match statement {
Assign(statement) => self.write_assign_statement(statement),
Do(statement) => self.write_do_statement(statement),
Call(statement) => self.write_function_call(statement),
CompoundAssign(statement) => self.write_compound_assign(statement),
Function(statement) => self.write_function_statement(statement),
GenericFor(statement) => self.write_generic_for(statement),
If(statement) => self.write_if_statement(statement),
LocalAssign(statement) => self.write_local_assign(statement),
LocalFunction(statement) => self.write_local_function(statement),
NumericFor(statement) => self.write_numeric_for(statement),
Repeat(statement) => self.write_repeat_statement(statement),
While(statement) => self.write_while_statement(statement),
TypeDeclaration(statement) => self.write_type_declaration_statement(statement),
}
}
fn write_assign_statement(&mut self, assign: &nodes::AssignStatement);
fn write_do_statement(&mut self, do_statement: &nodes::DoStatement);
fn write_compound_assign(&mut self, assign: &nodes::CompoundAssignStatement);
fn write_generic_for(&mut self, generic_for: &nodes::GenericForStatement);
fn write_if_statement(&mut self, if_statement: &nodes::IfStatement);
fn write_function_statement(&mut self, function: &nodes::FunctionStatement);
fn write_last_statement(&mut self, statement: &nodes::LastStatement);
fn write_local_assign(&mut self, assign: &nodes::LocalAssignStatement);
fn write_local_function(&mut self, function: &nodes::LocalFunctionStatement);
fn write_numeric_for(&mut self, numeric_for: &nodes::NumericForStatement);
fn write_repeat_statement(&mut self, repeat: &nodes::RepeatStatement);
fn write_while_statement(&mut self, while_statement: &nodes::WhileStatement);
fn write_type_declaration_statement(&mut self, statement: &nodes::TypeDeclarationStatement);
fn write_variable(&mut self, variable: &nodes::Variable) {
use nodes::Variable::*;
match variable {
Identifier(identifier) => self.write_identifier(identifier),
Field(field) => self.write_field(field),
Index(index) => self.write_index(index),
}
}
fn write_expression(&mut self, expression: &nodes::Expression) {
use nodes::Expression::*;
match expression {
Binary(binary) => self.write_binary_expression(binary),
Call(call) => self.write_function_call(call),
False(token) => self.write_false_expression(token),
Field(field) => self.write_field(field),
Function(function) => self.write_function(function),
Identifier(identifier) => self.write_identifier(identifier),
If(if_expression) => self.write_if_expression(if_expression),
Index(index) => self.write_index(index),
Nil(token) => self.write_nil_expression(token),
Number(number) => self.write_number(number),
Parenthese(parenthese) => self.write_parenthese(parenthese),
String(string) => self.write_string(string),
Table(table) => self.write_table(table),
True(token) => self.write_true_expression(token),
Unary(unary) => self.write_unary_expression(unary),
VariableArguments(token) => self.write_variable_arguments_expression(token),
TypeCast(type_cast) => self.write_type_cast(type_cast),
}
}
fn write_identifier(&mut self, identifier: &nodes::Identifier);
fn write_binary_expression(&mut self, binary: &nodes::BinaryExpression);
fn write_if_expression(&mut self, if_expression: &nodes::IfExpression);
fn write_unary_expression(&mut self, unary: &nodes::UnaryExpression);
fn write_function(&mut self, function: &nodes::FunctionExpression);
fn write_function_call(&mut self, call: &nodes::FunctionCall);
fn write_field(&mut self, field: &nodes::FieldExpression);
fn write_index(&mut self, index: &nodes::IndexExpression);
fn write_parenthese(&mut self, parenthese: &nodes::ParentheseExpression);
fn write_type_cast(&mut self, type_cast: &nodes::TypeCastExpression);
fn write_false_expression(&mut self, token: &Option<nodes::Token>);
fn write_true_expression(&mut self, token: &Option<nodes::Token>);
fn write_nil_expression(&mut self, token: &Option<nodes::Token>);
fn write_variable_arguments_expression(&mut self, token: &Option<nodes::Token>);
fn write_prefix(&mut self, prefix: &nodes::Prefix) {
use nodes::Prefix::*;
match prefix {
Call(call) => self.write_function_call(call),
Field(field) => self.write_field(field),
Identifier(identifier) => self.write_identifier(identifier),
Index(index) => self.write_index(index),
Parenthese(parenthese) => self.write_parenthese(parenthese),
}
}
fn write_table(&mut self, table: &nodes::TableExpression);
fn write_table_entry(&mut self, entry: &nodes::TableEntry);
fn write_number(&mut self, number: &nodes::NumberExpression);
fn write_arguments(&mut self, arguments: &nodes::Arguments) {
use nodes::Arguments::*;
match arguments {
String(string) => self.write_string(string),
Table(table) => self.write_table(table),
Tuple(tuple) => self.write_tuple_arguments(tuple),
}
}
fn write_tuple_arguments(&mut self, arguments: &nodes::TupleArguments);
fn write_string(&mut self, string: &nodes::StringExpression);
fn write_type(&mut self, r#type: &nodes::Type) {
match r#type {
nodes::Type::Name(type_name) => self.write_type_name(type_name),
nodes::Type::Field(type_field) => self.write_type_field(type_field),
nodes::Type::True(token) => self.write_true_type(token),
nodes::Type::False(token) => self.write_false_type(token),
nodes::Type::Nil(token) => self.write_nil_type(token),
nodes::Type::String(string_type) => self.write_string_type(string_type),
nodes::Type::Array(array_type) => self.write_array_type(array_type),
nodes::Type::Table(table_type) => self.write_table_type(table_type),
nodes::Type::TypeOf(expression_type) => self.write_expression_type(expression_type),
nodes::Type::Parenthese(parenthese_type) => self.write_parenthese_type(parenthese_type),
nodes::Type::Function(function_type) => self.write_function_type(function_type),
nodes::Type::Optional(optional_type) => self.write_optional_type(optional_type),
nodes::Type::Intersection(intersection_type) => {
self.write_intersection_type(intersection_type)
}
nodes::Type::Union(union_type) => self.write_union_type(union_type),
}
}
fn write_type_name(&mut self, type_name: &nodes::TypeName);
fn write_type_field(&mut self, type_field: &nodes::TypeField);
fn write_true_type(&mut self, token: &Option<nodes::Token>);
fn write_false_type(&mut self, token: &Option<nodes::Token>);
fn write_nil_type(&mut self, token: &Option<nodes::Token>);
fn write_string_type(&mut self, string_type: &nodes::StringType);
fn write_array_type(&mut self, array_type: &nodes::ArrayType);
fn write_table_type(&mut self, table_type: &nodes::TableType);
fn write_expression_type(&mut self, expression_type: &nodes::ExpressionType);
fn write_parenthese_type(&mut self, parenthese_type: &nodes::ParentheseType);
fn write_function_type(&mut self, function_type: &nodes::FunctionType);
fn write_optional_type(&mut self, optional_type: &nodes::OptionalType);
fn write_intersection_type(&mut self, intersection_type: &nodes::IntersectionType);
fn write_union_type(&mut self, union_type: &nodes::UnionType);
fn write_type_pack(&mut self, type_pack: &nodes::TypePack);
fn write_variadic_type_pack(&mut self, variadic_type_pack: &nodes::VariadicTypePack);
fn write_generic_type_pack(&mut self, generic_type_pack: &nodes::GenericTypePack);
fn write_function_return_type(&mut self, return_type: &nodes::FunctionReturnType) {
match return_type {
nodes::FunctionReturnType::Type(r#type) => {
self.write_type(r#type);
}
nodes::FunctionReturnType::TypePack(type_pack) => {
self.write_type_pack(type_pack);
}
nodes::FunctionReturnType::VariadicTypePack(variadic_type_pack) => {
self.write_variadic_type_pack(variadic_type_pack);
}
nodes::FunctionReturnType::GenericTypePack(generic_type_pack) => {
self.write_generic_type_pack(generic_type_pack);
}
}
}
fn write_variadic_argument_type(
&mut self,
variadic_argument_type: &nodes::VariadicArgumentType,
) {
match variadic_argument_type {
nodes::VariadicArgumentType::GenericTypePack(generic_type_pack) => {
self.write_generic_type_pack(generic_type_pack);
}
nodes::VariadicArgumentType::VariadicTypePack(variadic_type_pack) => {
self.write_variadic_type_pack(variadic_type_pack);
}
}
}
fn write_type_parameter(&mut self, type_parameter: &nodes::TypeParameter) {
match type_parameter {
nodes::TypeParameter::Type(r#type) => self.write_type(r#type),
nodes::TypeParameter::TypePack(type_pack) => self.write_type_pack(type_pack),
nodes::TypeParameter::VariadicTypePack(variadic_type_pack) => {
self.write_variadic_type_pack(variadic_type_pack);
}
nodes::TypeParameter::GenericTypePack(generic_type_pack) => {
self.write_generic_type_pack(generic_type_pack);
}
}
}
fn write_generic_type_pack_default(
&mut self,
generic_type_pack_default: &nodes::GenericTypePackDefault,
) {
match generic_type_pack_default {
nodes::GenericTypePackDefault::TypePack(type_pack) => self.write_type_pack(type_pack),
nodes::GenericTypePackDefault::VariadicTypePack(variadic_type_pack) => {
self.write_variadic_type_pack(variadic_type_pack);
}
nodes::GenericTypePackDefault::GenericTypePack(generic_type_pack) => {
self.write_generic_type_pack(generic_type_pack);
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::generator::{DenseLuaGenerator, ReadableLuaGenerator};
macro_rules! snapshot_node {
(
$generator_name:ident, $generator:expr, $node_name:ident, $write_name:ident => (
$($test_name:ident => $item:expr),+,
)
) => {
mod $node_name {
use super::*;
$(
#[test]
fn $test_name() {
let statement = $item;
let mut generator = $generator;
generator.$write_name(&statement.into());
let snapshot_name = concat!(
stringify!($generator_name),
"_",
stringify!($node_name),
"_",
stringify!($test_name),
);
insta::assert_snapshot!(
snapshot_name,
generator.into_string()
);
}
)*
}
}
}
macro_rules! test_numbers {
(
$generator:expr => (
$($name:ident => $value:expr),+,
)
) => {
$(
#[test]
fn $name() {
use std::str::FromStr;
let number = $crate::nodes::NumberExpression::from_str($value).unwrap();
let mut generator = $generator;
generator.write_expression(&number.into());
assert_eq!(generator.into_string(), $value);
}
)*
};
}
macro_rules! blocks_consistency {
(
$generator:expr => (
$($name:ident => $code:literal),+,
)
) => {
$(
#[test]
fn $name() {
let parser = $crate::Parser::default();
let expected_block = parser.parse($code)
.expect(&format!("unable to parse `{}`", $code));
let mut generator = $generator;
generator.write_block(&expected_block);
let generated_code = generator.into_string();
let generated_block = parser.parse(&generated_code)
.expect(&format!("unable to parse generated code `{}`", &generated_code));
assert_eq!(expected_block, generated_block);
}
)*
};
}
macro_rules! binary_precedence {
(
$generator:expr => (
$($name:ident($input:expr) => $expected:literal),+,
)
) => {
$(
#[test]
fn $name() {
let parser = $crate::Parser::default();
let expected_block = parser.parse(&format!("return {}", $expected))
.unwrap();
let expected_return = expected_block.get_last_statement()
.expect("it should have a return statement");
let expected = match expected_return {
LastStatement::Return(statement) => statement.iter_expressions()
.next()
.unwrap(),
_ => panic!("return statement expected"),
};
let mut generator = $generator;
generator.write_expression(&$input.into());
let generated_code = format!("return {}", generator.into_string());
let parsed_block = parser.parse(&generated_code)
.expect(&format!("unable to parse generated code: `{}`", &generated_code));
let parsed_return = parsed_block.get_last_statement()
.expect("it should have a return statement");
let parsed = match parsed_return {
LastStatement::Return(statement) => {
if statement.len() != 1 {
panic!("return statement has more than one expression")
}
statement.iter_expressions().next().unwrap()
},
_ => panic!("return statement expected"),
};
pretty_assertions::assert_eq!(parsed, expected);
}
)*
};
}
macro_rules! snapshot_generator {
($mod_name:ident, $generator:expr) => {
mod $mod_name {
use super::*;
use $crate::nodes::*;
mod edge_cases {
use super::*;
blocks_consistency!($generator => (
index_with_bracket_string => "return ok[ [[field]]]",
call_with_bracket_string => "return ok[[ [field] ]]",
concat_numbers => "return 9 .. 3",
concat_float_numbers => "return 9. .. 3",
concat_number_with_variable_arguments => "return 9 .. ...",
concat_variable_arguments_with_number => "return ... ..1",
double_unary_minus => "return - -10",
binary_minus_with_unary_minus => "return 100- -10",
));
}
mod numbers {
use super::*;
test_numbers!($generator => (
zero => "0",
one => "1",
integer => "123",
hex_number => "0x12",
hex_number_with_letter => "0x12a",
hex_with_exponent => "0x12p4",
));
}
mod binary {
use super::*;
binary_precedence!($generator => (
left_associative_wraps_left_operand_if_has_lower_precedence(
BinaryExpression::new(
BinaryOperator::Asterisk,
DecimalNumber::new(2.0),
BinaryExpression::new(
BinaryOperator::Plus,
DecimalNumber::new(1.0),
DecimalNumber::new(3.0),
)
)
) => "2 * (1 + 3)",
left_associative_wraps_right_operand_if_has_lower_precedence(
BinaryExpression::new(
BinaryOperator::And,
false,
BinaryExpression::new(
BinaryOperator::Or,
false,
true,
),
)
) => "false and (false or true)",
left_associative_wraps_right_operand_if_has_same_precedence(
BinaryExpression::new(
BinaryOperator::Equal,
true,
BinaryExpression::new(
BinaryOperator::LowerThan,
DecimalNumber::new(1.0),
DecimalNumber::new(2.0),
),
)
) => "true == (1 < 2)",
right_associative_wrap_unary_left_operand_if_has_lower_precedence(
BinaryExpression::new(
BinaryOperator::Caret,
UnaryExpression::new(
UnaryOperator::Minus,
DecimalNumber::new(2.0),
),
DecimalNumber::new(2.0),
)
) => "(-2) ^ 2",
right_associative_wraps_left_operand_if_has_lower_precedence(
BinaryExpression::new(
BinaryOperator::Caret,
BinaryExpression::new(
BinaryOperator::Plus,
DecimalNumber::new(1.0),
DecimalNumber::new(2.0),
),
DecimalNumber::new(3.0),
)
) => "(1 + 2) ^ 3",
right_associative_wraps_left_operand_if_has_same_precedence(
BinaryExpression::new(
BinaryOperator::Caret,
BinaryExpression::new(
BinaryOperator::Caret,
DecimalNumber::new(2.0),
DecimalNumber::new(2.0),
),
DecimalNumber::new(3.0),
)
) => "(2 ^ 2) ^ 3",
right_associative_does_not_wrap_right_operand_if_unary(
BinaryExpression::new(
BinaryOperator::Caret,
DecimalNumber::new(2.0),
UnaryExpression::new(
UnaryOperator::Minus,
DecimalNumber::new(2.0),
),
)
) => "2 ^ -2",
right_associative_does_not_wrap_right_operand_if_has_same_precedence(
BinaryExpression::new(
BinaryOperator::Caret,
DecimalNumber::new(2.0),
BinaryExpression::new(
BinaryOperator::Caret,
DecimalNumber::new(2.0),
DecimalNumber::new(3.0),
),
)
) => "2 ^ 2 ^ 3",
right_associative_does_not_wrap_right_operand_if_has_higher_precedence(
BinaryExpression::new(
BinaryOperator::Concat,
DecimalNumber::new(3.0),
BinaryExpression::new(
BinaryOperator::Plus,
DecimalNumber::new(9.0),
DecimalNumber::new(3.0),
),
)
) => "3 .. 9 + 3",
if_does_not_wrap_else(
IfExpression::new(
Expression::identifier("condition"),
10.0,
BinaryExpression::new(
BinaryOperator::Percent,
9.0,
2.0,
),
)
) => "if condition then 10 else 9 % 2",
binary_expression_wraps_if(
BinaryExpression::new(
BinaryOperator::Percent,
IfExpression::new(Expression::identifier("condition"), 10.0, 9.0),
2.0,
)
) => "(if condition then 10 else 9) % 2",
unary_does_not_wrap_if_with_binary_in_else_result(
UnaryExpression::new(
UnaryOperator::Not,
IfExpression::new(
Expression::identifier("condition"),
true,
BinaryExpression::new(
BinaryOperator::And,
false,
StringExpression::from_value("ok"),
)
),
)
) => "not if condition then true else false and 'ok'",
binary_wraps_unary_containing_an_if_expression(
BinaryExpression::new(
BinaryOperator::And,
UnaryExpression::new(
UnaryOperator::Not,
IfExpression::new(Expression::identifier("condition"), true, false),
),
StringExpression::from_value("ok"),
)
) => "(not if condition then true else false) and 'ok'",
));
}
mod snapshots {
use super::*;
snapshot_node!($mod_name, $generator, block, write_block => (
ambiguous_function_call_from_assign => Block::default()
.with_statement(
AssignStatement::from_variable(Variable::new("name"), Expression::identifier("variable"))
)
.with_statement(
AssignStatement::from_variable(
FieldExpression::new(ParentheseExpression::new(Expression::identifier("t")), "field"),
false
)
),
ambiguous_function_call_from_compound_assign => Block::default()
.with_statement(
CompoundAssignStatement::new(
CompoundOperator::Plus,
Variable::new("name"),
BinaryExpression::new(
BinaryOperator::Plus,
Expression::identifier("variable"),
Expression::identifier("value"),
)
)
)
.with_statement(
AssignStatement::from_variable(
IndexExpression::new(
ParentheseExpression::new(Expression::identifier("t")),
Expression::identifier("field"),
),
false
)
),
ambiguous_function_call_from_local_assign => Block::default()
.with_statement(
LocalAssignStatement::from_variable("name")
.with_value(
IfExpression::new(
Expression::identifier("condition"),
true,
FunctionCall::from_name("fn")
)
)
)
.with_statement(
FunctionCall::from_prefix(ParentheseExpression::new(Expression::identifier("fn")))
),
ambiguous_function_call_from_function_call => Block::default()
.with_statement(
FunctionCall::from_name("fn")
)
.with_statement(
CompoundAssignStatement::new(
CompoundOperator::Plus,
IndexExpression::new(ParentheseExpression::new(
Expression::identifier("t")),
Expression::identifier("field"),
),
1
)
),
ambiguous_function_call_from_repeat => Block::default()
.with_statement(
RepeatStatement::new(
Block::default(),
UnaryExpression::new(UnaryOperator::Not, Expression::identifier("variable"))
)
)
.with_statement(
CompoundAssignStatement::new(
CompoundOperator::Plus,
FieldExpression::new(ParentheseExpression::new(Expression::identifier("t")), "field"),
1
)
),
));
snapshot_node!($mod_name, $generator, expression, write_expression => (
false_value => false,
true_value => true,
nil_value => Expression::nil(),
variable_arguments => Expression::variable_arguments(),
true_in_parenthese => Expression::from(true).in_parentheses(),
));
snapshot_node!($mod_name, $generator, assign, write_statement => (
variable_with_one_value => AssignStatement::new(
vec![Variable::new("var")],
vec![Expression::from(false)],
),
two_variables_with_one_value => AssignStatement::new(
vec![Variable::new("foo"), Variable::new("var")],
vec![Expression::from(false)],
),
two_variables_with_two_values => AssignStatement::new(
vec![Variable::new("foo"), Variable::new("var")],
vec![Expression::nil(), Expression::from(false)],
),
));
snapshot_node!($mod_name, $generator, do_statement, write_statement => (
empty => DoStatement::default(),
nested_do => DoStatement::new(
Block::default().with_statement(DoStatement::default())
),
));
snapshot_node!($mod_name, $generator, compound_assign_statement, write_statement => (
increment_var_by_one => CompoundAssignStatement::new(
CompoundOperator::Plus,
Variable::new("var"),
1_f64,
),
));
snapshot_node!($mod_name, $generator, function_statement, write_statement => (
empty => FunctionStatement::from_name("foo", Block::default()),
empty_with_field => FunctionStatement::new(
FunctionName::from_name("foo").with_fields(vec!["bar".into()]),
Block::default(),
Vec::new(),
false
),
empty_with_one_typed_parameter => FunctionStatement::from_name("fn", Block::default())
.with_parameter(Identifier::new("a").with_type(TypeName::new("string"))),
empty_with_two_typed_parameters => FunctionStatement::from_name("fn", Block::default())
.with_parameter(Identifier::new("a").with_type(TypeName::new("string")))
.with_parameter(Identifier::new("b").with_type(TypeName::new("bool"))),
empty_variadic_with_one_typed_parameter => FunctionStatement::from_name("fn", Block::default())
.variadic()
.with_parameter(Identifier::new("a").with_type(TypeName::new("string"))),
empty_variadic_typed_with_one_typed_parameter => FunctionStatement::from_name("fn", Block::default())
.with_variadic_type(TypeName::new("any"))
.with_parameter(Identifier::new("a").with_type(TypeName::new("string"))),
empty_with_string_return_type => FunctionStatement::from_name("fn", Block::default())
.with_return_type(TypeName::new("string")),
empty_with_void_return_type => FunctionStatement::from_name("fn", Block::default())
.with_return_type(TypePack::default()),
empty_with_generic_pack_return_type => FunctionStatement::from_name("fn", Block::default())
.with_return_type(GenericTypePack::new("T")),
empty_with_variadic_pack_return_type => FunctionStatement::from_name("fn", Block::default())
.with_return_type(
VariadicTypePack::new(ParentheseType::new(
UnionType::new(Type::from(true), Type::nil())
))
),
empty_with_method => FunctionStatement::new(
FunctionName::from_name("foo").with_method("bar"),
Block::default(),
Vec::new(),
false
),
));
snapshot_node!($mod_name, $generator, generic_for, write_statement => (
empty => GenericForStatement::new(
vec!["var".into()],
vec![Expression::from(true)],
Block::default()
),
empty_with_typed_var => GenericForStatement::new(
vec![Identifier::new("var").with_type(TypeName::new("string"))],
vec![Expression::from(true)],
Block::default()
),
empty_with_two_typed_vars => GenericForStatement::new(
vec![
Identifier::new("key").with_type(TypeName::new("string")),
Identifier::new("value").with_type(TypeName::new("bool")),
],
vec![Expression::from(true)],
Block::default()
),
));
snapshot_node!($mod_name, $generator, type_declaration, write_type_declaration_statement => (
string_alias => TypeDeclarationStatement::new("Str", TypeName::new("string")),
exported_string_alias => TypeDeclarationStatement::new("Str", TypeName::new("string"))
.export(),
generic_array => TypeDeclarationStatement::new("Array", ArrayType::new(TypeName::new("T")))
.with_generic_parameters(
GenericParametersWithDefaults::from_type_variable("T")
),
generic_array_with_default
=> TypeDeclarationStatement::new("Array", ArrayType::new(TypeName::new("T")))
.with_generic_parameters(
GenericParametersWithDefaults::from_type_variable_with_default(
TypeVariableWithDefault::new("T", Type::nil())
)
),
table_with_one_property => TypeDeclarationStatement::new(
"Obj",
TableType::default()
.with_property(TablePropertyType::new("name", TypeName::new("string")))
),
table_with_indexer_type => TypeDeclarationStatement::new(
"StringArray",
TableType::default()
.with_indexer_type(TableIndexerType::new(TypeName::new("number"), TypeName::new("string")))
),
table_with_one_property_and_indexer_type => TypeDeclarationStatement::new(
"PackedArray",
TableType::default()
.with_property(TablePropertyType::new("n", TypeName::new("number")))
.with_indexer_type(TableIndexerType::new(TypeName::new("number"), TypeName::new("string")))
),
callback_with_variadic_type_is_string => TypeDeclarationStatement::new(
"Fn",
FunctionType::new(TypePack::default())
.with_variadic_type(VariadicTypePack::new(TypeName::new("string")))
),
callback_with_variadic_type_is_generic_pack => TypeDeclarationStatement::new(
"Fn",
FunctionType::new(TypePack::default())
.with_variadic_type(GenericTypePack::new("T"))
),
generic_fn_with_default_generic_pack
=> TypeDeclarationStatement::new("Fn", FunctionType::new(GenericTypePack::new("R")))
.with_generic_parameters(
GenericParametersWithDefaults::from_generic_type_pack_with_default(
GenericTypePackWithDefault::new(
GenericTypePack::new("R"),
GenericTypePack::new("T")
)
)
),
generic_fn_with_type_variable_and_default_generic_pack
=> TypeDeclarationStatement::new(
"Fn",
FunctionType::new(GenericTypePack::new("R"))
.with_argument(TypeName::new("T"))
)
.with_generic_parameters(
GenericParametersWithDefaults::from_type_variable("T")
.with_generic_type_pack_with_default(
GenericTypePackWithDefault::new(
GenericTypePack::new("R"),
VariadicTypePack::new(TypeName::new("string"))
)
)
),
generic_fn_with_type_variable_with_default_and_default_generic_pack
=> TypeDeclarationStatement::new(
"Fn",
FunctionType::new(GenericTypePack::new("R"))
.with_argument(TypeName::new("T"))
)
.with_generic_parameters(
GenericParametersWithDefaults::from_type_variable_with_default(
TypeVariableWithDefault::new("T", TypeName::new("boolean"))
)
.with_generic_type_pack_with_default(
GenericTypePackWithDefault::new(
GenericTypePack::new("R"),
VariadicTypePack::new(TypeName::new("string"))
)
)
),
));
snapshot_node!($mod_name, $generator, if_statement, write_statement => (
empty => IfStatement::create(false, Block::default()),
empty_with_empty_else => IfStatement::create(false, Block::default())
.with_else_block(Block::default()),
empty_with_empty_multiple_branch => IfStatement::create(false, Block::default())
.with_new_branch(Expression::nil(), Block::default())
.with_new_branch(false, Block::default()),
));
snapshot_node!($mod_name, $generator, local_assign, write_statement => (
foo_unassigned => LocalAssignStatement::from_variable("foo"),
foo_typed_unassigned => LocalAssignStatement::from_variable(
Identifier::new("foo").with_type(Type::from(true))
),
foo_and_bar_unassigned => LocalAssignStatement::from_variable("foo")
.with_variable("bar"),
foo_and_bar_typed_unassigned => LocalAssignStatement::from_variable("foo")
.with_variable(Identifier::new("bar").with_type(Type::from(false))),
var_assign_to_false => LocalAssignStatement::from_variable("var")
.with_value(false),
typed_generic_var_break_equal_sign => LocalAssignStatement::from_variable(
Identifier::new("var").with_type(
TypeName::new("List").with_type_parameter(TypeName::new("string"))
)
).with_value(false),
));
snapshot_node!($mod_name, $generator, local_function, write_statement => (
empty => LocalFunctionStatement::from_name("foo", Block::default()),
empty_variadic => LocalFunctionStatement::from_name("foo", Block::default())
.variadic(),
empty_with_one_parameter => LocalFunctionStatement::from_name("foo", Block::default())
.with_parameter("bar"),
empty_with_two_parameters => LocalFunctionStatement::from_name("foo", Block::default())
.with_parameter("bar")
.with_parameter("baz"),
empty_variadic_with_one_parameter => LocalFunctionStatement::from_name("foo", Block::default())
.with_parameter("bar")
.variadic(),
empty_with_generic_pack_return_type => LocalFunctionStatement::from_name("foo", Block::default())
.with_return_type(GenericTypePack::new("R")),
));
snapshot_node!($mod_name, $generator, numeric_for, write_statement => (
empty_without_step => NumericForStatement::new(
"i",
Expression::identifier("start"),
Expression::identifier("max"),
None,
Block::default()
),
empty_typed_without_step => NumericForStatement::new(
Identifier::new("i").with_type(TypeName::new("number")),
Expression::identifier("start"),
Expression::identifier("max"),
None,
Block::default()
),
empty_with_step => NumericForStatement::new(
"i",
Expression::identifier("start"),
Expression::identifier("max"),
Some(Expression::identifier("step")),
Block::default()
),
empty_typed_with_step => NumericForStatement::new(
Identifier::new("i").with_type(TypeName::new("number")),
Expression::identifier("start"),
Expression::identifier("max"),
Some(Expression::identifier("step")),
Block::default()
),
));
snapshot_node!($mod_name, $generator, repeat, write_statement => (
empty => RepeatStatement::new(
Block::default(),
false
),
));
snapshot_node!($mod_name, $generator, while_statement, write_statement => (
empty => WhileStatement::new(
Block::default(),
false
),
));
snapshot_node!($mod_name, $generator, last, write_last_statement => (
break_statement => LastStatement::new_break(),
continue_statement => LastStatement::new_continue(),
return_without_values => ReturnStatement::default(),
return_one_expression => ReturnStatement::one(Expression::from(true)),
return_two_expressions => ReturnStatement::one(Expression::from(true))
.with_expression(Expression::nil()),
return_parentheses => ReturnStatement::one(Expression::from(true).in_parentheses()),
));
snapshot_node!($mod_name, $generator, binary, write_expression => (
true_and_false => BinaryExpression::new(
BinaryOperator::And,
Expression::from(true),
Expression::from(false)
),
true_equal_false => BinaryExpression::new(
BinaryOperator::Equal,
Expression::from(true),
Expression::from(false)
),
type_cast_break_type_parameters => BinaryExpression::new(
BinaryOperator::Equal,
TypeCastExpression::new(
true,
TypeName::new("Array").with_type_parameter(TypeName::new("string"))
),
Expression::from(false)
),
wrap_left_to_break_type_name_parameters => BinaryExpression::new(
BinaryOperator::LowerThan,
TypeCastExpression::new(true, TypeName::new("Array")),
Expression::from(false)
),
wrap_left_to_break_type_field_parameters => BinaryExpression::new(
BinaryOperator::LowerThan,
TypeCastExpression::new(
true,
TypeField::new("Collections", TypeName::new("Array"))
),
Expression::from(false)
),
));
snapshot_node!($mod_name, $generator, field, write_expression => (
identifier_prefix => FieldExpression::new(Prefix::from_name("foo"), "bar"),
));
snapshot_node!($mod_name, $generator, index, write_expression => (
identifier_prefix_with_identifier_value => IndexExpression::new(
Prefix::from_name("foo"),
Prefix::from_name("bar"),
),
));
snapshot_node!($mod_name, $generator, function_expr, write_expression => (
empty => FunctionExpression::default(),
empty_variadic => FunctionExpression::default().variadic(),
empty_variadic_with_one_parameter => FunctionExpression::default()
.with_parameter("a")
.variadic(),
empty_variadic_with_two_parameter => FunctionExpression::default()
.with_parameter("a")
.with_parameter("b")
.variadic(),
empty_with_two_parameter => FunctionExpression::default()
.with_parameter("a")
.with_parameter("b"),
empty_with_generic_pack_return_type => FunctionExpression::default()
.with_return_type(GenericTypePack::new("R")),
));
snapshot_node!($mod_name, $generator, prefix, write_prefix => (
identifier => Prefix::from_name("foo"),
identifier_in_parenthese => Prefix::Parenthese(ParentheseExpression::new(Expression::identifier("foo"))),
));
snapshot_node!($mod_name, $generator, string, write_expression => (
only_letters => StringExpression::from_value("hello"),
with_single_quotes => StringExpression::from_value("I'm cool"),
with_dougle_quotes => StringExpression::from_value(r#"Say: "Hi""#),
with_single_and_double_quotes => StringExpression::from_value(r#"Say: "Don't""#),
));
snapshot_node!($mod_name, $generator, number, write_expression => (
number_1 => 1.0,
number_0_5 => 0.5,
number_123 => 123.0,
number_0_005 => 0.005,
number_nan => DecimalNumber::new(f64::NAN),
number_positive_infinity => DecimalNumber::new(f64::INFINITY),
number_negative_infinity => DecimalNumber::new(f64::NEG_INFINITY),
number_1_2345e_minus50 => 1.2345e-50,
number_thousand => 1000.0,
number_1_2345e50 => 1.2345e50,
number_100_25 => 100.25,
number_2000_05 => 2000.05,
binary_0b10101 => BinaryNumber::new(0b10101, false),
));
snapshot_node!($mod_name, $generator, table, write_expression => (
empty => TableExpression::default(),
list_with_single_value => TableExpression::new(vec![
TableEntry::Value(Expression::from(true)),
]),
list_with_two_values => TableExpression::new(vec![
TableEntry::Value(Expression::from(true)),
TableEntry::Value(Expression::from(false)),
]),
with_field_entry => TableExpression::new(vec![
TableFieldEntry::new("field", true).into(),
]),
with_index_entry => TableExpression::new(vec![
TableIndexEntry::new(false, true).into(),
]),
mixed_table => TableExpression::new(vec![
TableEntry::Value(Expression::from(true)),
TableFieldEntry::new("field", true).into(),
TableIndexEntry::new(false, true).into(),
]),
));
snapshot_node!($mod_name, $generator, unary, write_expression => (
not_true => UnaryExpression::new(
UnaryOperator::Not,
true,
),
two_unary_minus_breaks_between_them => UnaryExpression::new(
UnaryOperator::Minus,
UnaryExpression::new(
UnaryOperator::Minus,
Expression::identifier("a"),
),
),
wraps_in_parens_if_an_inner_binary_has_lower_precedence => UnaryExpression::new(
UnaryOperator::Not,
BinaryExpression::new(
BinaryOperator::Or,
false,
true,
),
),
does_not_wrap_in_parens_if_an_inner_binary_has_higher_precedence => UnaryExpression::new(
UnaryOperator::Minus,
BinaryExpression::new(
BinaryOperator::Caret,
DecimalNumber::new(2.0),
DecimalNumber::new(2.0),
),
),
));
snapshot_node!($mod_name, $generator, arguments, write_arguments => (
empty_tuple => TupleArguments::default(),
tuple_with_one_value => TupleArguments::new(vec![true.into()]),
tuple_with_two_values => TupleArguments::new(vec![true.into(), false.into()]),
));
}
}
};
}
snapshot_generator!(dense, DenseLuaGenerator::default());
snapshot_generator!(readable, ReadableLuaGenerator::default());
snapshot_generator!(token_based, TokenBasedLuaGenerator::new(""));
}