Support naked 'use' statements

This commit is contained in:
Bruce Hill 2024-04-24 13:53:37 -04:00
parent 7aa6b2a496
commit 061ec4fd8f
2 changed files with 76 additions and 41 deletions

View File

@ -300,17 +300,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
case Declare: {
auto decl = Match(ast, Declare);
if (decl->value->tag == Use) {
auto use = Match(decl->value, Use);
const char *path = use->raw_path;
const char *name = file_base_name(path);
if (strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) {
env->code->imports = CORD_all(env->code->imports, "#include \"", path, ".h\"\n");
env->code->object_files = CORD_all(env->code->object_files, "'", path, ".o' ");
} else {
env->code->imports = CORD_all(env->code->imports, "#include <", path, ".h>\n");
env->code->object_files = CORD_all(env->code->object_files, "-l", name, " ");
}
return CORD_EMPTY;
return compile_statement(env, decl->value);
} else {
type_t *t = get_type(env, decl->value);
if (t->tag == AbortType || t->tag == VoidType)
@ -790,6 +780,19 @@ CORD compile_statement(env_t *env, ast_t *ast)
return CORD_EMPTY;
}
case InlineCCode: return Match(ast, InlineCCode)->code;
case Use: {
auto use = Match(ast, Use);
const char *path = use->raw_path;
const char *name = file_base_name(path);
if (strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) {
env->code->imports = CORD_all(env->code->imports, "#include \"", path, ".h\"\n");
env->code->object_files = CORD_all(env->code->object_files, "'", path, ".o' ");
} else {
env->code->imports = CORD_all(env->code->imports, "#include <", path, ".h>\n");
env->code->object_files = CORD_all(env->code->object_files, "-l", name, " ");
}
return CORD_EMPTY;
}
default:
return CORD_asprintf("(void)%r;", compile(env, ast));
}
@ -1854,7 +1857,7 @@ CORD compile(env_t *env, ast_t *ast)
}
}
case InlineCCode: return Match(ast, InlineCCode)->code;
case Use: code_err(ast, "Uses are not supported yet");
case Use: return CORD_EMPTY;
case LinkerDirective: code_err(ast, "Linker directives are not supported yet");
case Extern: code_err(ast, "Externs are not supported yet");
case TableEntry: code_err(ast, "Table entries should not be compiled directly");
@ -1864,7 +1867,7 @@ CORD compile(env_t *env, ast_t *ast)
case Unknown: code_err(ast, "Unknown AST");
}
code_err(ast, "Unknown AST: %W", ast);
return NULL;
return CORD_EMPTY;
}
void compile_namespace(env_t *env, const char *ns_name, ast_t *block)

View File

