aboutsummaryrefslogtreecommitdiff
path: root/tests/codegen_test.c
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-09 05:14:44 +0200
committerhachem <im@hachem.wtf>2026-09-09 05:14:44 +0200
commit8b76d35b0a045e0a3277be422513b938ef33dcce (patch)
treeb876d92ba3afb810e38f3f83792fc3fb849dd457 /tests/codegen_test.c
parentb9eff51ee157b22d8fa46aeecac7b95d5ed345d9 (diff)
feat: fasm backend
Diffstat (limited to 'tests/codegen_test.c')
-rw-r--r--tests/codegen_test.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/tests/codegen_test.c b/tests/codegen_test.c
index 2ccba98..24cac6d 100644
--- a/tests/codegen_test.c
+++ b/tests/codegen_test.c
@@ -1,9 +1,9 @@
#include <stdio.h>
#include <string.h>
-#include "nasm.h"
#include "tests.h"
#include "parser.h"
+#include "codegen.h"
static void generate_to_buffer(struct Program* program, char* buffer, size_t size)
{
@@ -23,6 +23,24 @@ static void generate_to_buffer(struct Program* program, char* buffer, size_t siz
fclose(out);
}
+static void generate_fasm_to_buffer(struct Program* program, char* buffer, size_t size)
+{
+ FILE* out = tmpfile();
+ if (out == NULL)
+ {
+ buffer[0] = '\0';
+ return;
+ }
+
+ generate_fasm(program, out);
+ fflush(out);
+ rewind(out);
+
+ size_t read = fread(buffer, 1, size - 1, out);
+ buffer[read] = '\0';
+ fclose(out);
+}
+
static void test_generate_consts_and_data(struct TestContext* context)
{
struct Lexer lexer = create_lexer("const N = 5\ndata msg = \"hi\"\n");
@@ -41,6 +59,33 @@ static void test_generate_consts_and_data(struct TestContext* context)
free_program(&program);
}
+static void test_generate_fasm(struct TestContext* context)
+{
+ struct Lexer lexer = create_lexer(
+ "[entry: main]\nconst N = 5\ndata msg = \"hi\\n\"\nproc main\n{\nrax = N\nsyscall\n}\n");
+ struct Program program;
+ check(context, parse_program(&lexer, &program));
+
+ char buffer[1024];
+ generate_fasm_to_buffer(&program, buffer, sizeof(buffer));
+
+ // fasm framing differs from nasm
+ check(context, strstr(buffer, "format ELF64") != NULL);
+ check(context, strstr(buffer, "N = 5") != NULL);
+ check(context, strstr(buffer, "section '.data' writeable") != NULL);
+ check(context, strstr(buffer, "msg db \"hi\", 10") != NULL); // escape expanded to a byte
+ check(context, strstr(buffer, ".len = $ - msg") != NULL);
+ check(context, strstr(buffer, "section '.text' executable") != NULL);
+ check(context, strstr(buffer, "public main") != NULL);
+ // instruction bodies are identical to nasm
+ check(context, strstr(buffer, "mov rax, N") != NULL);
+ // nasm-only forms must be absent
+ check(context, strstr(buffer, "%define") == NULL);
+ check(context, strstr(buffer, "bits 64") == NULL);
+
+ free_program(&program);
+}
+
static void test_generate_text(struct TestContext* context)
{
struct Lexer lexer = create_lexer(
@@ -121,6 +166,25 @@ static void test_generate_while(struct TestContext* context)
free_program(&program);
}
+static void test_generate_while_named(struct TestContext* context)
+{
+ struct Lexer lexer = create_lexer(
+ "proc main\n{\nwhile .drain rcx > 0\n{\nrcx -= 1\n}\n}\n");
+ struct Program program;
+ check(context, parse_program(&lexer, &program));
+
+ char buffer[1024];
+ generate_to_buffer(&program, buffer, sizeof(buffer));
+
+ check(context, strstr(buffer, ".drain:") != NULL);
+ check(context, strstr(buffer, "jle .drain_end") != NULL);
+ check(context, strstr(buffer, "jmp .drain") != NULL);
+ check(context, strstr(buffer, ".drain_end:") != NULL);
+ check(context, strstr(buffer, ".while_0") == NULL);
+
+ free_program(&program);
+}
+
static void test_generate_negative(struct TestContext* context)
{
struct Lexer lexer = create_lexer(
@@ -524,10 +588,12 @@ void run_codegen_tests(struct TestContext* context)
test_generate_entry_and_bits(context);
test_generate_no_entry(context);
test_generate_consts_and_data(context);
+ test_generate_fasm(context);
test_generate_text(context);
test_generate_if(context);
test_generate_if_else(context);
test_generate_while(context);
+ test_generate_while_named(context);
test_generate_negative(context);
test_generate_call(context);
test_generate_param_substitution(context);