Added package with the documentation and the examples
[lwc.git] / fdb.c
blobbdb9c4bbefbced46f30956e1a1902c91f3800762
1 #include "global.h"
3 extern bool special_debug;
4 //******************************************************************************
5 // Database of the locations of function definitions
6 // && parsing of all of them later
7 // && re-parsing of auto-functions with checks
8 //******************************************************************************
10 Token *func_prologue;
11 typeID return_typeID;
13 typedef struct funcd_t {
14 struct funcd_t *next;
15 Token name, cname;
16 recID object;
17 bool have_this;
18 Token *dclstr;
19 Token *argv;
20 typeID *argt;
21 NormPtr body;
22 NormPtr alias;
23 typeID ret_type;
24 bool is_destructor;
25 bool polymorph;
26 bool done;
27 bool virt;
28 Token in_abstract;
29 } funcd;
31 static struct {
32 funcd *first, *last;
33 } definition [3];
35 static void _store_definition
36 (Token name, Token *dclstr, Token *argv, typeID *argt, NormPtr body,
37 recID r, typeID rett, Token cname, bool b, int ff, bool poly, bool have_this,
38 NormPtr alias)
40 funcd *f = (funcd*) malloc (sizeof * f);
41 f->is_destructor = b;
42 f->name = name;
43 f->cname = cname;
44 f->dclstr = intdup (dclstr);
45 f->argv = intdup (argv);
46 f->argt = argtdup (argt);
47 f->body = body;
48 f->alias = alias;
49 f->object = r;
50 f->next = 0;
51 f->ret_type = rett;
52 f->polymorph = poly;
53 f->have_this = have_this;
54 f->in_abstract = bt_macro;
55 f->virt = 0;
56 f->done = 0;
57 if (definition [ff].last) definition [ff].last->next = f;
58 else definition [ff].first = f;
59 definition [ff].last = f;
62 void store_definition
63 (Token name, Token *dclstr, Token *argv, typeID *argt, NormPtr body,
64 recID r, typeID rett, Token cname, bool b, deftype dt, bool ht)
66 _store_definition (name, dclstr, argv, argt, body, r, rett,
67 cname, b, dt, true, ht, -1);
70 void store_definition_alias
71 (Token name, Token *dclstr, Token *argv, typeID *argt, NormPtr alias,
72 recID r, typeID rett, Token cname, bool b, deftype dt, bool ht)
74 _store_definition (name, dclstr, argv, argt, -1, r, rett,
75 cname, b, dt, true, ht, alias);
78 #define CODELESS -1
80 void store_define_dtor (Token name, recID r)
82 Token argv [] = { -1 };
83 typeID argt [] = { pthis_of_struct (r), INTERNAL_ARGEND };
84 Token dclstr [] = {
85 RESERVED_static, RESERVED_inline, RESERVED_void,
86 '*', name, '(', RESERVED_struct,
87 name_of_struct (r), '*', RESERVED_this, ')', -1
89 _store_definition (name, dclstr, argv, argt, CODELESS, r,
90 typeID_voidP, name, true, DT_NORM, true, true, -1);
93 /**********************************************************************
94 Rename things on overload
95 **********************************************************************/
96 void rename_fdb (Token on, Token nn)
98 int i;
99 funcd *f;
101 for (i = DT_NORM; i <= DT_AUTO; i++)
102 for (f = definition [i].first; f; f = f->next)
103 if (f->name == on) {
104 intsubst (f->dclstr, on, nn);
105 f->name = nn;
106 break;
110 void remove_struct_from_def (Token n)
112 int i;
113 funcd *f;
115 for (i = DT_NORM; i <= DT_AUTO; i++)
116 for (f = definition [i].first; f; f = f->next)
117 if (f->name == n) {
118 remove_struct_from_this (f->dclstr, f->object);
119 break;
122 /**********************************************************************
123 --- Usage && comparison
124 record usage of important things to be able to
125 compare whether two functions are the same
126 **********************************************************************/
127 typedef enum { AF_NOTYET, AF_TRUE, AF_FALSE, AF_DEPENDS } AutoBool;
128 enum { USE_END, USE_TCONST, USE_FCALL, USE_VVAR, USE_MEMB, USE_UPCAST, USE_LTDEF, USE_TYPEID };
130 typedef struct {
131 int status;
132 union {
133 Token t;
134 Token *s;
135 recID r;
136 typeID T;
137 struct {
138 Token t1, t2;
139 } tt;
140 } u;
141 } usaged;
143 static bool textok = true;
144 static bool calls_pure = false;
145 static usaged *udata;
146 static int nudata, nudata_alloc;
148 static int add_udata ()
150 #define CHUNK 32
151 if (nudata + 1 >= nudata_alloc)
152 udata = (usaged*) realloc (udata, sizeof (usaged) * (nudata_alloc += CHUNK));
153 return nudata++;
156 void usage_tconst (Token v)
158 if (textok) {
159 int n = add_udata ();
160 udata [n].status = USE_TCONST;
161 udata [n].u.t = v;
165 void usage_typeID (typeID t)
167 if (textok) {
168 int n = add_udata ();
169 udata [n].status = USE_TYPEID;
170 udata [n].u.T = t;
172 if (base_of (t) == B_PURE) {
173 usage_call_pure ();
174 raise_skip_function ();
178 void usage_fcall (Token v)
180 if (textok) {
181 int n = add_udata ();
182 udata [n].status = USE_FCALL;
183 udata [n].u.t = v;
187 void usage_notok ()
189 textok = false;
192 void usage_call_pure ()
194 usage_fcall (RESERVED_0);
195 calls_pure = true;
198 void usage_vvar (Token *t)
200 if (!t) usage_notok ();
201 else if (textok) {
202 int n = add_udata ();
203 udata [n].status = USE_VVAR;
204 udata [n].u.s = t;
208 void usage_memb (Token v)
210 if (textok) {
211 int n = add_udata ();
212 udata [n].status = USE_MEMB;
213 udata [n].u.t = v;
217 void usage_set_pure ()
219 calls_pure = true;
222 void usage_upcast (recID r)
224 if (textok) {
225 int n = add_udata ();
226 udata [n].status = USE_UPCAST;
227 udata [n].u.r = r;
231 static usaged *reset_udata ()
233 textok = true;
234 calls_pure = false;
235 if (!udata) return 0;
237 int n = add_udata ();
238 udata [n].status = USE_END;
239 usaged *r = realloc (udata, sizeof (usaged) * nudata);
240 nudata = nudata_alloc = 0;
241 udata = 0;
242 return r;
245 static AutoBool is_another_autof (Token);
247 /* AutoBool means:
248 AF_TRUE: redefine
249 AF_FALSE: dispatch
250 AF_DEPENDS: depends
252 static int compare_usages (usaged *u1, recID rd, usaged *u2, recID rb, Token deps[])
254 int i, nd = 0, j;
256 if (!u1) return AF_FALSE;
258 for (i = 0; u1 [i].status != USE_END; i++)
259 switch (u1 [i].status) {
260 case USE_LTDEF:
261 case USE_TCONST:
262 if (u1 [i].u.t != u2 [i].u.t) return AF_TRUE;
263 ncase USE_TYPEID:
264 if (u1 [i].u.T != u2 [i].u.T) return AF_TRUE;
265 ncase USE_FCALL:
266 if (u1 [i].u.t == u2 [i].u.t) continue;
267 switch (is_another_autof (u1 [i].u.t)) {
268 case AF_TRUE: return AF_TRUE;
269 case AF_FALSE: continue;
270 default: for (j = 0; j < nd; j++)
271 if (deps [j] == u1 [i].u.t)
272 break;
273 if (j == nd)
274 deps [nd++] = u1 [i].u.t;
276 ncase USE_VVAR:
277 if (intcmp (u1 [i].u.s, u2 [i].u.s))
278 return AF_TRUE;
280 ncase USE_MEMB: {
281 Token p1 [64], p2 [64], *p;
282 lookup_variable_member (rd, u1[i].u.t, p1, true, 0);
283 lookup_variable_member (rb, u1[i].u.t, p2 + 2, true, 0);
284 p2 [1] = is_ancestor (rd, rb, &p, true) == 2 ? POINTSAT : '.';
285 p2 [0] = p [0];
286 if (intcmp (p1, p2))
287 return AF_TRUE;
289 ncase USE_UPCAST:
290 /* if different, will catch fcalls */
291 if (u1 [i].u.r != u2 [i].u.r)
292 continue;
294 Token *p1, p2 [64], *p;
295 is_ancestor (rd, u1 [i].u.r, &p1, true);
296 if (rb != u1 [i].u.r) {
297 is_ancestor (rb, u1 [i].u.r, &p, true);
298 intcpy (p2 + 2, p);
299 p2 [1] = is_ancestor (rd, rb, &p, true) == 2 ? POINTSAT : '.';
300 p2 [0] = p [0];
301 if (p2 [2] == -1) p2 [1] = -1;
302 if (p [0] == -1) intcpy (p2, p2 + 2);
303 } else {
304 is_ancestor (rd, rb, &p, true);
305 intcpy (p2, p);
307 if (intcmp (p1, p2))
308 return AF_TRUE;
312 deps [nd] = -1;
314 return nd ? AF_DEPENDS : AF_FALSE;
316 /**********************************************************************
317 --- fwd prototype
318 **********************************************************************/
319 static OUTSTREAM do_function_catch (funcd*);
320 /**********************************************************************
321 --- Auto functions, store & instantiate
322 **********************************************************************/
323 static struct adf {
324 struct adf *next;
325 Token dname, fname, pname;
326 recID r;
327 Token *proto, *argv, *dcltext;
328 struct adf **callers;
329 bool textok, cpure;
330 usaged *udata;
331 int status;
332 Token *deps;
333 bool have_this;
334 bool virt;
335 bool aliasing;
336 bool aliased;
337 int ncallers;
338 typeID ft;
339 } *first, *last;
341 static intnode * autoftree;
343 void commit_auto_define (Token dname, recID r, Token fname, Token pname, bool virt, Token *proto, Token *argv, typeID ft)
345 struct adf *a = (struct adf*) malloc (sizeof * a);
346 a->next = 0;
347 a->dname = dname;
348 a->fname = fname;
349 a->pname = pname;
350 a->r = r;
351 a->status = AF_NOTYET;
352 a->udata = 0;
353 a->deps = 0;
354 a->dcltext = 0;
355 a->proto = intdup (proto);
356 a->argv = intdup (argv);
357 a->callers = 0;
358 a->virt = virt;
359 a->aliasing = 0;
360 a->aliased = 0;
361 a->ncallers = 0;
362 a->cpure = false;
363 a->ft = ft;
365 if (last) last->next = a;
366 else first = a;
367 last = a;
368 union ival u = { .p = a };
369 intadd (&autoftree, a->fname, u);
372 static void add_caller (struct adf *a, struct adf *c)
374 if (!a->ncallers)
375 a->callers = (struct adf**) malloc (32 * sizeof *a->callers);
376 else if (a->ncallers % 32 == 0)
377 a->callers = (struct adf**) realloc (a->callers, a->ncallers += 32);
378 a->callers [a->ncallers++] = c;
381 static AutoBool is_another_autof (Token t)
383 intnode *n = intfind (autoftree, t);
384 if (!n) return AF_TRUE;
385 struct adf *a = (struct adf*) n->v.p;
386 return a->status == AF_NOTYET ? AF_DEPENDS : a->status;
389 static AutoBool check_dependancies (Token dep[])
391 int i, r = AF_FALSE;
393 for (i = 0; dep [i] != -1; i++)
394 switch (((struct adf*) intfind (autoftree, dep [i])->v.p)->status) {
395 case AF_TRUE: return AF_TRUE;
396 case AF_DEPENDS: r = AF_DEPENDS;
399 return r;
402 /* the case where the definition of an auto-function is
403 * { PARENT_CLASS }
404 * make f->body point to parent functions definition body
405 * if available or return false. */
406 static bool autofork (funcd *f)
408 funcd *s;
409 NormPtr p = f->body;
411 if (p == -1 || !(issymbol (CODE [p]) && CODE [p + 1] == '}'))
412 return true;
414 Token o = CODE [p];
415 recID r = lookup_object (o);
417 if (!r) parse_error (p, "Not an class in auto-start");
418 if (!isancestor (f->object, r)) parse_error (p, "Not derrived");
420 for (s = definition [DT_NORM].first; s; s = s->next)
421 if (s->cname == f->cname && s->object == r
422 && arglist_compare (s->argt, f->argt)) {
423 f->body = s->body;
424 for (p = 0; f->argv [p] != -1; p++)
425 intsubst1 (f->dclstr, f->argv [p], s->argv [p]);
426 f->argv = s->argv;
427 return true;
430 return false;
433 /* instantiate the definition of an auto function for a specific class
434 * and then parse it */
435 static Token *instantiate_auto (struct adf *a)
437 funcd *f;
438 Token *dproto;
439 int i;
441 for (f = definition [DT_AUTO].first; f; f = f->next)
442 if (f->name == a->dname)
443 break;
445 if (!f) return 0;
446 if (!autofork (f)) return 0;
448 a->have_this = f->have_this;
449 a->aliasing = f->alias != -1;
451 dproto = intdup (a->proto);
452 for (i = 0; a->argv [i] != -1; i++)
453 intsubst1 (dproto, a->argv [i], f->argv [i]);
455 funcd F = {
456 .name = a->fname, .cname = f->cname, .object = a->r,
457 .dclstr = dproto, .argv = f->argv,
458 .argt = argtdup (open_typeID (a->ft) + 3),
459 .body = f->body, .alias = f->alias, .ret_type = funcreturn (a->ft),
460 .is_destructor = f->is_destructor, .polymorph = false,
461 .have_this = f->have_this, .virt = a->virt
464 return combine_output (do_function_catch (&F));
467 static AutoBool same_code (struct adf *f)
469 struct adf *a = (struct adf*) intfind (autoftree, f->pname)->v.p;
470 Token depends [64];
472 if (!a->textok)
473 return AF_TRUE;
475 AutoBool r = compare_usages (f->udata, f->r, a->udata, a->r, depends);
476 if (r == AF_DEPENDS)
477 f->deps = intdup (depends);
478 return r;
481 static void dispatch_to_parent (struct adf *a)
483 int i = 0;
484 struct adf *p = (struct adf*) intfind (autoftree, a->pname)->v.p;
485 recID r = p->r;
486 OUTSTREAM O = new_stream ();
488 //PRINTF ("DISPATCH TO PARENT: %s %s\n", expand (a->fname), expand (a->pname));
489 if (HaveAliases && zero_offset (a->r, r)) {
490 outprintf (printproto_si (O, a->proto, a->fname, 1), alias_func (r, a->pname), ';', -1);
491 p->aliased = true;
492 } else {
493 outprintf (printproto (O,a->proto,a->fname, 0), '{', RESERVED_return,a->pname,'(',-1);
495 if (a->have_this)
496 outprintf (O, ISTR (upcast1_this (a->r, r)), -1);
497 else if (a->argv [0] != -1)
498 outprintf (O, a->argv [i++], -1);
500 for (; a->argv [i] != -1; i++)
501 outprintf (O, ',', a->argv [i], -1);
502 outprintf (O, ')', ';', '}', -1);
505 free (a->dcltext);
506 a->dcltext = combine_output (O);
509 static void rpure_r (struct adf *a)
511 int i;
512 if (a->dcltext) {
513 free (a->dcltext);
514 a->dcltext = 0;
515 if (a->virt) purify_vfunc (a->fname);
517 for (i = 0; i < a->ncallers; i++)
518 rpure_r (a->callers [i]);
521 static void remove_pure ()
523 struct adf *a, *c;
524 usaged *u;
525 intnode *n;
526 int i;
527 Token t;
529 for (a = first; a; a = a->next)
530 if (a->dcltext && !a->cpure && a->udata)
531 for (u = a->udata, i = 0; u [i].status != USE_END; i++)
532 if (u [i].status == USE_FCALL) {
533 t = u [i].u.t;
534 n = intfind (autoftree, t);
535 if (!n) continue;
536 c = (struct adf*) n->v.p;
537 if (c->r == a->r)
538 add_caller (c, a);
542 for (a = first; a; a = a->next)
543 if (a->cpure) rpure_r (a);
546 void define_auto_functions ()
548 struct adf *a, *fd;
551 // first, parse all of them, hypothetically
553 objective.recording = true;
554 for (a = first; a; a = a->next)
555 if (a->dcltext = instantiate_auto (a))
556 a->textok = textok, a->cpure = calls_pure, a->udata = reset_udata ();
557 objective.recording = false;
559 remove_pure ();
561 if (ExpandAllAutos)
562 goto free_Skylarov;
565 // now define or dispatch depending whether
566 // the two versions do different things
568 for (a = first; a; a = a->next)
569 if (a->dcltext)
570 if ((a->status = (a->pname == -1 ? AF_TRUE : same_code (a))) == AF_FALSE)
571 dispatch_to_parent (a);
574 // autofunctions calling autofunctions
575 // try to resolve known
577 for (fd = 0, a = first; a; a = a->next)
578 if (a->status == AF_DEPENDS) {
579 switch (a->status = check_dependancies (a->deps)) {
580 case AF_FALSE:
581 dispatch_to_parent (a);
582 ncase AF_DEPENDS:
583 if (!fd) fd = a;
584 continue;
587 if (fd) {
588 a = fd;
589 fd = 0;
594 // circular dependancies left. suppose false
596 for (a = first; a; a = a->next)
597 if (a->status == AF_DEPENDS)
598 dispatch_to_parent (a);
600 free_Skylarov:
602 // print the code (and the prototype + linkonce)
604 for (a = first; a; a = a->next)
605 if (a->dcltext) {
606 printproto (FPROTOS, a->proto, a->fname, 1);
607 bool staticinline = intchr (a->proto, RESERVED_static) || intchr (a->proto, RESERVED_inline);
608 if (!a->aliasing) {
609 if (!OneBigFile && !staticinline)
610 output_itoken (FPROTOS, linkonce_text (a->fname));
611 else if (staticinline&&0)
612 /* Disabled: was for gcc alias bug */
613 outprintf (FPROTOS, RESERVED___attribute__, '(', '(', RESERVED_used, ')', ')', -1);
615 output_itoken (FPROTOS, ';');
616 outprintf (AUTOFUNCTIONS, ISTR (a->dcltext), -1);
619 // (Do you remember malloc?)
620 for (a = first; a; a = a->next) {
621 if (a->dcltext) free (a->dcltext);
622 if (a->udata) free (a->udata);
623 if (a->deps) free (a->deps);
624 if (a->proto) free (a->proto);
625 if (a->argv) free (a->argv);
626 if (a->ncallers) free (a->callers);
629 /**********************************************************************
630 --- Abstract Class functions, store & instantiate
631 **********************************************************************/
632 /**********************************************************************
633 Parse all functions
634 **********************************************************************/
635 bool may_throw;
637 static typeID elliptic_arg (typeID t)
639 return typeID_elliptic (t) ? ptrup (elliptic_type (t)) : t;
642 static OUTSTREAM do_alias_function (funcd *f)
644 recID cls = f->object;
645 Token fnm = 0;
646 NormPtr p = f->alias;
647 OUTSTREAM o = new_stream ();
649 if (ISSYMBOL (CODE [p + 1]) && CODE [p + 2] == ')')
650 fnm = CODE [p + 1];
651 else parse_error (p, "alias (func)");
653 fnm = lookup_function_member_uname (&cls, fnm);
654 if (objective.recording)
655 usage_fcall (fnm);
656 #ifndef BROKEN_ALIASES
657 if (HaveAliases)
658 outprintf (printproto (o, f->dclstr, f->name, 1), alias_func (cls, fnm), ';', -1);
659 else
660 #endif
662 outprintf (printproto_si (o, f->dclstr, f->name, 1), '{',
663 RESERVED_return, fnm, '(', -1);
664 if (f->have_this)
665 outprintf (o, RESERVED_this, -1);
666 /*XXX: this will break if there are arguments. Add them! */
667 outprintf (o, ')', ';', '}', -1);
669 return o;
672 static OUTSTREAM do_function (funcd *f)
674 #ifdef DEBUG
675 if (debugflag.FUNCPROGRESS)
676 PRINTF ("FUNCTION ["COLS"%s"COLE"]\n", expand(f->name));
677 #endif
678 f->done = true;
680 /* Feature: alias functions */
681 if (f->alias != -1)
682 return do_alias_function (f);
683 /* ~~~~~~~~~~~~~~~~~~~~~~~~ */
685 int i;
686 bool MAIN; // and gcc warnings get sillier all the time....
687 OUTSTREAM o = new_stream ();
689 return_typeID = f->ret_type;
690 if (objective.recording)
691 usage_typeID (return_typeID);
692 if (MAIN = f->name == RESERVED_main)
693 MainModule = true;
694 objective.isdtor = f->is_destructor;
696 /* abstract template class type */
697 SAVE_VAR (bt_macro, f->in_abstract);
698 SAVE_VAR (bt_replace, name_of_struct (f->object));
699 SAVE_VAR (in_function, f->name);
700 SAVE_VAR (may_throw, false);
701 current_scope [++top_scope] = f->object;
703 /* set expression semantics in member functions */
704 if ((objective.yes = f->object != 0)) {
705 objective.func = f->name;
706 objective.class = f->object;
707 objective.efunc = f->cname;
708 objective.classP = pthis_of_struct (f->object);
709 objective.have_this = f->have_this;
710 objective.polymorph = f->polymorph;
712 open_local_scope ();
713 for (i = 0; f->argt [i] != -1; i++)
714 if (f->argv [i] != -1) {
715 typeID t = elliptic_arg (f->argt [i]);
716 enter_local_obj (f->argv [i], t);
717 if (objective.recording)
718 usage_typeID (t);
719 } else break;
722 if (objective.yes)
723 printproto (o, f->dclstr, f->name, 0);
724 else outprintf (o, ISTR (f->dclstr), - 1);
725 if (f->body != CODELESS)
726 compound_statement (o, f->body);
727 else outprintf (o, '{', '}', -1);
730 /* Feature: dtors call dtors of dtorable members */
731 if (f->is_destructor) {
732 backspace_token (o);
733 Token dtn;
734 if ((dtn = idtor (f->object))) {
735 make_intern_dtor (f->object);
736 outprintf (o, dtn, '(', R(this), ')', ';', -1);
738 outprintf (o, RESERVED_return, RESERVED_this, ';', '}', -1);
739 if (objective.recording)
740 usage_notok ();
742 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
744 /* Everybody's favorite addition */
745 if (MAIN)
746 outprintf (o, BACKSPACE, RESERVED_return, RESERVED_0, ';', '}', -1);
748 if (!may_throw) {
749 xmark_nothrow (objective.yes ? FSP (f->object) : Global, f->cname, f->name);
750 if (f->is_destructor) set_dtor_nothrow (f->object);
752 //PRINTF (COLS"%i"COLE"may_throw=%s\n", may_throw, expand (f->name));
753 close_local_scope ();
755 RESTOR_VAR (bt_macro);
756 RESTOR_VAR (bt_replace);
757 RESTOR_VAR (in_function);
758 RESTOR_VAR (may_throw);
759 --top_scope;
761 if (f->is_destructor && vdtor (f->object))
762 o = dispatch_vdtor (f->object, o);
764 return o;
767 static OUTSTREAM do_function_catch (funcd *f)
769 SAVE_VAR (bt_macro, bt_macro);
770 SAVE_VAR (bt_replace, bt_replace);
771 SAVE_VAR (in_function, in_function);
772 SAVE_VAR (top_scope, top_scope);
773 SAVE_VAR (may_throw, may_throw);
775 jmp_buf ENV;
776 OUTSTREAM O;
777 if (!setjmp (ENV)) {
778 set_catch (&ENV, 0, 0, 1);
779 O = do_function (f);
780 } else {
781 /* function has been skipped because it references pure typedef */
782 O = new_stream ();
783 if (f->is_destructor && idtor (f->object)) {
784 make_intern_dtor (f->object);
785 outprintf (INTERNAL_CODE, ISTR (f->dclstr), '{', idtor (f->object), '(',
786 RESERVED_this, ')', ';', RESERVED_return, RESERVED_this,
787 ';', '}', -1);
789 RESTOR_VAR (bt_macro);
790 RESTOR_VAR (bt_replace);
791 RESTOR_VAR (in_function);
792 RESTOR_VAR (top_scope);
793 RESTOR_VAR (may_throw);
795 clear_catch ();
796 return O;
799 void do_functions ()
801 funcd *f;
803 for (f = definition [DT_NORM].first; f; f = f->next)
804 if (!f->done)
805 concate_streams (FUNCDEFCODE, do_function (f));