@ -102,6 +102,37 @@ type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t)
code_err(ast, "Math operations between %T and %T are not supported", lhs_t, rhs_t);
}
static env_t *load_module(env_t *env, ast_t *use_ast)
{
auto use = Match(use_ast, Use);
const char *name = file_base_name(use->raw_path);
env_t *module_env = Table$str_get(*env->imports, name);
if (module_env)
return module_env;
module_env = new_compilation_unit();
module_env->file_prefix = heap_strf("%s$", name);
Table$str_set(module_env->imports, name, module_env);
const char *my_name = heap_strn(CORD_to_const_char_star(env->file_prefix), CORD_len(env->file_prefix)-1);
Table$str_set(module_env->imports, my_name, env);
const char *resolved_path = resolve_path(use->raw_path, use_ast->file->filename, getenv("USE_PATH"));
if (!resolved_path)
code_err(use_ast, "No such file exists: \"%s\"", use->raw_path);
file_t *f = load_file(resolved_path);
if (!f) errx(1, "No such file: %s", resolved_path);
ast_t *ast = parse_file(f, NULL);
if (!ast) errx(1, "Could not compile!");
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
bind_statement(module_env, stmt->ast);
}
Table$str_set(env->imports, name, module_env);
return module_env;
}
void bind_statement(env_t *env, ast_t *statement)
{
switch (statement->tag) {
@ -114,7 +145,10 @@ void bind_statement(env_t *env, ast_t *statement)
const char *name = Match(decl->var, Var)->name;
if (get_binding(env, name))
code_err(decl->var, "A %T called '%s' has already been defined", get_binding(env, name)->type, name);
bind_statement(env, decl->value);
if (decl->value->tag == Use)
(void)load_module(env, decl->value);
else
bind_statement(env, decl->value);
type_t *type = get_type(env, decl->value);
CORD code = CORD_cat(env->scope_prefix ? env->scope_prefix : "$", name);
set_binding(env, name, new(binding_t, .type=type, .code=code));
@ -153,7 +187,7 @@ void bind_statement(env_t *env, ast_t *statement)
type->__data.StructType.opaque = false;
type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env);
Table$str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type, .code=CORD_all(env->file_prefix, def->name)));
Table$str_set(env->locals, def->name, new(binding_t, .type=typeinfo_type, .code=CORD_all(env->file_prefix, def->name)));
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
bind_statement(ns_env, stmt->ast);
@ -199,7 +233,7 @@ void bind_statement(env_t *env, ast_t *statement)
}
type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env);
Table$str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type));
Table$str_set(env->locals, def->name, new(binding_t, .type=typeinfo_type));
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
bind_statement(ns_env, stmt->ast);
@ -223,38 +257,36 @@ void bind_statement(env_t *env, ast_t *statement)
.code="(Text_t)"));
type_t *typeinfo_type = Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env);
Table$str_set(env->globals, def->name, new(binding_t, .type=typeinfo_type));
Table$str_set(env->locals, def->name, new(binding_t, .type=typeinfo_type));
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
bind_statement(ns_env, stmt->ast);
break;
}
case Use: {
auto use = Match(statement, Use);
const char *name = file_base_name(use->raw_path);
if (Table$str_get(*env->imports, name))
break;
env_t *module_env = new_compilation_unit();
module_env->file_prefix = heap_strf("%s$", name);
Table$str_set(module_env->imports, name, module_env);
const char *my_name = heap_strn(CORD_to_const_char_star(env->file_prefix), CORD_len(env->file_prefix)-1);
Table$str_set(module_env->imports, my_name, env);
const char *resolved_path = resolve_path(use->raw_path, statement->file->filename, getenv("USE_PATH"));
if (!resolved_path)
code_err(statement, "No such file exists: \"%s\"", use->raw_path);
file_t *f = load_file(resolved_path);
if (!f) errx(1, "No such file: %s", resolved_path);
ast_t *ast = parse_file(f, NULL);
if (!ast) errx(1, "Could not compile!");
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
bind_statement(module_env, stmt->ast);
env_t *module_env = load_module(env, statement);
for (table_t *bindings = module_env->locals; bindings != module_env->globals; bindings = bindings->fallback) {
for (int64_t i = 1; i <= Table$length(*bindings); i++) {
struct {const char *name; binding_t *binding; } *entry = Table$entry(*bindings, i);
if (entry->name[0] == '_')
continue;
if (Table$str_get(*env->locals, entry->name))
code_err(statement, "This module imports a symbol called '%s', which would clobber another variable", entry->name);
printf("Imported binding: %s\n", entry->name);
Table$str_set(env->locals, entry->name, entry->binding);
}
}
for (int64_t i = 1; i <= Table$length(*module_env->types); i++) {
struct {const char *name; type_t *type; } *entry = Table$entry(*module_env->types, i);
if (entry->name[0] == '_')
continue;
if (Table$str_get(*env->types, entry->name))
continue;
//code_err(statement, "This module imports a type called '%s', which would clobber another type", entry->name);
printf("Imported type: %s\n", entry->name);
Table$str_set(env->types, entry->name, entry->type);
}
Table$str_set(env->imports, name, module_env);
break;
}
case Extern: {