code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(119 lines)
1 // Logic for converting user's Tomo names into valid C identifiers
3 #include <string.h>
4 #include <sys/stat.h>
6 #include "environment.h"
7 #include "stdlib/paths.h"
8 #include "stdlib/text.h"
10 static const char *c_keywords[] = {
11 // Maintain sorted order:
12 "_Alignas",
13 "_Alignof",
14 "_Atomic",
15 "_BitInt",
16 "_Bool",
17 "_Complex",
18 "_Decimal128",
19 "_Decimal32",
20 "_Decimal64",
21 "_Generic",
22 "_Imaginary",
23 "_Noreturn",
24 "_Static_assert",
25 "_Thread_local",
26 "alignas",
27 "__alignof__",
28 "auto",
29 "bool",
30 "break",
31 "case",
32 "char",
33 "const",
34 "constexpr",
35 "continue",
36 "default",
37 "do",
38 "double",
39 "else",
40 "enum",
41 "extern",
42 "false",
43 "float",
44 "for",
45 "goto",
46 "if",
47 "inline",
48 "int",
49 "long",
50 "nullptr",
51 "register",
52 "restrict",
53 "return",
54 "short",
55 "signed",
56 "sizeof",
57 "static",
58 "static_assert",
59 "struct",
60 "switch",
61 "thread_local",
62 "true",
63 "typedef",
64 "typeof",
65 "typeof_unqual",
66 "union",
67 "unsigned",
68 "void",
69 "volatile",
70 "while",
71 };
73 static CONSTFUNC bool is_keyword(const char *word, size_t len) {
74 int64_t lo = 0, hi = sizeof(c_keywords) / sizeof(c_keywords[0]) - 1;
75 while (lo <= hi) {
76 int64_t mid = (lo + hi) / 2;
77 int32_t cmp = strncmp(word, c_keywords[mid], len + 1);
78 if (cmp == 0) return true;
79 else if (cmp > 0) lo = mid + 1;
80 else if (cmp < 0) hi = mid - 1;
82 return false;
85 public
86 Text_t valid_c_name(const char *name) {
87 size_t len = strlen(name);
88 size_t trailing_underscores = 0;
89 while (trailing_underscores < len && name[len - 1 - trailing_underscores] == '_')
90 trailing_underscores += 1;
91 if (is_keyword(name, len - trailing_underscores)) {
92 return Texts(Text$from_str(name), Text("_"));
94 return Text$from_str(name);
97 public
98 Text_t CONSTFUNC namespace_name(env_t *env, namespace_t *ns, Text_t name) {
99 for (; ns; ns = ns->parent) {
100 name = Texts(ns->name, "$", name);
102 if (env->id_suffix.length > 0) name = Texts(name, env->id_suffix);
103 return name;
106 public
107 Text_t get_id_suffix(const char *filename) {
108 assert(filename);
109 Path_t path = Path$from_str(filename);
110 Path_t build_dir = Path$sibling(path, Text(".build"));
111 if (mkdir(Path$as_c_string(build_dir), 0755) != 0) {
112 if (!Path$is_directory(build_dir, true)) err(1, "Could not make .build directory");
114 Path_t id_file = Path$child(build_dir, Texts(Path$base_name(path), Text$from_str(".id")));
115 OptionalText_t id = Path$read(id_file);
116 if (id.tag == TEXT_NONE) err(1, "Could not read ID file: %s", Path$as_c_string(id_file));
117 id = Text$trim(id, Text(" \r\n"), true, true);
118 return Texts("$", id);