Disallow 'use' statements that aren't top level
This commit is contained in:
parent
f605df8230
commit
d1b2e9f598
2
ast.c
2
ast.c
@ -152,7 +152,7 @@ CORD ast_to_xml(ast_t *ast)
|
||||
T(FieldAccess, "<FieldAccess field=\"%s\">%r</FieldAccess>", data.field, ast_to_xml(data.fielded))
|
||||
T(Optional, "<Optional>%r</Optional>", ast_to_xml(data.value))
|
||||
T(DocTest, "<DocTest>%r<output>%r</output></DocTest>", optional_tagged("expression", data.expr), xml_escape(data.output))
|
||||
T(Use, "<Use>%r</Use>", xml_escape(data.name))
|
||||
T(Use, "<Use>%r</Use>", xml_escape(data.path))
|
||||
T(LinkerDirective, "<LinkerDirective>%r</LinkerDirective>", xml_escape(data.directive))
|
||||
T(InlineCCode, "<InlineCode>%r</InlineCode>", xml_escape(data.code))
|
||||
#undef T
|
||||
|
2
ast.h
2
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 {
|
||||
|
12
compile.c
12
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 <tomo/lib", use->name, ".h>\n");
|
||||
return CORD_all("#include <tomo/lib", use->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;
|
||||
}
|
||||
|
23
parse.c
23
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) {
|
||||
|
10
tomo.c
10
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;
|
||||
}
|
||||
|
12
typecheck.c
12
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: {
|
||||
|
Loading…
Reference in New Issue
Block a user