use super::*;
use crate::ast::AstString;
impl<'cst, 'ast> Printer<'cst, 'ast> {
pub(super) fn write_expression(&mut self, expression: Expression) {
self.advance(expression.location.begin);
let cst_nodes = self.cst_nodes;
match expression.kind() {
ExpressionKind::Nil => self.keyword("nil"),
ExpressionKind::Boolean(value) => self.keyword(if value { "true" } else { "false" }),
ExpressionKind::Integer { value, .. } => {
let source: Option<AstString<'ast>> = match expression_cst(cst_nodes, expression) {
Some(CstNode::ExprConstantInteger(CstExprConstantInteger {
value: source,
})) => Some(*source),
_ => None,
};
if let Some(source) = source {
self.write_bytes(source.as_bytes());
} else {
self.write_bytes(value.to_string().as_bytes());
}
}
ExpressionKind::Number { value, .. } => {
let source: Option<AstString<'ast>> = match expression_cst(cst_nodes, expression) {
Some(CstNode::ExprConstantNumber(CstExprConstantNumber { value: source })) => {
Some(*source)
}
_ => None,
};
if let Some(source) = source {
self.write_bytes(source.as_bytes());
} else if value.is_infinite() {
self.write_bytes(if value > 0.0 { b"1e500" } else { b"-1e500" });
} else if value.is_nan() {
self.write_bytes(b"0/0");
} else if value.fract() == 0.0
&& value >= i32::MIN as f64
&& value <= i32::MAX as f64
{
self.write_bytes((value as i32).to_string().as_bytes());
} else {
self.write_bytes(value.to_string().as_bytes());
}
}
ExpressionKind::String {
value,
quote_style: _,
} => {
let string_cst: Option<(AstString<'ast>, CstStringQuoteStyle, u32)> =
match expression_cst(cst_nodes, expression) {
Some(CstNode::ExprConstantString(CstExprConstantString {
source_string,
quote_style,
block_depth,
..
})) => Some((*source_string, *quote_style, *block_depth)),
_ => None,
};
if let Some((source_string, quote_style, block_depth)) = string_cst {
self.write_source_string(source_string.as_bytes(), quote_style, block_depth);
} else {
self.write_string(value.as_bytes());
}
}
ExpressionKind::Local { local, .. } => self.identifier(local.name.bytes()),
ExpressionKind::Global(name) => self.identifier(name.bytes()),
ExpressionKind::Varargs => self.symbol("..."),
ExpressionKind::Grouped(inner) => {
self.symbol("(");
self.write_expression(inner);
let group_cst = match expression_cst(cst_nodes, expression) {
Some(CstNode::ExprGroup(CstExprGroup { close_position })) => {
Some(*close_position)
}
_ => None,
};
if let Some(close_position) = group_cst {
self.maybe_advance_and_write(Some(close_position), ")", false);
} else {
self.advance_before(expression.location.end, 1);
self.symbol(")");
}
}
ExpressionKind::Call {
func,
type_args,
args,
..
} => {
let call_cst =
if let Some(CstNode::ExprCall(cst)) = expression_cst(cst_nodes, expression) {
Some(cst)
} else {
None
};
self.write_expression(func);
if self.write_types && !type_args.is_empty() {
self.write_type_instantiation(
type_args,
call_cst
.as_ref()
.and_then(|cst| cst.explicit_types.as_ref()),
);
}
self.maybe_advance_and_write(
call_cst.as_ref().and_then(|cst| cst.open_parens),
"(",
call_cst.is_none(),
);
self.write_expression_list_with_commas(
args,
call_cst.as_ref().map(|cst| cst.comma_positions.as_slice()),
);
self.maybe_advance_and_write(
call_cst.as_ref().and_then(|cst| cst.close_parens),
")",
call_cst.is_none(),
);
}
ExpressionKind::IndexName {
expr,
index,
index_location,
op_position,
op,
} => {
self.write_expression(expr);
self.advance(op_position);
self.symbol(op.symbol());
self.advance(index_location.begin);
self.identifier(index.bytes());
}
ExpressionKind::IndexExpr { expr, index } => {
let index_cst = if let Some(CstNode::ExprIndexExpr(CstExprIndexExpr {
open_bracket,
close_bracket,
})) = expression_cst(cst_nodes, expression)
{
Some((*open_bracket, *close_bracket))
} else {
None
};
self.write_expression(expr);
if let Some((open, _)) = index_cst {
self.maybe_advance_and_write(Some(open), "[", false);
} else {
self.advance(Position::new(
index.location.begin.line,
index.location.begin.column.saturating_sub(1),
));
self.symbol("[");
}
self.write_expression(index);
if let Some((_, close)) = index_cst {
self.maybe_advance_and_write(Some(close), "]", false);
} else {
self.symbol("]");
}
}
ExpressionKind::If {
condition,
then_expression,
else_expression,
..
} => {
self.keyword("if");
let cst = expression_cst(cst_nodes, expression).and_then(|node| match node {
CstNode::ExprIfElse(cst) => Some(cst),
_ => None,
});
self.write_else_if_expression(condition, then_expression, else_expression, cst);
}
ExpressionKind::Unary { op, rhs } => {
self.symbol(op.symbol());
self.write_expression(rhs);
}
ExpressionKind::Binary { lhs, op, rhs } => {
self.write_expression(lhs);
if let Some(CstNode::ExprOp(cst)) = expression_cst(cst_nodes, expression) {
self.advance(cst.op);
} else {
self.maybe_space(rhs.location.begin, op.symbol().len() as u32);
}
self.symbol(op.symbol());
self.write_expression(rhs);
}
ExpressionKind::TypeAssertion { expr, annotation } => {
self.write_expression(expr);
if self.write_types {
if let Some(CstNode::ExprTypeAssertion(CstExprTypeAssertion { op })) =
expression_cst(cst_nodes, expression)
{
self.advance(*op);
} else {
self.maybe_space(annotation.location.begin, 2);
}
self.symbol("::");
self.write_type(annotation);
}
}
ExpressionKind::Error { expressions, .. } => {
self.symbol("(error-expr");
for (index, expression) in expressions.iter().enumerate() {
self.symbol(if index == 0 { ": " } else { ", " });
self.write_expression(*expression);
}
self.symbol(")");
}
ExpressionKind::Table { items } => {
self.symbol("{");
let table_cst = match expression_cst(cst_nodes, expression) {
Some(CstNode::ExprTable(cst)) => Some(cst),
_ => None,
};
if let Some(cst) = table_cst {
for (index, item) in items.iter().enumerate() {
let cst_item = cst.items.get(index);
match item {
TableItem::List { value } => self.write_expression(*value),
TableItem::Record { key, value } => {
self.write_table_record_key(*key);
if let Some(position) = cst_item.and_then(|item| item.equals) {
self.advance(position);
} else {
self.maybe_space(value.location.begin, 1);
}
self.symbol("=");
self.write_expression(*value);
}
TableItem::General { key, value } => {
self.maybe_advance_and_write(
cst_item.and_then(|item| item.indexer_open),
"[",
true,
);
self.write_expression(*key);
self.maybe_advance_and_write(
cst_item.and_then(|item| item.indexer_close),
"]",
false,
);
self.maybe_advance_and_write(
cst_item.and_then(|item| item.equals),
"=",
false,
);
self.write_expression(*value);
}
}
if let Some(cst_item) = cst_item
&& let Some(separator) = cst_item.separator
{
if let Some(position) = cst_item.separator_position {
self.advance(position);
}
self.symbol(match separator {
TableSeparator::Comma => ",",
TableSeparator::Semicolon => ";",
});
}
}
self.advance_before(expression.location.end, 1);
self.symbol("}");
} else {
for (index, item) in items.iter().enumerate() {
if index > 0 {
self.symbol(",");
}
match item {
TableItem::List { value } => self.write_expression(*value),
TableItem::Record { key, value } => {
self.write_table_record_key(*key);
self.maybe_space(value.location.begin, 1);
self.symbol("=");
self.write_expression(*value);
}
TableItem::General { key, value } => {
self.symbol("[");
self.write_expression(*key);
self.symbol("]=");
self.write_expression(*value);
}
}
}
self.maybe_space(expression.location.end, 1);
self.symbol("}");
}
}
ExpressionKind::FunctionLiteral(function) => {
let function_cst = function_cst(cst_nodes, function);
let attr_lists = match function_cst {
Some(CstNode::ExprFunction(cst)) => Some(cst.attr_lists.as_slice()),
_ => None,
};
self.write_attributes(function.attributes, attr_lists);
if let Some(CstNode::ExprFunction(cst)) = function_cst
&& cst.function_keyword.has_value()
{
self.advance(cst.function_keyword);
}
self.keyword("function");
self.write_function_body(function);
}
ExpressionKind::InterpString {
strings,
expressions,
} => {
let interp_cst = match expression_cst(cst_nodes, expression) {
Some(CstNode::ExprInterpString(cst)) => Some(cst),
_ => None,
};
if let Some(cst) = interp_cst {
self.symbol("`");
for (index, string) in strings.iter().enumerate() {
if index > 0 {
if let Some(position) = cst.string_positions.get(index) {
self.advance(*position);
}
self.symbol("}");
}
if let Some(source_string) = cst.source_strings.get(index) {
self.write_source_string_content(source_string.as_bytes());
} else {
self.write_multiline(string.as_bytes());
}
if let Some(expression) = expressions.get(index) {
self.symbol("{");
self.write_expression(*expression);
}
}
self.symbol("`");
return;
}
self.symbol("`");
for (index, string) in strings.iter().enumerate() {
if index > 0 {
self.symbol("}");
}
self.write_multiline(string.as_bytes());
if let Some(expression) = expressions.get(index) {
self.symbol("{");
self.write_expression(*expression);
}
}
self.symbol("`");
}
ExpressionKind::Instantiate { expr, type_args } => {
self.write_expression(expr);
if self.write_types {
let instantiate_cst = if let Some(CstNode::ExprExplicitTypeInstantiation(
CstExprExplicitTypeInstantiation { instantiation },
)) = expression_cst(cst_nodes, expression)
{
Some(instantiation)
} else {
None
};
self.write_type_instantiation(type_args, instantiate_cst);
}
}
}
}
}