289 lines
8.3 KiB
C
289 lines
8.3 KiB
C
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include "../src/utils/bpalloc.h"
|
|
#include "../src/assembler/assembler.h"
|
|
|
|
static void stopTesting_(const char *file, int line)
|
|
{
|
|
fprintf(stderr, "\n%s:%d :: Failed to set up test environment\n", file, line);
|
|
abort();
|
|
}
|
|
#define stopTestingIf(exp) \
|
|
do { \
|
|
if(exp) { \
|
|
stopTesting_(__FILE__, __LINE__); \
|
|
} \
|
|
} while(0);
|
|
|
|
static void testCase(int line, bool exp, const char *msg)
|
|
{
|
|
if(exp == false)
|
|
fprintf(stdout, "Test case failed (line %d) :: %s\n", line, msg);
|
|
else
|
|
fprintf(stdout, "Test case passed (line %d)\n", line);
|
|
}
|
|
|
|
typedef struct {
|
|
Opcode opcode;
|
|
int operand_count;
|
|
Operand *operands;
|
|
} StaticInstruction;
|
|
|
|
typedef struct {
|
|
int instr_count;
|
|
StaticInstruction *instr_list;
|
|
} StaticExecutable;
|
|
|
|
static Executable *buildExpectedExecutable(BPAlloc *alloc, StaticExecutable *static_exp_exe)
|
|
{
|
|
ExeBuilder *builder = ExeBuilder_New(alloc);
|
|
stopTestingIf(builder == NULL);
|
|
|
|
Error error;
|
|
Error_Init(&error);
|
|
for(int i = 0; i < static_exp_exe->instr_count; i += 1) {
|
|
StaticInstruction instr = static_exp_exe->instr_list[i];
|
|
bool ok = ExeBuilder_Append(builder, &error, instr.opcode, instr.operands, instr.operand_count, -1, -1);
|
|
stopTestingIf(ok == false);
|
|
}
|
|
|
|
Executable *exe = ExeBuilder_Finalize(builder, &error);
|
|
stopTestingIf(exe == NULL);
|
|
|
|
Error_Free(&error);
|
|
return exe;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
struct {
|
|
int line;
|
|
bool fail;
|
|
const char *text;
|
|
StaticExecutable expected;
|
|
} tests[] = {
|
|
|
|
// Test the assembly of an empty string
|
|
// into an executable with no instructions.
|
|
{
|
|
.line = __LINE__,
|
|
.text = "",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 0,
|
|
.instr_list = NULL,
|
|
},
|
|
},
|
|
|
|
// Test the assembly of the simplest
|
|
// executable possible
|
|
{
|
|
.line = __LINE__,
|
|
.text = "POS",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 1,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
}
|
|
},
|
|
},
|
|
},
|
|
|
|
// Invalid opcode
|
|
{
|
|
.line = __LINE__,
|
|
.text = "GUCCI",
|
|
.fail = true,
|
|
},
|
|
|
|
// Label but no opcode
|
|
{
|
|
.line = __LINE__,
|
|
.text = "label:",
|
|
.fail = true,
|
|
},
|
|
|
|
// Basic executable with a label
|
|
{
|
|
.line = __LINE__,
|
|
.text = "label: POS",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 1,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
}
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
.line = __LINE__,
|
|
.text = " label : POS ",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 1,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
}
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
.line = __LINE__,
|
|
.text = " label : POS ; ",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 1,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
}
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
.line = __LINE__,
|
|
.text = " label0 : POS ; "
|
|
" label1 : NEG ; ",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 2,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
{
|
|
.opcode = OPCODE_NEG,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
.line = __LINE__,
|
|
.text = " label0 : POS ; "
|
|
" label1 : NEG ",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 2,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
{
|
|
.opcode = OPCODE_NEG,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
.line = __LINE__,
|
|
.text = " POS ; "
|
|
" label1 : NEG ",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 2,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
{
|
|
.opcode = OPCODE_NEG,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
{
|
|
.line = __LINE__,
|
|
.text = " label0 : POS ; "
|
|
" NEG ",
|
|
.fail = false,
|
|
.expected = (StaticExecutable) {
|
|
.instr_count = 2,
|
|
.instr_list = (StaticInstruction[]) {
|
|
{
|
|
.opcode = OPCODE_POS,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
{
|
|
.opcode = OPCODE_NEG,
|
|
.operands = NULL,
|
|
.operand_count = 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
Error error;
|
|
char pool[4096];
|
|
|
|
for(size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i += 1) {
|
|
|
|
// Use an allocator backed by a static
|
|
// buffer to avoid reallocating a pool
|
|
// for each test.
|
|
BPAlloc *alloc = BPAlloc_Init3(pool, sizeof(pool), -1, NULL, NULL, NULL);
|
|
stopTestingIf(alloc == NULL);
|
|
|
|
Error_Init(&error);
|
|
|
|
Source *src = Source_FromString(NULL, tests[i].text, -1, &error);
|
|
stopTestingIf(src == NULL);
|
|
|
|
Executable *got_exe = assemble(src, &error);
|
|
|
|
if(tests[i].fail == true) {
|
|
testCase(tests[i].line, got_exe == NULL, "Managed to assemble an invalid source");
|
|
} else {
|
|
Executable *exp_exe = buildExpectedExecutable(alloc, &tests[i].expected);
|
|
|
|
testCase(tests[i].line, got_exe != NULL, "Failed to assemble a valid source");
|
|
/*
|
|
fprintf(stderr, "== Generated ==\n");
|
|
Executable_Dump(got_exe);
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "== Expected ==\n");
|
|
Executable_Dump(exp_exe);
|
|
*/
|
|
testCase(tests[i].line, Executable_Equiv(got_exe, exp_exe, stderr, "Executable diff :: "), "Invalid assemblation result");
|
|
|
|
Executable_Free(got_exe);
|
|
Executable_Free(exp_exe);
|
|
}
|
|
Source_Free(src);
|
|
Error_Free(&error);
|
|
BPAlloc_Free(alloc);
|
|
}
|
|
return 0;
|
|
} |