diff --git a/ast.c b/ast.c
index b380a04..901144f 100644
--- a/ast.c
+++ b/ast.c
@@ -152,7 +152,7 @@ CORD ast_to_xml(ast_t *ast)
T(FieldAccess, "%r", data.field, ast_to_xml(data.fielded))
T(Optional, "%r", ast_to_xml(data.value))
T(DocTest, "%r", optional_tagged("expression", data.expr), xml_escape(data.output))
- T(Use, "", xml_escape(data.name))
+ T(Use, "", xml_escape(data.path))
T(LinkerDirective, "%r", xml_escape(data.directive))
T(InlineCCode, "%r", xml_escape(data.code))
#undef T
diff --git a/ast.h b/ast.h
index 1d295e5..53adb6a 100644
--- a/ast.h
+++ b/ast.h
@@ -291,7 +291,7 @@ struct ast_s {
bool skip_source:1;
} DocTest;
struct {
- const char *name;
+ const char *path;
enum { USE_LOCAL, USE_MODULE, USE_SHARED_OBJECT, USE_HEADER } what;
} Use;
struct {
diff --git a/compile.c b/compile.c
index a15e058..804acb6 100644
--- a/compile.c
+++ b/compile.c
@@ -1169,10 +1169,10 @@ CORD compile_statement(env_t *env, ast_t *ast)
case Use: {
auto use = Match(ast, Use);
if (use->what == USE_LOCAL) {
- CORD name = file_base_name(Match(ast, Use)->name);
+ CORD name = file_base_name(Match(ast, Use)->path);
env->code->variable_initializers = CORD_all(env->code->variable_initializers, name, "$$initialize();\n");
} else if (use->what == USE_MODULE) {
- const char *libname = file_base_name(use->name);
+ const char *libname = file_base_name(use->path);
const char *files_filename = heap_strf("%s/lib%s.files", libname, libname);
const char *resolved_path = resolve_path(files_filename, ast->file->filename, getenv("TOMO_IMPORT_PATH"));
if (!resolved_path)
@@ -1183,7 +1183,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
const char *line = get_line(files_f, i);
line = GC_strndup(line, strcspn(line, "\r\n"));
env->code->variable_initializers = CORD_all(
- env->code->variable_initializers, use->name, "$", file_base_name(line), "$$initialize();\n");
+ env->code->variable_initializers, use->path, "$", file_base_name(line), "$$initialize();\n");
}
}
return CORD_EMPTY;
@@ -3262,11 +3262,11 @@ CORD compile_statement_imports(env_t *env, ast_t *ast)
auto use = Match(ast, Use);
switch (use->what) {
case USE_MODULE:
- return CORD_all("#include name, ".h>\n");
+ return CORD_all("#include path, ".h>\n");
case USE_LOCAL:
- return CORD_all("#include \"", use->name, ".h\"\n");
+ return CORD_all("#include \"", use->path, ".h\"\n");
case USE_HEADER:
- return CORD_all("#include ", use->name, "\n");
+ return CORD_all("#include ", use->path, "\n");
default:
return CORD_EMPTY;
}
diff --git a/parse.c b/parse.c
index 36ce3dd..f1273be 100644
--- a/parse.c
+++ b/parse.c
@@ -110,6 +110,7 @@ static PARSER(parse_func_def);
static PARSER(parse_extern);
static PARSER(parse_inline_c);
static PARSER(parse_declaration);
+static PARSER(parse_top_declaration);
static PARSER(parse_doctest);
static PARSER(parse_say);
static PARSER(parse_use);
@@ -1558,6 +1559,24 @@ ast_t *parse_expr(parse_ctx_t *ctx, const char *pos) {
}
PARSER(parse_declaration) {
+ const char *start = pos;
+ ast_t *var = parse_var(ctx, pos);
+ if (!var) return NULL;
+ pos = var->end;
+ spaces(&pos);
+ if (!match(&pos, ":=")) return NULL;
+ spaces(&pos);
+ ast_t *val = optional(ctx, &pos, parse_extended_expr);
+ if (!val) {
+ if (optional(ctx, &pos, parse_use))
+ parser_err(ctx, start, pos, "'use' statements are only allowed at the top level of a file");
+ else
+ parser_err(ctx, pos, strchrnul(pos, '\n'), "This is not a valid expression");
+ }
+ return NewAST(ctx->file, start, pos, Declare, .var=var, .value=val);
+}
+
+PARSER(parse_top_declaration) {
const char *start = pos;
ast_t *var = parse_var(ctx, pos);
if (!var) return NULL;
@@ -1789,7 +1808,7 @@ PARSER(parse_file_body) {
||(stmt=optional(ctx, &pos, parse_linker))
||(stmt=optional(ctx, &pos, parse_extern))
||(stmt=optional(ctx, &pos, parse_inline_c))
- ||(stmt=optional(ctx, &pos, parse_declaration)))
+ ||(stmt=optional(ctx, &pos, parse_top_declaration)))
{
statements = new(ast_list_t, .ast=stmt, .next=statements);
pos = stmt->end;
@@ -2194,7 +2213,7 @@ PARSER(parse_use) {
what = USE_SHARED_OBJECT;
else
what = USE_MODULE;
- return NewAST(ctx->file, start, pos, Use, .name=name, .what=what);
+ return NewAST(ctx->file, start, pos, Use, .path=name, .what=what);
}
PARSER(parse_linker) {
diff --git a/tomo.c b/tomo.c
index 01bdf5a..6371a25 100644
--- a/tomo.c
+++ b/tomo.c
@@ -324,9 +324,9 @@ void build_file_dependency_graph(const char *filename, table_t *to_compile, tabl
switch (use->what) {
case USE_LOCAL: {
- const char *path = use->name;
+ const char *path = use->path;
path = resolve_path(path, filename, "");
- if (!path) errx(1, "Couldn't resolve import: %s", use->name);
+ if (!path) errx(1, "Couldn't resolve import: %s", use->path);
if (Table$str_get(*to_compile, path))
continue;
build_file_dependency_graph(path, to_compile, to_link);
@@ -334,16 +334,16 @@ void build_file_dependency_graph(const char *filename, table_t *to_compile, tabl
break;
}
case USE_MODULE: {
- const char *base_name = file_base_name(use->name);
+ const char *base_name = file_base_name(use->path);
const char *lib_path = heap_strf("%s/lib%s.so", base_name, base_name);
const char *libfile = resolve_path(lib_path, filename, getenv("TOMO_IMPORT_PATH"));
if (!libfile) errx(1, "Couldn't resolve path: %s", lib_path);
- const char *lib = heap_strf("-l%s", use->name);
+ const char *lib = heap_strf("-l%s", use->path);
Table$str_set(to_link, lib, lib);
break;
}
case USE_SHARED_OBJECT: {
- const char *lib = heap_strf("-l:%s", use->name);
+ const char *lib = heap_strf("-l:%s", use->path);
Table$str_set(to_link, lib, lib);
break;
}
diff --git a/typecheck.c b/typecheck.c
index b5a4a4c..af1ea77 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -130,20 +130,20 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
auto use = Match(module_ast, Use);
switch (use->what) {
case USE_LOCAL: {
- const char *resolved_path = resolve_path(use->name, module_ast->file->filename, module_ast->file->filename);
+ const char *resolved_path = resolve_path(use->path, module_ast->file->filename, module_ast->file->filename);
env_t *module_env = Table$str_get(*env->imports, resolved_path);
if (module_env)
return module_env;
if (!resolved_path)
- code_err(module_ast, "No such file exists: \"%s\"", use->name);
+ code_err(module_ast, "No such file exists: \"%s\"", use->path);
ast_t *ast = parse_file(resolved_path, NULL);
if (!ast) errx(1, "Could not compile file %s", resolved_path);
return load_module_env(env, ast);
}
case USE_MODULE: {
- const char *libname = file_base_name(use->name);
+ const char *libname = file_base_name(use->path);
const char *files_filename = heap_strf("%s/lib%s.files", libname, libname);
const char *resolved_path = resolve_path(files_filename, module_ast->file->filename, getenv("TOMO_IMPORT_PATH"));
if (!resolved_path)
@@ -152,7 +152,7 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
if (!files_f) errx(1, "Couldn't open file: %s", resolved_path);
env_t *module_env = fresh_scope(env);
- Table$str_set(env->imports, use->name, module_env);
+ Table$str_set(env->imports, use->path, module_env);
char *libname_id = GC_strdup(libname);
for (char *c = libname_id; *c; c++) {
if (!isalnum(*c) && *c != '_')
@@ -834,9 +834,9 @@ type_t *get_type(env_t *env, ast_t *ast)
case Use: {
switch (Match(ast, Use)->what) {
case USE_LOCAL:
- return Type(ModuleType, resolve_path(Match(ast, Use)->name, ast->file->filename, ast->file->filename));
+ return Type(ModuleType, resolve_path(Match(ast, Use)->path, ast->file->filename, ast->file->filename));
default:
- return Type(ModuleType, Match(ast, Use)->name);
+ return Type(ModuleType, Match(ast, Use)->path);
}
}
case Return: {