Files
centvrion/centvrion/compiler/emit_stmt.py
2026-04-21 14:54:36 +02:00

122 lines
4.2 KiB
Python

from centvrion.ast_nodes import (
Designa, DesignaIndex, DesignaDestructure, SiStatement, DumStatement,
PerStatement, Defini, Redi, Erumpe, Continva, ExpressionStatement, ID,
)
from centvrion.compiler.emit_expr import emit_expr
def emit_stmt(node, ctx):
"""
Emit C code for a CENTVRION statement node.
Returns lines — list of C statements.
"""
if isinstance(node, Designa):
# Function alias: resolved at compile time, no runtime code needed
if isinstance(node.value, ID) and node.value.name in ctx.func_resolve:
return []
val_lines, val_var = emit_expr(node.value, ctx)
return val_lines + [f'cent_scope_set(&_scope, "{node.id.name}", {val_var});']
if isinstance(node, DesignaIndex):
idx_lines, idx_var = emit_expr(node.index, ctx)
val_lines, val_var = emit_expr(node.value, ctx)
arr_tmp = ctx.fresh_tmp()
return (
idx_lines + val_lines + [
f'CentValue {arr_tmp} = cent_scope_get(&_scope, "{node.id.name}");',
f"cent_list_index_set(&{arr_tmp}, {idx_var}, {val_var});",
f'cent_scope_set(&_scope, "{node.id.name}", {arr_tmp});',
]
)
if isinstance(node, DesignaDestructure):
n = len(node.ids)
val_lines, val_var = emit_expr(node.value, ctx)
lines = val_lines[:]
lines.append(f'if ({val_var}.type != CENT_LIST) cent_type_error("Cannot destructure non-array value");')
lines.append(f'if ({val_var}.lval.len != {n}) cent_runtime_error("Destructuring mismatch");')
for i, id_node in enumerate(node.ids):
tmp = ctx.fresh_tmp()
lines.append(f"CentValue {tmp} = cent_list_index({val_var}, cent_int({i + 1}));")
lines.append(f'cent_scope_set(&_scope, "{id_node.name}", {tmp});')
return lines
if isinstance(node, SiStatement):
cond_lines, cond_var = emit_expr(node.test, ctx)
then_lines = _emit_body(node.statements, ctx)
lines = cond_lines + [f"if (cent_truthy({cond_var})) {{"]
lines += [f" {l}" for l in then_lines]
if node.else_part:
else_lines = _emit_body(node.else_part, ctx)
lines += ["} else {"]
lines += [f" {l}" for l in else_lines]
lines += ["}"]
return lines
if isinstance(node, DumStatement):
# DVM loops UNTIL condition is true (inverted while)
lines = ["while (1) {"]
cond_lines, cond_var = emit_expr(node.test, ctx)
lines += [f" {l}" for l in cond_lines]
lines += [f" if (cent_truthy({cond_var})) break;"]
body_lines = _emit_body(node.statements, ctx)
lines += [f" {l}" for l in body_lines]
lines += ["}"]
return lines
if isinstance(node, PerStatement):
arr_lines, arr_var = emit_expr(node.data_list, ctx)
i_var = ctx.fresh_tmp()
var_name = node.variable_name.name
body_lines = _emit_body(node.statements, ctx)
lines = arr_lines + [
f'if ({arr_var}.type != CENT_LIST) cent_type_error("PER requires an array");',
f"for (int {i_var} = 0; {i_var} < {arr_var}.lval.len; {i_var}++) {{",
f' cent_scope_set(&_scope, "{var_name}", {arr_var}.lval.items[{i_var}]);',
]
lines += [f" {l}" for l in body_lines]
lines += ["}"]
return lines
if isinstance(node, Defini):
# Function definitions are hoisted by emitter.py; no-op here.
return []
if isinstance(node, Redi):
lines = []
val_vars = []
for v in node.values:
v_lines, v_var = emit_expr(v, ctx)
lines.extend(v_lines)
val_vars.append(v_var)
if len(val_vars) == 1:
lines.append(f"_return_val = {val_vars[0]};")
else:
# multiple return values → pack into a list
lst_tmp = ctx.fresh_tmp()
lines.append(f"CentValue {lst_tmp} = cent_list_new({len(val_vars)});")
for vv in val_vars:
lines.append(f"cent_list_push(&{lst_tmp}, {vv});")
lines.append(f"_return_val = {lst_tmp};")
lines.append("goto _func_return;")
return lines
if isinstance(node, Erumpe):
return ["break;"]
if isinstance(node, Continva):
return ["continue;"]
if isinstance(node, ExpressionStatement):
lines, _ = emit_expr(node.expression, ctx)
return lines
raise NotImplementedError(type(node).__name__)
def _emit_body(stmts, ctx):
lines = []
for s in stmts:
lines.extend(emit_stmt(s, ctx))
return lines