da760c64afc19446994fa5ee395cbc78c538c20c
[m6w6/ext-psi] / src / context_validate.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #include "php.h"
6
7 #include <sys/param.h>
8 #include <dlfcn.h>
9
10 #include "php_psi.h"
11 #include "php_psi_stdinc.h"
12 #include "php_psi_stdtypes.h"
13 #include "php_psi_macros.h"
14 #include "php_psi_redirs.h"
15
16 #include "calc.h"
17 #include "marshal.h"
18 #include "engine.h"
19
20 static int validate_lib(PSI_Data *data, void **dlopened) {
21 char lib[MAXPATHLEN];
22 const char *ptr = data->psi.file.ln;
23 size_t len;
24
25 if (!ptr) {
26 /* FIXME: assume stdlib */
27 return 1;
28 } else if (!strchr(ptr, '/')) {
29 len = snprintf(lib, MAXPATHLEN, "lib%s.%s", ptr, PHP_PSI_SHLIB_SUFFIX);
30 if (MAXPATHLEN == len) {
31 data->error(NULL, PSI_WARNING, "Library name too long: '%s'", ptr);
32 }
33 lib[len] = 0;
34 ptr = lib;
35 }
36 if (!(*dlopened = dlopen(ptr, RTLD_LAZY|RTLD_LOCAL))) {
37 data->error(NULL, PSI_WARNING, "Could not open library '%s': %s.",
38 data->psi.file.ln, dlerror());
39 return 0;
40 }
41 return 1;
42 }
43
44 static inline int locate_decl_type_alias(decl_typedefs *defs, decl_type *type) {
45 size_t i;
46 struct psi_std_type *stdtyp;
47
48 if (type->real) {
49 return 1;
50 }
51 for (i = 0; i < defs->count; ++i) {
52 decl_typedef *def = defs->list[i];
53
54 if (def->type->type != type->type && !strcmp(def->alias, type->name)) {
55 type->real = def->type;
56 return 1;
57 }
58 }
59 for (stdtyp = &psi_std_types[0]; stdtyp->type_tag; ++stdtyp) {
60 if (!strcmp(type->name, stdtyp->alias ?: stdtyp->type_name)) {
61 type->type = stdtyp->type_tag;
62 return 1;
63 }
64 }
65
66 return 0;
67 }
68 static inline int locate_decl_type_struct(decl_structs *structs, decl_type *type) {
69 size_t i;
70
71 if (type->strct) {
72 return 1;
73 }
74 for (i = 0; i < structs->count; ++i) {
75 if (!strcmp(structs->list[i]->name, type->name)) {
76 type->strct = structs->list[i];
77 return 1;
78 }
79 }
80 return 0;
81 }
82
83 static inline int validate_decl_type(PSI_Data *data, decl_type *type) {
84 switch (type->type) {
85 case PSI_T_CHAR:
86 case PSI_T_SHORT:
87 case PSI_T_INT:
88 case PSI_T_LONG:
89 case PSI_T_NAME:
90 if (!data->defs || !locate_decl_type_alias(data->defs, type)) {
91 return 0;
92 }
93 if (type->real) {
94 return validate_decl_type(data, type->real);
95 }
96 return 1;
97 case PSI_T_STRUCT:
98 if (!data->structs || !locate_decl_type_struct(data->structs, type)) {
99 return 0;
100 }
101 break;
102 }
103 return 1;
104 }
105 static inline int validate_decl_typedef(PSI_Data *data, decl_typedef *def) {
106 if (!validate_decl_type(data, def->type)) {
107 data->error(def->token, PSI_WARNING,
108 "Type '%s' cannot be aliased to %s'%s'",
109 def->type->name, def->type->type == PSI_T_STRUCT?"struct ":"",def->alias);
110 return 0;
111 }
112 /* FIXME: check def->alias */
113 return 1;
114 }
115
116 static inline int validate_constant(PSI_Data *data, constant *c) {
117 /* FIXME */
118 return 1;
119 }
120
121 static inline int validate_decl_arg(PSI_Data *data, decl_arg *arg) {
122 if (!validate_decl_type(data, arg->type)) {
123 data->error(arg->type->token, PSI_WARNING,
124 "Cannot use '%s'(%d) as type for decl var '%s'",
125 arg->type->name, arg->type->type, arg->var->name);
126 return 0;
127 }
128 return 1;
129 }
130
131 static int psi_sort_struct_arg_cmp(const void *_a, const void *_b) {
132 decl_arg *a = *(decl_arg **)_a, *b = *(decl_arg **)_b;
133
134 if (a->layout->pos == b->layout->pos) {
135 if (a->layout->len == b->layout->len) {
136 return 0;
137 } else if (a->layout->len > b->layout->len) {
138 return -1;
139 } else {
140 return 1;
141 }
142 } else if (a->layout->pos > b->layout->pos) {
143 return 1;
144 } else {
145 return -1;
146 }
147 }
148 static void psi_sort_struct_arg_swp(void *a, void *b) {
149 decl_arg **_a = a, **_b = b, *_c;
150
151 _c = *_b;
152 *_b = *_a;
153 *_a = _c;
154 }
155 static inline void psi_sort_struct_args(decl_struct *s) {
156 zend_insert_sort(s->args->args, s->args->count, sizeof(*s->args->args),
157 psi_sort_struct_arg_cmp, psi_sort_struct_arg_swp);
158 }
159
160 static inline int validate_decl_struct(PSI_Data *data, decl_struct *s) {
161 size_t i;
162
163 for (i = 0; i < s->args->count; ++i) {
164 if (!validate_decl_arg(data, s->args->args[i])) {
165 return 0;
166 }
167 }
168
169 for (i = 0; i < s->args->count; ++i) {
170 decl_arg *darg = s->args->args[i];
171
172 if (!validate_decl_arg(data, darg)) {
173 return 0;
174 }
175
176 ZEND_ASSERT(!darg->var->arg || darg->var->arg == darg);
177 darg->var->arg = darg;
178
179 if (darg->layout) {
180 size_t size;
181
182 if (darg->var->array_size) {
183 size = psi_t_size(real_decl_type(darg->type)->type) * darg->var->array_size;
184 } else if (darg->var->pointer_level) {
185 size = psi_t_size(PSI_T_POINTER);
186 } else {
187 decl_type *real = real_decl_type(darg->type);
188
189 if (real->type == PSI_T_STRUCT) {
190 size = real->strct->size;
191 } else {
192 size = psi_t_size(real->type);
193 }
194 }
195 if (darg->layout->len != size) {
196 data->error(darg->token, PSI_WARNING,
197 "Computed length %zu of %s.%s does not match"
198 " pre-defined length %zu of type '%s'",
199 darg->layout->len, s->name, darg->var->name, size,
200 darg->type->name);
201 return 0;
202 }
203 } else {
204 token_t t;
205
206 if (darg->var->pointer_level && (!darg->var->array_size || darg->var->pointer_level == 1)) {
207 t = PSI_T_POINTER;
208 } else {
209 t = real_decl_type(darg->type)->type;
210 }
211
212 if (i) {
213 decl_arg *last = s->args->args[i-1];
214 darg->layout = init_decl_struct_layout(
215 psi_t_align(t, last->layout->pos + last->layout->len),
216 psi_t_size(t) * darg->var->array_size);
217 } else {
218 darg->layout = init_decl_struct_layout(0, psi_t_size(t));
219 }
220 }
221 if (s->size < darg->layout->pos + darg->layout->len) {
222 s->size = darg->layout->pos + darg->layout->len;
223 }
224 }
225
226 psi_sort_struct_args(s);
227
228 return 1;
229 }
230
231 static const char * const abi_ccs[] = {
232 "default", /* \ */
233 "extern", /* > - all the same */
234 "cdecl", /* / */
235 "mscdecl",
236 "stdcall",
237 "fastcall",
238 };
239 static inline int validate_decl_abi(PSI_Data *data, decl_abi *abi) {
240 size_t i;
241
242 for (i = 0; i < sizeof(abi_ccs)/sizeof(char*); ++i) {
243 if (strcasecmp(abi->convention, abi_ccs[i])) {
244 return 1;
245 }
246 }
247 return 0;
248 }
249 static inline int validate_decl_func(PSI_Data *data, void *dl, decl *decl, decl_arg *func)
250 {
251 struct psi_func_redir *redir;
252
253 if (!strcmp(func->var->name, "dlsym")) {
254 data->error(func->token, PSI_WARNING, "Cannot dlsym dlsym (sic!)");
255 return 0;
256 }
257
258 if (!validate_decl_arg(data, func)) {
259 return 0;
260 }
261 for (redir = &psi_func_redirs[0]; redir->name; ++redir) {
262 if (!strcmp(func->var->name, redir->name)) {
263 decl->call.sym = redir->func;
264 }
265 }
266 if (!decl->call.sym) {
267 #ifndef RTLD_NEXT
268 # define RTLD_NEXT ((void *) -1l)
269 #endif
270 decl->call.sym = dlsym(dl ?: RTLD_NEXT, func->var->name);
271 if (!decl->call.sym) {
272 data->error(func->token, PSI_WARNING,
273 "Failed to locate symbol '%s': %s",
274 func->var->name, dlerror());
275 }
276 }
277 return 1;
278 }
279
280 static inline int validate_decl(PSI_Data *data, void *dl, decl *decl) {
281 if (!validate_decl_abi(data, decl->abi)) {
282 data->error(decl->abi->token, PSI_WARNING,
283 "Invalid calling convention: '%s'", decl->abi->token->text);
284 return 0;
285 }
286 if (!validate_decl_func(data, dl, decl, decl->func)) {
287 return 0;
288 }
289 if (decl->args) {
290 size_t i;
291
292 for (i = 0; i < decl->args->count; ++i) {
293 if (!validate_decl_arg(data, decl->args->args[i])) {
294 return 0;
295 }
296 }
297 }
298 return 1;
299 }
300 static inline decl_arg *locate_decl_var_arg(decl_var *var, decl_args *args, decl_arg *func) {
301 size_t i;
302
303 for (i = 0; i < args->count; ++i) {
304 decl_arg *arg = args->args[i];
305
306 if (!strcmp(var->name, arg->var->name)) {
307 ZEND_ASSERT(!var->arg || var->arg == arg);
308 return var->arg = arg;
309 }
310 }
311 if (func && !strcmp(var->name, func->var->name)) {
312 return var->arg = func;
313 }
314
315 return NULL;
316 }
317 static inline decl_arg *locate_struct_member(decl_struct *s, decl_var *var) {
318 if (s->args) {
319 return locate_decl_var_arg(var, s->args, NULL);
320 }
321
322 return NULL;
323 }
324 static inline constant *locate_num_exp_constant(num_exp *exp, constants *consts) {
325 size_t i;
326
327 for (i = 0; i < consts->count; ++i) {
328 constant *cnst = consts->list[i];
329
330 if (!strcmp(cnst->name, exp->u.numb)) {
331 free(exp->u.numb);
332 return exp->u.cnst = cnst;
333 }
334 }
335
336 return NULL;
337 }
338 static inline int validate_num_exp(PSI_Data *data, decl_args *dargs, decl_arg *func, num_exp *exp) {
339 if (exp->operand) {
340 switch (exp->operator) {
341 case PSI_T_PLUS:
342 exp->calculator = psi_calc_add;
343 break;
344 case PSI_T_MINUS:
345 exp->calculator = psi_calc_sub;
346 break;
347 case PSI_T_ASTERISK:
348 exp->calculator = psi_calc_mul;
349 break;
350 case PSI_T_SLASH:
351 exp->calculator = psi_calc_div;
352 break;
353 EMPTY_SWITCH_DEFAULT_CASE();
354 }
355 if (!validate_num_exp(data, dargs, func, exp->operand)) {
356 return 0;
357 }
358 }
359 switch (exp->t) {
360 case PSI_T_NAME:
361 if (!locate_decl_var_arg(exp->u.dvar, dargs, func)) {
362 data->error(exp->token, PSI_WARNING, "Unknown variable '%s' in numeric expression",
363 exp->u.dvar->name);
364 return 0;
365 }
366 return 1;
367 case PSI_T_NSNAME:
368 if (!locate_num_exp_constant(exp, data->consts)) {
369 data->error(exp->token, PSI_WARNING, "Unknown constant '%s' in numeric expression",
370 exp->u.numb);
371 return 0;
372 }
373 return 1;
374 case PSI_T_NUMBER:
375 return 1;
376 default:
377 return 0;
378 }
379 }
380 static inline int validate_set_value_handler(set_value *set) {
381 switch (set->func->type) {
382 case PSI_T_TO_BOOL:
383 set->func->handler = psi_to_bool;
384 break;
385 case PSI_T_TO_INT:
386 set->func->handler = psi_to_int;
387 break;
388 case PSI_T_TO_FLOAT:
389 set->func->handler = psi_to_double;
390 break;
391 case PSI_T_TO_STRING:
392 set->func->handler = psi_to_string;
393 break;
394 case PSI_T_TO_ARRAY:
395 set->func->handler = psi_to_array;
396 break;
397 case PSI_T_TO_OBJECT:
398 set->func->handler = psi_to_object;
399 break;
400 case PSI_T_VOID:
401 set->func->handler = psi_to_void;
402 break;
403 case PSI_T_ELLIPSIS:
404 if (set->outer.set && set->outer.set->func->type == PSI_T_TO_ARRAY) {
405 set->func->handler = psi_to_recursive;
406 set->inner = set->outer.set->inner;
407 set->count = set->outer.set->count;
408 break;
409 }
410 /* no break */
411 default:
412 return 0;
413 }
414 return 1;
415 }
416 static inline void decl_var_arg_v(decl_args *args, va_list argp) {
417 int argc;
418 decl_arg **argv;
419
420 memset(args, 0, sizeof(*args));
421
422 while ((argc = va_arg(argp, int))) {
423 argv = va_arg(argp, decl_arg **);
424 while (argc--) {
425 add_decl_arg(args, *argv++);
426 }
427 }
428 }
429 static inline int validate_set_value_ex(PSI_Data *data, set_value *set, decl_arg *ref, decl_args *ref_list) {
430 size_t i;
431 decl_type *ref_type;
432 decl_var *set_var = set->vars->vars[0];
433
434 if (!validate_set_value_handler(set)) {
435 data->error(set->func->token, PSI_WARNING, "Invalid cast '%s' in `set` statement", set->func->name);
436 return 0;
437 }
438
439 for (i = 0; i < set->vars->count; ++i) {
440 decl_var *svar = set->vars->vars[i];
441 if (!svar->arg && !locate_decl_var_arg(svar, ref_list, NULL)) {
442 data->error(svar->token, PSI_WARNING, "Unknown variable '%s' in `set` statement", svar->name);
443 return 0;
444 }
445 }
446
447 if (!ref) {
448 ref = set_var->arg;
449 }
450 ref_type = real_decl_type(ref->type);
451
452 if (set->count) {
453 int is_to_array = (set->func->type == PSI_T_TO_ARRAY);
454 int is_pointer_to_struct = (ref_type->type == PSI_T_STRUCT && ref->var->pointer_level);
455
456 if (!is_to_array && !is_pointer_to_struct) {
457 data->error(set->func->token, E_WARNING, "Inner `set` statement casts only work with "
458 "to_array() casts on structs or pointers: %s(%s...", set->func->name, set->vars->vars[0]->name);
459 return 0;
460 }
461 }
462 if (set->num) {
463 if (!validate_num_exp(data, ref_list, ref, set->num)) {
464 return 0;
465 }
466 }
467
468 if (ref_type->type == PSI_T_STRUCT) {
469 /* to_array(struct, to_...) */
470 if (!set->outer.set || set->outer.set->inner != set->inner) {
471 for (i = 0; i < set->count; ++i) {
472 decl_var *sub_var = set->inner[i]->vars->vars[0];
473 decl_arg *sub_ref = locate_struct_member(ref_type->strct, sub_var);
474
475 if (sub_ref) {
476 if (!validate_set_value_ex(data, set->inner[i], sub_ref, ref_type->strct->args)) {
477 return 0;
478 }
479 }
480 }
481 }
482 } else if (set->count == 1) {
483 /* to_array(ptr, to_string(*ptr)) */
484 decl_var *sub_var = set->inner[0]->vars->vars[0];
485 decl_arg *sub_ref = locate_decl_var_arg(sub_var, ref_list, ref);
486
487 if (sub_ref) {
488 if (strcmp(sub_var->name, set_var->name)) {
489 data->error(sub_var->token, E_WARNING, "Inner `set` statement casts on pointers must reference the same variable");
490 return 0;
491 }
492 if (!validate_set_value_ex(data, set->inner[0], sub_ref, ref_list)) {
493 return 0;
494 }
495 }
496 } else if (set->count > 1) {
497 data->error(set->func->token, E_WARNING, "Inner `set` statement casts on pointers may only occur once");
498 return 0;
499 }
500
501 return 1;
502 }
503 static inline int validate_set_value(PSI_Data *data, set_value *set, ...) {
504 va_list argp;
505 decl_args args = {0};
506 int check;
507
508 va_start(argp, set);
509 decl_var_arg_v(&args, argp);
510 va_end(argp);
511
512 check = validate_set_value_ex(data, set, NULL, &args);
513 if (args.args) {
514 free(args.args);
515 }
516 return check;
517 }
518 static inline decl *locate_impl_decl(decls *decls, return_stmt *ret) {
519 if (decls) {
520 size_t i;
521
522 for (i = 0; i < decls->count; ++i) {
523 if (!strcmp(decls->list[i]->func->var->name, ret->set->vars->vars[0]->name)) {
524 ret->decl = decls->list[i]->func;
525 return decls->list[i];
526 }
527 }
528 }
529
530 return NULL;
531 }
532 static inline int validate_impl_ret_stmt(PSI_Data *data, impl *impl) {
533 return_stmt *ret;
534
535 /* we must have exactly one ret stmt delcaring the native func to call */
536 /* and which type cast to apply */
537 if (impl->stmts->ret.count != 1) {
538 if (impl->stmts->ret.count > 1) {
539 data->error(impl->stmts->ret.list[1]->token, PSI_WARNING,
540 "Too many `return` statements for implmentation %s;"
541 " found %zu, exactly one is needed",
542 impl->func->name, impl->stmts->ret.count);
543 } else {
544 data->error(impl->func->token, PSI_WARNING,
545 "Missing `return` statement for implementation %s",
546 impl->func->name);
547 }
548 return 0;
549 }
550
551 ret = impl->stmts->ret.list[0];
552
553 if (!(impl->decl = locate_impl_decl(data->decls, ret))) {
554 data->error(ret->token, PSI_WARNING,
555 "Missing declaration '%s' for `return` statment for implementation %s",
556 ret->set->vars->vars[0]->name, impl->func->name);
557 return 0;
558 }
559
560 if (!validate_set_value(data, ret->set, 1, &ret->decl, impl->decl->args ? (int) impl->decl->args->count : 0, impl->decl->args ? impl->decl->args->args : NULL, 0)) {
561 return 0;
562 }
563
564 impl->decl->impl = impl;
565
566 return 1;
567 }
568
569 static inline int validate_impl_let_stmts(PSI_Data *data, impl *impl) {
570 size_t i, j;
571 /* we can have multiple let stmts */
572
573 /* check that we have a decl arg for every let stmt */
574 for (i = 0; i < impl->stmts->let.count; ++i) {
575 let_stmt *let = impl->stmts->let.list[i];
576 decl_var *let_var;
577 int check = 0;
578
579 if (let->val && let->val->kind == PSI_LET_TMP) {
580 let_var = let->val->data.var;
581 } else {
582 let_var = let->var;
583 }
584
585 if (!locate_decl_var_arg(let_var, impl->decl->args, impl->decl->func)) {
586 data->error(let_var->token, PSI_WARNING, "Unknown variable '%s' in `let` statement"
587 " of implementation '%s'", let_var->name, impl->func->name);
588 return 0;
589 }
590
591 switch (let->val->kind) {
592 case PSI_LET_NULL:
593 break;
594 case PSI_LET_TMP:
595 /* e.g. let bar = &strval($bar); // decl_arg(char **bar) */
596 /* e.g. let foo = *bar; */
597 let->var->pointer_level = let->val->data.var->pointer_level;
598 let->var->arg = init_decl_arg(
599 init_decl_type(
600 real_decl_type(let->val->data.var->arg->type)->type,
601 real_decl_type(let->val->data.var->arg->type)->name),
602 init_decl_var(
603 let->var->name,
604 let->var->pointer_level,
605 let->var->array_size));
606 break;
607 case PSI_LET_NUMEXP:
608 if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.num)) {
609 return 0;
610 }
611 break;
612 case PSI_LET_CALLOC:
613 if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->nmemb)) {
614 return 0;
615 }
616 if (!validate_num_exp(data, impl->decl->args, impl->decl->func, let->val->data.alloc->size)) {
617 return 0;
618 }
619 break;
620 case PSI_LET_FUNC:
621 if (impl->func->args) {
622 for (j = 0; j < impl->func->args->count; ++j) {
623 impl_arg *iarg = impl->func->args->args[j];
624
625 if (!strcmp(let->val->data.func->var->name, iarg->var->name)) {
626 let->val->data.func->arg = iarg;
627 check = 1;
628 break;
629 }
630 }
631 }
632 if (!check) {
633 data->error(let->var->token, PSI_WARNING, "Unknown value '$%s' of `let` statement"
634 " for variable '%s' of implementation '%s'",
635 let->val->data.func->var->name, let->var->name, impl->func->name);
636 return 0;
637 }
638 break;
639 }
640 }
641
642 /* check that we have a let stmt for every decl arg */
643 if (impl->decl->args) for (i = 0; i < impl->decl->args->count; ++i) {
644 decl_arg *darg = impl->decl->args->args[i];
645 int check = 0;
646
647 for (j = 0; j < impl->stmts->let.count; ++j) {
648 let_stmt *let = impl->stmts->let.list[j];
649
650 if (!strcmp(let->var->name, darg->var->name)) {
651 darg->let = let;
652 check = 1;
653 break;
654 }
655 }
656 if (!check) {
657 data->error(impl->func->token, PSI_WARNING,
658 "Missing `let` statement for arg '%s %.*s%s'"
659 " of declaration '%s' for implementation '%s'",
660 darg->type->name, (int) darg->var->pointer_level, "*****",
661 darg->var->name, impl->decl->func->var->name, impl->func->name);
662 return 0;
663 }
664 }
665
666 return 1;
667 }
668 static inline int validate_impl_set_stmts(PSI_Data *data, impl *impl) {
669 size_t i, j, k;
670 /* we can have any count of set stmts; processing out vars */
671 /* check that set stmts reference known variables */
672 for (i = 0; i < impl->stmts->set.count; ++i) {
673 set_stmt *set = impl->stmts->set.list[i];
674 int check = 0;
675
676 if (impl->func->args) for (j = 0; j < impl->func->args->count; ++j) {
677 impl_arg *iarg = impl->func->args->args[j];
678
679 if (!strcmp(set->var->name, iarg->var->name)) {
680 set->arg = iarg;
681 check = 1;
682 break;
683 }
684 }
685 if (!check) {
686 data->error(set->var->token, PSI_WARNING, "Unknown variable '$%s' of `set` statement"
687 " of implementation '%s'",
688 set->var->name, impl->func->name);
689 return 0;
690 }
691
692 for (j = 0; j < set->val->vars->count; ++j) {
693 decl_var *set_var = set->val->vars->vars[j];
694
695 check = 0;
696 if (impl->decl->args) {
697 for (k = 0; k < impl->decl->args->count; ++k) {
698 decl_arg *set_arg = impl->decl->args->args[k];
699
700 if (!strcmp(set_var->name, set_arg->var->name)) {
701 check = 1;
702 set_var->arg = set_arg;
703 if (!validate_set_value(data, set->val, 1, &set_arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) {
704 return 0;
705 }
706 break;
707 }
708 }
709 }
710 if (!check) {
711 for (k = 0; k < impl->stmts->let.count; ++k) {
712 let_stmt *let = impl->stmts->let.list[k];
713
714 /* check temp vars */
715 if (let->val && let->val->kind == PSI_LET_TMP) {
716 if (!strcmp(set_var->name, let->var->name)) {
717 check = 1;
718 set_var->arg = let->var->arg;
719 if (!validate_set_value(data, set->val, 1, &set_var->arg, 1, &impl->decl->func, impl->decl->args->count, impl->decl->args->args, 0)) {
720 return 0;
721 }
722 break;
723 }
724 }
725 }
726 }
727
728 if (!check) {
729 data->error(set_var->token, PSI_WARNING, "Unknown value '%s' of `set` statement"
730 " for variable '$%s' of implementation '%s'",
731 set_var->name, set->arg->var->name, impl->func->name);
732 return 0;
733 }
734 }
735 }
736 return 1;
737 }
738 static inline decl *locate_free_decl(decls *decls, free_call *f) {
739 if (decls) {
740 size_t i;
741
742 for (i = 0; i < decls->count; ++i) {
743 if (!strcmp(decls->list[i]->func->var->name, f->func)) {
744 f->decl = decls->list[i];
745 return decls->list[i];
746 }
747 }
748 }
749
750 return NULL;
751 }
752 static inline int validate_impl_free_stmts(PSI_Data *data, impl *impl) {
753 size_t i, j, k, l;
754 /* we can have any count of free stmts; freeing any out vars */
755 for (i = 0; i < impl->stmts->fre.count; ++i) {
756 free_stmt *fre = impl->stmts->fre.list[i];
757
758 for (j = 0; j < fre->calls->count; ++j) {
759 free_call *free_call = fre->calls->list[j];
760
761 /* first find the decl of the free func */
762 if (!locate_free_decl(data->decls, free_call)) {
763 data->error(free_call->token, PSI_WARNING,
764 "Missing declaration '%s' in `free` statement"
765 " of implementation '%s'",
766 free_call->func, impl->func->name);
767 return 0;
768 }
769
770
771
772 /* now check for known vars */
773 for (l = 0; l < free_call->vars->count; ++l) {
774 int check = 0;
775 decl_var *free_var = free_call->vars->vars[l];
776
777 if (!strcmp(free_var->name, impl->decl->func->var->name)) {
778 check = 1;
779 free_var->arg = impl->decl->func;
780 } else if (impl->decl->args) {
781 for (k = 0; k < impl->decl->args->count; ++k) {
782 decl_arg *free_arg = impl->decl->args->args[k];
783
784 if (!strcmp(free_var->name, free_arg->var->name)) {
785 check = 1;
786 free_var->arg = free_arg;
787 break;
788 }
789 }
790 }
791
792 if (!check) {
793 data->error(free_var->token, PSI_WARNING,
794 "Unknown variable '%s' of `free` statement"
795 " of implementation '%s'",
796 free_var->name, impl->func->name);
797 return 0;
798 }
799 }
800 }
801 }
802 return 1;
803 }
804 static inline int validate_impl_stmts(PSI_Data *data, impl *impl) {
805 if (!impl->stmts) {
806 data->error(impl->func->token, PSI_WARNING,
807 "Missing body for implementation %s!",
808 impl->func->name);
809 return 0;
810 }
811
812 if (!validate_impl_ret_stmt(data, impl)) {
813 return 0;
814 }
815
816 if (!validate_impl_let_stmts(data, impl)) {
817 return 0;
818 }
819 if (!validate_impl_set_stmts(data, impl)) {
820 return 0;
821 }
822 if (!validate_impl_free_stmts(data, impl)) {
823 return 0;
824 }
825
826 return 1;
827 }
828
829 static inline int validate_impl_args(PSI_Data *data, impl *impl) {
830 int def = 0;
831 size_t i;
832
833 for (i = 0; i < impl->func->args->count; ++i) {
834 impl_arg *iarg = impl->func->args->args[i];
835
836 if (iarg->def) {
837 def = 1;
838 } else if (def) {
839 data->error(impl->func->token, PSI_WARNING,
840 "Non-optional argument %zu '$%s' of implementation '%s'"
841 " follows optional argument",
842 i+1, iarg->var->name, impl->func->name);
843 return 0;
844 }
845 }
846
847 return 1;
848 }
849 static inline int validate_impl(PSI_Data *data, impl *impl) {
850 if (!validate_impl_args(data, impl)) {
851 return 0;
852 }
853 return validate_impl_stmts(data, impl);
854 }
855
856
857 int PSI_ContextValidate(PSI_Context *C, PSI_Parser *P)
858 {
859 PSI_Data *D;
860 void *dlopened = NULL;
861 size_t count = C->count++;
862
863 C->data = realloc(C->data, C->count * sizeof(*C->data));
864 D = PSI_DataExchange(&C->data[count], PSI_DATA(P));
865
866 if (D->defs) {
867 size_t i;
868
869 for (i = 0; i < D->defs->count; ++i) {
870 if (validate_decl_typedef(PSI_DATA(C), D->defs->list[i])) {
871 C->defs = add_decl_typedef(C->defs, D->defs->list[i]);
872 }
873 }
874 }
875 if (D->structs) {
876 size_t i;
877
878 for (i = 0; i < D->structs->count; ++i) {
879 if (validate_decl_struct(PSI_DATA(C), D->structs->list[i])) {
880 C->structs = add_decl_struct(C->structs, D->structs->list[i]);
881 }
882 }
883 }
884 if (D->consts) {
885 size_t i;
886
887 for (i = 0; i < D->consts->count; ++i) {
888 if (validate_constant(PSI_DATA(C), D->consts->list[i])) {
889 C->consts = add_constant(C->consts, D->consts->list[i]);
890 }
891 }
892 }
893
894 if (!validate_lib(D, &dlopened)) {
895 return 0;
896 }
897
898 add_decl_lib(&C->psi.libs, dlopened);
899
900 if (D->decls) {
901 size_t i;
902
903 for (i = 0; i < D->decls->count; ++i) {
904 if (validate_decl(PSI_DATA(C), dlopened, D->decls->list[i])) {
905 C->decls = add_decl(C->decls, D->decls->list[i]);
906 }
907 }
908 }
909 if (D->impls) {
910 size_t i;
911
912 for (i = 0; i < D->impls->count; ++i) {
913 if (validate_impl(PSI_DATA(C), D->impls->list[i])) {
914 C->impls = add_impl(C->impls, D->impls->list[i]);
915 }
916 }
917 }
918
919 return 1;
920 }
921
922 void PSI_ContextValidatePredef(PSI_Context *C, PSI_Data *D)
923 {
924 size_t i;
925
926 for (i = 0; i < D->defs->count; ++i) {
927 decl_typedef *def = D->defs->list[i];
928
929 if (validate_decl_typedef(D, def)) {
930 C->defs = add_decl_typedef(C->defs, def);
931 }
932 }
933
934 for (i = 0; i < D->consts->count; ++i) {
935 constant *constant = D->consts->list[i];
936
937 if (validate_constant(D, constant)) {
938 C->consts = add_constant(C->consts, constant);
939 }
940 }
941
942 for (i = 0; i < D->structs->count; ++i) {
943 decl_struct *dstruct = D->structs->list[i];
944
945 if (validate_decl_struct(D, dstruct)) {
946 C->structs = add_decl_struct(C->structs, dstruct);
947 }
948 }
949
950 for (i = 0; i < D->decls->count; ++i) {
951 decl *decl = D->decls->list[i];
952
953 if (validate_decl(D, NULL, decl)) {
954 C->decls = add_decl(C->decls, decl);
955 }
956 }
957 }