|
|
@@ -12,6 +12,70 @@
|
|
12
|
12
|
#include "sym.h"
|
|
13
|
13
|
#include "type.h"
|
|
14
|
14
|
|
|
|
15
|
+/* . */
|
|
|
16
|
+
|
|
|
17
|
+static int global_dot_type_infer(const struct func *func, struct node *n)
|
|
|
18
|
+{
|
|
|
19
|
+ struct node *sou, *member;
|
|
|
20
|
+ struct type *t;
|
|
|
21
|
+ struct tfield *f;
|
|
|
22
|
+
|
|
|
23
|
+ if (n->sym->type)
|
|
|
24
|
+ return 0;
|
|
|
25
|
+
|
|
|
26
|
+ sou = n->expr.args;
|
|
|
27
|
+ member = sou->next;
|
|
|
28
|
+ if (!sou->sym->type)
|
|
|
29
|
+ return 0;
|
|
|
30
|
+
|
|
|
31
|
+ t = type_base(sou->sym->type);
|
|
|
32
|
+
|
|
|
33
|
+ /* TODO: add union */
|
|
|
34
|
+ if (t->ttype != T_STRUCT) {
|
|
|
35
|
+ _e("%#N: %N is neither struct nor union (type '%T').\n",
|
|
|
36
|
+ n, sou, sou->sym->type);
|
|
|
37
|
+ return -EINVAL;
|
|
|
38
|
+ }
|
|
|
39
|
+
|
|
|
40
|
+ tfields_foreach(f, t->sou.fields) {
|
|
|
41
|
+ if (!strcmp(f->name, member->string.data)) {
|
|
|
42
|
+ /* given `sou.member` where sou is a
|
|
|
43
|
+ * struct/union, infer that the expression's
|
|
|
44
|
+ * type is equal to member's type. */
|
|
|
45
|
+ n->sym->type = f->type;
|
|
|
46
|
+ return 0;
|
|
|
47
|
+ }
|
|
|
48
|
+ }
|
|
|
49
|
+
|
|
|
50
|
+ _e("%#N: type '%T' has no member named '%s'.\n",
|
|
|
51
|
+ n, t, member->string.data);
|
|
|
52
|
+ return -EINVAL;
|
|
|
53
|
+}
|
|
|
54
|
+
|
|
|
55
|
+
|
|
|
56
|
+/* :deref */
|
|
|
57
|
+
|
|
|
58
|
+static int global_deref_type_infer(const struct func *func, struct node *n)
|
|
|
59
|
+{
|
|
|
60
|
+ struct node *ptr = n->expr.args;
|
|
|
61
|
+ struct type *t;
|
|
|
62
|
+
|
|
|
63
|
+ if (n->sym->type || !ptr->sym->type)
|
|
|
64
|
+ return 0;
|
|
|
65
|
+
|
|
|
66
|
+ t = type_base(ptr->sym->type);
|
|
|
67
|
+ if (t->ttype != T_POINTER) {
|
|
|
68
|
+ _e("%#N: can't dereference %N (type '%T').\n",
|
|
|
69
|
+ n, ptr, ptr->sym->type);
|
|
|
70
|
+ return -EINVAL;
|
|
|
71
|
+ }
|
|
|
72
|
+
|
|
|
73
|
+ /* given `*p` where p is a pointer, infer that the
|
|
|
74
|
+ * expression's type is equal to p's concrete type. */
|
|
|
75
|
+ n->sym->type = t->ptr.type;
|
|
|
76
|
+ return 0;
|
|
|
77
|
+}
|
|
|
78
|
+
|
|
15
|
79
|
|
|
16
|
80
|
/* :map */
|
|
17
|
81
|
|
|
|
@@ -65,7 +129,7 @@ static int global_map_type_infer(const struct func *func, struct node *n)
|
|
65
|
129
|
static int global_map_static_validate(const struct func *func, struct node *n)
|
|
66
|
130
|
{
|
|
67
|
131
|
if (n->expr.args->ntype != N_IDENT) {
|
|
68
|
|
- _e("%#N: trying to lookup a key in %N, which is not a map.\n",
|
|
|
132
|
+ _e("%#N: can't lookup a key in %N, which is not a map.\n",
|
|
69
|
133
|
n, n);
|
|
70
|
134
|
return -EINVAL;
|
|
71
|
135
|
}
|
|
|
@@ -222,6 +286,31 @@ struct type t_block_func = {
|
|
222
|
286
|
.func = { .type = &t_void, .vargs = 1 },
|
|
223
|
287
|
};
|
|
224
|
288
|
|
|
|
289
|
+struct type t_string_array = {
|
|
|
290
|
+ .ttype = T_ARRAY,
|
|
|
291
|
+
|
|
|
292
|
+ .array = { .type = &t_char, .len = 64 }, /* TODO: tunable */
|
|
|
293
|
+};
|
|
|
294
|
+
|
|
|
295
|
+struct type t_string = {
|
|
|
296
|
+ .ttype = T_TYPEDEF,
|
|
|
297
|
+
|
|
|
298
|
+ .tdef = { .name = ":string", .type = &t_string_array },
|
|
|
299
|
+};
|
|
|
300
|
+
|
|
|
301
|
+struct tfield f_dot[] = {
|
|
|
302
|
+ { .type = &t_void },
|
|
|
303
|
+ { .type = &t_string },
|
|
|
304
|
+
|
|
|
305
|
+ { .type = NULL }
|
|
|
306
|
+};
|
|
|
307
|
+
|
|
|
308
|
+struct type t_dot_func = {
|
|
|
309
|
+ .ttype = T_FUNC,
|
|
|
310
|
+
|
|
|
311
|
+ .func = { .type = &t_void, .args = f_dot },
|
|
|
312
|
+};
|
|
|
313
|
+
|
|
225
|
314
|
struct tfield f_2args[] = {
|
|
226
|
315
|
{ .type = &t_void },
|
|
227
|
316
|
{ .type = &t_void },
|
|
|
@@ -254,6 +343,17 @@ static const struct func global_funcs[] = {
|
|
254
|
343
|
.static_ret = 1,
|
|
255
|
344
|
},
|
|
256
|
345
|
|
|
|
346
|
+ {
|
|
|
347
|
+ .name = ".",
|
|
|
348
|
+ .type = &t_dot_func,
|
|
|
349
|
+ .type_infer = global_dot_type_infer,
|
|
|
350
|
+ },
|
|
|
351
|
+ {
|
|
|
352
|
+ .name = ":deref",
|
|
|
353
|
+ .type = &t_1arg_func,
|
|
|
354
|
+ .type_infer = global_deref_type_infer,
|
|
|
355
|
+ },
|
|
|
356
|
+
|
|
257
|
357
|
{
|
|
258
|
358
|
.name = "+",
|
|
259
|
359
|
.type = &t_2args_func,
|
|
|
@@ -330,18 +430,6 @@ static const struct func global_num_func = {
|
|
330
|
430
|
.name = ":num",
|
|
331
|
431
|
};
|
|
332
|
432
|
|
|
333
|
|
-struct type t_string_array = {
|
|
334
|
|
- .ttype = T_ARRAY,
|
|
335
|
|
-
|
|
336
|
|
- .array = { .type = &t_char, .len = 64 }, /* TODO: tunable */
|
|
337
|
|
-};
|
|
338
|
|
-
|
|
339
|
|
-struct type t_string = {
|
|
340
|
|
- .ttype = T_TYPEDEF,
|
|
341
|
|
-
|
|
342
|
|
- .tdef = { .name = ":string", .type = &t_string_array },
|
|
343
|
|
-};
|
|
344
|
|
-
|
|
345
|
433
|
static const struct func global_string_func = {
|
|
346
|
434
|
.name = ":string",
|
|
347
|
435
|
.type = &t_string,
|