Cthulhu  0.2.10
Cthulhu compiler collection
attrib.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-3.0-only
2 
3 #include "ctu/sema/attrib.h"
4 
5 #include "arena/arena.h"
6 #include "base/util.h"
8 #include "ctu/ast.h"
9 
10 #include "cthulhu/tree/query.h"
11 
12 #include "ctu/sema/sema.h"
13 
14 #include "std/str.h"
15 #include "std/vector.h"
16 
17 #include "core/macros.h"
18 
19 #include "memory/memory.h"
20 #include "base/panic.h"
21 
22 static const char *attrib_name(const vector_t *path, arena_t *arena)
23 {
24  return str_join("::", path, arena);
25 }
26 
27 static ctu_attrib_t *get_attrib(tree_t *sema, const vector_t *path, arena_t *arena)
28 {
29  CT_UNUSED(arena);
30 
31  CTASSERTF(vector_len(path) == 1, "expected 1 path element but got `%s`", attrib_name(path, arena));
32  const char *name = vector_tail(path);
33 
34  return ctu_get_attrib(sema, name);
35 }
36 
37 static ctu_attrib_t *attrib_create(const char *name, ctu_attrib_apply_t fn_apply, arena_t *arena)
38 {
39  CTASSERT(name != NULL);
40  CTASSERT(fn_apply != NULL);
41 
42  ctu_attrib_t *it = ARENA_MALLOC(sizeof(ctu_attrib_t), name, NULL, arena);
43  it->name = name;
44  it->fn_apply = fn_apply;
45  return it;
46 }
47 
48 static const char *get_first_string(tree_t *sema, tree_t *decl, const vector_t *args)
49 {
50  if (vector_len(args) != 1)
51  {
52  msg_notify(sema->reports, &kEvent_IncorrectParamCount, decl->node, "expected 1 string argument");
53  return NULL;
54  }
55 
56  ctu_t *arg = vector_tail(args);
57  if (arg->kind != eCtuExprString)
58  {
59  msg_notify(sema->reports, &kEvent_IncorrectParamType, arg->node, "expected string argument");
60  return NULL;
61  }
62 
63  return arg->text;
64 }
65 
66 #define MALFORMED_ENTRY(REPORTS, NODE) msg_notify(REPORTS, &kEvent_MalformedAttribute, NODE, "malformed entry point type, must be either `gui` or `cli`")
67 
68 static tree_linkage_t choose_linkage(tree_t *sema, const ctu_t *expr)
69 {
70  if (expr->kind != eCtuExprName)
71  {
72  MALFORMED_ENTRY(sema->reports, expr->node);
73  return eLinkEntryCli;
74  }
75 
76  const vector_t *path = expr->path;
77  if (vector_len(path) > 1)
78  {
79  MALFORMED_ENTRY(sema->reports, expr->node);
80  return eLinkEntryCli;
81  }
82 
83  const char *name = vector_tail(path);
84  if (str_equal(name, "gui"))
85  {
86  return eLinkEntryGui;
87  }
88 
89  if (str_equal(name, "cli"))
90  {
91  return eLinkEntryCli;
92  }
93 
94  MALFORMED_ENTRY(sema->reports, expr->node);
95  return eLinkEntryCli;
96 }
97 
98 static tree_linkage_t get_linkage(tree_t *sema, tree_t *decl, const vector_t *args)
99 {
100  switch (vector_len(args))
101  {
102  case 0: return eLinkEntryCli;
103  case 1: return choose_linkage(sema, vector_tail(args));
104 
105  default:
106  msg_notify(sema->reports, &kEvent_IncorrectParamCount, tree_get_node(decl), "entry attribute takes at most 1 argument, ignoring extra arguments");
107  return eLinkEntryCli;
108  }
109 }
110 
114 
115 static tree_attribs_t *dup_tree_attribs(const tree_attribs_t *attribs)
116 {
117  arena_t *arena = get_global_arena();
118  return arena_memdup(attribs, sizeof(tree_attribs_t), arena);
119 }
120 
121 static void apply_entry(tree_t *sema, tree_t *decl, const vector_t *args)
122 {
123  if (!tree_is(decl, eTreeDeclFunction))
124  {
125  msg_notify(sema->reports, &kEvent_InvalidAttributeApplication, decl->node, "entry attribute can only be applied to functions");
126  return;
127  }
128 
129  const tree_attribs_t *old = tree_get_attrib(decl);
130  if (old->link != eLinkModule && old->link != eLinkExport)
131  {
132  msg_notify(sema->reports, &kEvent_InvalidAttributeApplication, decl->node, "entry attribute can only be applied to public functions");
133  return;
134  }
135 
136  tree_attribs_t *copy = dup_tree_attribs(old);
137  copy->link = get_linkage(sema, decl, args);
138  tree_set_attrib(decl, copy);
139 }
140 
141 static void apply_deprecated(tree_t *sema, tree_t *decl, const vector_t *args)
142 {
143  if (!tree_is(decl, eTreeDeclFunction))
144  {
145  msg_notify(sema->reports, &kEvent_InvalidAttributeApplication, decl->node, "deprecated attribute can only be applied to functions");
146  return;
147  }
148 
149  const tree_attribs_t *old = tree_get_attrib(decl);
150  if (old->deprecated != NULL)
151  {
152  msg_notify(sema->reports, &kEvent_DuplicateAttribute, decl->node, "deprecated attribute already applied");
153  return;
154  }
155 
156  const char *msg = get_first_string(sema, decl, args);
157  if (msg == NULL) { return; }
158 
159  tree_attribs_t *copy = dup_tree_attribs(old);
160  copy->deprecated = msg;
161  tree_set_attrib(decl, copy);
162 }
163 
164 static void apply_section(tree_t *sema, tree_t *decl, const vector_t *args)
165 {
166  if (!tree_is(decl, eTreeDeclFunction))
167  {
168  msg_notify(sema->reports, &kEvent_InvalidAttributeApplication, decl->node, "section attribute can only be applied to functions");
169  return;
170  }
171 
172  const tree_attribs_t *old = tree_get_attrib(decl);
173  if (old->section != NULL)
174  {
175  msg_notify(sema->reports, &kEvent_DuplicateAttribute, decl->node, "section attribute already applied");
176  return;
177  }
178 
179  const char *msg = get_first_string(sema, decl, args);
180  if (msg == NULL) { return; }
181 
182  tree_attribs_t *copy = dup_tree_attribs(old);
183  copy->section = msg;
184  tree_set_attrib(decl, copy);
185 }
186 
187 static void apply_extern(tree_t *sema, tree_t *decl, const vector_t *args)
188 {
189  if (!tree_is(decl, eTreeDeclFunction))
190  {
191  msg_notify(sema->reports, &kEvent_InvalidAttributeApplication, decl->node, "`extern` can only be applied to functions");
192  return;
193  }
194 
195  const tree_attribs_t *old = tree_get_attrib(decl);
196  if (old->mangle != NULL)
197  {
198  msg_notify(sema->reports, &kEvent_DuplicateAttribute, decl->node, "`extern` already applied to this symbol");
199  return;
200  }
201 
202  tree_attribs_t *copy = dup_tree_attribs(old);
203  copy->link = eLinkImport;
204  if (vector_len(args) == 0)
205  {
206  copy->mangle = tree_get_name(decl);
207  }
208  else
209  {
210  const char *msg = get_first_string(sema, decl, args);
211  if (msg == NULL) { return; }
212 
213  copy->mangle = msg;
214  }
215  tree_set_attrib(decl, copy);
216 }
217 
218 static void apply_layout(tree_t *sema, tree_t *decl, const vector_t *args)
219 {
220  CT_UNUSED(args);
221 
222  if (!tree_is(decl, eTreeTypeStruct))
223  {
224  msg_notify(sema->reports, &kEvent_InvalidAttributeApplication, decl->node, "layout attribute can only be applied to structs");
225  return;
226  }
227 
228  msg_notify(sema->reports, &kEvent_UnimplementedAttribute, tree_get_node(decl), "layout attribute not implemented");
229 }
230 
231 void ctu_init_attribs(tree_t *sema, arena_t *arena)
232 {
233  ctu_attrib_t *entry = attrib_create("entry", apply_entry, arena);
234  tree_module_set(sema, eCtuTagAttribs, entry->name, entry);
235 
236  ctu_attrib_t *deprecated = attrib_create("deprecated", apply_deprecated, arena);
237  tree_module_set(sema, eCtuTagAttribs, deprecated->name, deprecated);
238 
239  ctu_attrib_t *section = attrib_create("section", apply_section, arena);
240  tree_module_set(sema, eCtuTagAttribs, section->name, section);
241 
242  ctu_attrib_t *attrib_extern = attrib_create("extern", apply_extern, arena);
243  tree_module_set(sema, eCtuTagAttribs, attrib_extern->name, attrib_extern);
244 
245  ctu_attrib_t *layout = attrib_create("layout", apply_layout, arena);
246  tree_module_set(sema, eCtuTagAttribs, layout->name, layout);
247 }
248 
249 void ctu_apply_attribs(tree_t *sema, tree_t *decl, const vector_t *attribs)
250 {
251  arena_t *arena = get_global_arena();
252  size_t len = vector_len(attribs);
253  for (size_t i = 0; i < len; i++)
254  {
255  ctu_t *attrib = vector_get(attribs, i);
256  CTASSERTF(attrib->kind == eCtuAttrib, "expected attrib but got %d", attrib->kind);
257 
258  ctu_attrib_t *it = get_attrib(sema, attrib->attrib_path, arena);
259  if (it == NULL)
260  {
261  msg_notify(sema->reports, &kEvent_AttribNotFound, attrib->node, "attrib '%s' not found", attrib_name(attrib->attrib_path, arena));
262  continue;
263  }
264 
265  it->fn_apply(sema, decl, attrib->attrib_args);
266  }
267 }
void ctu_apply_attribs(tree_t *sema, tree_t *decl, const vector_t *attribs)
Definition: attrib.c:249
#define MALFORMED_ENTRY(REPORTS, NODE)
Definition: attrib.c:66
void ctu_init_attribs(tree_t *sema, arena_t *arena)
Definition: attrib.c:231
CT_PUREFN CT_TREE_API const node_t * tree_get_node(const tree_t *tree)
Definition: context.c:94
CT_PUREFN CT_TREE_API const char * tree_get_name(const tree_t *tree)
Definition: context.c:102
CT_PUREFN CT_TREE_API bool tree_is(const tree_t *self, tree_kind_t kind)
Definition: query.c:91
CT_TREE_API const tree_attribs_t * tree_get_attrib(const tree_t *self)
Definition: query.c:83
@ eCtuAttrib
Definition: ast.h:77
@ eCtuExprName
Definition: ast.h:27
@ eCtuExprString
Definition: ast.h:25
ctu_attrib_t * ctu_get_attrib(tree_t *sema, const char *name)
Definition: sema.c:108
CT_NODISCARD CT_PUREFN CT_BASE_API bool str_equal(const char *lhs, const char *rhs)
compare strings equality
Definition: util.c:76
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
Definition: memory.c:16
#define CT_UNUSED(x)
mark a variable as unused
Definition: macros.h:46
CT_NODISCARD CT_ARENA_API void * arena_memdup(STA_READS(size) const void *ptr, size_t size, arena_t *arena)
duplicate a memory region from a custom allocator duplicate a region of memory and return a pointer t...
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
Definition: arena.h:392
CT_NOTIFY_API event_builder_t msg_notify(INOUT_NOTNULL logger_t *logs, const diagnostic_t *diagnostic, const node_t *node, STA_FORMAT_STRING const char *fmt,...)
notify the logger of a new message
#define CTASSERT(expr)
assert a condition, prints the condition as a message
Definition: panic.h:130
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
Definition: panic.h:116
CT_NODISCARD CT_STD_API char * str_join(const char *sep, const vector_t *parts, arena_t *arena)
join strings
Definition: str.c:274
tree_linkage_t
the linkage of a declaration
Definition: ops.h:72
CT_TREE_API void * tree_module_set(tree_t *self, size_t tag, const char *name, void *value)
set a declaration in the current module
Definition: sema.c:111
CT_TREE_API void tree_set_attrib(tree_t *self, const tree_attribs_t *attrib)
Definition: decl.c:251
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
Definition: vector.c:134
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_tail(const vector_t *vector)
get the last element of a vector
Definition: vector.c:143
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
Definition: vector.c:152
void(* ctu_attrib_apply_t)(tree_t *sema, tree_t *decl, const vector_t *args)
Definition: attrib.h:9
an allocator object
Definition: arena.h:86
ctu_attrib_apply_t fn_apply
Definition: attrib.h:13
const char * name
Definition: attrib.h:12
Definition: ast.h:86
const vector_t * attrib_path
Definition: ast.h:238
ctu_kind_t kind
Definition: ast.h:87
const vector_t * attrib_args
Definition: ast.h:239
char * text
Definition: ast.h:159
const node_t * node
Definition: ast.h:88
const vector_t * path
Definition: ast.h:167
const char * mangle
override the mangle of the declaration
Definition: tree.h:54
const char * deprecated
the reason for deprecation, or NULL if not deprecated
Definition: tree.h:56
tree_linkage_t link
the link type of the declaration
Definition: tree.h:51
const char * section
override the section of the declaration
Definition: tree.h:55
Definition: tree.h:67
logger_t * reports
Definition: tree.h:227
const node_t * node
Definition: tree.h:69
a generic vector of pointers
Definition: vector.c:16