122 lines
4.2 KiB
Python
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
|