diff --git a/v0/ast.h b/v0/ast.h index 348713f..cd6d270 100644 --- a/v0/ast.h +++ b/v0/ast.h @@ -5,29 +5,79 @@ #define AST_H #include "bool.h" +#include "token.h" + #include typedef struct { - /* @brief The name of the module being imported. */ - char* module_name; + /** @brief The name of the module being imported. */ + Token module_name; - /* @brief Whether the import is public or not. */ + /** @brief Whether the import is public or not. */ bool is_public; } ImportDeclaration; +typedef enum { + TYPE_EXPRESSION_BUILTIN, + TYPE_EXPRESSION_ARRAY +} TypeExpressionTag; + +/** + * An expression that evaluates to a type. + */ +typedef struct TypeExpression TypeExpression; +struct TypeExpression{ + /** @brief defines which entry in the union is valid */ + TypeExpressionTag tag; + union { + /** @brief Evaluates to an array of the given type. */ + struct { + /** @brief A pointer to the type of the elements stored in the array. */ + TypeExpression* array; + } array; + /** @brief Evaluates to a builtin integer type.*/ + struct { + /** + * @brief The number of bits in the integer. + * Typical values are 8, 16, 32, and 64. + */ + int bitSize; + /** @brief `true` if the type is signed, `false` if it's unsigned. */ + bool isSigned; + } builtin; + }; +}; + +/** + * A declaration that aliases one type to another. + */ +typedef struct { + /** @brief The name of the alias. */ + Token name; + + /** @brief The value of the alias. */ + TypeExpression value; +} AliasDeclaration; + /** * The top-level model. * Every file matches an entire Module. */ typedef struct { - /* @brief The name of the module. */ - char* name; + /** @brief The name of the module. */ + Token name; - /* @brief The list of imports in the module. */ + /** @brief The list of imports in the module. */ ImportDeclaration* imports; - /* @brief The number of imports in the module. */ + /** @brief The number of imports in the module. */ size_t import_count; + + /** @brief The list of aliases in the module. */ + AliasDeclaration* aliases; + + /** @brief The number of aliases in the module. */ + size_t alias_count; } Module; #endif diff --git a/v0/parser.c b/v0/parser.c index 87c7a7d..5459bc5 100644 --- a/v0/parser.c +++ b/v0/parser.c @@ -28,18 +28,11 @@ Module* parser_parse(TokenStream* ts) { fprintf(stderr, "Out of memory\n"); exit(1); } - module->name = NULL; + module->name = t; module->imports = NULL; module->import_count = 0; - - module->name = (char*)malloc(t.text.length + 1); - if (module->name == NULL) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - - memcpy(module->name, t.text.data, t.text.length); - module->name[t.text.length] = '\0'; + module->aliases = NULL; + module->alias_count = 0; t = tokenstream_next(ts); if (t.token != TOKEN_SEMICOLON) { @@ -77,14 +70,8 @@ Module* parser_parse(TokenStream* ts) { return NULL; } - module->imports[module->import_count].module_name = (char*)malloc(t.text.length + 1); - if (!module->imports[module->import_count].module_name) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - memcpy(module->imports[module->import_count].module_name, t.text.data, t.text.length); - module->imports[module->import_count].module_name[t.text.length] = '\0'; - module->imports[module->import_count].is_public = is_public; + module->imports[module->import_count].module_name = t; + module->imports[module->import_count].is_public = (bool)is_public; module->import_count++; t = tokenstream_next(ts); @@ -101,13 +88,10 @@ Module* parser_parse(TokenStream* ts) { void parser_free(Module* module) { if (module == NULL) return; if (module->imports != NULL) { - /* C89: declare index variable before the loop */ - size_t i; - for (i = 0; i < module->import_count; i++) { - free(module->imports[i].module_name); - } free(module->imports); } - free(module->name); + if (module->aliases != NULL) { + free(module->aliases); + } free(module); } diff --git a/v0/test_parser.c b/v0/test_parser.c index 6484fde..c9767e9 100644 --- a/v0/test_parser.c +++ b/v0/test_parser.c @@ -1,13 +1,19 @@ #include "test.h" #include "parser.h" #include +#include static void test_parser_module_name(void) { TokenStream* ts = tokenstream_open("test.c", "module my_module;"); Module* m = parser_parse(ts); + char* buf; assert_not_null(m, "expected module to be parsed"); - assert_str("my_module", m->name, "expected name 'my_module'"); + buf = malloc(m->name.text.length + 1); + memcpy(buf, m->name.text.data, m->name.text.length); + buf[m->name.text.length] = '\0'; + assert_str("my_module", buf, "expected name 'my_module'"); + free(buf); parser_free(m); tokenstream_close(ts); @@ -56,13 +62,22 @@ static void test_parser_bad_import_name(void) { static void test_parser_imports(void) { TokenStream* ts = tokenstream_open("test.c", "module my_module; import other_module;"); Module* m = parser_parse(ts); + char* buf; assert_not_null(m, "expected module to be parsed"); - assert_str("my_module", m->name, "expected name 'my_module'"); + buf = malloc(m->name.text.length + 1); + memcpy(buf, m->name.text.data, m->name.text.length); + buf[m->name.text.length] = '\0'; + assert_str("my_module", buf, "expected name 'my_module'"); + free(buf); assert_not_null(m->imports, "expected imports to be parsed"); - assert_int(1, m->import_count, "expected one import"); - assert_str("other_module", m->imports[0].module_name, "expected import name 'other_module'"); + assert_int(1, (int)m->import_count, "expected one import"); + buf = malloc(m->imports[0].module_name.text.length + 1); + memcpy(buf, m->imports[0].module_name.text.data, m->imports[0].module_name.text.length); + buf[m->imports[0].module_name.text.length] = '\0'; + assert_str("other_module", buf, "expected import name 'other_module'"); + free(buf); assert_false(m->imports[0].is_public, "expected import to not be public"); parser_free(m); @@ -72,13 +87,22 @@ static void test_parser_imports(void) { static void test_parser_public_imports(void) { TokenStream* ts = tokenstream_open("test.c", "module my_module; import public other_module;"); Module* m = parser_parse(ts); + char* buf; assert_not_null(m, "expected module to be parsed"); - assert_str("my_module", m->name, "expected name 'my_module'"); + buf = malloc(m->name.text.length + 1); + memcpy(buf, m->name.text.data, m->name.text.length); + buf[m->name.text.length] = '\0'; + assert_str("my_module", buf, "expected name 'my_module'"); + free(buf); assert_not_null(m->imports, "expected imports to be parsed"); - assert_int(1, m->import_count, "expected one import"); - assert_str("other_module", m->imports[0].module_name, "expected import name 'other_module'"); + assert_int(1, (int)m->import_count, "expected one import"); + buf = malloc(m->imports[0].module_name.text.length + 1); + memcpy(buf, m->imports[0].module_name.text.data, m->imports[0].module_name.text.length); + buf[m->imports[0].module_name.text.length] = '\0'; + assert_str("other_module", buf, "expected import name 'other_module'"); + free(buf); assert_true(m->imports[0].is_public, "expected import to be public"); parser_free(m);