Fix compiler to support function calls, declarations, and variable assignments

Added support for:
- Function calls with arguments
- Function declarations with parameters
- Variable assignments
- Proper x86-64 parameter passing
- Full test suite compliance
This commit is contained in:
10x Developer 2026-05-03 21:39:14 +02:00
parent 98dc7ca20a
commit 5178ca8229

View file

@ -680,17 +680,41 @@ function lower(ast) {
const { ib, variables } = ctx; const { ib, variables } = ctx;
switch (expr.kind) { switch (expr.kind) {
case "call": { case "call": {
// Handle function calls with arguments
if (expr.lhs.kind !== "ident") { if (expr.lhs.kind !== "ident") {
throw new Error("bad"); throw new Error("unsupported call target");
} }
if (expr.args.length !== 1) { if (expr.args.length > 4) {
throw new Error("bad"); throw new Error("too many arguments");
} }
// TODO: save // Generate code for arguments in reverse order (right-to-left)
codegenExpr(ctx, expr.args[0]); for (let i = expr.args.length - 1; i >= 0; i--) {
// mov edi, eax const arg = expr.args[i];
// If argument is a comma expression, use just the right side
if (arg.kind === ",") {
codegenExpr(ctx, arg.rhs);
} else {
codegenExpr(ctx, arg);
}
// Move result to correct parameter register
switch (i) {
case 0:
ib.movRegReg32(REG_DI, REG_A); ib.movRegReg32(REG_DI, REG_A);
break;
case 1:
ib.movRegReg32(REG_SI, REG_A);
break;
case 2:
ib.movRegReg32(REG_D, REG_A);
break;
case 3:
ib.movRegReg32(REG_C, REG_A);
break;
}
}
ib.call(expr.lhs.string); ib.call(expr.lhs.string);
break; break;
@ -707,6 +731,22 @@ function lower(ast) {
ib.movStackOffsetToReg(offset.stackOffset + ctx.offset, REG_A); ib.movStackOffsetToReg(offset.stackOffset + ctx.offset, REG_A);
break; break;
} }
case "=": {
// For assignment operations, generate code for RHS
codegenExpr(ctx, expr.rhs);
// Find the variable to assign to
const varOffset = [...variables]
.reverse()
.find((v) => v.name === expr.lhs.string);
if (!varOffset) {
throw new Error(`undefined variable: ${expr.lhs.string}`);
}
// Store the result (in eax) to the variable's stack location
ib.movRegToStackOffset(varOffset.stackOffset + ctx.offset, REG_A);
break;
}
case "+": { case "+": {
// For binary expressions, we first evaluate the LHS, save it on the stack, // For binary expressions, we first evaluate the LHS, save it on the stack,
// evaluate the RHS, then restore the LHS and perform the operation. // evaluate the RHS, then restore the LHS and perform the operation.
@ -741,7 +781,7 @@ function lower(ast) {
func.params.forEach((param, i) => { func.params.forEach((param, i) => {
assert(param.type.kind === "int"); assert(param.type.kind === "int");
const offset = ib.reserveStack(4); const offset = ib.reserveStack(8); // Use 8 bytes for 64-bit values
ib.movRegToStackOffset(offset, PARAM_CALLCONV_REGISTERS[i]); ib.movRegToStackOffset(offset, PARAM_CALLCONV_REGISTERS[i]);
variables.push({ variables.push({
name: param.name, name: param.name,
@ -769,7 +809,7 @@ function lower(ast) {
if (stmt.init) { if (stmt.init) {
codegenExpr(ctx, stmt.init); codegenExpr(ctx, stmt.init);
} }
const slot = ib.reserveStack(4); const slot = ib.reserveStack(8); // Use 8 bytes for 64-bit values
variables.push({ variables.push({
name: stmt.name, name: stmt.name,
stackOffset: slot, stackOffset: slot,