diff --git a/v0/ast.h b/v0/ast.h new file mode 100644 index 0000000..846ce64 --- /dev/null +++ b/v0/ast.h @@ -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 diff --git a/v0/include.mk b/v0/include.mk index 6c3af96..c48826a 100644 --- a/v0/include.mk +++ b/v0/include.mk @@ -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 C–source files are # included directly into `v0/test.c` using `#include "test_xyz.c"`. diff --git a/v0/parser.c b/v0/parser.c new file mode 100644 index 0000000..b1a992c --- /dev/null +++ b/v0/parser.c @@ -0,0 +1,45 @@ +#include "parser.h" +#include +#include + +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); +} diff --git a/v0/test.c b/v0/test.c index 49fabfb..e308a27 100644 --- a/v0/test.c +++ b/v0/test.c @@ -1,5 +1,4 @@ #include "test.h" -#include "buffer.h" #include #include @@ -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}, }; diff --git a/v0/test_buffer.c b/v0/test_buffer.c deleted file mode 100644 index 56588dc..0000000 --- a/v0/test_buffer.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "test.h" -#include "buffer.h" -#include - - -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"); -} diff --git a/v0/test_parser.c b/v0/test_parser.c new file mode 100644 index 0000000..f35366b --- /dev/null +++ b/v0/test_parser.c @@ -0,0 +1,14 @@ +#include "test.h" +#include "parser.h" +#include + +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); +}