Added package with the documentation and the examples
[lwc.git] / fspace.c
blobdf9934508c2e27451b40119f0218a21c2e601dae
1 /*****************************************************************************
3 Function namespaces. Overloading.
5 Overloading happens only when we have a second declaration of
6 the same name with different types in the same function space.
7 Then some things need to be renamed and are:
9 - prototype of function definition: rename_fdb
10 - name of auto functions to be reparsed: rename_hier
12 *****************************************************************************/
14 #include "global.h"
16 /**************************************************
17 Declarations, comparison of
18 prototypes, default arguments
19 and properties.
20 **************************************************/
21 typeID *promoted_arglist (typeID *tt)
23 typeID tr [64];
24 int i, j;
26 for (j = i = 0; tt [i] != INTERNAL_ARGEND; i++)
27 tr [j++] = tt [i] == B_ELLIPSIS ? B_ELLIPSIS :
28 isstructure (tt [i]) ?
29 ptrup (tt [i]) : bt_promotion (tt [i]);
30 tr [j] = -1;
31 return intdup (tr);
34 typeID *promoted_arglist_t (typeID t)
36 return promoted_arglist (open_typeID (t) + 2);
39 static char *mangle_type (char *p, typeID t, bool promo)
41 if (is_reference (t)) t = ptrdown (dereference (t));
42 int *ot = open_typeID (t);
43 int i;
44 for (i = 1; ot [i] != -1; i++)
45 if (ot [i] == '*' || ot [i] == '[') *p++ = 'P';
46 else if (in2 (ot [i], '(', B_ELLIPSIS)) {
47 *p++ = ot [i] == '(' ? 'F' : 'E';
48 while (!in2 (ot [i], INTERNAL_ARGEND, -1)) i++;
49 if (ot [i] == -1) break;
50 } else parse_error (0, "BUG arglist");
51 if (ot [0] >= 0) {
52 char *tp = expand (ISSYMBOL (ot [0]) ? ot [0] :
53 name_of_struct (ot [0]));
54 /* Feature: structure by reference */
55 if (i == 1) *p++ = 'P';
56 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
57 *p++ = 'S';
58 while (*tp) *p++ = *tp++;
59 } else if (ot [1] == -1 && promo) {
60 if (ot [0] < B_FLOAT) *p++ = 'i';
61 else if (ot [0] < B_VOID) *p++ = 'f';
62 else if (ot [0] == B_VOID) *p++ = 'v';
63 } else switch (ot [0]) {
64 #define uif if (!promo) *p++ = 'u';
65 case B_UCHAR: uif
66 case B_SCHAR: *p++ = 'c';
67 ncase B_USINT: uif
68 case B_SSINT: *p++ = 's';
69 ncase B_UINT: uif
70 case B_SINT: *p++ = 'i';
71 ncase B_ULONG: uif
72 case B_SLONG: *p++ = 'l';
73 ncase B_ULLONG: uif
74 case B_SLLONG: *p++ = 'L';
75 ncase B_FLOAT: *p++ = 'f';
76 ncase B_DOUBLE: *p++ = 'F';
77 ncase B_LDOUBLE: *p++ = 'D';
78 ndefault: *p++ = 'v';
80 return p;
83 char *nametype (char *ret, typeID t)
85 *mangle_type (ret, t, 0) = 0;
86 return ret;
89 bool arglist_compare (typeID *l1, typeID *l2)
91 for (; *l1 != -1 && *l2 != -1; l1++, l2++)
92 if (*l1 != *l2) {
93 if (isstructptr (*l1) && isstructptr (*l2)) {
94 recID r1 = aliasclass (base_of (*l1));
95 recID r2 = aliasclass (base_of (*l2));
96 if (r1 == r2 || is_ancestor (r1, r2, 0, 0)
97 || is_ancestor (r2, r1, 0, 0)) continue;
99 return false;
101 return *l1 == *l2;
104 char *type_string (char *r, typeID t)
106 int argc;
107 char *p = r;
108 int *ot = open_typeID (t) + 2;
110 for (argc = 0; *ot != INTERNAL_ARGEND; argc++)
111 if (*ot == B_ELLIPSIS) *p++ = 'E';
112 else p = mangle_type (p, *ot++, 1);
113 sprintf (p, "%i", argc);
114 return r;
117 static void addflag (funcp *p, Token sp)
119 Token *n = mallocint (intlen (p->prototype) + 2);
120 sintprintf (n, sp, ISTR (p->prototype), -1);
121 free (p->prototype);
122 p->prototype = n;
125 static funcp *_declare_function (fspace *SF, Token e, Token f, typeID t, Token *proto,
126 Token *xargs, int flagz, Token section)
128 char st [256];
129 funcp *p, *w;
130 typeID *ovarglist = promoted_arglist_t (t);
131 bool rename;
132 Token un;
133 bool used = flagz & FUNCP_VIRTUAL;
134 fspace S;
136 if (!(S = intfind (*SF, e))) {
137 /*** first time ***/
138 p = (funcp*) malloc (sizeof *p);
139 *p = (funcp) {
140 .next = 0, .name = f, .type = t,
141 .prototype = proto ? intdup (proto) : 0,
142 .ovarglist = ovarglist, .dflt_args = 0,
143 .xargs = intdup (xargs), .flagz = flagz, .used = used,
144 .section = section
146 union ival u = { .p = p };
147 intadd (SF, e, u);
148 return p;
151 p = (funcp*) S->v.p;
153 for (rename = true, un = p->name, w = p; w; w = w->next)
154 if (w->name != un) {
155 rename = false;
156 break;
159 if (rename) {
160 /*** second time ***/
161 // overload existing functions declared previously
162 for (w = p; w; w = w->next)
163 if (arglist_compare (ovarglist, w->ovarglist)) {
164 // same function prototype again. no overload
165 if (t != w->type)
166 {fprintf (stderr, "BAD FUNCTION[%s]\n", expand (e));
167 parse_error_ll ("overloading match, type mis-match");
169 if (flagz & FUNCP_STATIC && !intchr (w->prototype, RESERVED_static))
170 addflag (w, RESERVED_static);
171 if (flagz & FUNCP_INLINE && !intchr (w->prototype, RESERVED_inline))
172 addflag (w, RESERVED_inline);
173 free (ovarglist);
174 return w;
176 Token nf1 = name_overload_fun (f, type_string (st, p->type));
177 rename_fdb (p->name, nf1);
178 rename_hier (p->name, nf1);
179 for (w = p; w; p = w, w = w->next) {
180 if (w->prototype)
181 intsubst (w->prototype, w->name, nf1);
182 w->name = nf1;
185 Token nf2 = name_overload_fun (f, type_string (st, t));
186 if (nf2 == nf1) parse_error_tok (nf1, "Different functions, same overloaded name!");
187 if (proto)
188 intsubst (proto, f, nf2);
189 p->next = (funcp*) malloc (sizeof *p);
190 p = p->next;
191 *p = (funcp) {
192 .next = 0, .name = nf2, .type = t,
193 .prototype = proto ? intdup (proto) : 0,
194 .ovarglist = ovarglist, .dflt_args = 0,
195 .xargs = intdup (xargs), .flagz = flagz, .used = used
197 return p;
200 /*** >2 time ***/
201 for (w = p; w; p = w, w = w->next)
202 if (arglist_compare (ovarglist, w->ovarglist)) {
203 if (t != w->type)
204 {fprintf (stderr, "BAD FUNCTION[%s]\n", expand (e));
205 parse_error_ll ("overload match, type mismatch");
207 if (flagz & FUNCP_STATIC && !intchr (w->prototype, RESERVED_static))
208 addflag (w, RESERVED_static);
209 if (flagz & FUNCP_INLINE && !intchr (w->prototype, RESERVED_inline))
210 addflag (w, RESERVED_inline);
211 free (ovarglist);
212 return w;
215 Token nf = name_overload_fun (f, type_string (st, t));
216 for (w = p; w; p = w, w = w->next)
217 if (w->name == nf)
218 parse_error_tok (nf, "Error: overloaded functions boil down to same name.");
219 if (proto)
220 intsubst (proto, f, nf);
221 p->next = (funcp*) malloc (sizeof *p);
222 p = p->next;
223 *p = (funcp) {
224 .next = 0, .name = nf, .type = t,
225 .prototype = proto ? intdup (proto) : 0,
226 .ovarglist = ovarglist, .dflt_args = 0,
227 .xargs = intdup (xargs), .flagz = flagz, .used = used,
228 .section = section
230 return p;
233 static typeID rmv_last_arg (typeID ft)
235 int *oo = open_typeID (ft);
236 int *o = allocaint (intlen (oo) + 2);
237 intcpy (o, oo);
238 int i;
239 for (i = 0; o [i] != INTERNAL_ARGEND; i++);
240 while ((o [i-1] = o [i]) != -1) i++;
241 return enter_type (o);
244 funcp *xdeclare_function (fspace *S, Token e, Token f, typeID t, Token *proto,
245 Token *xargs, int flagz, Token **dflt, Token section)
247 #ifdef DEBUG
248 if (debugflag.DCL_TRACE) {
249 PRINTF ("DECLARING FUNCTION ["COLS"%s"COLE", %s]\n", expand (f), expand (e));
250 PRINTF ("dflt=%p OF TYPE: ", dflt);
251 debug_pr_type (t);
252 PRINTF ("flagz=%i\n", flagz);
254 #endif
255 int dargc, i;
256 funcp *p;
258 if (Streams_Closed) proto = 0;
260 f = (p = _declare_function (S, e, f, t, proto, xargs, flagz, section))->name;
261 if (!dflt) return p;
263 for (dargc = 0; dflt [dargc]; dargc++);
265 proto = p->prototype;
266 for (i = 0, --dargc; i <= dargc; i++) {
267 t = rmv_last_arg (t);
268 p = p->next = (funcp*) malloc (sizeof *p);
269 *p = (funcp) {
270 .next = 0, .name = f, .type = t,
271 .prototype = proto, .ovarglist = promoted_arglist_t (t),
272 .dflt_args = &dflt [dargc - i], .section = section,
273 .xargs = intdup (xargs), .flagz = flagz, .used = flagz & FUNCP_VIRTUAL
277 return p;
280 void xmark_section_linkonce (fspace S, Token fn, Token ofn)
282 funcp *p = (funcp*) intfind (S, fn)->v.p;
283 while (p->name != ofn)
284 p = p->next;
285 p->flagz |= FUNCP_LINKONCE;
286 p->used = true;
289 void xmark_nothrow (fspace S, Token fn, Token ofn)
291 intnode *n = intfind (S, fn);
292 if (!n) return;
293 funcp *p = (funcp*) n->v.p;
294 while (p->name != ofn)
295 p = p->next;
296 p->flagz |= FUNCP_NOTHROW;
299 /* function is used by alias so if static inline, mark __attribute__ ((used)) */
300 int xmark_function_USED (fspace S, Token ofn)
302 funcp *p;
303 for (p = (funcp*) S->v.p; p; p = p->next)
304 if (p->name == ofn) {
305 p->flagz |= FUNCP_USED;
306 return 1;
308 if (S->less && xmark_function_USED (S->less, ofn))
309 return 1;
310 return S->more ? xmark_function_USED (S->more, ofn) : 0;
313 /* lookup a declaration. exact arglist match */
314 funcp *xlookup_function_dcl (fspace S, Token f, typeID argv[])
316 S = intfind (S, f);
317 if (!S) return 0;
319 funcp *p;
320 for (p = (funcp*) S->v.p; p; p = p->next)
321 if (arglist_compare (p->ovarglist, argv))
322 return p;
323 return 0;
326 /**************************************************
327 Lookups in function spaces
328 **************************************************/
330 fspace Global;
332 typeID lookup_function_symbol (Token e)
334 intnode *n = intfind (Global, e);
335 if (!n) return -1;
336 funcp *p = (funcp*) n->v.p;
337 if (p->next)
338 expr_errort ("function is overloaded. can't get address by name", e);
339 p->used = 1;
340 return p->type;
343 bool have_function (fspace S, Token f)
345 return intfind (S, f) != 0;
348 Token xlookup_function_uname (fspace S, Token f)
350 intnode *n = intfind (S, f);
351 if (!n) return 0;
352 funcp *p = (funcp*) n->v.p;
353 if (p->next)
354 parse_error_tok (f, "function is overloaded. can't get alias by name");
355 p->used = 1;
356 return p->name;
359 /* returns:
360 -1. lists, for one, have different argc
361 0. call list doesn't match
362 1. match after promotion
363 2. exact match
365 The second list is the call argument list while the first
366 the list of the function prototype. It matters
368 static int callist_compare (typeID *l1, typeID *l2)
370 if (*l1 == typeID_void && *l2 == -1)
371 return 2;
372 int ret = 2;
373 for (; *l2 != -1; l1++, l2++)
374 if (*l1 != *l2) {
375 if (in2 (B_ELLIPSIS, *l1, *l2) || typeID_elliptic (*l2)
376 || (*l1 >= 0 && typeID_elliptic (*l1)))
377 return ret;
378 if (*l1 < 0) return -1;
379 /* Feature: Hierarchy matches types */
380 if (isstructptr (*l1) && isstructptr (*l2)) {
381 recID r1 = aliasclass (dbase_of (*l1));
382 recID r2 = aliasclass (base_of (*l2));
383 if (r1 == r2) continue;
384 if (is_ancestor (r2, r1, 0, 0))
385 goto candidate;
387 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
388 if (ispointer (*l1) && ispointer (*l2))
389 if (*l1 == typeID_voidP || *l2 == typeID_voidP)
390 goto candidate;
391 if (is_reference (*l1) && bt_promotion (ptrdown (dereference (*l1))) == *l2)
392 goto candidate;
393 if (*l2 == typeID_int && *l1 == typeID_float)
394 goto candidate;
395 if (*l1 == typeID_int && *l2 == typeID_float)
396 goto candidate;
397 /* XXX: Comparing '0' with pointer is ok.... */
398 ret = 0; continue;
399 candidate:
400 ret = 1;
402 return *l1 == *l2 || *l1 == B_ELLIPSIS || typeID_elliptic (*l1) ? ret : -1;
405 /* the return value means:
406 -1: name does not even exist
407 0: no match
408 1: matches in number of arguments
409 2: -candidate- conversions match
410 3: exact match
412 int xlookup_function (fspace S, Token e, typeID argv[], flookup *ret)
414 S = intfind (S, e);
415 funcp *o, *match = 0;
416 int mt = -1, error = 0, rez;
418 if (!S) return -1;
419 o = (funcp*) S->v.p;
420 typeID *ovarglist = promoted_arglist (argv);
422 for (; o; o = o->next) {
423 rez = callist_compare (o->ovarglist, ovarglist);
424 if (rez == -1) continue;
425 if (mt < rez) {
426 mt = rez;
427 match = o;
428 error = 0;
429 } else if (mt == rez) {
430 error = 1;
434 if (!ret) return mt + 1;
436 if (error) expr_errort ("AMBIGOUS overload call", e);
438 free (ovarglist);
439 if (mt == -1) return 0;
440 match->used = true;
441 ret->oname = match->name;
442 ret->t = match->type;
443 if (ret->dflt_args = match->dflt_args) {
444 for (o = (funcp*) S->v.p; o->name != match->name; o = o->next);
445 o->used = true;
447 ret->xargs = match->xargs;
448 ret->flagz = match->flagz;
449 ret->prototype = match->prototype;
450 return mt + 1;
453 /**************************************************
455 Export the prototypes used
457 **************************************************/
459 OUTSTREAM printproto (OUTSTREAM O, Token proto[], Token fnm, bool palias)
461 int i = 0;
462 if (palias) {
463 if (StdcallMembers)
464 for (; proto [i] != -1; i++) {
465 if (proto [i] == fnm) {
466 output_itoken (O, RESERVED_attr_stdcall);
467 break;
469 output_itoken (O, proto [i]);
471 outprintf (O, ISTR (proto + i), -1);
472 } else {
473 for (i = 0; proto [i] != -1; i++) {
474 if (proto [i] == RESERVED___attribute__)
475 break;
476 output_itoken (O, proto [i]);
479 return O;
482 OUTSTREAM printproto_si (OUTSTREAM O, Token proto[], Token fnm, bool palias)
484 if (!intchr (proto, RESERVED_static))
485 output_itoken (O, RESERVED_static);
486 if (!intchr (proto, RESERVED_inline))
487 output_itoken (O, RESERVED_inline);
488 return printproto (O, proto, fnm, palias);
491 void export_fspace (fspace F)
493 funcp *p;
495 for (p = (funcp*) F->v.p; p; p = p->next)
496 if (p->used && !p->dflt_args && p->prototype
497 && !(p->flagz & (/*FUNCP_PURE|*/FUNCP_AUTO))) {
498 outprintf (FPROTOS, ISTR (p->prototype), -1);
499 if (p->flagz & FUNCP_LINKONCE && !(p->flagz & FUNCP_STATIC))
500 output_itoken (FPROTOS, linkonce_text (p->name));
501 else if (p->section)
502 outprintf (FPROTOS, RESERVED___attribute__, '(', '(',
503 RESERVED___section__, '(', p->section, ')', ')', ')',-1);
504 output_itoken (FPROTOS, ';');
507 if (F->less) export_fspace (F->less);
508 if (F->more) export_fspace (F->more);
511 void export_fspace_lwc (fspace F)
513 funcp *p;
515 for (p = (funcp*) F->v.p; p; p = p->next)
516 if (p->used && !p->dflt_args && p->prototype
517 && !(p->flagz & (/*FUNCP_PURE|*/FUNCP_AUTO))) {
518 printproto (FPROTOS, p->prototype, p->name, 1);
519 if (p->flagz & FUNCP_LINKONCE && !(p->flagz & FUNCP_STATIC))
520 output_itoken (FPROTOS, linkonce_text (p->name));
521 else if (p->section)
522 outprintf (FPROTOS, RESERVED___attribute__, '(', '(',
523 RESERVED___section__, '(', p->section, ')', ')', ')',-1);
524 if (p->flagz & FUNCP_USED)
525 outprintf (FPROTOS, RESERVED___attribute__, '(', '(', RESERVED_used, ')', ')', -1);
526 output_itoken (FPROTOS, ';');
529 if (F->less) export_fspace_lwc (F->less);
530 if (F->more) export_fspace_lwc (F->more);