aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.h1
-rw-r--r--src/compile.c130
-rw-r--r--src/enums.c33
-rw-r--r--src/environment.c33
-rw-r--r--src/environment.h5
-rw-r--r--src/parse.c9
-rw-r--r--src/stdlib/files.c17
-rw-r--r--src/stdlib/files.h2
-rw-r--r--src/stdlib/nums.c4
-rw-r--r--src/stdlib/util.h2
-rw-r--r--src/structs.c11
-rw-r--r--src/tomo.c114
-rw-r--r--src/typecheck.c41
13 files changed, 195 insertions, 207 deletions
diff --git a/src/ast.h b/src/ast.h
index 2de9f007..47ff3caf 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -189,6 +189,7 @@ struct ast_s {
ast_t *var;
type_ast_t *type;
ast_t *value;
+ bool top_level:1;
} Declare;
struct {
ast_list_t *targets, *values;
diff --git a/src/compile.c b/src/compile.c
index 52c8a736..02d4795c 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -799,7 +799,7 @@ CORD compile_type(type_t *t)
if (!text->lang || streq(text->lang, "Text"))
return "Text_t";
else
- return CORD_all(namespace_prefix(text->env, text->env->namespace->parent), text->lang, "$$type");
+ return namespace_name(text->env, text->env->namespace, "$type");
}
case ListType: return "List_t";
case SetType: return "Table_t";
@@ -820,11 +820,11 @@ CORD compile_type(type_t *t)
case StructType: {
DeclareMatch(s, t, StructType);
if (s->external) return s->name;
- return CORD_all("struct ", namespace_prefix(s->env, s->env->namespace->parent), s->name, "$$struct");
+ return CORD_all("struct ", namespace_name(s->env, s->env->namespace, "$struct"));
}
case EnumType: {
DeclareMatch(e, t, EnumType);
- return CORD_all(namespace_prefix(e->env, e->env->namespace->parent), e->name, "$$type");
+ return namespace_name(e->env, e->env->namespace, "$type");
}
case OptionalType: {
type_t *nonnull = Match(t, OptionalType)->type;
@@ -843,7 +843,7 @@ CORD compile_type(type_t *t)
if (nonnull == PATH_TYPE_TYPE)
return "OptionalPathType_t";
DeclareMatch(s, nonnull, StructType);
- return CORD_all(namespace_prefix(s->env, s->env->namespace->parent), "$Optional", s->name, "$$type");
+ return namespace_name(s->env, s->env->namespace->parent, CORD_all("$Optional", s->name, "$$type"));
}
default:
compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_str(t));
@@ -874,7 +874,7 @@ CORD compile_lvalue(env_t *env, ast_t *ast)
DeclareMatch(index, ast, Index);
type_t *container_t = get_type(env, index->indexed);
if (container_t->tag == OptionalType)
- code_err(index->indexed, "This value might be null, so it can't be safely used as an assignment target");
+ code_err(index->indexed, "This value might be none, so it can't be safely used as an assignment target");
if (!index->index && container_t->tag == PointerType)
return compile(env, ast);
@@ -1060,7 +1060,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
if (clause->pattern->tag == Var) {
const char *clause_tag_name = Match(clause->pattern, Var)->name;
- code = CORD_all(code, "case ", namespace_prefix(enum_t->env, enum_t->env->namespace), "tag$", clause_tag_name, ": {\n",
+ code = CORD_all(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, CORD_all("tag$", clause_tag_name)), ": {\n",
compile_statement(env, clause->body),
"break;\n"
"}\n");
@@ -1071,7 +1071,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum type");
const char *clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name;
- code = CORD_all(code, "case ", namespace_prefix(enum_t->env, enum_t->env->namespace), "tag$", clause_tag_name, ": {\n");
+ code = CORD_all(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, CORD_all("tag$", clause_tag_name)), ": {\n");
type_t *tag_type = NULL;
for (tag_t *tag = enum_t->tags; tag; tag = tag->next) {
if (streq(tag->name, clause_tag_name)) {
@@ -1089,7 +1089,8 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
code_err(args->value, "This is not a valid variable to bind to");
const char *var_name = Match(args->value, Var)->name;
if (!streq(var_name, "_")) {
- code = CORD_all(code, compile_declaration(tag_type, compile(env, args->value)), " = _when_subject.", clause_tag_name, ";\n");
+ CORD var = CORD_all("_$", var_name);
+ code = CORD_all(code, compile_declaration(tag_type, var), " = _when_subject.", clause_tag_name, ";\n");
scope = fresh_scope(scope);
set_binding(scope, Match(args->value, Var)->name, tag_type, CORD_EMPTY);
}
@@ -1106,8 +1107,9 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
const char *var_name = Match(arg->value, Var)->name;
if (!streq(var_name, "_")) {
- code = CORD_all(code, compile_declaration(field->type, compile(env, arg->value)), " = _when_subject.", clause_tag_name, ".", field->name, ";\n");
- set_binding(scope, Match(arg->value, Var)->name, field->type, CORD_EMPTY);
+ CORD var = CORD_cat("_$", var_name);
+ code = CORD_all(code, compile_declaration(field->type, var), " = _when_subject.", clause_tag_name, ".", field->name, ";\n");
+ set_binding(scope, Match(arg->value, Var)->name, field->type, var);
}
field = field->next;
}
@@ -1859,7 +1861,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
}
if (fn->ret->tag == OptionalType) {
- // Use an optional variable `cur` for each iteration step, which will be checked for null
+ // Use an optional variable `cur` for each iteration step, which will be checked for none
code = CORD_all(code, compile_declaration(fn->ret, "cur"), ";\n");
get_next = CORD_all("(cur=", get_next, ", !", check_none(fn->ret, "cur"), ")");
if (for_->vars) {
@@ -1967,8 +1969,11 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
case Use: {
DeclareMatch(use, ast, Use);
if (use->what == USE_LOCAL) {
- CORD name = file_base_id(Match(ast, Use)->path);
- return with_source_info(env, ast, CORD_all("_$", name, "$$initialize();\n"));
+ Path_t path = Path$from_str(Match(ast, Use)->path);
+ Path_t in_file = Path$from_str(ast->file->filename);
+ path = Path$resolved(path, Path$parent(in_file));
+ CORD suffix = get_id_suffix(Path$as_c_string(path));
+ return with_source_info(env, ast, CORD_all("$initialize", suffix, "();\n"));
} else if (use->what == USE_MODULE) {
glob_t tm_files;
if (glob(String(TOMO_HOME"/installed/", use->path, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0)
@@ -1976,17 +1981,11 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
CORD initialization = CORD_EMPTY;
- char *lib_id = String(use->path);
- for (char *p = lib_id; *p; p++) {
- if (!isalnum(*p) && *p != '_')
- *p = '_';
- }
-
for (size_t i = 0; i < tm_files.gl_pathc; i++) {
const char *filename = tm_files.gl_pathv[i];
initialization = CORD_all(
initialization,
- with_source_info(env, ast, CORD_all("_$", lib_id, "$", file_base_id(filename), "$$initialize();\n")));
+ with_source_info(env, ast, CORD_all("$initialize", get_id_suffix(filename), "();\n")));
}
globfree(&tm_files);
return initialization;
@@ -2582,11 +2581,11 @@ CORD compile_none(type_t *t)
case CStringType: return "NULL";
case PointerType: return CORD_all("((", compile_type(t), ")NULL)");
case ClosureType: return "NONE_CLOSURE";
- case NumType: return "nan(\"null\")";
+ case NumType: return "nan(\"none\")";
case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_none=true})");
case EnumType: {
env_t *enum_env = Match(t, EnumType)->env;
- return CORD_all("((", compile_type(t), "){", namespace_prefix(enum_env, enum_env->namespace), "null})");
+ return CORD_all("((", compile_type(t), "){", namespace_name(enum_env, enum_env->namespace, "none"), "})");
}
default: compiler_err(NULL, NULL, NULL, "none isn't implemented for this type: ", type_to_str(t));
}
@@ -2712,8 +2711,8 @@ CORD compile(env_t *env, ast_t *ast)
binding_t *b = get_binding(env, Match(ast, Var)->name);
if (b)
return b->code ? b->code : CORD_cat("_$", Match(ast, Var)->name);
- return CORD_cat("_$", Match(ast, Var)->name);
- // code_err(ast, "I don't know of any variable by this name");
+ // return CORD_cat("_$", Match(ast, Var)->name);
+ code_err(ast, "I don't know of any variable by this name");
}
case Int: {
const char *str = Match(ast, Int)->str;
@@ -2899,7 +2898,7 @@ CORD compile(env_t *env, ast_t *ast)
if (!lang || streq(lang, "Text"))
lang_constructor = "Text";
else
- lang_constructor = CORD_all(namespace_prefix(Match(text_t, TextType)->env, Match(text_t, TextType)->env->namespace->parent), lang);
+ lang_constructor = namespace_name(Match(text_t, TextType)->env, Match(text_t, TextType)->env->namespace->parent, lang);
ast_list_t *chunks = Match(ast, TextJoin)->children;
if (!chunks) {
@@ -3038,7 +3037,7 @@ CORD compile(env_t *env, ast_t *ast)
}
case Lambda: {
DeclareMatch(lambda, ast, Lambda);
- CORD name = CORD_all(namespace_prefix(env, env->namespace), "lambda$", String(lambda->id));
+ CORD name = namespace_name(env, env->namespace, CORD_all("lambda$", String(lambda->id)));
env->code->function_naming = CORD_all(
env->code->function_naming,
@@ -3817,13 +3816,13 @@ CORD compile(env_t *env, ast_t *ast)
DeclareMatch(e, value_t, EnumType);
for (tag_t *tag = e->tags; tag; tag = tag->next) {
if (streq(f->field, tag->name)) {
- CORD prefix = namespace_prefix(e->env, e->env->namespace);
+ CORD tag_name = namespace_name(e->env, e->env->namespace, CORD_all("tag$", tag->name));
if (fielded_t->tag == PointerType) {
CORD fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
- return CORD_all("((", fielded, ")->$tag == ", prefix, "tag$", tag->name, ")");
+ return CORD_all("((", fielded, ")->$tag == ", tag_name, ")");
} else {
CORD fielded = compile(env, f->fielded);
- return CORD_all("((", fielded, ").$tag == ", prefix, "tag$", tag->name, ")");
+ return CORD_all("((", fielded, ").$tag == ", tag_name, ")");
}
}
}
@@ -3963,15 +3962,15 @@ CORD compile_type_info(type_t *t)
DeclareMatch(text, t, TextType);
if (!text->lang || streq(text->lang, "Text"))
return "&Text$info";
- return CORD_all("(&", namespace_prefix(text->env, text->env->namespace->parent), text->lang, "$$info)");
+ return CORD_all("(&", namespace_name(text->env, text->env->namespace, "$info"), ")");
}
case StructType: {
DeclareMatch(s, t, StructType);
- return CORD_all("(&", namespace_prefix(s->env, s->env->namespace->parent), s->name, "$$info)");
+ return CORD_all("(&", namespace_name(s->env, s->env->namespace, "$info"), ")");
}
case EnumType: {
DeclareMatch(e, t, EnumType);
- return CORD_all("(&", namespace_prefix(e->env, e->env->namespace->parent), e->name, "$$info)");
+ return CORD_all("(&", namespace_name(e->env, e->env->namespace, "$info"), ")");
}
case ListType: {
type_t *item_t = Match(t, ListType)->item_type;
@@ -4182,13 +4181,12 @@ CORD compile_function(env_t *env, CORD name_code, ast_t *ast, CORD *staticdefs)
}
env_t *body_scope = fresh_scope(env);
- while (body_scope->namespace && body_scope->namespace->parent) {
+ while (body_scope->namespace) {
body_scope->locals->fallback = body_scope->locals->fallback->fallback;
body_scope->namespace = body_scope->namespace->parent;
}
body_scope->deferred = NULL;
- body_scope->namespace = NULL;
for (arg_ast_t *arg = args; arg; arg = arg->next) {
type_t *arg_type = get_arg_ast_type(env, arg);
set_binding(body_scope, arg->name, arg_type, CORD_cat("_$", arg->name));
@@ -4330,7 +4328,7 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
case Declare: {
DeclareMatch(decl, ast, Declare);
const char *decl_name = Match(decl->var, Var)->name;
- CORD full_name = CORD_all(namespace_prefix(env, env->namespace), decl_name);
+ CORD full_name = namespace_name(env, env->namespace, decl_name);
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
if (t->tag == FunctionType) t = Type(ClosureType, t);
CORD val_code = compile_declared_value(env, ast);
@@ -4341,17 +4339,19 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
is_private ? "static " : "public ",
compile_declaration(t, full_name), " = ", val_code, ";\n");
} else {
- CORD checked_access = CORD_all("check_initialized(", full_name, ", \"", decl_name, "\")");
+ CORD init_var = namespace_name(env, env->namespace, CORD_all(decl_name, "$$initialized"));
+ CORD checked_access = CORD_all("check_initialized(", full_name, ", ", init_var, ", \"", decl_name, "\")");
set_binding(env, decl_name, t, checked_access);
+ CORD initialized_name = namespace_name(env, env->namespace, CORD_all(decl_name, "$$initialized"));
return CORD_all(
- "static bool ", full_name, "$initialized = false;\n",
+ "static bool ", initialized_name, " = false;\n",
is_private ? "static " : "public ",
compile_declaration(t, full_name), ";\n");
}
}
case FunctionDef: {
- CORD name_code = CORD_all(namespace_prefix(env, env->namespace), Match(Match(ast, FunctionDef)->name, Var)->name);
+ CORD name_code = namespace_name(env, env->namespace, Match(Match(ast, FunctionDef)->name, Var)->name);
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case ConvertDef: {
@@ -4359,7 +4359,7 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
const char *name = get_type_name(Match(type, FunctionType)->ret);
if (!name)
code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(Match(type, FunctionType)->ret));
- CORD name_code = CORD_all(namespace_prefix(env, env->namespace), name, "$", String(get_line_number(ast->file, ast->start)));
+ CORD name_code = namespace_name(env, env->namespace, CORD_all(name, "$", String(get_line_number(ast->file, ast->start))));
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case StructDef: {
@@ -4379,8 +4379,8 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
}
case LangDef: {
DeclareMatch(def, ast, LangDef);
- CORD code = CORD_all("public const TypeInfo_t ", namespace_prefix(env, env->namespace),
- def->name, "$$info = {", String((int64_t)sizeof(Text_t)), ", ", String((int64_t)__alignof__(Text_t)),
+ CORD code = CORD_all("public const TypeInfo_t ", namespace_name(env, env->namespace, CORD_all(def->name, "$$info")),
+ " = {", String((int64_t)sizeof(Text_t)), ", ", String((int64_t)__alignof__(Text_t)),
", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", CORD_quoted(def->name), "}};\n");
env_t *ns_env = namespace_env(env, def->name);
return CORD_all(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : CORD_EMPTY);
@@ -4392,7 +4392,7 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
*extended = *ns_env;
extended->locals = new(Table_t, .fallback=env->locals);
extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
- extended->libname = env->libname;
+ extended->id_suffix = env->id_suffix;
return compile_top_level_code(extended, extend->body);
}
case Extern: return CORD_EMPTY;
@@ -4418,18 +4418,19 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast)
} else if (stmt->ast->tag == Declare) {
DeclareMatch(decl, stmt->ast, Declare);
const char *decl_name = Match(decl->var, Var)->name;
- CORD full_name = CORD_all(namespace_prefix(env, env->namespace), decl_name);
+ CORD full_name = namespace_name(env, env->namespace, decl_name);
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
if (t->tag == FunctionType) t = Type(ClosureType, t);
CORD val_code = compile_declared_value(env, stmt->ast);
if ((decl->value && !is_constant(env, decl->value)) || (!decl->value && has_heap_memory(t))) {
+ CORD initialized_name = namespace_name(env, env->namespace, CORD_all(decl_name, "$$initialized"));
env->code->variable_initializers = CORD_all(
env->code->variable_initializers,
with_source_info(
env, stmt->ast,
CORD_all(
full_name, " = ", val_code, ",\n",
- full_name, "$initialized = true;\n")));
+ initialized_name, " = true;\n")));
}
} else if (stmt->ast->tag == StructDef) {
initialize_vars_and_statics(namespace_env(env, Match(stmt->ast, StructDef)->name),
@@ -4485,7 +4486,7 @@ CORD compile_file(env_t *env, ast_t *ast)
env->code->lambdas, "\n",
env->code->staticdefs, "\n",
top_level_code,
- "public void ", namespace_prefix(env, env->namespace), "$initialize(void) {\n",
+ "public void ", namespace_name(env, env->namespace, "$initialize"), "(void) {\n",
"static bool initialized = false;\n",
"if (initialized) return;\n",
"initialized = true;\n",
@@ -4532,13 +4533,13 @@ CORD compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
}
case LangDef: {
DeclareMatch(def, ast, LangDef);
- CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
+ CORD full_name = namespace_name(env, env->namespace, def->name);
return CORD_all(
// Constructor macro:
- "#define ", namespace_prefix(env, env->namespace), def->name,
- "(text) ((", namespace_prefix(env, env->namespace), def->name, "$$type){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n"
- "#define ", namespace_prefix(env, env->namespace), def->name,
- "s(...) ((", namespace_prefix(env, env->namespace), def->name, "$$type)Texts(__VA_ARGS__))\n"
+ "#define ", namespace_name(env, env->namespace, def->name),
+ "(text) ((", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n"
+ "#define ", namespace_name(env, env->namespace, def->name),
+ "s(...) ((", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), ")Texts(__VA_ARGS__))\n"
"extern const TypeInfo_t ", full_name, "$$info;\n"
);
}
@@ -4569,7 +4570,7 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a
*extended = *ns_env;
extended->locals = new(Table_t, .fallback=env->locals);
extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
- extended->libname = env->libname;
+ extended->id_suffix = env->id_suffix;
ns_env = extended;
block = extend->body;
@@ -4621,7 +4622,7 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a
return CORD_all(
decl->value ? compile_statement_type_header(env, header_path, decl->value) : CORD_EMPTY,
- "extern ", compile_declaration(t, CORD_cat(namespace_prefix(env, env->namespace), decl_name)), ";\n");
+ "extern ", compile_declaration(t, namespace_name(env, env->namespace, decl_name)), ";\n");
}
case FunctionDef: {
DeclareMatch(fndef, ast, FunctionDef);
@@ -4640,9 +4641,9 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a
CORD ret_type_code = compile_type(ret_t);
if (ret_t->tag == AbortType)
ret_type_code = CORD_all("__attribute__((noreturn)) _Noreturn ", ret_type_code);
- CORD name = CORD_all(namespace_prefix(env, env->namespace), decl_name);
+ CORD name = namespace_name(env, env->namespace, decl_name);
if (env->namespace && env->namespace->parent && env->namespace->name && streq(decl_name, env->namespace->name))
- name = CORD_all(namespace_prefix(env, env->namespace), String(get_line_number(ast->file, ast->start)));
+ name = namespace_name(env, env->namespace, String(get_line_number(ast->file, ast->start)));
return CORD_all(ret_type_code, " ", name, arg_signature, ";\n");
}
case ConvertDef: {
@@ -4661,8 +4662,7 @@ CORD compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *a
CORD name = get_type_name(ret_t);
if (!name)
code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t));
- name = CORD_all(namespace_prefix(env, env->namespace), name);
- CORD name_code = CORD_all(name, "$", String(get_line_number(ast->file, ast->start)));
+ CORD name_code = namespace_name(env, env->namespace, CORD_all(name, "$", String(get_line_number(ast->file, ast->start))));
return CORD_all(ret_type_code, " ", name_code, arg_signature, ";\n");
}
default: return CORD_EMPTY;
@@ -4686,20 +4686,24 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
if (ast->tag == StructDef) {
DeclareMatch(def, ast, StructDef);
if (def->external) return;
- CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
- *info->header = CORD_all(*info->header, "typedef struct ", full_name, "$$struct ", full_name, "$$type;\n");
+ CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct"));
+ CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type"));
+ *info->header = CORD_all(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n");
} else if (ast->tag == EnumDef) {
DeclareMatch(def, ast, EnumDef);
- CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
- *info->header = CORD_all(*info->header, "typedef struct ", full_name, "$$struct ", full_name, "$$type;\n");
+ CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct"));
+ CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type"));
+ *info->header = CORD_all(*info->header, "typedef struct ", struct_name, " ", type_name, ";\n");
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
- *info->header = CORD_all(*info->header, "typedef struct ", full_name, "$", tag->name, "$$struct ", full_name, "$", tag->name, "$$type;\n");
+ CORD tag_struct = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$struct"));
+ CORD tag_type = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$type"));
+ *info->header = CORD_all(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n");
}
} else if (ast->tag == LangDef) {
DeclareMatch(def, ast, LangDef);
- *info->header = CORD_all(*info->header, "typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "$$type;\n");
+ *info->header = CORD_all(*info->header, "typedef Text_t ", namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")), ";\n");
}
}
@@ -4721,7 +4725,7 @@ CORD compile_file_header(env_t *env, Path_t header_path, ast_t *ast)
visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_make_typedefs, &info});
visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_define_types_and_funcs, &info});
- header = CORD_all(header, "void ", namespace_prefix(env, env->namespace), "$initialize(void);\n");
+ header = CORD_all(header, "void ", namespace_name(env, env->namespace, "$initialize"), "(void);\n");
return header;
}
diff --git a/src/enums.c b/src/enums.c
index 9676918c..e391086e 100644
--- a/src/enums.c
+++ b/src/enums.c
@@ -16,7 +16,6 @@
CORD compile_enum_typeinfo(env_t *env, ast_t *ast)
{
DeclareMatch(def, ast, EnumDef);
- CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
// Compile member types and constructors:
CORD member_typeinfos = CORD_EMPTY;
@@ -36,7 +35,8 @@ CORD compile_enum_typeinfo(env_t *env, ast_t *ast)
type_t *t = Table$str_get(*env->types, def->name);
const char *metamethods = is_packed_data(t) ? "PackedDataEnum$metamethods" : "Enum$metamethods";
- CORD typeinfo = CORD_all("public const TypeInfo_t ", full_name, "$$info = {",
+ CORD info = namespace_name(env, env->namespace, CORD_all(def->name, "$$info"));
+ CORD typeinfo = CORD_all("public const TypeInfo_t ", info, " = {",
String((int64_t)type_size(t)), "u, ", String((int64_t)type_align(t)), "u, .metamethods=", metamethods,
", {.tag=EnumInfo, .EnumInfo={.name=\"", def->name, "\", "
".num_tags=", String((int64_t)num_tags), ", .tags=(NamedType_t[]){");
@@ -56,8 +56,6 @@ CORD compile_enum_typeinfo(env_t *env, ast_t *ast)
CORD compile_enum_constructors(env_t *env, ast_t *ast)
{
DeclareMatch(def, ast, EnumDef);
- CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
-
CORD constructors = CORD_EMPTY;
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
@@ -69,8 +67,11 @@ CORD compile_enum_constructors(env_t *env, ast_t *ast)
if (field->next) arg_sig = CORD_cat(arg_sig, ", ");
}
if (arg_sig == CORD_EMPTY) arg_sig = "void";
- CORD constructor_impl = CORD_all("public inline ", full_name, "$$type ", full_name, "$tagged$", tag->name, "(", arg_sig, ") { return (",
- full_name, "$$type){.$tag=", full_name, "$tag$", tag->name, ", .", tag->name, "={");
+ CORD type_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$type"));
+ CORD tagged_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tagged$", tag->name));
+ CORD tag_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name));
+ CORD constructor_impl = CORD_all("public inline ", type_name, " ", tagged_name, "(", arg_sig, ") { return (",
+ type_name, "){.$tag=", tag_name, ", .", tag->name, "={");
for (arg_ast_t *field = tag->fields; field; field = field->next) {
constructor_impl = CORD_all(constructor_impl, "$", field->name);
if (field->next) constructor_impl = CORD_cat(constructor_impl, ", ");
@@ -84,14 +85,16 @@ CORD compile_enum_constructors(env_t *env, ast_t *ast)
CORD compile_enum_header(env_t *env, ast_t *ast)
{
DeclareMatch(def, ast, EnumDef);
- CORD full_name = CORD_all(namespace_prefix(env, env->namespace), def->name);
CORD all_defs = CORD_EMPTY;
- CORD enum_def = CORD_all("struct ", full_name, "$$struct {\n"
- "\tenum { ", full_name, "$null=0, ");
+ CORD struct_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$struct"));
+ CORD none_name = namespace_name(env, env->namespace, CORD_all(def->name, "$none"));
+ CORD enum_def = CORD_all("struct ", struct_name, " {\n"
+ "\tenum { ", none_name, "=0, ");
bool has_any_tags_with_fields = false;
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
- enum_def = CORD_all(enum_def, full_name, "$tag$", tag->name);
+ CORD tag_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name));
+ enum_def = CORD_all(enum_def, tag_name);
if (tag->next) enum_def = CORD_all(enum_def, ", ");
has_any_tags_with_fields = has_any_tags_with_fields || (tag->fields != NULL);
}
@@ -103,14 +106,16 @@ CORD compile_enum_header(env_t *env, ast_t *ast)
if (!tag->fields) continue;
CORD field_def = compile_struct_header(env, WrapAST(ast, StructDef, .name=CORD_to_const_char_star(CORD_all(def->name, "$", tag->name)), .fields=tag->fields));
all_defs = CORD_all(all_defs, field_def);
- enum_def = CORD_all(enum_def, full_name, "$", tag->name, "$$type ", tag->name, ";\n");
+ CORD tag_type = namespace_name(env, env->namespace, CORD_all(def->name, "$", tag->name, "$$type"));
+ enum_def = CORD_all(enum_def, tag_type, " ", tag->name, ";\n");
}
enum_def = CORD_all(enum_def, "};\n");
}
enum_def = CORD_all(enum_def, "};\n");
all_defs = CORD_all(all_defs, enum_def);
- all_defs = CORD_all(all_defs, "extern const TypeInfo_t ", full_name, "$$info;\n");
+ CORD info = namespace_name(env, env->namespace, CORD_all(def->name, "$$info"));
+ all_defs = CORD_all(all_defs, "extern const TypeInfo_t ", info, ";\n");
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
@@ -121,7 +126,9 @@ CORD compile_enum_header(env_t *env, ast_t *ast)
if (field->next) arg_sig = CORD_all(arg_sig, ", ");
}
if (arg_sig == CORD_EMPTY) arg_sig = "void";
- CORD constructor_def = CORD_all(full_name, "$$type ", full_name, "$tagged$", tag->name, "(", arg_sig, ");\n");
+ CORD enum_type = namespace_name(env, env->namespace, CORD_all(def->name, "$$type"));
+ CORD tagged_name = namespace_name(env, env->namespace, CORD_all(def->name, "$tagged$", tag->name));
+ CORD constructor_def = CORD_all(enum_type, " ", tagged_name, "(", arg_sig, ");\n");
all_defs = CORD_all(all_defs, constructor_def);
}
return all_defs;
diff --git a/src/environment.c b/src/environment.c
index b950cf9e..227af572 100644
--- a/src/environment.c
+++ b/src/environment.c
@@ -2,11 +2,13 @@
// (variable bindings, code sections, etc.)
#include <stdlib.h>
#include <signal.h>
+#include <sys/stat.h>
#include "cordhelpers.h"
#include "environment.h"
#include "parse.h"
#include "stdlib/datatypes.h"
+#include "stdlib/paths.h"
#include "stdlib/tables.h"
#include "stdlib/text.h"
#include "stdlib/util.h"
@@ -531,18 +533,28 @@ env_t *global_env(bool source_mapping)
return env;
}
-CORD CONSTFUNC namespace_prefix(env_t *env, namespace_t *ns)
+CORD CONSTFUNC namespace_name(env_t *env, namespace_t *ns, CORD name)
{
- CORD prefix = CORD_EMPTY;
for (; ns; ns = ns->parent)
- prefix = CORD_all(ns->name, "$", prefix);
- if (env->locals != env->globals) {
- if (env->libname)
- prefix = CORD_all("_$", env->libname, "$", prefix);
- else
- prefix = CORD_all("_$", prefix);
+ name = CORD_all(ns->name, "$", name);
+ if (env->id_suffix)
+ name = CORD_all(name, env->id_suffix);
+ return name;
+}
+
+CORD get_id_suffix(const char *filename)
+{
+ assert(filename);
+ Path_t path = Path$from_str(filename);
+ Path_t build_dir = Path$with_component(Path$parent(path), Text(".build"));
+ if (mkdir(Path$as_c_string(build_dir), 0755) != 0) {
+ if (!Path$is_directory(build_dir, true))
+ err(1, "Could not make .build directory");
}
- return prefix;
+ Path_t id_file = Path$with_component(build_dir, Texts(Path$base_name(path), Text$from_str(".id")));
+ OptionalText_t id = Path$read(id_file);
+ if (id.length < 0) err(1, "Could not read ID file: ", id_file);
+ return Text$as_c_string(Texts(Text("$"), id));
}
env_t *load_module_env(env_t *env, ast_t *ast)
@@ -552,8 +564,9 @@ env_t *load_module_env(env_t *env, ast_t *ast)
if (cached) return cached;
env_t *module_env = fresh_scope(env);
module_env->code = new(compilation_unit_t);
- module_env->namespace = new(namespace_t, .name=file_base_id(name));
module_env->namespace_bindings = module_env->locals;
+ module_env->id_suffix = get_id_suffix(ast->file->filename);
+
Table$str_set(module_env->imports, name, module_env);
ast_list_t *statements = Match(ast, Block)->statements;
diff --git a/src/environment.h b/src/environment.h
index 1c6d52a5..74de3449 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -48,7 +48,7 @@ typedef struct env_s {
type_t *fn_ret;
loop_ctx_t *loop_ctx;
deferral_t *deferred;
- CORD libname; // Currently compiling library name (if any)
+ const char *id_suffix;
namespace_t *namespace;
Closure_t *comprehension_action;
bool do_source_mapping:1;
@@ -61,7 +61,8 @@ typedef struct {
env_t *global_env(bool source_mapping);
env_t *load_module_env(env_t *env, ast_t *ast);
-CORD namespace_prefix(env_t *env, namespace_t *ns);
+CORD namespace_name(env_t *env, namespace_t *ns, CORD name);
+CORD get_id_suffix(const char *filename);
env_t *get_namespace_by_type(env_t *env, type_t *t);
env_t *namespace_scope(env_t *env);
env_t *fresh_scope(env_t *env);
diff --git a/src/parse.c b/src/parse.c
index 12fafc0c..fcbf7e6b 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1723,6 +1723,13 @@ PARSER(parse_declaration) {
return NewAST(ctx->file, start, pos, Declare, .var=var, .type=type, .value=val);
}
+PARSER(parse_top_declaration) {
+ ast_t *declaration = parse_declaration(ctx, pos);
+ if (declaration)
+ declaration->__data.Declare.top_level = true;
+ return declaration;
+}
+
PARSER(parse_update) {
const char *start = pos;
ast_t *lhs = optional(ctx, &pos, parse_expr);
@@ -1948,7 +1955,7 @@ PARSER(parse_file_body) {
||(stmt=optional(ctx, &pos, parse_use))
||(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;
diff --git a/src/stdlib/files.c b/src/stdlib/files.c
index 900129f8..87b0205c 100644
--- a/src/stdlib/files.c
+++ b/src/stdlib/files.c
@@ -79,23 +79,6 @@ public char *file_base_name(const char *path)
return buf;
}
-public char *file_base_id(const char *path)
-{
- const char *slash = strrchr(path, '/');
- if (slash) path = slash + 1;
- assert(!isdigit(*path));
- const char *end = path + strcspn(path, ".");
- size_t len = (size_t)(end - path);
- char *buf = GC_MALLOC_ATOMIC(len+1);
- strncpy(buf, path, len);
- buf[len] = '\0';
- for (char *p = buf; *p; p++) {
- if (!isalnum(*p))
- *p = '_';
- }
- return buf;
-}
-
static file_t *_load_file(const char* filename, FILE *file)
{
if (!file) return NULL;
diff --git a/src/stdlib/files.h b/src/stdlib/files.h
index 68827c2a..f650f78e 100644
--- a/src/stdlib/files.h
+++ b/src/stdlib/files.h
@@ -18,8 +18,6 @@ typedef struct {
char *resolve_path(const char *path, const char *relative_to, const char *system_path);
__attribute__((pure, nonnull))
char *file_base_name(const char *path);
-__attribute__((pure, nonnull))
-char *file_base_id(const char *path);
__attribute__((nonnull))
file_t *load_file(const char *filename);
__attribute__((nonnull, returns_nonnull))
diff --git a/src/stdlib/nums.c b/src/stdlib/nums.c
index 3213fd2f..34fbb162 100644
--- a/src/stdlib/nums.c
+++ b/src/stdlib/nums.c
@@ -105,7 +105,7 @@ public OptionalNum_t Num$parse(Text_t text) {
if (end > str && end[0] == '\0')
return d;
else
- return nan("null");
+ return nan("none");
}
static bool Num$is_none(const void *n, const TypeInfo_t *info)
@@ -210,7 +210,7 @@ public OptionalNum32_t Num32$parse(Text_t text) {
if (end > str && end[0] == '\0')
return d;
else
- return nan("null");
+ return nan("none");
}
static bool Num32$is_none(const void *n, const TypeInfo_t *info)
diff --git a/src/stdlib/util.h b/src/stdlib/util.h
index 25cd49f9..3b00e6e9 100644
--- a/src/stdlib/util.h
+++ b/src/stdlib/util.h
@@ -14,7 +14,7 @@
#define new(t, ...) ((t*)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t)))
#define heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x))
#define stack(x) (__typeof(x)*)((__typeof(x)[1]){x})
-#define check_initialized(var, name) *({ if (!var ## $initialized) fail("The variable " name " is being accessed before it has been initialized!"); \
+#define check_initialized(var, init_var, name) *({ if (!init_var) fail("The variable " name " is being accessed before it has been initialized!"); \
&var; })
#define IF_DECLARE(decl, expr, block) if (({ decl; expr ? ({ block; 1; }) : 0; })) {}
diff --git a/src/structs.c b/src/structs.c
index cad6fea2..b398b871 100644
--- a/src/structs.c
+++ b/src/structs.c
@@ -14,8 +14,8 @@
CORD compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque)
{
- CORD typeinfo_name = CORD_all(namespace_prefix(env, env->namespace), name, "$$info");
- CORD type_code = Match(t, StructType)->external ? name : CORD_all("struct ", namespace_prefix(env, env->namespace), name, "$$struct");
+ CORD typeinfo_name = namespace_name(env, env->namespace, CORD_cat(name, "$$info"));
+ CORD type_code = Match(t, StructType)->external ? name : CORD_all("struct ", namespace_name(env, env->namespace, CORD_cat(name, "$$struct")));
int num_fields = 0;
for (arg_ast_t *f = fields; f; f = f->next)
@@ -47,8 +47,8 @@ CORD compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t
CORD compile_struct_header(env_t *env, ast_t *ast)
{
DeclareMatch(def, ast, StructDef);
- CORD typeinfo_name = CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info");
- CORD type_code = def->external ? def->name : CORD_all("struct ", namespace_prefix(env, env->namespace), def->name, "$$struct");
+ CORD typeinfo_name = namespace_name(env, env->namespace, CORD_all(def->name, "$$info"));
+ CORD type_code = def->external ? def->name : CORD_all("struct ", namespace_name(env, env->namespace, CORD_all(def->name, "$$struct")));
CORD fields = CORD_EMPTY;
for (arg_ast_t *field = def->fields; field; field = field->next) {
@@ -70,9 +70,8 @@ CORD compile_struct_header(env_t *env, ast_t *ast)
CORD optional_code = CORD_EMPTY;
if (!def->opaque) {
optional_code = CORD_all("DEFINE_OPTIONAL_TYPE(", compile_type(t), ", ", unpadded_size, ",",
- namespace_prefix(env, env->namespace), "$Optional", def->name, "$$type);\n");
+ namespace_name(env, env->namespace, CORD_all("$Optional", def->name, "$$type")), ");\n");
}
return CORD_all(struct_code, optional_code, typeinfo_code);
}
-
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/tomo.c b/src/tomo.c
index dd61891e..ba6c3995 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -91,7 +91,6 @@ static void transpile_code(env_t *base_env, Path_t path);
static void compile_object_file(Path_t path);
static Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t object_files, List_t extra_ldlibs);
static void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_link);
-static Text_t escape_lib_name(Text_t lib_name);
static void build_library(Path_t lib_dir);
static void install_library(Path_t lib_dir);
static void compile_files(env_t *env, List_t files, List_t *object_files, List_t *ldlibs);
@@ -336,16 +335,6 @@ void wait_for_child_success(pid_t child)
}
}
-Text_t escape_lib_name(Text_t lib_name)
-{
- char *libname_id = String(lib_name);
- for (char *p = libname_id; *p; p++) {
- if (!isalnum(*p) && *p != '_')
- *p = '_';
- }
- return Text$from_str(libname_id);
-}
-
Path_t build_file(Path_t path, const char *extension)
{
Path_t build_dir = Path$with_component(Path$parent(path), Text(".build"));
@@ -386,20 +375,24 @@ static void _make_typedefs_for_library(libheader_info_t *info, ast_t *ast)
{
if (ast->tag == StructDef) {
DeclareMatch(def, ast, StructDef);
- CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
- CORD_put(CORD_all("typedef struct ", full_name, "$$struct ", full_name, "$$type;\n"), info->output);
+ CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct"));
+ CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type"));
+ CORD_put(CORD_all("typedef struct ", struct_name, " ", type_name, ";\n"), info->output);
} else if (ast->tag == EnumDef) {
DeclareMatch(def, ast, EnumDef);
- CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
- CORD_put(CORD_all("typedef struct ", full_name, "$$struct ", full_name, "$$type;\n"), info->output);
+ CORD struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$struct"));
+ CORD type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type"));
+ CORD_put(CORD_all("typedef struct ", struct_name, " ", type_name, ";\n"), info->output);
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
- CORD_put(CORD_all("typedef struct ", full_name, "$", tag->name, "$$struct ", full_name, "$", tag->name, "$$type;\n"), info->output);
+ CORD tag_struct_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$struct"));
+ CORD tag_type_name = namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$", tag->name, "$$type"));
+ CORD_put(CORD_all("typedef struct ", tag_struct_name, " ", tag_type_name, ";\n"), info->output);
}
} else if (ast->tag == LangDef) {
DeclareMatch(def, ast, LangDef);
- CORD_put(CORD_all("typedef Text_t ", namespace_prefix(info->env, info->env->namespace), def->name, "$$type;\n"), info->output);
+ CORD_put(CORD_all("typedef Text_t ", namespace_name(info->env, info->env->namespace, CORD_all(def->name, "$$type")), ";\n"), info->output);
}
}
@@ -438,7 +431,7 @@ static void _compile_file_header_for_library(env_t *env, Path_t header_path, Pat
visit_topologically(
Match(file_ast, Block)->statements, (Closure_t){.fn=(void*)_compile_statement_header_for_library, &info});
- CORD_put(CORD_all("void ", namespace_prefix(module_env, module_env->namespace), "$initialize(void);\n"), output);
+ CORD_put(CORD_all("void ", namespace_name(module_env, module_env->namespace, "$initialize"), "(void);\n"), output);
}
void build_library(Path_t lib_dir)
@@ -455,10 +448,6 @@ void build_library(Path_t lib_dir)
compile_files(env, tm_files, &object_files, &extra_ldlibs);
- // Library name replaces all stretchs of non-alphanumeric chars with an underscore
- // So e.g. https://github.com/foo/baz --> https_github_com_foo_baz
- env->libname = Text$as_c_string(escape_lib_name(lib_dir_name));
-
// Build a "whatever.h" header that loads all the headers:
Path_t header_path = Path$with_component(lib_dir, Texts(lib_dir_name, Text(".h")));
FILE *header = fopen(String(header_path), "w");
@@ -473,28 +462,8 @@ void build_library(Path_t lib_dir)
if (fclose(header) == -1)
print_err("Failed to write header file: ", header_path);
- // Build up a list of symbol renamings:
- Path_t build_dir = Path$with_component(lib_dir, Text(".build"));
- Path_t symbol_renames = Path$with_component(build_dir, Text("symbol_renames.txt"));
- if (is_stale_for_any(symbol_renames, object_files)) {
- Path$remove(symbol_renames, true);
- FILE *prog;
- for (int64_t i = 0; i < object_files.length; i++) {
- Path_t obj = *(Path_t*)(object_files.data + i*object_files.stride);
- prog = run_cmd("nm -g '", obj, "' | awk '$2~/^[DTB]$/ && $3~/^_\\$/{print $3 \" _$",
- CORD_to_const_char_star(env->libname), "\" substr($3,2)}' "
- ">>", symbol_renames);
- if (!prog) print_err("Could not find symbols!");
- int status = pclose(prog);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- errx(WEXITSTATUS(status), "Failed to create symbol rename table with `nm` and `awk`");
- }
- } else {
- if (verbose) whisper("Unchanged: ", symbol_renames);
- }
-
Path_t shared_lib = Path$with_component(lib_dir, Texts(Text("lib"), lib_dir_name, Text(SHARED_SUFFIX)));
- if (!is_stale_for_any(shared_lib, object_files) && !is_stale(shared_lib, symbol_renames)) {
+ if (!is_stale_for_any(shared_lib, object_files)) {
if (verbose) whisper("Unchanged: ", shared_lib);
return;
}
@@ -515,28 +484,6 @@ void build_library(Path_t lib_dir)
if (!quiet)
print("Compiled library:\t", shared_lib);
-
- prog = run_cmd("objcopy --redefine-syms='", symbol_renames, "' '", shared_lib, "'");
- status = pclose(prog);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- errx(WEXITSTATUS(status), "Failed to run `objcopy` to add library prefix to symbols");
-
-#if defined(__ELF__)
- prog = run_cmd("patchelf --rename-dynamic-symbols '", symbol_renames, "' '", shared_lib, "'");
- status = pclose(prog);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- errx(WEXITSTATUS(status), "Failed to run `patchelf` to rename dynamic symbols with library prefix");
-#elif defined(__MACH__)
- prog = run_cmd("llvm-objcopy --redefine-syms='", symbol_renames, "' '", shared_lib, "'");
- status = pclose(prog);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- errx(WEXITSTATUS(status), "Failed to run `llvm-objcopy` to rename dynamic symbols with library prefix");
-#else
-#error "Unknown platform (not ELF or MACH)"
-#endif
-
- if (verbose)
- print("Successfully renamed symbols with library prefix!");
}
void install_library(Path_t lib_dir)
@@ -549,6 +496,7 @@ void install_library(Path_t lib_dir)
if (verbose) whisper("Moving files to ", dest);
xsystem("mkdir -p '", dest, "'");
xsystem("cp -r '", lib_dir, "'/* '", dest, "/'");
+ xsystem("cp -r '", lib_dir, "'/.build '", dest, "/'");
}
if (verbose) whisper("Linking "TOMO_HOME"/lib/lib", lib_dir_name, SHARED_SUFFIX);
xsystem("mkdir -p '"TOMO_HOME"'/lib/");
@@ -564,6 +512,8 @@ void install_library(Path_t lib_dir)
print("Installed \033[1m", lib_dir_name, "\033[m to "TOMO_HOME"/installed");
}
+#include "stdlib/random.h"
+
void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *extra_ldlibs)
{
Table_t to_link = {};
@@ -578,6 +528,33 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *
build_file_dependency_graph(filename, &dependency_files, &to_link);
}
+ // Make sure all files and dependencies have a .id file:
+ for (int64_t i = 0; i < dependency_files.entries.length; i++) {
+ struct {
+ Path_t filename;
+ staleness_t staleness;
+ } *entry = (dependency_files.entries.data + i*dependency_files.entries.stride);
+
+ Path_t id_file = build_file(entry->filename, ".id");
+ if (!Path$exists(id_file)) {
+ static const char id_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ char id_str[8];
+ for (int j = 0; j < (int)sizeof(id_str); j++) {
+ id_str[j] = id_chars[random_range(0, sizeof(id_chars)-1)];
+ }
+ Text_t filename_id = Text("");
+ Text_t base = Path$base_name(entry->filename);
+ TextIter_t state = NEW_TEXT_ITER_STATE(base);
+ for (int64_t j = 0; j < base.length; j++) {
+ uint32_t c = Text$get_main_grapheme_fast(&state, j);
+ if (c == '.') break;
+ if (isalpha(c) || isdigit(c) || c == '_')
+ filename_id = Texts(filename_id, Text$from_strn((char[]){(char)c}, 1));
+ }
+ Path$write(id_file, Texts(filename_id, Text("_"), Text$from_strn(id_str, sizeof(id_str))), 0644);
+ }
+ }
+
// (Re)compile header files, eagerly for explicitly passed in files, lazily
// for downstream dependencies:
for (int64_t i = 0; i < dependency_files.entries.length; i++) {
@@ -585,6 +562,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *
Path_t filename;
staleness_t staleness;
} *entry = (dependency_files.entries.data + i*dependency_files.entries.stride);
+
if (entry->staleness.h || clean_build) {
transpile_header(env, entry->filename);
entry->staleness.o = true;
@@ -661,8 +639,8 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l
return;
staleness_t staleness = {
- .h=is_stale(build_file(path, ".h"), path),
- .c=is_stale(build_file(path, ".c"), path),
+ .h=is_stale(build_file(path, ".h"), path) || is_stale(build_file(path, ".h"), build_file(path, ".id")),
+ .c=is_stale(build_file(path, ".c"), path) || is_stale(build_file(path, ".c"), build_file(path, ".id")),
};
staleness.o = staleness.c || staleness.h
|| is_stale(build_file(path, ".o"), build_file(path, ".c"))
@@ -807,7 +785,7 @@ void transpile_code(env_t *base_env, Path_t path)
"int ", main_binding->code, "$parse_and_run(int argc, char *argv[]) {\n",
module_env->do_source_mapping ? "#line 1\n" : CORD_EMPTY,
"tomo_init();\n",
- namespace_prefix(module_env, module_env->namespace), "$initialize();\n"
+ namespace_name(module_env, module_env->namespace, "$initialize"), "();\n"
"\n",
compile_cli_arg_call(module_env, main_binding->code, main_binding->type),
"return 0;\n"
diff --git a/src/typecheck.c b/src/typecheck.c
index 6c483511..0247c926 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -188,19 +188,13 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
env_t *module_env = fresh_scope(env);
Table$str_set(env->imports, use->path, module_env);
- char *libname_id = String(use->path);
- for (char *p = libname_id; *p; p++) {
- if (!isalnum(*p) && *p != '_')
- *p = '_';
- }
- module_env->libname = libname_id;
+
for (size_t i = 0; i < tm_files.gl_pathc; i++) {
const char *filename = tm_files.gl_pathv[i];
ast_t *ast = parse_file(filename, NULL);
if (!ast) print_err("Could not compile file ", filename);
env_t *module_file_env = fresh_scope(module_env);
- char *file_prefix = file_base_id(filename);
- module_file_env->namespace = new(namespace_t, .name=file_prefix);
+ module_file_env->namespace = NULL;
env_t *subenv = load_module_env(module_file_env, ast);
for (int64_t j = 0; j < subenv->locals->entries.length; j++) {
struct {
@@ -236,7 +230,7 @@ void prebind_statement(env_t *env, ast_t *statement)
type_t *type = Type(StructType, .name=def->name, .opaque=true, .external=def->external, .env=ns_env); // placeholder
Table$str_set(env->types, def->name, type);
set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
- CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info"));
+ namespace_name(env, env->namespace, CORD_all(def->name, "$$info")));
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
prebind_statement(ns_env, stmt->ast);
break;
@@ -250,7 +244,7 @@ void prebind_statement(env_t *env, ast_t *statement)
type_t *type = Type(EnumType, .name=def->name, .opaque=true, .env=ns_env); // placeholder
Table$str_set(env->types, def->name, type);
set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
- CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info"));
+ namespace_name(env, env->namespace, CORD_all(def->name, "$$info")));
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
prebind_statement(ns_env, stmt->ast);
break;
@@ -264,7 +258,7 @@ void prebind_statement(env_t *env, ast_t *statement)
type_t *type = Type(TextType, .lang=def->name, .env=ns_env);
Table$str_set(env->types, def->name, type);
set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
- CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info"));
+ namespace_name(env, env->namespace, CORD_all(def->name, "$$info")));
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
prebind_statement(ns_env, stmt->ast);
break;
@@ -276,7 +270,7 @@ void prebind_statement(env_t *env, ast_t *statement)
*extended = *ns_env;
extended->locals = new(Table_t, .fallback=env->locals);
extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
- extended->libname = env->libname;
+ extended->id_suffix = env->id_suffix;
for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next)
prebind_statement(extended, stmt->ast);
List_t new_bindings = extended->locals->entries;
@@ -320,8 +314,11 @@ void bind_statement(env_t *env, ast_t *statement)
code_err(statement, "I couldn't figure out the type of this value");
if (type->tag == FunctionType)
type = Type(ClosureType, type);
- CORD prefix = namespace_prefix(env, env->namespace);
- CORD code = CORD_cat(prefix ? prefix : "$", name);
+ CORD code;
+ if (name[0] != '_' && (env->namespace || decl->top_level))
+ code = namespace_name(env, env->namespace, name);
+ else
+ code = CORD_all("_$", name);
set_binding(env, name, type, code);
break;
}
@@ -329,8 +326,7 @@ void bind_statement(env_t *env, ast_t *statement)
DeclareMatch(def, statement, FunctionDef);
const char *name = Match(def->name, Var)->name;
type_t *type = get_function_def_type(env, statement);
- CORD code = CORD_all(namespace_prefix(env, env->namespace), name);
- set_binding(env, name, type, code);
+ set_binding(env, name, type, namespace_name(env, env->namespace, name));
break;
}
case ConvertDef: {
@@ -340,8 +336,8 @@ void bind_statement(env_t *env, ast_t *statement)
if (!name)
code_err(statement, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t));
- CORD code = CORD_all(namespace_prefix(env, env->namespace), name, "$",
- String(get_line_number(statement->file, statement->start)));
+ CORD code = namespace_name(env, env->namespace,
+ CORD_all(name, "$", String(get_line_number(statement->file, statement->start))));
binding_t binding = {.type=type, .code=code};
env_t *type_ns = get_namespace_by_type(env, ret_t);
List$insert(&type_ns->namespace->constructors, &binding, I(0), sizeof(binding));
@@ -435,9 +431,10 @@ void bind_statement(env_t *env, ast_t *statement)
for (tag_t *tag = tags; tag; tag = tag->next) {
if (Match(tag->type, StructType)->fields) { // Constructor:
type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type);
- set_binding(ns_env, tag->name, constructor_t, CORD_all(namespace_prefix(env, env->namespace), def->name, "$tagged$", tag->name));
+ set_binding(ns_env, tag->name, constructor_t, namespace_name(env, env->namespace, CORD_all(def->name, "$tagged$", tag->name)));
} else { // Empty singleton value:
- CORD code = CORD_all("((", namespace_prefix(env, env->namespace), def->name, "$$type){", namespace_prefix(env, env->namespace), def->name, "$tag$", tag->name, "})");
+ CORD code = CORD_all("((", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), "){",
+ namespace_name(env, env->namespace, CORD_all(def->name, "$tag$", tag->name)), "})");
set_binding(ns_env, tag->name, type, code);
}
Table$str_set(env->types, String(def->name, "$", tag->name), tag->type);
@@ -455,7 +452,7 @@ void bind_statement(env_t *env, ast_t *statement)
Table$str_set(env->types, def->name, type);
set_binding(ns_env, "from_text", NewFunctionType(type, {.name="text", .type=TEXT_TYPE}),
- CORD_all("(", namespace_prefix(env, env->namespace), def->name, "$$type)"));
+ CORD_all("(", namespace_name(env, env->namespace, CORD_all(def->name, "$$type")), ")"));
for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
bind_statement(ns_env, stmt->ast);
@@ -468,7 +465,7 @@ void bind_statement(env_t *env, ast_t *statement)
*extended = *ns_env;
extended->locals = new(Table_t, .fallback=env->locals);
extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
- extended->libname = env->libname;
+ extended->id_suffix = env->id_suffix;
for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next)
bind_statement(extended, stmt->ast);
List_t new_bindings = extended->locals->entries;