Implement parser module and update AST
This commit is contained in:
@@ -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
@@ -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"`.
|
||||
|
||||
+45
@@ -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);
|
||||
}
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user