diff --git a/v0/parser.c b/v0/parser.c index 73dbabe..ca97689 100644 --- a/v0/parser.c +++ b/v0/parser.c @@ -39,108 +39,105 @@ Module* parser_parse(TokenStream* ts) { while (1) { t = tokenstream_next(ts); - if (t.token != TOKEN_IMPORT) { - break; - } + if (t.token == TOKEN_IMPORT) { + ImportDeclaration* new_imports = realloc(module->imports, (module->import_count + 1) * sizeof(ImportDeclaration)); + if (!new_imports) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + module->imports = new_imports; - ImportDeclaration* new_imports = realloc(module->imports, (module->import_count + 1) * sizeof(ImportDeclaration)); - if (!new_imports) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - module->imports = new_imports; - - t = tokenstream_next(ts); - bool is_public = false; - if (t.token == TOKEN_PUBLIC) { - is_public = true; t = tokenstream_next(ts); - } - - if (t.token != TOKEN_IDENTIFIER) { - log_on_line(&t.location, t.location.column_end, "expected module name to import"); - parser_free(module); - return NULL; - } - - char* name = (char*)malloc(t.text.length + 1); - memcpy(name, t.text.data, t.text.length); - name[t.text.length] = '\0'; - - module->imports[module->import_count] = (ImportDeclaration){ .module_name = name, .is_public = is_public }; - module->import_count++; - - t = tokenstream_next(ts); - if (t.token != TOKEN_SEMICOLON) { - log_on_line(&t.location, t.location.column_end, "expected ';' after import"); - parser_free(module); - return NULL; - } - } - - while (t.token == TOKEN_ALIAS) { - AliasDeclaration* new_aliases = realloc(module->aliases, (module->alias_count + 1) * sizeof(AliasDeclaration)); - if (!new_aliases) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - module->aliases = new_aliases; - - t = tokenstream_next(ts); - if (t.token != TOKEN_IDENTIFIER) { - log_on_line(&t.location, t.location.column_end, "expected alias name"); - parser_free(module); - return NULL; - } - char* name = (char*)malloc(t.text.length + 1); - memcpy(name, t.text.data, t.text.length); - name[t.text.length] = '\0'; - AliasDeclaration alias; - alias.name = name; - - t = tokenstream_next(ts); - if (t.token != TOKEN_ASSIGN) { - log_on_line(&t.location, t.location.column_end, "expected '='"); - parser_free(module); - return NULL; - } - - t = tokenstream_next(ts); - - TypeExpression type; - if (t.token == TOKEN_IDENTIFIER && strncmp(t.text.data, "int32", t.text.length) == 0) { - type = (TypeExpression){ .tag = TYPE_EXPRESSION_BUILTIN, .builtin = { .bitSize = 32, .isSigned = true } }; - t = tokenstream_next(ts); - if (t.token == TOKEN_BRACKET_OPEN) { - t = tokenstream_next(ts); - if (t.token != TOKEN_BRACKET_CLOSE) { - log_on_line(&t.location, t.location.column_end, "expected ']'"); - parser_free(module); - return NULL; - } - TypeExpression* inner = malloc(sizeof(TypeExpression)); - *inner = type; - type = (TypeExpression){ .tag = TYPE_EXPRESSION_ARRAY, .array = { .array = inner } }; + bool is_public = false; + if (t.token == TOKEN_PUBLIC) { + is_public = true; t = tokenstream_next(ts); } + + if (t.token != TOKEN_IDENTIFIER) { + log_on_line(&t.location, t.location.column_end, "expected module name to import"); + parser_free(module); + return NULL; + } + + char* name = (char*)malloc(t.text.length + 1); + memcpy(name, t.text.data, t.text.length); + name[t.text.length] = '\0'; + + module->imports[module->import_count] = (ImportDeclaration){ .module_name = name, .is_public = is_public }; + module->import_count++; + + t = tokenstream_next(ts); + if (t.token != TOKEN_SEMICOLON) { + log_on_line(&t.location, t.location.column_end, "expected ';' after import"); + parser_free(module); + return NULL; + } + } else if (t.token == TOKEN_ALIAS) { + AliasDeclaration* new_aliases = realloc(module->aliases, (module->alias_count + 1) * sizeof(AliasDeclaration)); + if (!new_aliases) { + fprintf(stderr, "Out of memory\n"); + exit(1); + } + module->aliases = new_aliases; + + t = tokenstream_next(ts); + if (t.token != TOKEN_IDENTIFIER) { + log_on_line(&t.location, t.location.column_end, "expected alias name"); + parser_free(module); + return NULL; + } + char* name = (char*)malloc(t.text.length + 1); + memcpy(name, t.text.data, t.text.length); + name[t.text.length] = '\0'; + AliasDeclaration alias; + alias.name = name; + + t = tokenstream_next(ts); + if (t.token != TOKEN_ASSIGN) { + log_on_line(&t.location, t.location.column_end, "expected '='"); + parser_free(module); + return NULL; + } + + t = tokenstream_next(ts); + + TypeExpression type; + if (t.token == TOKEN_IDENTIFIER && strncmp(t.text.data, "int32", t.text.length) == 0) { + type = (TypeExpression){ .tag = TYPE_EXPRESSION_BUILTIN, .builtin = { .bitSize = 32, .isSigned = true } }; + t = tokenstream_next(ts); + if (t.token == TOKEN_BRACKET_OPEN) { + t = tokenstream_next(ts); + if (t.token != TOKEN_BRACKET_CLOSE) { + log_on_line(&t.location, t.location.column_end, "expected ']'"); + parser_free(module); + return NULL; + } + TypeExpression* inner = malloc(sizeof(TypeExpression)); + *inner = type; + type = (TypeExpression){ .tag = TYPE_EXPRESSION_ARRAY, .array = { .array = inner } }; + t = tokenstream_next(ts); + } + } else { + log_on_line(&t.location, t.location.column_end, "expected type"); + parser_free(module); + return NULL; + } + + alias.value = type; + + module->aliases[module->alias_count] = alias; + module->alias_count++; + + if (t.token != TOKEN_SEMICOLON) { + log_on_line(&t.location, t.location.column_end, "expected ';'"); + parser_free(module); + return NULL; + } } else { - log_on_line(&t.location, t.location.column_end, "expected type"); - parser_free(module); - return NULL; + break; } - - alias.value = type; - - module->aliases[module->alias_count] = alias; - module->alias_count++; - - if (t.token != TOKEN_SEMICOLON) { - log_on_line(&t.location, t.location.column_end, "expected ';'"); - parser_free(module); - return NULL; - } - t = tokenstream_next(ts); - } + } return module; } diff --git a/v0/test.c b/v0/test.c index 3a0d8d8..512a5b8 100644 --- a/v0/test.c +++ b/v0/test.c @@ -199,6 +199,7 @@ static TestCase s_tests[] = { {"log_error", test_log_error}, {"log_on_line", test_log_on_line}, {"log_on_line_variadic", test_log_on_line_variadic}, + {"parser_alias_and_import_mix", test_parser_alias_and_import_mix}, }; diff --git a/v0/test_parser.c b/v0/test_parser.c index eae846f..b5e563b 100644 --- a/v0/test_parser.c +++ b/v0/test_parser.c @@ -110,3 +110,17 @@ static void test_parser_alias_array(void) { assert_true(valueType->builtin.isSigned, "expected signed"); } + +static void test_parser_alias_and_import_mix(void) { + Module* m = test_get_ast(); + + assert_not_null(m, "expected module to be parsed"); + assert_int(2, (int)m->import_count, "expected 2 imports"); + assert_int(2, (int)m->alias_count, "expected 2 aliases"); + + assert_str("foo", m->imports[0].module_name, "expected import 1 name 'foo'"); + assert_str("bar", m->imports[1].module_name, "expected import 2 name 'bar'"); + assert_str("myalias", m->aliases[0].name, "expected alias 1 name 'myalias'"); + assert_str("otheralias", m->aliases[1].name, "expected alias 2 name 'otheralias'"); + parser_free(m); +} diff --git a/v0/tests/parser_alias_and_import_mix.c2 b/v0/tests/parser_alias_and_import_mix.c2 new file mode 100644 index 0000000..5628cc9 --- /dev/null +++ b/v0/tests/parser_alias_and_import_mix.c2 @@ -0,0 +1,9 @@ +module mymodule; + +import foo; + +alias myalias = int32[]; + +import bar; + +alias otheralias = int32;