use std::fmt::Write;
use t_ree::{
expression::{Expression, ExpressionKind, Literal, MatchPattern},
operator::{
ArithmeticOperator, BinaryOperator, BitwiseOperator, ComparisonOperator, LogicalOperator,
},
types::{IntWidth, Signedness, Type},
};
use super::Emitter;
use t_ree::operator::UnaryOperator;
impl Emitter {
pub(crate) fn emit_expression(&mut self, expression: &Expression) {
if self.is_auto_ref_chain(expression)
&& expression
.resolved_type
.as_ref()
.is_some_and(|t| matches!(t, Type::Pointer(..)))
{
if let ExpressionKind::Variable(name) = &expression.kind {
let resolved = self.resolve_variable_name(name);
if self.pointer_param_variables.contains(&resolved) {
self.push(&resolved);
} else {
write!(self.output, "(&{resolved})").unwrap();
}
} else {
self.push("(&");
self.emit_place(expression);
self.push(")");
}
return;
}
if let ExpressionKind::Dereference(inner) = &expression.kind
&& self.is_auto_ref_chain(inner)
&& !self.is_pointer_param(inner)
{
self.emit_place(inner);
return;
}
match &expression.kind {
ExpressionKind::Literal(literal) => self.emit_literal(literal),
ExpressionKind::Variable(name) => {
let resolved = self.resolve_variable_name(name);
self.push(&resolved);
}
ExpressionKind::BinaryOperation(op, left, right) => {
self.push("(");
self.emit_expression(left);
self.push(" ");
self.emit_binary_operator(op);
self.push(" ");
self.emit_expression(right);
self.push(")");
}
ExpressionKind::UnaryOperation(op, operand) => {
self.emit_unary_operator(op);
self.push("(");
self.emit_expression(operand);
self.push(")");
}
ExpressionKind::Call(callee, args) => {
self.emit_expression(callee);
self.push("(");
for (index, arg) in args.iter().enumerate() {
if index > 0 {
self.push(", ");
}
self.emit_expression(arg);
}
self.push(")");
}
ExpressionKind::Field(object, field) => {
let effective_object = if let ExpressionKind::Field(grandchild, inner_field) =
&object.kind
{
if self.is_identity_downcast(grandchild.resolved_type.as_ref(), inner_field) {
grandchild.as_ref()
} else {
object.as_ref()
}
} else {
object.as_ref()
};
if self.is_identity_downcast(effective_object.resolved_type.as_ref(), field) {
self.emit_expression(effective_object);
} else if self.is_typedef_downcast(effective_object.resolved_type.as_ref()) {
if let Some(resolved_type) = expression.resolved_type.as_ref() {
self.push("(");
self.emit_type(resolved_type);
self.push(")");
}
self.emit_expression(effective_object);
} else if self.is_direct_auto_ref(effective_object) {
self.emit_place(effective_object);
if self.is_pointer_param(effective_object) {
self.push("->");
} else {
self.push(".");
}
self.push(field);
} else {
let is_derefed_pointer_param =
if let ExpressionKind::Dereference(inner) = &effective_object.kind {
self.is_pointer_param(inner)
} else {
false
};
self.emit_expression(effective_object);
if is_derefed_pointer_param
|| self.is_pointer_type(effective_object.resolved_type.as_ref())
{
self.push("->");
} else {
self.push(".");
}
self.push(field);
}
}
ExpressionKind::Index(array, index) => {
self.emit_expression(array);
if self.is_array_newtype(array.resolved_type.as_ref()) {
self.push(".data");
}
self.push("[");
self.emit_expression(index);
self.push("]");
}
ExpressionKind::Dereference(operand) => {
if let ExpressionKind::Field(object, field) = &operand.kind
&& matches!(object.resolved_type, Some(Type::Pointer(_, _)))
{
self.emit_expression(object);
self.push("->");
self.push(field);
} else {
self.push("(*");
self.emit_expression(operand);
self.push(")");
}
}
ExpressionKind::Convert(expression, ty) | ExpressionKind::Transmute(expression, ty) => {
if let Type::Named(enum_name) = ty
&& let Some(Type::Enum(variants)) = self.newtypes.get(enum_name).cloned()
{
let value_type = expression.resolved_type.as_ref();
let variant_name = if let Some(Type::Named(name)) = value_type {
name.clone()
} else {
String::new()
};
let tag = value_type
.and_then(|vt| variants.iter().position(|v| v == vt))
.unwrap_or(0);
write!(
self.output,
"(struct {enum_name}){{.tag = {tag}, .value.{variant_name} = "
)
.unwrap();
self.emit_expression(expression);
self.push("}");
} else if self.is_array_newtype(Some(ty)) {
let target_struct = self.array_newtype_struct_name(ty);
if self.is_array_newtype(expression.resolved_type.as_ref()) {
write!(self.output, "(*(struct {target_struct} *)&").unwrap();
self.emit_expression(expression);
self.push(")");
} else {
write!(self.output, "(struct {target_struct}){{.data = ").unwrap();
self.emit_expression(expression);
self.push("}");
}
} else {
self.push("((");
self.emit_type(ty);
self.push(")");
self.emit_expression(expression);
self.push(")");
}
}
ExpressionKind::SizeOf(ty) => {
self.push("sizeof(");
self.emit_type(ty);
self.push(")");
}
ExpressionKind::TypeConstruction(name, fields) => {
let emit_name =
if let Some(Type::Named(resolved_name)) = expression.resolved_type.as_ref() {
resolved_name.as_str()
} else {
name.as_str()
};
let fallback = Type::Named(name.clone());
let resolved_inner =
self.resolve_type(self.newtypes.get(name).unwrap_or(&fallback));
let is_struct = matches!(resolved_inner, Type::Tuple(ref f) if !f.is_empty())
|| matches!(resolved_inner, Type::Array(..));
if is_struct {
let is_direct_tuple = self
.newtypes
.get(emit_name)
.is_some_and(|inner| matches!(inner, Type::Tuple(_)));
if is_direct_tuple {
write!(self.output, "(struct {emit_name}){{").unwrap();
} else {
write!(self.output, "({emit_name}){{").unwrap();
}
for (index, (field_name, value)) in fields.iter().enumerate() {
if index > 0 {
self.push(", ");
}
write!(self.output, ".{field_name} = ").unwrap();
if let ExpressionKind::TypeConstruction(inner_name, inner_fields) =
&value.kind
{
let field_type_name = self.newtypes.get(emit_name).and_then(|inner| {
if let Type::Tuple(fields) = inner {
fields.iter().find_map(|f| {
if let Type::Named(n) = f {
if n == field_name {
Some(n.as_str())
} else {
None
}
} else {
None
}
})
} else {
None
}
});
if let Some(expected_name) = field_type_name
&& expected_name != inner_name
{
let inner_is_struct = self.newtypes.get(inner_name).is_some_and(
|inner| matches!(inner, Type::Tuple(f) if !f.is_empty()),
);
if inner_is_struct {
let expected_is_direct = self
.newtypes
.get(expected_name)
.is_some_and(|i| matches!(i, Type::Tuple(_)));
if expected_is_direct {
write!(self.output, "(struct {expected_name}){{").unwrap();
} else {
write!(self.output, "({expected_name}){{").unwrap();
}
for (j, (fname, fval)) in inner_fields.iter().enumerate() {
if j > 0 {
self.push(", ");
}
write!(self.output, ".{fname} = ").unwrap();
self.emit_expression(fval);
}
self.push("}");
continue;
}
}
}
self.emit_expression(value);
}
self.push("}");
} else {
write!(self.output, "(({name})").unwrap();
self.emit_expression(&fields[0].1);
self.push(")");
}
}
ExpressionKind::ArrayLiteral(elements) => {
if let Some(ty @ Type::Vector(..)) = &expression.resolved_type {
self.push("(");
self.emit_type(ty);
self.push(")");
}
self.push("{");
for (index, element) in elements.iter().enumerate() {
if index > 0 {
self.push(", ");
}
self.emit_expression(element);
}
self.push("}");
}
ExpressionKind::TupleLiteral(fields) => {
self.push("{");
for (index, field) in fields.iter().enumerate() {
if index > 0 {
self.push(", ");
}
self.emit_expression(field);
}
self.push("}");
}
ExpressionKind::Block(block) => {
self.push("({\n");
self.indent_level += 1;
self.push_shadow_scope();
self.emit_block_content(block);
self.pop_shadow_scope();
self.indent_level -= 1;
self.indent();
self.push("})");
}
ExpressionKind::If {
condition,
then_branch,
else_branch,
} => {
if let (Some(then_result), Some(else_block)) = (&then_branch.result, else_branch)
&& then_branch.statements.is_empty()
&& else_block.statements.is_empty()
&& let Some(else_result) = &else_block.result
{
self.push("(");
self.emit_expression(condition);
self.push(" ? ");
self.emit_expression(then_result);
self.push(" : ");
self.emit_expression(else_result);
self.push(")");
return;
}
self.push("({\n");
self.indent_level += 1;
self.indent();
self.push("if (");
self.emit_expression(condition);
self.push(") {\n");
self.indent_level += 1;
self.push_shadow_scope();
self.emit_block_content(then_branch);
self.pop_shadow_scope();
self.indent_level -= 1;
self.indent();
self.push("}");
if let Some(else_branch) = else_branch {
self.push(" else {\n");
self.indent_level += 1;
self.push_shadow_scope();
self.emit_block_content(else_branch);
self.pop_shadow_scope();
self.indent_level -= 1;
self.indent();
self.push("}");
}
self.newline();
self.indent_level -= 1;
self.indent();
self.push("})");
}
ExpressionKind::Match { value, arms } => {
let is_enum_match = arms
.iter()
.any(|arm| matches!(arm.pattern, MatchPattern::Variant(..)));
let match_index = self.temp_counter;
self.temp_counter += 1;
let result_type = arms
.first()
.and_then(|arm| arm.body.result.as_ref())
.and_then(|r| r.resolved_type.clone())
.filter(|ty| !ty.is_unit());
self.push("({\n");
self.indent_level += 1;
let enum_variants = if is_enum_match {
let enum_name = if let Some(Type::Named(name)) = &value.resolved_type {
name.clone()
} else {
String::new()
};
self.newtypes
.get(&enum_name)
.and_then(|inner| {
if let Type::Enum(variants) = inner {
Some(variants.clone())
} else {
None
}
})
.unwrap_or_default()
} else {
Vec::new()
};
if let Some(ref ty) = result_type {
self.indent();
self.emit_type(ty);
writeln!(self.output, " _match{match_index};").unwrap();
}
self.indent();
self.push("switch (");
self.emit_expression(value);
if is_enum_match {
self.push(".tag");
}
self.push(") {\n");
for arm in arms {
self.indent();
match &arm.pattern {
MatchPattern::Integer(value) => {
write!(self.output, "case {value}:").unwrap();
}
MatchPattern::Variable(name) => {
write!(self.output, "case {name}:").unwrap();
}
MatchPattern::Wildcard => self.push("default:"),
MatchPattern::Variant(variant_name, _) => {
let tag = enum_variants
.iter()
.position(|v| matches!(v, Type::Named(n) if n == variant_name))
.unwrap_or(0);
write!(self.output, "case {tag}:").unwrap();
}
}
self.push(" {\n");
self.indent_level += 1;
if let MatchPattern::Variant(variant_name, binding_name) = &arm.pattern {
self.indent();
self.emit_type(&Type::Named(variant_name.clone()));
write!(self.output, " {binding_name} = ").unwrap();
self.emit_expression(value);
writeln!(self.output, ".value.{variant_name};").unwrap();
}
for statement in &arm.body.statements {
self.emit_statement(statement);
}
if let Some(result) = &arm.body.result {
self.indent();
if result_type.is_some() {
write!(self.output, "_match{match_index} = ").unwrap();
}
self.emit_expression(result);
self.push(";\n");
}
self.indent();
self.push("break;\n");
self.indent_level -= 1;
self.indent();
self.push("}\n");
}
self.indent();
self.push("}\n");
if result_type.is_some() {
self.indent();
writeln!(self.output, "_match{match_index};").unwrap();
}
self.indent_level -= 1;
self.indent();
self.push("})");
}
ExpressionKind::Replace(target, value) => {
let index = self.temp_counter;
self.temp_counter += 1;
self.push("({ ");
if let Some(ty) = &target.resolved_type {
self.emit_type(ty);
}
write!(self.output, " _replace{index} = ").unwrap();
self.emit_assign_target(target);
self.push("; ");
self.emit_assign_target(target);
self.push(" = ");
self.emit_expression(value);
write!(self.output, "; _replace{index}; }})").unwrap();
}
ExpressionKind::OpAssign(operator, target, value) => {
self.emit_assign_target(target);
let symbol = match operator {
ArithmeticOperator::Add => " += ",
ArithmeticOperator::Subtract => " -= ",
ArithmeticOperator::Multiply => " *= ",
ArithmeticOperator::Divide => " /= ",
ArithmeticOperator::Remainder => " %= ",
};
self.push(symbol);
self.emit_expression(value);
}
ExpressionKind::Slice(array, start, end) => {
self.push("((");
if let Some(ref ty) = expression.resolved_type {
self.emit_type(ty);
}
self.push("){.data = ");
match (start, end) {
(None, None) => {
self.emit_expression(array);
self.push(", .length = sizeof(");
self.emit_expression(array);
self.push(") / sizeof((");
self.emit_expression(array);
self.push(")[0])})");
}
(Some(start), Some(end)) => {
self.push("&");
self.emit_expression(array);
self.push("[");
self.emit_expression(start);
self.push("], .length = (");
self.emit_expression(end);
self.push(") - (");
self.emit_expression(start);
self.push(")})");
}
_ => unreachable!(),
}
}
ExpressionKind::Print(args) => {
self.emit_print(args);
}
}
}
fn emit_print(&mut self, args: &[Expression]) {
let mut flat_specifiers = Vec::new();
let mut flat_args: Vec<&Expression> = Vec::new();
let mut field_suffixes: Vec<Option<Vec<String>>> = Vec::new();
for arg in args {
let resolved = arg.resolved_type.as_ref().map(|ty| self.resolve_type(ty));
if let Some(Type::Tuple(fields)) = &resolved {
let mut suffixes = Vec::new();
for field in fields {
if let Type::Named(field_name) = field {
flat_specifiers.push(self.format_specifier(field));
suffixes.push(field_name.clone());
}
}
flat_args.push(arg);
field_suffixes.push(Some(suffixes));
} else {
flat_specifiers.push(match &arg.resolved_type {
Some(ty) => self.format_specifier(ty),
None => "%d".into(),
});
flat_args.push(arg);
field_suffixes.push(None);
}
}
self.push("printf(\"");
for (index, specifier) in flat_specifiers.iter().enumerate() {
if index > 0 {
self.push(" ");
}
self.push(specifier);
}
self.push("\\n\"");
for (arg, suffixes) in flat_args.iter().zip(&field_suffixes) {
match suffixes {
None => {
self.push(", ");
if arg
.resolved_type
.as_ref()
.is_some_and(|ty| self.resolve_type(ty) == Type::Bool)
{
self.push("(");
self.emit_expression(arg);
self.push(" ? \"true\" : \"false\")");
} else {
self.emit_expression(arg);
}
}
Some(fields) => {
for field_name in fields {
self.push(", ");
self.emit_expression(arg);
write!(self.output, ".{field_name}").unwrap();
}
}
}
}
self.push(")");
}
pub(crate) fn is_stdio_function(name: &str) -> bool {
matches!(
name,
"fopen"
| "fclose"
| "fread"
| "fwrite"
| "fgets"
| "fputs"
| "feof"
| "fseek"
| "ftell"
| "rewind"
| "fflush"
| "fdopen"
| "fprintf"
| "fscanf"
| "fgetc"
| "fputc"
| "ungetc"
| "freopen"
| "tmpfile"
| "tmpnam"
| "remove"
| "rename"
)
}
pub(crate) fn is_pointer_type(&self, ty: Option<&Type>) -> bool {
match ty {
Some(Type::Pointer(_, _)) => true,
Some(Type::Named(name)) => self
.newtypes
.get(name)
.is_some_and(|inner| self.is_pointer_type(Some(inner))),
_ => false,
}
}
pub(crate) fn is_array_newtype(&self, resolved_type: Option<&Type>) -> bool {
let Some(ty) = resolved_type else {
return false;
};
let name = match ty {
Type::Named(name) => name,
Type::Pointer(_, inner) => match inner.as_ref() {
Type::Named(name) => name,
_ => return false,
},
_ => return false,
};
let Some(inner) = self.newtypes.get(name) else {
return false;
};
match inner {
Type::Array(..) => true,
Type::Named(_) => self.is_array_newtype(Some(inner)),
_ => false,
}
}
fn array_newtype_struct_name(&self, ty: &Type) -> String {
let Type::Named(name) = ty else {
return String::new();
};
let Some(inner) = self.newtypes.get(name) else {
return name.clone();
};
match inner {
Type::Array(..) => name.clone(),
Type::Named(_) => self.array_newtype_struct_name(inner),
_ => name.clone(),
}
}
pub(crate) fn is_identity_downcast(&self, object_type: Option<&Type>, field: &str) -> bool {
let ty = match object_type {
Some(Type::Named(name)) => Some(name.as_str()),
Some(Type::Pointer(_, inner)) => {
if let Type::Named(name) = inner.as_ref() {
Some(name.as_str())
} else {
None
}
}
_ => None,
};
let Some(type_name) = ty else {
return false;
};
let Some(inner) = self.newtypes.get(type_name) else {
return false;
};
if let Type::Named(inner_name) = inner {
inner_name == field
} else {
false
}
}
pub(crate) fn is_typedef_downcast(&self, object_type: Option<&Type>) -> bool {
let Some(Type::Named(name)) = object_type else {
return false;
};
let Some(inner) = self.newtypes.get(name) else {
return false;
};
let resolved = self.resolve_type(inner);
!matches!(
resolved,
Type::Tuple(_) | Type::Enum(_) | Type::Pointer(..) | Type::Array(..)
)
}
fn resolve_type(&self, ty: &Type) -> Type {
if let Type::Named(name) = ty
&& let Some(inner) = self.newtypes.get(name)
{
return self.resolve_type(inner);
}
ty.clone()
}
fn format_specifier(&self, ty: &Type) -> String {
let resolved = self.resolve_type(ty);
match &resolved {
Type::Bool => "%s".into(),
Type::Int(width, Signedness::Signed) => match width {
IntWidth::W64 => "%ld".into(),
IntWidth::W128 => "%lld".into(),
IntWidth::WSize => "%td".into(),
_ => "%d".into(),
},
Type::Int(width, Signedness::Unsigned) => match width {
IntWidth::W64 => "%lu".into(),
IntWidth::W128 => "%llu".into(),
IntWidth::WSize => "%zu".into(),
_ => "%u".into(),
},
Type::Float(_) => "%g".into(),
Type::Pointer(_, inner)
if matches!(
inner.as_ref(),
Type::Int(IntWidth::W8, Signedness::Unsigned)
) =>
{
"%s".into()
}
Type::Pointer(_, _) => "%p".into(),
_ => "%d".into(),
}
}
fn emit_literal(&mut self, literal: &Literal) {
match literal {
Literal::Bool(true) => self.push("true"),
Literal::Bool(false) => self.push("false"),
Literal::Integer(value) => write!(self.output, "{value}").unwrap(),
Literal::Float(value) => {
if value.fract() == 0.0 {
write!(self.output, "{value}.0").unwrap();
} else {
write!(self.output, "{value}").unwrap();
}
}
Literal::Null => self.push("NULL"),
Literal::String(bytes) => {
self.push("(const uint8_t *)\"");
for &byte in bytes {
match byte {
b'\n' => self.push("\\n"),
b'\r' => self.push("\\r"),
b'\t' => self.push("\\t"),
b'\\' => self.push("\\\\"),
b'"' => self.push("\\\""),
b'\0' => self.push("\\0"),
0x20..=0x7e => self.output.push(byte as char),
_ => write!(self.output, "\\x{byte:02x}").unwrap(),
}
}
self.push("\"");
}
}
}
fn emit_binary_operator(&mut self, op: &BinaryOperator) {
self.push(match op {
BinaryOperator::Arithmetic(ArithmeticOperator::Add) => "+",
BinaryOperator::Arithmetic(ArithmeticOperator::Subtract) => "-",
BinaryOperator::Arithmetic(ArithmeticOperator::Multiply) => "*",
BinaryOperator::Arithmetic(ArithmeticOperator::Divide) => "/",
BinaryOperator::Arithmetic(ArithmeticOperator::Remainder) => "%",
BinaryOperator::Comparison(ComparisonOperator::Equal) => "==",
BinaryOperator::Comparison(ComparisonOperator::NotEqual) => "!=",
BinaryOperator::Comparison(ComparisonOperator::Less) => "<",
BinaryOperator::Comparison(ComparisonOperator::LessEqual) => "<=",
BinaryOperator::Comparison(ComparisonOperator::Greater) => ">",
BinaryOperator::Comparison(ComparisonOperator::GreaterEqual) => ">=",
BinaryOperator::Logical(LogicalOperator::And) => "&&",
BinaryOperator::Logical(LogicalOperator::Or) => "||",
BinaryOperator::Bitwise(BitwiseOperator::And) => "&",
BinaryOperator::Bitwise(BitwiseOperator::Or) => "|",
BinaryOperator::Bitwise(BitwiseOperator::Xor) => "^",
BinaryOperator::Bitwise(BitwiseOperator::ShiftLeft) => "<<",
BinaryOperator::Bitwise(BitwiseOperator::ShiftRight) => ">>",
});
}
fn emit_unary_operator(&mut self, op: &UnaryOperator) {
self.push(match op {
UnaryOperator::Negate => "-",
UnaryOperator::LogicalNot => "!",
UnaryOperator::BitwiseNot => "~",
});
}
}