Implement parser module and update AST

This commit is contained in:
2026-04-24 14:50:54 +02:00
parent 2d1ccd52e6
commit a173e37adc
6 changed files with 78 additions and 48 deletions
+16
View File
@@ -0,0 +1,16 @@
/**
* Holds the AST model
*/
#ifndef AST_H
#define AST_H
/**
* The top-level model.
* Every file matches an entire Module.
*/
typedef struct {
/// @brief The name of the module.
char* name;
} Module;
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
V0_SRC := v0/buffer.c v0/main.c v0/token.c
V0_SRC := v0/main.c v0/token.c v0/parser.c
# V0_TEST must only include `v0/test.c` itself, as all other test Csource files are
# included directly into `v0/test.c` using `#include "test_xyz.c"`.
+45
View File
@@ -0,0 +1,45 @@
#include "parser.h"
#include <stdlib.h>
#include <string.h>
Module* parser_parse(TokenStream* ts) {
Token t = tokenstream_next(ts);
if (t != TOKEN_MODULE) {
return NULL;
}
t = tokenstream_next(ts);
if (t != TOKEN_IDENTIFIER) {
return NULL;
}
TokenInfo info;
tokenstream_info(ts, &info);
Module* module = (Module*)malloc(sizeof(Module));
if (module == NULL) return NULL;
module->name = (char*)malloc(info.text_length + 1);
if (module->name == NULL) {
free(module);
return NULL;
}
memcpy(module->name, info.text, info.text_length);
module->name[info.text_length] = '\0';
t = tokenstream_next(ts);
if (t != TOKEN_SEMICOLON) {
free(module->name);
free(module);
return NULL;
}
return module;
}
void parser_free(Module* module) {
if (module == NULL) return;
free(module->name);
free(module);
}
+2 -7
View File
@@ -1,5 +1,4 @@
#include "test.h"
#include "buffer.h"
#include <setjmp.h>
#include <stdio.h>
@@ -16,18 +15,13 @@ typedef struct {
Test func;
} TestCase;
#include "test_buffer.c"
#include "test_token.c"
#include "test_parser.c"
static int s_totalTests;
static int s_greenTests;
static TestCase s_tests[] = {
{"buffer_string_reads_chars", test_buffer_string_reads_chars},
{"buffer_string_eof", test_buffer_string_eof},
{"buffer_string_eof_after_content", test_buffer_string_eof_after_content},
{"buffer_file_reads_chars", test_buffer_file_reads_chars},
{"buffer_file_open_fail", test_buffer_file_open_fail},
{"tokenstream_open_fail", test_tokenstream_open_fail},
{"tokenstream_simple_keyword", test_tokenstream_simple_keyword},
{"tokenstream_keywords_and_symbols", test_tokenstream_keywords_and_symbols},
@@ -36,6 +30,7 @@ static TestCase s_tests[] = {
{"tokenstream_whitespace_ignored", test_tokenstream_whitespace_ignored},
{"tokenstream_void_function_signature", test_tokenstream_void_function_signature},
{"tokenstream_info", test_tokenstream_info},
{"parser_module_name", test_parser_module_name},
};
-40
View File
@@ -1,40 +0,0 @@
#include "test.h"
#include "buffer.h"
#include <stdio.h>
static void test_buffer_string_reads_chars(void) {
Buffer* buf = buffer_open_string("hi");
if (buffer_read(buf) != 'h') fail("expected 'h'");
if (buffer_read(buf) != 'i') fail("expected 'i'");
buffer_close(buf);
}
static void test_buffer_string_eof(void) {
Buffer* buf = buffer_open_string("");
if (buffer_read(buf) != (char)-1) fail("expected -1 on empty string");
buffer_close(buf);
}
static void test_buffer_string_eof_after_content(void) {
Buffer* buf = buffer_open_string("a");
buffer_read(buf);
if (buffer_read(buf) != (char)-1) fail("expected -1 after end of string");
buffer_close(buf);
}
static void test_buffer_file_reads_chars(void) {
Buffer* buf = buffer_open_file("v0/test_buffer.txt");
if (buf == NULL) fail("could not open file");
if (buffer_read(buf) != 'a') fail("expected 'a'");
if (buffer_read(buf) != 'b') fail("expected 'b'");
if (buffer_read(buf) != 'c') fail("expected 'c'");
if (buffer_read(buf) != '\n') fail("expected newline after content");
if (buffer_read(buf) != (char)-1) fail("expected -1 after file");
buffer_close(buf);
}
static void test_buffer_file_open_fail(void) {
Buffer* buf = buffer_open_file("v0/does_not_exist.txt");
if (buf != NULL) fail("expected NULL for non-existent file");
}
+14
View File
@@ -0,0 +1,14 @@
#include "test.h"
#include "parser.h"
#include <string.h>
static void test_parser_module_name(void) {
TokenStream* ts = tokenstream_open("module my_module;");
Module* m = parser_parse(ts);
if (m == NULL) fail("expected module to be parsed");
if (strcmp(m->name, "my_module") != 0) fail("expected name 'my_module'");
parser_free(m);
tokenstream_close(ts);
}