diff options
| -rw-r--r-- | src/codegen_wasm.c | 49 | ||||
| -rw-r--r-- | tests/wasm.sh | 31 |
2 files changed, 76 insertions, 4 deletions
diff --git a/src/codegen_wasm.c b/src/codegen_wasm.c index 1072b67..335a527 100644 --- a/src/codegen_wasm.c +++ b/src/codegen_wasm.c @@ -39,11 +39,19 @@ static void codegen_func_prologue(CodeGen* g, AstNode* ast) { static void codegen_func_epilogue(CodeGen* g, AstNode* ast) { } +static void codegen_int_expr(CodeGen* g, AstNode* ast) { + fprintf(g->out, " i32.const %d\n", ast->node_int_value); +} + static void codegen_binary_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) { codegen_expr(g, ast->node_lhs, gen_mode); codegen_expr(g, ast->node_rhs, gen_mode); if (ast->node_op == TokenKind_plus) { - fprintf(g->out, "i32.add\n"); + fprintf(g->out, " i32.add\n"); + } else if (ast->node_op == TokenKind_minus) { + fprintf(g->out, " i32.sub\n"); + } else if (ast->node_op == TokenKind_le) { + fprintf(g->out, " i32.le_s\n"); } else { unreachable(); } @@ -53,11 +61,24 @@ static void codegen_lvar(CodeGen* g, AstNode* ast, GenMode gen_mode) { fprintf(g->out, " local.get $l_%s\n", ast->name); } +static void codegen_func_call(CodeGen* g, AstNode* ast) { + AstNode* args = ast->node_args; + for (int i = 0; i < args->node_len; ++i) { + AstNode* arg = args->node_items + i; + codegen_expr(g, arg, GenMode_rval); + } + fprintf(g->out, " call $%s\n", ast->name); +} + static void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) { - if (ast->kind == AstNodeKind_binary_expr) { + if (ast->kind == AstNodeKind_int_expr) { + codegen_int_expr(g, ast); + } else if (ast->kind == AstNodeKind_binary_expr) { codegen_binary_expr(g, ast, gen_mode); } else if (ast->kind == AstNodeKind_lvar) { codegen_lvar(g, ast, gen_mode); + } else if (ast->kind == AstNodeKind_func_call) { + codegen_func_call(g, ast); } else { unreachable(); } @@ -67,7 +88,25 @@ static void codegen_return_stmt(CodeGen* g, AstNode* ast) { if (ast->node_expr) { codegen_expr(g, ast->node_expr, GenMode_rval); } - codegen_func_epilogue(g, ast); + fprintf(g->out, " return\n"); +} + +static void codegen_if_stmt(CodeGen* g, AstNode* ast) { + codegen_expr(g, ast->node_cond, GenMode_rval); + fprintf(g->out, " (if (result i32)\n"); + fprintf(g->out, " (then\n"); + codegen_stmt(g, ast->node_then); + fprintf(g->out, " )\n"); + if (ast->node_else) { + fprintf(g->out, " (else\n"); + codegen_stmt(g, ast->node_else); + fprintf(g->out, " )\n"); + } else { + fprintf(g->out, " (else\n"); + fprintf(g->out, " i32.const 0\n"); + fprintf(g->out, " )\n"); + } + fprintf(g->out, " )\n"); } static void codegen_nop(CodeGen* g, AstNode* ast) { @@ -85,6 +124,8 @@ static void codegen_stmt(CodeGen* g, AstNode* ast) { codegen_block_stmt(g, ast); } else if (ast->kind == AstNodeKind_return_stmt) { codegen_return_stmt(g, ast); + } else if (ast->kind == AstNodeKind_if_stmt) { + codegen_if_stmt(g, ast); } else if (ast->kind == AstNodeKind_nop) { codegen_nop(g, ast); } else { @@ -95,7 +136,7 @@ static void codegen_stmt(CodeGen* g, AstNode* ast) { static void codegen_func(CodeGen* g, AstNode* ast) { g->current_func = ast; - fprintf(g->out, "(func (export \"%s\") \n", ast->name); + fprintf(g->out, "(func $%s (export \"%s\")", ast->name, ast->name); codegen_func_prologue(g, ast); codegen_stmt(g, ast->node_body); diff --git a/tests/wasm.sh b/tests/wasm.sh index d024989..e97c05f 100644 --- a/tests/wasm.sh +++ b/tests/wasm.sh @@ -23,3 +23,34 @@ cat > expected <<'EOF' EOF diff -u expected output + + +cat > main.c <<'EOF' +int fib(int n) { + if (n <= 1) { + return 1; + } else { + return fib(n - 1) + fib(n - 2); + } +} +EOF + +"$ducc" "${CFLAGS:-}" --wasm -o main.wat main.c + +wat2wasm main.wat -o main.wasm + +cat > main.mjs <<'EOF' +import { readFile } from 'fs/promises'; + +const wasmBuffer = await readFile('./main.wasm'); +const { instance } = await WebAssembly.instantiate(wasmBuffer); + +console.log(instance.exports.fib(10)); +EOF +node main.mjs > output + +cat > expected <<'EOF' +89 +EOF + +diff -u expected output |
