aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.md1
-rw-r--r--src/compile.c10
-rw-r--r--src/enums.c14
-rw-r--r--src/environment.c25
-rw-r--r--src/environment.h2
-rw-r--r--src/naming.c72
-rw-r--r--src/naming.h12
-rw-r--r--src/structs.c7
-rw-r--r--src/tomo.c1
-rw-r--r--src/typecheck.c1
10 files changed, 106 insertions, 39 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 2fd0c006..fade9357 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -43,6 +43,7 @@
C/assembly files or their `#include`s.
- Memory offsets for enums with different member alignments were miscalculated.
- Optional types with trailing padding were not correctly being detected as `none`
+ - Tomo identifiers that happened to coincide with C keywords were not allowed.
## v0.2
diff --git a/src/compile.c b/src/compile.c
index 2b714acf..1648363a 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -11,6 +11,7 @@
#include "enums.h"
#include "environment.h"
#include "modules.h"
+#include "naming.h"
#include "parse.h"
#include "stdlib/integers.h"
#include "stdlib/nums.h"
@@ -1120,7 +1121,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
const char *var_name = Match(args->value, Var)->name;
if (!streq(var_name, "_")) {
Text_t var = Texts("_$", var_name);
- code = Texts(code, compile_declaration(tag_type, var), " = _when_subject.", clause_tag_name, ";\n");
+ code = Texts(code, compile_declaration(tag_type, var), " = _when_subject.", valid_c_name(clause_tag_name), ";\n");
scope = fresh_scope(scope);
set_binding(scope, Match(args->value, Var)->name, tag_type, EMPTY_TEXT);
}
@@ -1138,7 +1139,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
const char *var_name = Match(arg->value, Var)->name;
if (!streq(var_name, "_")) {
Text_t var = Texts("_$", var_name);
- code = Texts(code, compile_declaration(field->type, var), " = _when_subject.", clause_tag_name, ".", field->name, ";\n");
+ code = Texts(code, compile_declaration(field->type, var), " = _when_subject.",
+ valid_c_name(clause_tag_name), ".", valid_c_name(field->name), ";\n");
set_binding(scope, Match(arg->value, Var)->name, field->type, var);
}
field = field->next;
@@ -3840,10 +3842,10 @@ Text_t compile(env_t *env, ast_t *ast)
if (streq(field->name, f->field)) {
if (fielded_t->tag == PointerType) {
Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
- return Texts("(", fielded, ")->", f->field);
+ return Texts("(", fielded, ")->", valid_c_name(f->field));
} else {
Text_t fielded = compile(env, f->fielded);
- return Texts("(", fielded, ").", f->field);
+ return Texts("(", fielded, ").", valid_c_name(f->field));
}
}
}
diff --git a/src/enums.c b/src/enums.c
index c6bd9560..113eb91d 100644
--- a/src/enums.c
+++ b/src/enums.c
@@ -4,12 +4,13 @@
#include <stdio.h>
#include "ast.h"
-#include "stdlib/text.h"
#include "compile.h"
-#include "structs.h"
#include "environment.h"
-#include "typecheck.h"
+#include "naming.h"
+#include "stdlib/text.h"
#include "stdlib/util.h"
+#include "structs.h"
+#include "typecheck.h"
Text_t compile_enum_typeinfo(env_t *env, ast_t *ast)
{
@@ -69,7 +70,7 @@ Text_t compile_enum_constructors(env_t *env, ast_t *ast)
Text_t tagged_name = namespace_name(env, env->namespace, Texts(def->name, "$tagged$", tag->name));
Text_t tag_name = namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name));
Text_t constructor_impl = Texts("public inline ", type_name, " ", tagged_name, "(", arg_sig, ") { return (",
- type_name, "){.$tag=", tag_name, ", .", tag->name, "={");
+ type_name, "){.$tag=", tag_name, ", .", valid_c_name(tag->name), "={");
for (arg_ast_t *field = tag->fields; field; field = field->next) {
constructor_impl = Texts(constructor_impl, "$", field->name);
if (field->next) constructor_impl = Texts(constructor_impl, ", ");
@@ -109,10 +110,11 @@ Text_t compile_enum_header(env_t *env, ast_t *ast)
"union {\n");
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
- Text_t field_def = compile_struct_header(env, WrapAST(ast, StructDef, .name=Text$as_c_string(Texts(def->name, "$", tag->name)), .fields=tag->fields));
+ Text_t field_def = compile_struct_header(
+ env, WrapAST(ast, StructDef, .name=Text$as_c_string(Texts(def->name, "$", tag->name)), .fields=tag->fields));
all_defs = Texts(all_defs, field_def);
Text_t tag_type = namespace_name(env, env->namespace, Texts(def->name, "$", tag->name, "$$type"));
- enum_def = Texts(enum_def, tag_type, " ", tag->name, ";\n");
+ enum_def = Texts(enum_def, tag_type, " ", valid_c_name(tag->name), ";\n");
}
enum_def = Texts(enum_def, "};\n};\n");
all_defs = Texts(all_defs, enum_def);
diff --git a/src/environment.c b/src/environment.c
index 3faad24d..f43e8daf 100644
--- a/src/environment.c
+++ b/src/environment.c
@@ -5,6 +5,7 @@
#include <sys/stat.h>
#include "environment.h"
+#include "naming.h"
#include "parse.h"
#include "stdlib/datatypes.h"
#include "stdlib/paths.h"
@@ -543,30 +544,6 @@ env_t *global_env(bool source_mapping)
return env;
}
-Text_t CONSTFUNC namespace_name(env_t *env, namespace_t *ns, Text_t name)
-{
- for (; ns; ns = ns->parent)
- name = Texts(ns->name, "$", name);
- if (env->id_suffix.length > 0)
- name = Texts(name, env->id_suffix);
- return name;
-}
-
-Text_t get_id_suffix(const char *filename)
-{
- assert(filename);
- Path_t path = Path$from_str(filename);
- Path_t build_dir = Path$sibling(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");
- }
- Path_t id_file = Path$child(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 Texts(Text("$"), id);
-}
-
env_t *load_module_env(env_t *env, ast_t *ast)
{
const char *name = ast->file->filename;
diff --git a/src/environment.h b/src/environment.h
index 18b749ed..eb5b55bc 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -60,8 +60,6 @@ typedef struct {
env_t *global_env(bool source_mapping);
env_t *load_module_env(env_t *env, ast_t *ast);
-Text_t namespace_name(env_t *env, namespace_t *ns, Text_t name);
-Text_t get_id_suffix(const char *filename);
env_t *get_namespace_by_type(env_t *env, type_t *t);
env_t *fresh_scope(env_t *env);
env_t *for_scope(env_t *env, ast_t *ast);
diff --git a/src/naming.c b/src/naming.c
new file mode 100644
index 00000000..abe87569
--- /dev/null
+++ b/src/naming.c
@@ -0,0 +1,72 @@
+// Logic for converting user's Tomo names into valid C identifiers
+
+#include <ctype.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "environment.h"
+#include "stdlib/paths.h"
+#include "stdlib/print.h"
+#include "stdlib/text.h"
+
+static const char *c_keywords[] = { // Maintain sorted order:
+ "_Alignas", "_Alignof", "_Atomic", "_BitInt", "_Bool", "_Complex", "_Decimal128", "_Decimal32", "_Decimal64", "_Generic",
+ "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local",
+ "alignas", "alignof", "auto", "bool", "break", "case", "char", "const", "constexpr", "continue", "default", "do", "double",
+ "else", "enum", "extern", "false", "float", "for", "goto", "if", "inline", "int", "long", "nullptr", "register", "restrict",
+ "return", "short", "signed", "sizeof", "static", "static_assert", "struct", "switch", "thread_local", "true", "typedef",
+ "typeof", "typeof_unqual", "union", "unsigned", "void", "volatile", "while",
+};
+
+static CONSTFUNC bool is_keyword(const char *word, size_t len) {
+ int64_t lo = 0, hi = sizeof(c_keywords)/sizeof(c_keywords[0])-1;
+ while (lo <= hi) {
+ int64_t mid = (lo + hi) / 2;
+ int32_t cmp = strncmp(word, c_keywords[mid], len);
+ if (cmp == 0)
+ return true;
+ else if (cmp > 0)
+ lo = mid + 1;
+ else if (cmp < 0)
+ hi = mid - 1;
+ }
+ return false;
+}
+
+public Text_t valid_c_name(const char *name)
+{
+ size_t len = strlen(name);
+ size_t trailing_underscores = 0;
+ while (trailing_underscores < len && name[len-1-trailing_underscores] == '_')
+ trailing_underscores += 1;
+ if (is_keyword(name, len-trailing_underscores)) {
+ return Texts(Text$from_str(name), Text("_"));
+ }
+ return Text$from_str(name);
+}
+
+public Text_t CONSTFUNC namespace_name(env_t *env, namespace_t *ns, Text_t name)
+{
+ for (; ns; ns = ns->parent)
+ name = Texts(ns->name, "$", name);
+ if (env->id_suffix.length > 0)
+ name = Texts(name, env->id_suffix);
+ return name;
+}
+
+public Text_t get_id_suffix(const char *filename)
+{
+ assert(filename);
+ Path_t path = Path$from_str(filename);
+ Path_t build_dir = Path$sibling(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");
+ }
+ Path_t id_file = Path$child(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 Texts(Text("$"), id);
+}
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/naming.h b/src/naming.h
new file mode 100644
index 00000000..30d4d061
--- /dev/null
+++ b/src/naming.h
@@ -0,0 +1,12 @@
+#pragma once
+
+// Compilation environments
+
+#include "environment.h"
+#include "stdlib/datatypes.h"
+
+Text_t valid_c_name(const char *name);
+Text_t namespace_name(env_t *env, namespace_t *ns, Text_t name);
+Text_t get_id_suffix(const char *filename);
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/structs.c b/src/structs.c
index 3e51f81b..873300c5 100644
--- a/src/structs.c
+++ b/src/structs.c
@@ -4,11 +4,12 @@
#include <stdio.h>
#include "ast.h"
-#include "stdlib/text.h"
#include "compile.h"
#include "environment.h"
-#include "typecheck.h"
+#include "naming.h"
+#include "stdlib/text.h"
#include "stdlib/util.h"
+#include "typecheck.h"
Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque)
{
@@ -60,7 +61,7 @@ Text_t compile_struct_header(env_t *env, ast_t *ast)
else if (field->value)
code_err(field->value, "This is an opaque type, so it can't be used as a struct field type");
}
- fields = Texts(fields, compile_declaration(field_t, Text$from_str(field->name)),
+ fields = Texts(fields, compile_declaration(field_t, valid_c_name(field->name)),
field_t->tag == BoolType ? Text(":1") : EMPTY_TEXT, ";\n");
}
Text_t struct_code = def->external ? EMPTY_TEXT : Texts(type_code, " {\n", fields, "};\n");
diff --git a/src/tomo.c b/src/tomo.c
index e105cb7a..e8012f9e 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -15,6 +15,7 @@
#include "ast.h"
#include "compile.h"
#include "modules.h"
+#include "naming.h"
#include "parse.h"
#include "stdlib/bools.h"
#include "stdlib/bytes.h"
diff --git a/src/typecheck.c b/src/typecheck.c
index d151c511..ba30931e 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -11,6 +11,7 @@
#include "ast.h"
#include "environment.h"
#include "modules.h"
+#include "naming.h"
#include "parse.h"
#include "stdlib/paths.h"
#include "stdlib/tables.h"