1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 #include <vdb/extern.h>
27 #include "schema-priv.h"
28 #include "schema-parse.h"
29 #include "schema-expr.h"
30 #include "schema-dump.h"
31
32 #include <klib/symbol.h>
33 #include <klib/symtab.h>
34 #include <klib/out.h>
35 #include <klib/rc.h>
36 #include <sysalloc.h>
37
38 #include <stdlib.h>
39 #include <string.h>
40 #include <assert.h>
41
42
43 /*--------------------------------------------------------------------------
44 * SIndirectConst
45 * a parameterized constant
46 */
47 #if SLVL >= 3
48
49 /* Whack
50 */
SIndirectConstWhack(void * item,void * ignore)51 void CC SIndirectConstWhack ( void *item, void *ignore )
52 {
53 SIndirectConst * self = item;
54 SExpressionWhack ( self -> td );
55 free ( self );
56 }
57
58 /* Mark
59 */
SIndirectConstMark(void * item,void * data)60 void CC SIndirectConstMark ( void * item, void * data )
61 {
62 const SIndirectConst * self = item;
63 if ( self != NULL )
64 SExpressionMark ( ( void* ) self -> td, data );
65 }
66
67 /* Dump
68 * dump "const", dump object
69 */
SIndirectConstDump(const SIndirectConst * self,struct SDumper * d)70 rc_t SIndirectConstDump ( const SIndirectConst *self, struct SDumper *d )
71 {
72 return KSymbolDump ( self != NULL ? self -> name : NULL, d );
73 }
74
SIndirectConstDefDump(void * item,void * data)75 bool CC SIndirectConstDefDump ( void *item, void *data )
76 {
77 SDumper *b = data;
78 const SIndirectConst *self = ( const void* ) item;
79
80 /* check for this being a function */
81 if ( self -> td == NULL )
82 b -> rc = SDumperPrint ( b, "function %N", self -> name );
83 else
84 b -> rc = SDumperPrint ( b, "%E %N", self -> td, self -> name );
85
86 return ( b -> rc != 0 ) ? true : false;
87 }
88 #endif
89
90 /*--------------------------------------------------------------------------
91 * SIndirectType
92 */
93 #if SLVL >= 3
94
95 /* Whack
96 */
SIndirectTypeWhack(void * item,void * ignore)97 void CC SIndirectTypeWhack ( void *item, void *ignore )
98 {
99 free ( item );
100 }
101
102
103 /* Find
104 */
VSchemaFindITypeid(const VSchema * self,uint32_t id)105 SIndirectType *VSchemaFindITypeid ( const VSchema *self, uint32_t id )
106 {
107 SIndirectType *pt = VectorGet ( & self -> pt, id );
108 while ( pt == NULL )
109 {
110 self = self -> dad;
111 if ( self == NULL )
112 break;
113 pt = VectorGet ( & self -> pt, id );
114 }
115 return pt;
116 }
117
118
119 /* Dump
120 */
SIndirectTypeDump(const SIndirectType * self,struct SDumper * d)121 rc_t SIndirectTypeDump ( const SIndirectType *self, struct SDumper *d )
122 {
123 return KSymbolDump ( self != NULL ? self -> name : NULL, d );
124 }
125
126 #endif
127
128 /*--------------------------------------------------------------------------
129 * SFormParamlist
130 */
131 #if SLVL >= 3
132
133 /* Whack
134 */
SFormParmlistWhack(SFormParmlist * self,void (CC * pwhack)(void *,void *))135 void SFormParmlistWhack ( SFormParmlist *self, void ( CC * pwhack ) ( void*, void* ) )
136 {
137 VectorWhack ( & self -> parms, pwhack, NULL );
138 }
139
140
141 /* Mark
142 */
SFormParmlistMark(const SFormParmlist * self,void (CC * mark)(void *,void *),const VSchema * schema)143 void SFormParmlistMark ( const SFormParmlist *self,
144 void ( CC * mark ) ( void*, void* ), const VSchema *schema )
145 {
146 if ( self != NULL )
147 VectorForEach ( & self -> parms, false, mark, ( void* ) schema );
148 }
149
150
151 /* Dump
152 * dump param list
153 */
SFormParamlistDump(const SFormParmlist * self,SDumper * b,bool (CC * dump)(void *,void *),const char * begin,const char * end,const char * empty)154 rc_t SFormParamlistDump ( const SFormParmlist *self, SDumper *b,
155 bool ( CC * dump ) ( void*, void* ),
156 const char *begin, const char *end, const char *empty )
157 {
158 rc_t rc;
159 void *item;
160 uint32_t i, parm_cnt = VectorLength ( & self -> parms );
161 bool compact = SDumperMode ( b ) == sdmCompact ? true : false;
162
163 /* if the guy has no specific parameters */
164 if ( parm_cnt == 0 )
165 {
166 if ( self -> vararg )
167 return SDumperPrint ( b, "%s...%s", begin, end );
168 return SDumperPrint ( b, empty );
169 }
170
171 /* print mandatory params */
172 SDumperSepString ( b, begin );
173 for ( rc = 0, i = 0; i < ( uint32_t ) self -> mand; ++ i )
174 {
175 item = VectorGet ( & self -> parms, i );
176 rc = SDumperSep ( b );
177 if ( rc == 0 && ( * dump ) ( item, b ) )
178 rc = b -> rc;
179 SDumperSepString ( b, compact ? "," : ", " );
180 }
181 if ( rc != 0 )
182 return rc;
183
184 if ( i != 0 )
185 SDumperSepString ( b, compact ? "*" : " * " );
186 else
187 {
188 /* issue "begin" */
189 rc = SDumperSep ( b );
190 if ( rc != 0 )
191 return rc;
192
193 SDumperSepString ( b, compact ? "*" : "* " );
194 }
195
196 /* print optional params */
197 for ( ; i < parm_cnt; ++ i )
198 {
199 item = VectorGet ( & self -> parms, i );
200 rc = SDumperSep ( b );
201 if ( rc == 0 && ( * dump ) ( item, b ) )
202 rc = b -> rc;
203 SDumperSepString ( b, compact ? "," : ", " );
204 }
205 if ( rc != 0 )
206 return rc;
207
208 /* print optional vararg */
209 if ( self -> vararg )
210 return SDumperPrint ( b, compact ? ",...%s" : ", ...%s", end );
211
212 /* close */
213 return SDumperPrint ( b, end );
214 }
215
216 #endif
217
218 /*--------------------------------------------------------------------------
219 * SFunction
220 */
221
222 #if SLVL >= 3
223
224 /* Whack
225 */
SFunctionDestroy(SFunction * self)226 void SFunctionDestroy ( SFunction *self )
227 {
228 SExpressionWhack ( self -> rt );
229 #if SLVL >= 4
230 if ( self -> script )
231 {
232 SExpressionWhack ( self -> u . script . rtn );
233 VectorWhack ( & self -> u . script . prod, SProductionWhack, NULL );
234 }
235 #endif
236 BSTreeWhack ( & self -> sscope, KSymbolWhack, NULL );
237 BSTreeWhack ( & self -> fscope, KSymbolWhack, NULL );
238 SFormParmlistWhack ( & self -> fact, SIndirectConstWhack );
239 SFormParmlistWhack ( & self -> func, SProductionWhack );
240 VectorWhack ( & self -> type, NULL, NULL );
241 VectorWhack ( & self -> schem, SIndirectConstWhack, NULL );
242 }
243
SFunctionWhack(void * self,void * ignore)244 void CC SFunctionWhack ( void *self, void *ignore )
245 {
246 SFunctionDestroy ( self );
247 free ( self );
248 }
249
250 /* Cmp
251 * Sort
252 */
SFunctionCmp(const void * item,const void * n)253 int64_t CC SFunctionCmp ( const void *item, const void *n )
254 {
255 const uint32_t *a = item;
256 const SFunction *b = n;
257
258 if ( * a > b -> version )
259 return 1;
260 return ( int64_t ) ( * a >> 24 ) - ( int64_t ) ( b -> version >> 24 );
261 }
262
SFunctionSort(const void * item,const void * n)263 int64_t CC SFunctionSort ( const void *item, const void *n )
264 {
265 const SFunction *a = item;
266 const SFunction *b = n;
267
268 return ( int64_t ) ( a -> version >> 24 ) - ( int64_t ) ( b -> version >> 24 );
269 }
270
271 #if _DEBUGGING && 0
272 static String no_name = { "<no-name>", sizeof "<no-name>" - 1, sizeof "<no-name>" - 1 };
273 #define DBG_CXBIND1( op, name, id, val ) \
274 OUTMSG (( "%s:%d - cx_bind %s: name=%S, id=%u, val=%p\n", __func__, __LINE__, op, & name, id, val ))
275 #define DBG_CXBIND2( op, name, id, old, new ) \
276 OUTMSG (( "%s:%d - cx_bind %s: name=%S, id=%u, old=%p, new=%p\n", __func__, __LINE__, op, & name, id, old, new ))
277 #else
278 #define DBG_CXBIND1( op, name, id, val ) \
279 ( ( void ) 0 )
280 #define DBG_CXBIND2( op, name, id, old, new ) \
281 ( ( void ) 0 )
282 #endif
283
284 /* Bind
285 * perform schema and factory param substitution
286 * returns prior param values
287 *
288 * 9/11/13
289 * "self" is a cursor-local cloned version of schema decl
290 */
SFunctionBindSchemaParms(const SFunction * self,Vector * prior,const Vector * subst,Vector * cx_bind)291 rc_t SFunctionBindSchemaParms ( const SFunction *self,
292 Vector *prior, const Vector *subst, Vector *cx_bind )
293 {
294 rc_t rc = 0;
295 uint32_t i, count;
296 void *cx_old, *cx_new;
297
298 const SIndirectType *id;
299 const SIndirectConst *ic;
300
301 /* count input params
302 the first bunch are types
303 the remainder are constants */
304 uint32_t expected = VectorLength ( & self -> type ) + VectorLength ( & self -> schem );
305 uint32_t actual = VectorLength ( subst );
306
307 /* initialize return value
308 the prior values act as a stack for recursion */
309 VectorInit ( prior, 0, actual );
310
311 /* param counts must match */
312 if ( actual < expected )
313 rc = RC ( rcVDB, rcFunction, rcEvaluating, rcParam, rcInsufficient );
314 else if ( actual > expected )
315 rc = RC ( rcVDB, rcFunction, rcEvaluating, rcParam, rcExcessive );
316 if ( rc != 0 )
317 {
318 PLOGERR ( klogWarn, ( klogWarn, rc,
319 "schema parameter count mismatch - function: '$(f)'; expected $(i), received $(count)",
320 "f=%.*s,count=%u,i=%u",
321 self -> name ? self -> name -> name . size : 0,
322 self -> name ? self -> name -> name . addr : NULL,
323 expected, actual ));
324 return rc;
325 }
326
327 /* bind types */
328 count = VectorLength ( & self -> type );
329 for ( i = 0; i < count; ++ i )
330 {
331 /* get the indirect type object */
332 id = VectorGet ( & self -> type, i );
333 assert ( id != NULL );
334
335 /* get the new type expression */
336 cx_new = VectorGet ( subst, id -> pos );
337 assert ( cx_new != NULL );
338
339 /* update the binding vector */
340 rc = VectorSwap ( cx_bind, id -> type_id, cx_new, & cx_old );
341 if ( rc != 0 )
342 break;
343 DBG_CXBIND2 ( "bind schema type", id -> name -> name, id -> type_id, cx_old, cx_new );
344
345 /* save old value on stack for recursion */
346 rc = VectorSet ( prior, id -> pos, cx_old );
347 if ( rc != 0 )
348 {
349 cx_new = cx_old;
350 VectorSwap ( cx_bind, id -> type_id, cx_new, & cx_old );
351 DBG_CXBIND2 ( "revert bind type", id -> name -> name, id -> type_id, cx_old, cx_new );
352 break;
353 }
354 }
355
356 /* bind constants */
357 if ( rc == 0 )
358 {
359 count = VectorLength ( & self -> schem );
360 for ( i = 0 ; i < count; ++ i )
361 {
362 ic = VectorGet ( & self -> schem, i );
363 assert ( ic != NULL );
364
365 /* get the new constant value expression */
366 cx_new = VectorGet ( subst, ic -> pos );
367 assert ( cx_new != NULL );
368
369 /* update the binding vector */
370 rc = VectorSwap ( cx_bind, ic -> expr_id, cx_new, & cx_old );
371 if ( rc != 0 )
372 break;
373 DBG_CXBIND2 ( "bind schema const", ic -> name -> name, ic -> expr_id, cx_old, cx_new );
374
375 /* save old value on stack for recursion */
376 rc = VectorSet ( prior, ic -> pos, cx_old );
377 if ( rc != 0 )
378 {
379 cx_new = cx_old;
380 VectorSwap ( cx_bind, ic -> expr_id, cx_new, & cx_old );
381 DBG_CXBIND2 ( "revert bind const", ic -> name -> name, ic -> expr_id, cx_old, cx_new );
382 break;
383 }
384 }
385
386 /* if there was no error, we're done */
387 if ( rc == 0 )
388 return 0;
389
390 /* reverse the damage done by binding constants */
391 while ( i -- > 0 )
392 {
393 ic = VectorGet ( & self -> schem, i );
394 assert ( ic != NULL );
395
396 /* get the old constant value expression */
397 cx_new = VectorGet ( prior, ic -> pos );
398 assert ( cx_new != NULL );
399
400 /* restore the binding vector */
401 VectorSwap ( cx_bind, ic -> expr_id, cx_new, & cx_old );
402 DBG_CXBIND2 ( "revert bind const", ic -> name -> name, ic -> expr_id, cx_old, cx_new );
403 }
404
405 /* reset i */
406 i = VectorLength ( & self -> type );
407 }
408
409 /* reverse the damage done by binding types */
410 while ( i -- > 0 )
411 {
412 /* get the indirect type object */
413 id = VectorGet ( & self -> type, i );
414 assert ( id != NULL );
415
416 /* get the old type expression */
417 cx_new = VectorGet ( prior, id -> pos );
418 assert ( cx_new != NULL );
419
420 /* restore the binding vector */
421 VectorSwap ( cx_bind, id -> type_id, cx_new, & cx_old );
422 DBG_CXBIND2 ( "revert bind type", id -> name -> name, id -> type_id, cx_old, cx_new );
423 }
424
425 /* a non-zero rc indicates the Vector is invalid */
426 VectorWhack ( prior, NULL, NULL );
427 return rc;
428 }
429
SFunctionBindFactParms(const SFunction * self,Vector * parms,Vector * prior,const Vector * subst,Vector * cx_bind)430 rc_t SFunctionBindFactParms ( const SFunction *self,
431 Vector *parms, Vector *prior, const Vector *subst, Vector *cx_bind )
432 {
433 rc_t rc = 0;
434 SIndirectConst *ic;
435 void *cx_old, *cx_new;
436 uint32_t i, /*count,*/ act_count, form_count;
437
438 /* count input params */
439 /*count =*/ act_count = VectorLength ( subst );
440
441 /* must have minimum count */
442 if ( act_count < self -> fact . mand )
443 {
444 rc = RC ( rcVDB, rcFunction, rcEvaluating, rcParam, rcInsufficient );
445 PLOGERR ( klogWarn, ( klogWarn, rc,
446 "missing mandatory factory parameters - function: '$(func)'; expected $(mand), received $(count)",
447 "func=%.*s,mand=%u,count=%u",
448 self -> name -> name . size, self -> name -> name . addr,
449 self -> fact . mand, act_count ));
450 return rc;
451 }
452
453 /* test against maximum count */
454 form_count = VectorLength ( & self -> fact . parms );
455 if ( act_count > form_count )
456 {
457 if ( ! self -> fact . vararg )
458 {
459 rc = RC ( rcVDB, rcFunction, rcEvaluating, rcParam, rcExcessive );
460 PLOGERR ( klogWarn, ( klogWarn, rc,
461 "extra factory parameters - function: '$(func)'; expected $(mand), received $(count)",
462 "func=%.*s,mand=%u,count=%u",
463 self -> name -> name . size, self -> name -> name . addr,
464 form_count, act_count ));
465 return rc;
466 }
467 /*count = form_count;*/
468 }
469
470 /* initialize return values
471 the "parms" vector is a positional vector of expressions,
472 and is the only way to get at varargs.
473 the prior values act as a stack for recursion */
474 VectorInit ( parms, 0, act_count );
475 VectorInit ( prior, 0, form_count );
476
477 /* bind actual formal parameter values */
478 for ( i = 0; i < form_count && i < act_count; ++ i )
479 {
480 /* get the indirect constant object */
481 ic = VectorGet ( & self -> fact . parms, i );
482 assert ( ic != NULL );
483
484 /* get the new value expression */
485 assert ( ic -> pos == i );
486 cx_new = VectorGet ( subst, i );
487 assert ( cx_new != NULL );
488
489 /* update the positional vector */
490 rc = VectorAppend ( parms, NULL, cx_new );
491 if ( rc != 0 )
492 break;
493
494 /* update the binding vector */
495 rc = VectorSwap ( cx_bind, ic -> expr_id, cx_new, & cx_old );
496 if ( rc != 0 )
497 break;
498 DBG_CXBIND2 ( "bind fact const", ic -> name -> name, ic -> expr_id, cx_old, cx_new );
499
500 /* save the old value on stack for recursion */
501 rc = VectorSet ( prior, i, cx_old );
502 if ( rc != 0 )
503 {
504 cx_new = cx_old;
505 VectorSwap ( cx_bind, ic -> expr_id, cx_new, & cx_old );
506 DBG_CXBIND2 ( "revert bind const", ic -> name -> name, ic -> expr_id, cx_old, cx_new );
507 break;
508 }
509 }
510
511 if ( rc == 0 )
512 {
513 /* this loop should only actually execute
514 to record missing optional formals */
515 assert ( i == form_count || ( i == act_count && act_count < form_count ) );
516
517 /* record optional formal parameter values */
518 for ( ; i < form_count; ++ i )
519 {
520 /* get the indirect constant object */
521 ic = VectorGet ( & self -> fact . parms, i );
522 assert ( ic != NULL );
523
524 /* get the new value expression */
525 assert ( ic -> pos == i );
526 cx_new = VectorGet ( subst, i );
527
528 /* save the same value on stack for recursion */
529 rc = VectorSet ( prior, i, cx_new );
530 if ( rc != 0 )
531 break;
532
533 DBG_CXBIND1 ( "ignore optional fact const", ic -> name -> name, ic -> expr_id, cx_new );
534 }
535 }
536
537 if ( rc == 0 )
538 {
539 /* this loop should only actually execute
540 to record vararg params beyond all formals */
541 assert ( i == form_count );
542
543 /* set vararg values */
544 for ( ; i < act_count; ++ i )
545 {
546 /* get the extra value expression */
547 cx_new = VectorGet ( subst, i );
548 assert ( cx_new != NULL );
549
550 /* update the positional vector */
551 rc = VectorAppend ( parms, NULL, cx_new );
552 if ( rc != 0 )
553 break;
554
555 DBG_CXBIND1 ( "vararg fact const", no_name, 0, cx_new );
556 }
557
558 if ( rc == 0 )
559 return 0;
560
561 i = form_count;
562 }
563
564 while ( i -- > 0 )
565 {
566 /* get the indirect type object */
567 ic = VectorGet ( & self -> fact . parms, i );
568 assert ( ic != NULL );
569
570 /* get the old type expression */
571 cx_new = VectorGet ( subst, ic -> pos );
572 assert ( cx_new != NULL );
573
574 /* restore the binding vector */
575 VectorSwap ( cx_bind, ic -> expr_id, cx_new, & cx_old );
576 DBG_CXBIND2 ( "revert bind const", ic -> name -> name, ic -> expr_id, cx_old, cx_new );
577 }
578
579 VectorWhack ( parms, NULL, NULL );
580 VectorWhack ( prior, NULL, NULL );
581
582 return rc;
583 }
584
585 /* Rest-ore
586 * restore schema and factory param substitution
587 * destroys prior param vector
588 */
SFunctionRestSchemaParms(const SFunction * self,Vector * prior,Vector * cx_bind)589 void SFunctionRestSchemaParms ( const SFunction *self, Vector *prior, Vector *cx_bind )
590 {
591 rc_t rc;
592 uint32_t i, count;
593 void * cx_old, * ignore;
594
595 /* must have whole thing in prior */
596 assert ( VectorLength ( prior ) == VectorLength ( & self -> type ) + VectorLength ( & self -> schem ) );
597
598 /* restore prior values */
599 count = VectorLength ( & self -> type );
600 for ( i = 0; i < count; ++ i )
601 {
602 /* get the indirect type object */
603 const SIndirectType *id = VectorGet ( & self -> type, i );
604 assert ( id != NULL );
605
606 /* get the old type expression */
607 cx_old = VectorGet ( prior, id -> pos );
608
609 /* update the binding vector */
610 rc = VectorSwap ( cx_bind, id -> type_id, cx_old, & ignore );
611 assert ( rc == 0 );
612
613 DBG_CXBIND2 ( "restore bind type", id -> name -> name, id -> type_id, ignore, cx_old );
614 }
615
616 count = VectorLength ( & self -> schem );
617 for ( i = 0; i < count; ++ i )
618 {
619 const SIndirectConst *ic = VectorGet ( & self -> schem, i );
620 assert ( ic != NULL );
621
622 /* get the old constant value expression */
623 cx_old = VectorGet ( prior, ic -> pos );
624
625 /* restore the binding vector */
626 rc = VectorSwap ( cx_bind, ic -> expr_id, cx_old, & ignore );
627 assert ( rc == 0 );
628
629 DBG_CXBIND2 ( "restore bind const", ic -> name -> name, ic -> expr_id, ignore, cx_old );
630 }
631
632 VectorWhack ( prior, NULL, NULL );
633 }
634
SFunctionRestFactParms(const SFunction * self,Vector * prior,Vector * cx_bind)635 void SFunctionRestFactParms ( const SFunction *self, Vector *prior, Vector *cx_bind )
636 {
637 rc_t rc;
638 uint32_t i, count;
639 void * cx_old, * ignore;
640
641 /* must have whole thing in prior */
642 assert ( VectorLength ( prior ) == VectorLength ( & self -> fact . parms ) );
643
644 /* restore prior values */
645 count = VectorLength ( & self -> fact . parms );
646 for ( i = 0; i < count; ++ i )
647 {
648 const SIndirectConst *ic = VectorGet ( & self -> fact . parms, i );
649 assert ( ic != NULL );
650
651 /* get the old constant value expression */
652 cx_old = VectorGet ( prior, ic -> pos );
653
654 /* restore the binding vector */
655 rc = VectorSwap ( cx_bind, ic -> expr_id, cx_old, & ignore );
656 assert ( rc == 0 );
657
658 DBG_CXBIND2 ( "restore bind const", ic -> name -> name, ic -> expr_id, ignore, cx_old );
659 }
660
661 VectorWhack ( prior, NULL, NULL );
662 }
663
664
665 /* Mark
666 */
SFunctionClearMark(void * item,void * ignore)667 void CC SFunctionClearMark ( void *item, void *ignore )
668 {
669 SFunction *self = item;
670 self -> marked = false;
671 }
672
SFunctionMark(void * item,void * data)673 void CC SFunctionMark ( void * item, void * data )
674 {
675 SFunction * self = item;
676 const VSchema * schema = data;
677 if ( self != NULL && ! self -> marked )
678 {
679 self -> marked = true;
680 SExpressionMark ( ( void * )self -> rt, data );
681 SFormParmlistMark ( & self -> fact, SIndirectConstMark, schema );
682 SFormParmlistMark ( & self -> func, SProductionMark, schema );
683 VectorForEach ( & self -> schem, false, SIndirectConstMark, data );
684
685 if ( self -> script )
686 {
687 SExpressionMark ( ( void * )self -> u . script . rtn, ( void * )schema );
688 VectorForEach ( & self -> u . script . prod, false, SProductionMark, data );
689 }
690 }
691 }
692
SFuncNameMark(const SNameOverload * self,const VSchema * schema)693 void SFuncNameMark ( const SNameOverload *self, const VSchema *schema )
694 {
695 if ( self != NULL )
696 {
697 VectorForEach ( & self -> items, false, SFunctionMark, ( void * ) schema );
698 }
699 }
700
701
702 /* Dump
703 */
SFunctionDump(const SFunction * self,struct SDumper * d)704 rc_t SFunctionDump ( const SFunction *self, struct SDumper *d )
705 {
706 return FQNDump ( self != NULL ? self -> name : NULL, d );
707 }
708
SFunctionDeclDumpSchemaParms(const SFunction * self,SDumper * b)709 rc_t SFunctionDeclDumpSchemaParms ( const SFunction *self, SDumper *b )
710 {
711 bool compact = SDumperMode ( b ) == sdmCompact ? true : false;
712
713 /* this first part is weird, because the types and
714 constants are kept separately, although they were
715 specified in a single list */
716 uint32_t i, j, sparm_cnt = VectorLength ( & self -> type ) +
717 VectorLength ( & self -> schem );
718 if ( sparm_cnt == 0 )
719 return 0;
720
721 SDumperSepString ( b, compact ? "<" : "< " );
722 for ( i = j = 0; i < sparm_cnt; ++ i )
723 {
724 const SIndirectType *id = VectorGet ( & self -> type, i - j );
725 rc_t rc = SDumperSep ( b );
726 if ( rc != 0 )
727 return rc;
728 if ( id != NULL && id -> pos == i )
729 rc = SDumperPrint ( b, "type %N", id -> name );
730 else
731 {
732 const SIndirectConst *ic = VectorGet ( & self -> schem, j );
733 assert ( id == NULL || id -> pos > i );
734 if ( ic == NULL )
735 rc = SDumperWrite ( b, "NULL", 4 );
736 else
737 SIndirectConstDefDump ( ( void* ) ic, b );
738 }
739 if ( rc != 0 )
740 return rc;
741 SDumperSepString ( b, compact ? "," : ", " );
742 }
743
744 return SDumperPrint ( b, compact ? ">" : " > " );
745 }
746
SFunctionDeclDumpFactParms(const SFunction * self,SDumper * b)747 rc_t SFunctionDeclDumpFactParms ( const SFunction *self, SDumper *b )
748 {
749 if ( SDumperMode ( b ) == sdmCompact )
750 return SFormParamlistDump ( & self -> fact, b, SIndirectConstDefDump, "<", ">", "" );
751 return SFormParamlistDump ( & self -> fact, b, SIndirectConstDefDump, " < ", " >", "" );
752 }
753
SFunctionDeclDump(void * item,void * data)754 bool CC SFunctionDeclDump ( void *item, void *data )
755 {
756 SDumper *b = data;
757 const SFunction *self = ( const void* ) item;
758 const char *func_class = "extern";
759
760 bool compact = SDumperMode ( b ) == sdmCompact ? true : false;
761
762 if ( SDumperMarkedMode ( b ) && ! self -> marked )
763 return false;
764
765 if ( self -> script )
766 func_class = "schema";
767 else if ( self -> validate )
768 func_class = "validate";
769
770 /* a type of function */
771 b -> rc = SDumperPrint ( b, "%s function ", func_class );
772 if ( b -> rc == 0 )
773 {
774 if ( self -> untyped )
775 b -> rc = SDumperPrint ( b, compact ? "__untyped %N()" : "__untyped %N ()", self -> name );
776 else if ( self -> row_length )
777 b -> rc = SDumperPrint ( b, compact ? "__row_length %N()" : "__row_length %N ()", self -> name );
778 else
779 {
780 /* could have schema parameters */
781 b -> rc = SFunctionDeclDumpSchemaParms ( self, b );
782
783 /* a return type expression, followed by a function name */
784 if ( b -> rc == 0 )
785 {
786 if ( self -> validate )
787 b -> rc = SDumperPrint ( b, "void %N", self -> name );
788 else
789 b -> rc = SDumperPrint ( b, "%E %N", self -> rt, self -> name );
790 }
791
792 /* version should be given */
793 if ( b -> rc == 0 )
794 b -> rc = SDumperVersion ( b, self -> version );
795
796 /* factory parameters */
797 if ( b -> rc == 0 )
798 b -> rc = SFunctionDeclDumpFactParms ( self, b );
799
800 /* function parameters */
801 if ( b -> rc == 0 )
802 {
803 if ( compact )
804 b -> rc = SFormParamlistDump ( & self -> func, b, SProductionDefDump, "(", ")", "()" );
805 else
806 b -> rc = SFormParamlistDump ( & self -> func, b, SProductionDefDump, " ( ", " )", " ()" );
807 }
808 }
809 }
810
811 if ( b -> rc == 0 )
812 {
813 #if SLVL >= 4
814 if ( self -> script )
815 {
816 if ( ! compact )
817 b -> rc = SDumperWrite ( b, "\n", 1 );
818 if ( b -> rc == 0 )
819 b -> rc = SFunctionBodyDump ( self, b );
820 }
821 else
822 #endif
823 {
824 if ( self -> u . ext . fact != NULL )
825 b -> rc = SDumperPrint ( b, compact ? "=%N" : " = %N", self -> u . ext . fact );
826 if ( b -> rc == 0 )
827 b -> rc = SDumperPrint ( b, compact ? ";" : ";\n" );
828 }
829 }
830
831 if ( b -> rc == 0 )
832 b -> rc = AliasDump ( self -> name, b );
833
834 return ( b -> rc != 0 ) ? true : false;
835 }
836
837 #endif
838
839
840 /*--------------------------------------------------------------------------
841 * VSchema
842 */
843
844 #if SLVL >= 3
845
846 /*
847 * formal-symbol = ID
848 */
849 static
formal_symbol(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,uint32_t id,const void * obj)850 rc_t formal_symbol ( KSymTable *tbl, KTokenSource *src, KToken *t,
851 const SchemaEnv *env, uint32_t id, const void *obj )
852 {
853 rc_t rc;
854
855 /* allow symbol redefines in current scope only */
856 if ( t -> sym != NULL )
857 {
858 KTokenSourceReturn ( src, t );
859 next_shallow_token ( tbl, src, t, true );
860 }
861
862 /* must have a parameter name */
863 if ( t -> id != eIdent )
864 return KTokenExpected ( t, klogErr, "undefined identifier" );
865
866 /* create the symbol in current scope */
867 rc = KSymTableCreateSymbol ( tbl, & t -> sym, & t -> str, id, obj );
868 if ( rc != 0 )
869 KTokenRCExplain ( t, klogInt, rc );
870
871 return rc;
872 }
873
874
875 /*
876 * param-formal = [ 'control' ] <typespec> ID
877 */
878 static
param_formal(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFormParmlist * sig)879 rc_t param_formal ( KSymTable *tbl, KTokenSource *src, KToken *t,
880 const SchemaEnv *env, VSchema *self, SFormParmlist *sig )
881 {
882 rc_t rc;
883
884 /* create the factory formal parameter,
885 which is just a production awaiting an expr */
886 SProduction *param = malloc ( sizeof * param );
887 if ( param == NULL )
888 {
889 rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
890 return KTokenRCExplain ( t, klogInt, rc );
891 }
892
893 /* finish initialization */
894 memset ( param, 0, sizeof * param );
895
896 /* accept 'control' keyword */
897 if ( t -> id == kw_control )
898 {
899 param -> control = true;
900 next_token ( tbl, src, t );
901 }
902
903 /* if parsing v0 text, then this is a persisted
904 column schema. it will have only a formal param
905 name, but no type. substitute "any" */
906 if ( env -> schema_param_types_absent )
907 {
908 KTokenSourceReturn ( src, t );
909 CONST_STRING ( & t -> str, "any" );
910 t -> sym = KSymTableFindIntrinsic ( tbl, & t -> str );
911 assert ( t -> sym != NULL );
912 t -> id = t -> sym -> type;
913 }
914
915 /* should start off with a type */
916 rc = vardim_type_expr ( tbl, src, t, env, self, & param -> fd );
917 if ( rc != 0 )
918 {
919 free ( param );
920 return rc;
921 }
922
923 /* create a name */
924 rc = formal_symbol ( tbl, src, t, env, eFuncParam, param );
925 if ( rc != 0 )
926 {
927 SProductionWhack ( param, NULL );
928 return rc;
929 }
930 param -> name = t -> sym;
931
932 /* append to param list */
933 rc = VectorAppend ( & sig -> parms, & param -> cid . id, param );
934 if ( rc != 0 )
935 {
936 SProductionWhack ( param, NULL );
937 return KTokenRCExplain ( t, klogInt, rc );
938 }
939
940 next_token ( tbl, src, t );
941 return 0;
942 }
943
944
945 /*
946 * fact-formals = <fact-formal> [ ',' <fact-formals> ]
947 * fact-formal = <fact-typedecl> ID
948 * fact-parmname = ID
949 */
950 static
fact_formal(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFormParmlist * sig)951 rc_t fact_formal ( KSymTable *tbl, KTokenSource *src, KToken *t,
952 const SchemaEnv *env, VSchema *self, SFormParmlist *sig )
953 {
954 rc_t rc;
955 SIndirectConst *param = malloc ( sizeof * param );
956 if ( param == NULL )
957 {
958 rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
959 return KTokenRCExplain ( t, klogInt, rc );
960 }
961
962 param -> td = NULL;
963 param -> expr_id = 0;
964
965 #if ACCEPT_FUNCTION_AS_FACT_PARAM
966 /* type could be 'function' */
967 if ( t -> id == kw_function )
968 next_token ( tbl, src, t );
969
970 /* should be a typedecl */
971 else
972 #endif
973 {
974 rc = type_expr ( tbl, src, t, env, self, & param -> td );
975 if ( rc != 0 )
976 {
977 free ( param );
978 return KTokenFailure ( t, klogErr, rc,
979 #if ACCEPT_FUNCTION_AS_FACT_PARAM
980 "function or "
981 #endif
982 "data type" );
983 }
984 }
985
986 /* get its name */
987 rc = formal_symbol ( tbl, src, t, env, eFactParam, param );
988 if ( rc != 0 )
989 {
990 SIndirectConstWhack ( param, NULL );
991 return rc;
992 }
993 param -> name = t -> sym;
994
995 /* store as a parameter */
996 rc = VectorAppend ( & sig -> parms, & param -> pos, param );
997 if ( rc != 0 )
998 {
999 SIndirectConstWhack ( param, NULL );
1000 return KTokenRCExplain ( t, klogInt, rc );
1001 }
1002
1003 /* set binding constant */
1004 param -> expr_id = ++ self -> num_indirect;
1005
1006 next_token ( tbl, src, t );
1007 return 0;
1008 }
1009
1010
1011 /*
1012 * formal-params = <formal-param> [ ',' <formal-params> ]
1013 */
1014 static
formal_params(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFormParmlist * sig,rc_t (* formal_param)(KSymTable *,KTokenSource *,KToken *,const SchemaEnv *,VSchema *,SFormParmlist *))1015 rc_t formal_params ( KSymTable *tbl, KTokenSource *src, KToken *t,
1016 const SchemaEnv *env, VSchema *self, SFormParmlist *sig,
1017 rc_t ( * formal_param ) ( KSymTable*, KTokenSource*, KToken*,
1018 const SchemaEnv*, VSchema*, SFormParmlist* ) )
1019 {
1020 while ( t -> sym != NULL || t -> id == eIdent )
1021 {
1022 rc_t rc = ( * formal_param ) ( tbl, src, t, env, self, sig );
1023 if ( rc != 0 )
1024 return rc;
1025
1026 if ( t -> id != eComma )
1027 break;
1028
1029 next_token ( tbl, src, t );
1030 }
1031
1032 return 0;
1033 }
1034
1035
1036 /*
1037 * formal-signature = <formal-params> [ '*' <formal-params> ] [',' '...' ]
1038 * | '*' <formal-params> [',' '...' ]
1039 * | '...'
1040 */
1041 static
formal_signature(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFormParmlist * sig,rc_t (* formal_param)(KSymTable *,KTokenSource *,KToken *,const SchemaEnv *,VSchema *,SFormParmlist *))1042 rc_t formal_signature ( KSymTable *tbl, KTokenSource *src, KToken *t,
1043 const SchemaEnv *env, VSchema *self, SFormParmlist *sig,
1044 rc_t ( * formal_param ) ( KSymTable*, KTokenSource*, KToken*,
1045 const SchemaEnv*, VSchema*, SFormParmlist* ) )
1046 {
1047 /* read mandatory parameters */
1048 rc_t rc = formal_params ( tbl, src, t, env, self, sig, formal_param );
1049
1050 /* remember the number of mandatory params seen */
1051 sig -> mand = VectorLength ( & sig -> parms );
1052
1053 /* read optional parameters */
1054 if ( rc == 0 && t -> id == eAsterisk )
1055 {
1056 next_token ( tbl, src, t );
1057 rc = formal_params ( tbl, src, t, env, self, sig, formal_param );
1058 if ( rc == 0 && VectorLength ( & sig -> parms ) == sig -> mand )
1059 KTokenExpected ( t, klogWarn, "optional parameter" );
1060 }
1061
1062 /* accept '...' */
1063 if ( t -> id == eEllipsis )
1064 {
1065 /* but only if there was at least one real parameter */
1066 if ( VectorLength ( & sig -> parms ) == 0 )
1067 {
1068 rc = RC ( rcVDB, rcSchema, rcParsing, rcParam, rcInsufficient );
1069 return KTokenFailure ( t, klogErr, rc, "vararg parameter requires at least one real parameter" );
1070 }
1071
1072 sig -> vararg = true;
1073 next_token ( tbl, src, t );
1074 }
1075
1076 return 0;
1077 }
1078
1079 /*
1080 * parm-signature = <parm-formals> [ '*' <parm-formals> ] [',' '...' ]
1081 * | '*' <parm-formals> [',' '...' ]
1082 * | '...'
1083 */
1084 static
parm_signature(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFormParmlist * sig)1085 rc_t parm_signature ( KSymTable *tbl, KTokenSource *src, KToken *t,
1086 const SchemaEnv *env, VSchema *self, SFormParmlist *sig )
1087 {
1088 /* open list */
1089 rc_t rc = expect ( tbl, src, t, eLeftParen, "(", true );
1090 if ( rc != 0 )
1091 return rc;
1092
1093 /* parse list */
1094 rc = formal_signature ( tbl, src, t, env, self, sig, param_formal );
1095 if ( rc != 0 )
1096 return 0;
1097
1098 /* expect close */
1099 return expect ( tbl, src, t, eRightParen, ")", true );
1100 }
1101
1102 /*
1103 * fact-signature = <fact-formals> [ '*' <fact-formals> ] [ ',' '...' ]
1104 * | '*' <fact-formals> [ ',' '...' ]
1105 * | '...'
1106 */
fact_signature(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFormParmlist * sig)1107 rc_t fact_signature ( KSymTable *tbl, KTokenSource *src, KToken *t,
1108 const SchemaEnv *env, VSchema *self, SFormParmlist *sig )
1109 {
1110 /* open list */
1111 rc_t rc = expect ( tbl, src, t, eLeftAngle, "<", true );
1112 if ( rc != 0 )
1113 return rc;
1114
1115 /* parse list */
1116 rc = formal_signature ( tbl, src, t, env, self, sig, fact_formal );
1117 if ( rc != 0 )
1118 return rc;
1119
1120 /* expect close */
1121 return expect ( tbl, src, t, eRightAngle, ">", true );
1122 }
1123
1124
1125 /*
1126 * schema-signature = <schema-formals>
1127 * schema-formals = <schema-formal> [ ',' <schema-formals> ]
1128 * schema-formal = <schema-typedecl> ID
1129 * schema-parmname = ID
1130 */
schema_signature(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFunction * sig)1131 rc_t schema_signature ( KSymTable *tbl, KTokenSource *src, KToken *t,
1132 const SchemaEnv *env, VSchema *self, SFunction *sig )
1133 {
1134 rc_t rc;
1135
1136 /* open list */
1137 if ( t -> id != eLeftAngle )
1138 return KTokenExpected ( t, klogErr, "<" );
1139
1140 /* gather schema parameters */
1141 do
1142 {
1143 const SExpression *td;
1144 const SDatatype *dt;
1145
1146 /* check parameter type */
1147 switch ( next_token ( tbl, src, t ) -> id )
1148 {
1149 case kw_type:
1150 td = NULL;
1151 next_token ( tbl, src, t );
1152 break;
1153
1154 case eDatatype:
1155 dt = t -> sym -> u . obj;
1156 if ( dt -> domain == ddUint )
1157 {
1158 /* evaluate the type expression */
1159 rc = type_expr ( tbl, src, t, env, self, & td );
1160 if ( rc != 0 )
1161 return KTokenFailure ( t, klogErr, rc, "unsigned integer datatype" );
1162
1163 /* the type should be totally resolved */
1164 assert ( td != NULL && td -> var == eTypeExpr );
1165 assert ( ( ( const STypeExpr* ) td ) -> resolved );
1166 if ( ( ( const STypeExpr* ) td ) -> fd . td . dim == 1 )
1167 break;
1168
1169 SExpressionWhack ( td );
1170 return KTokenExpected ( t, klogErr, "single dimensional unsigned integer datatype" );
1171 }
1172
1173 default:
1174 return KTokenExpected ( t, klogErr, "type keyword or unsigned integer datatype" );
1175 }
1176
1177 /* get parameter name */
1178 if ( t -> id != eIdent )
1179 {
1180 if ( td != NULL )
1181 SExpressionWhack ( td );
1182 return KTokenExpected ( t, klogErr, "parameter name" );
1183 }
1184
1185 if ( td == NULL )
1186 {
1187 SIndirectType *formal = malloc ( sizeof * formal );
1188 if ( formal == NULL )
1189 {
1190 rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
1191 return KTokenRCExplain ( t, klogInt, rc );
1192 }
1193
1194 /* initialize to raw format,
1195 undefined type, and no dimension */
1196 formal -> type_id = 0;
1197
1198 /* create symbol */
1199 rc = KSymTableCreateConstSymbol ( tbl, & formal -> name,
1200 & t -> str, eSchemaType, formal );
1201 if ( rc == 0 )
1202 {
1203 /* record positional */
1204 rc = VectorAppend ( & sig -> type, & formal -> pos, formal );
1205 if ( rc == 0 )
1206 {
1207 void *ignore;
1208
1209 /* record formal */
1210 rc = VectorAppend ( & self -> pt, & formal -> id, formal );
1211 if ( rc != 0 )
1212 VectorSwap ( & sig -> type, formal -> pos, NULL, & ignore );
1213 else
1214 formal -> pos += VectorLength ( & sig -> schem );
1215 }
1216 }
1217 if ( rc != 0 )
1218 {
1219 free ( formal );
1220 return KTokenRCExplain ( t, klogInt, rc );
1221 }
1222
1223 formal -> type_id = ++ self -> num_indirect;
1224 }
1225 else
1226 {
1227 SIndirectConst *formal = malloc ( sizeof * formal );
1228 if ( formal == NULL )
1229 {
1230 SExpressionWhack ( td );
1231 rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
1232 return KTokenRCExplain ( t, klogInt, rc );
1233 }
1234
1235 /* initialize with no value */
1236 formal -> expr_id = 0;
1237 formal -> td = td;
1238
1239 /* create symbol */
1240 rc = KSymTableCreateConstSymbol ( tbl, & formal -> name,
1241 & t -> str, eSchemaParam, formal );
1242 if ( rc == 0 )
1243 {
1244 /* record formal */
1245 rc = VectorAppend ( & sig -> schem, & formal -> pos, formal );
1246 if ( rc == 0 )
1247 formal -> pos += VectorLength ( & sig -> type );
1248 }
1249 if ( rc != 0 )
1250 {
1251 SIndirectConstWhack ( formal, NULL );
1252 return KTokenRCExplain ( t, klogInt, rc );
1253 }
1254
1255 formal -> expr_id = ++ self -> num_indirect;
1256 }
1257 }
1258 while ( next_token ( tbl, src, t ) -> id == eComma );
1259
1260 /* expect close */
1261 return expect ( tbl, src, t, eRightAngle, ">", true );
1262 }
1263
1264 static
return_type_expr(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFunction * f)1265 rc_t return_type_expr ( KSymTable *tbl, KTokenSource *src, KToken *t,
1266 const SchemaEnv *env, VSchema *self, SFunction *f )
1267 {
1268 if ( f -> validate )
1269 return expect ( tbl, src, t, kw_void, "void", true );
1270 return vardim_type_expr ( tbl, src, t, env, self, & f -> rt );
1271 }
1272
1273
1274 static
func_decl(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,SFunction * f,uint32_t type)1275 rc_t func_decl ( KSymTable *tbl, KTokenSource *src, KToken *t,
1276 const SchemaEnv *env, VSchema *self, SFunction *f, uint32_t type )
1277 {
1278 rc_t rc;
1279
1280 /* check for __untyped or __row_length function */
1281 if ( t -> id == kw___untyped || t -> id == kw___row_length )
1282 {
1283 uint32_t sym_type;
1284
1285 /* can't be a script function */
1286 if ( type == eScriptFunc )
1287 return KTokenExpected ( t, klogErr, "script function return type" );
1288
1289 /* can't be a validate function */
1290 if ( f -> validate )
1291 return KTokenExpected ( t, klogErr, "void return type" );
1292
1293 /* determine variant */
1294 if ( t -> id == kw___untyped )
1295 {
1296 f -> untyped = true;
1297 sym_type = eUntypedFunc;
1298 }
1299 else
1300 {
1301 f -> row_length = true;
1302 sym_type = eRowLengthFunc;
1303 }
1304
1305 /* treat keyword as a NULL return type */
1306 next_token ( tbl, src, t );
1307
1308 /* create function name */
1309 rc = create_fqn ( tbl, src, t, env, sym_type, NULL );
1310 if ( rc != 0 )
1311 {
1312 if ( GetRCState ( rc ) == rcExists )
1313 return rc;
1314 return KTokenFailure ( t, klogErr, rc, "fully qualified name" );
1315 }
1316
1317 /* record symbol */
1318 f -> name = t -> sym;
1319 next_token ( tbl, src, t );
1320
1321 /* consume empty param list */
1322 rc = expect ( tbl, src, t, eLeftParen, "(", true );
1323 if ( rc == 0 )
1324 rc = expect ( tbl, src, t, eRightParen, ")", true );
1325 return rc;
1326 }
1327
1328
1329 /* initialize vectors */
1330 VectorInit ( & f -> fact . parms, 0, 8 );
1331 VectorInit ( & f -> func . parms, 0, 8 );
1332 VectorInit ( & f -> type, 0, 8 );
1333 VectorInit ( & f -> schem, 0, 8 );
1334
1335 /* get schema signature */
1336 if ( t -> id == eLeftAngle )
1337 {
1338 /* enter schema param scope */
1339 rc = KSymTablePushScope ( tbl, & f -> sscope );
1340 if ( rc != 0 )
1341 return KTokenRCExplain ( t, klogInt, rc );
1342
1343 /* parse schema params */
1344 rc = schema_signature ( tbl, src, t, env, self, f );
1345
1346 /* interpret return type within schema param scope */
1347 if ( rc == 0 )
1348 {
1349 rc = return_type_expr ( tbl, src, t, env, self, f );
1350 if ( rc != 0 )
1351 KTokenFailure ( t, klogErr, rc, "return type" );
1352 }
1353
1354 /* pop scope */
1355 KSymTablePopScope ( tbl );
1356
1357 /* bail on problems */
1358 if ( rc != 0 )
1359 return rc;
1360
1361 /* "t" contains a lookahead token. while unlikely,
1362 it could have matched something defined in schema
1363 param scope. re-evaluate if possible */
1364 if ( t -> sym != NULL ) switch ( t -> sym -> type )
1365 {
1366 case eSchemaType:
1367 case eSchemaParam:
1368 t -> id = eIdent;
1369 t -> sym = KSymTableFind ( tbl, & t -> str );
1370 if ( t -> sym != NULL )
1371 t -> id = t -> sym -> type;
1372 break;
1373 }
1374 }
1375 else
1376 {
1377 /* get return type within global scope */
1378 rc = return_type_expr ( tbl, src, t, env, self, f );
1379 if ( rc != 0 )
1380 return KTokenFailure ( t, klogErr, rc, "return type" );
1381 }
1382
1383 /* get function name */
1384 rc = create_fqn ( tbl, src, t, env, type, NULL );
1385 if ( rc != 0 ) switch ( GetRCState ( rc ) )
1386 {
1387 case rcExists:
1388 break;
1389 case rcUnexpected:
1390 if ( type == 0 && t -> sym != NULL )
1391 {
1392 if ( t -> sym -> type == eFunction || t -> sym -> type == eScriptFunc )
1393 break;
1394 }
1395 default:
1396 return KTokenFailure ( t, klogErr, rc, "fully qualified name" );
1397 }
1398
1399 /* record symbol - new or redefined */
1400 f -> name = t -> sym;
1401
1402 /* get version */
1403 if ( next_token ( tbl, src, t ) -> id == eHash )
1404 {
1405 bool allow_release = ( f -> name -> type != eFunction ) ? true : false;
1406 next_token ( tbl, src, t );
1407 rc = maj_min_rel ( tbl, src, t, env, self, & f -> version, allow_release );
1408 if ( rc != 0 )
1409 return rc;
1410 }
1411
1412 /* parse formal parameters - enter schema scope */
1413 rc = KSymTablePushScope ( tbl, & f -> sscope );
1414 if ( rc != 0 )
1415 KTokenRCExplain ( t, klogInt, rc );
1416 else
1417 {
1418 /* enter function scope */
1419 rc = KSymTablePushScope ( tbl, & f -> fscope );
1420 if ( rc != 0 )
1421 KTokenRCExplain ( t, klogInt, rc );
1422 else
1423 {
1424 /* gather factory parameters */
1425 if ( t -> id == eLeftAngle )
1426 rc = fact_signature ( tbl, src, t, env, self, & f -> fact );
1427
1428 /* gather function parameters */
1429 if ( rc == 0 )
1430 rc = parm_signature ( tbl, src, t, env, self, & f -> func );
1431
1432 /* leave function scope */
1433 KSymTablePopScope ( tbl );
1434 }
1435
1436 /* leave schema scope */
1437 KSymTablePopScope ( tbl );
1438 }
1439
1440 /* go a bit further */
1441 if ( rc == 0 )
1442 {
1443 /* detect script body */
1444 if ( t -> id == eLeftCurly )
1445 {
1446 #if SLVL >= 4
1447 /* if user already specified extern function
1448 or if user specified vararg factory params */
1449 if ( type == eFunction || f -> fact . vararg )
1450 #endif
1451 return KTokenExpected ( t, klogErr, "; or =" );
1452 #if SLVL >= 4
1453 /* if no type was specified */
1454 if ( type == 0 )
1455 {
1456 /* if name was previously defined as a function */
1457 if ( f -> name -> type == eFunction )
1458 return KTokenExpected ( t, klogErr, "; or =" );
1459
1460 /* name is either undefined or script - clobber to script */
1461 ( ( KSymbol* ) f -> name ) -> type = eScriptFunc;
1462 }
1463
1464 /* parse remainder as script function */
1465 return script_body ( tbl, src, t, env, self, f );
1466 #endif
1467 }
1468
1469 /* detect case where should be script but isn't */
1470 if ( f -> name -> type == eScriptFunc )
1471 return KTokenExpected ( t, klogErr, "{" );
1472
1473 /* definitely an extern function */
1474 if ( type == 0 )
1475 ( ( KSymbol* ) f -> name ) -> type = eFunction;
1476
1477 /* process factory spec */
1478 if ( t -> id == eAssign )
1479 {
1480 /* get factory name */
1481 next_token ( tbl, src, t );
1482 rc = create_fqn ( tbl, src, t, env, eFactory, NULL );
1483 if ( rc != 0 ) switch ( GetRCState ( rc ) )
1484 {
1485 case rcExists:
1486 break;
1487 case rcUnexpected:
1488 if ( t -> sym != NULL && t -> sym -> type == eFunction )
1489 break;
1490 default:
1491 return rc;
1492 }
1493
1494 f -> u . ext . fact = t -> sym;
1495 next_token ( tbl, src, t );
1496 }
1497
1498 /* expect a semicolon */
1499 rc = expect ( tbl, src, t, eSemiColon, ";", true );
1500 }
1501
1502 return rc;
1503 }
1504
1505 static
function_decl(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self,uint32_t type,bool validate)1506 rc_t function_decl ( KSymTable *tbl, KTokenSource *src, KToken *t,
1507 const SchemaEnv *env, VSchema *self, uint32_t type, bool validate )
1508 {
1509 rc_t rc;
1510 void *ignore;
1511
1512 /* create object */
1513 SFunction *f = malloc ( sizeof * f );
1514 if ( f == NULL )
1515 {
1516 rc = RC ( rcVDB, rcSchema, rcParsing, rcMemory, rcExhausted );
1517 return KTokenRCExplain ( t, klogInt, rc );
1518 }
1519
1520 memset ( f, 0, sizeof * f );
1521 f -> validate = validate;
1522
1523 /* parse function decl */
1524 rc = func_decl ( tbl, src, t, env, self, f, type );
1525
1526 /* check validation functions for exactly two parameters */
1527 if ( f -> validate && ( rc == 0 || GetRCState ( rc ) == rcExists ) )
1528 {
1529 if ( f -> func . mand != 2 ||
1530 f -> func . vararg != 0 ||
1531 VectorLength ( & f -> func . parms ) != 2 )
1532 {
1533 rc = RC ( rcVDB, rcSchema, rcParsing, rcFunction, rcInvalid );
1534 KTokenRCExplain ( t, klogInt, rc );
1535 }
1536 }
1537
1538 if ( rc == 0 )
1539 {
1540 /* need an overloaded name entry */
1541 SNameOverload *name = ( void* ) f -> name -> u . obj;
1542 if ( name == NULL )
1543 {
1544 /* create name */
1545 rc = SNameOverloadMake ( & name, f -> name, 0, 4 );
1546 if ( rc == 0 )
1547 {
1548 /* insert it - it's allowed to be empty */
1549 rc = VectorAppend ( & self -> fname, & name -> cid . id, name );
1550 if ( rc != 0 )
1551 SNameOverloadWhack ( name, NULL );
1552 }
1553 }
1554
1555 /* now need to record function */
1556 if ( rc == 0 )
1557 {
1558 /* assume it's new in this schema */
1559 rc = VectorAppend ( & self -> func, & f -> id, f );
1560 if ( rc == 0 )
1561 {
1562 /* insert into name overload and exit on success */
1563 uint32_t idx;
1564 rc = VectorInsertUnique ( & name -> items, f, & idx, SFunctionSort );
1565 if ( rc == 0 )
1566 return 0;
1567
1568 /* expected failure is that a function already exists */
1569 if ( GetRCState ( rc ) != rcExists )
1570 VectorSwap ( & self -> func, f -> id, NULL, & ignore );
1571 else
1572 {
1573 /* see if new function trumps old */
1574 SFunction *exist = VectorGet ( & name -> items, idx );
1575 if ( f -> version > exist -> version )
1576 {
1577 /* insert our function in name overload */
1578 VectorSwap ( & name -> items, idx, f, & ignore );
1579
1580 /* if existing is in another schema... */
1581 if ( ( const void* ) name != exist -> name -> u . obj )
1582 return 0;
1583
1584 /* need to swap with old */
1585 assert ( exist -> id >= VectorStart ( & self -> func ) );
1586 assert ( exist -> id < f -> id );
1587 VectorSwap ( & self -> func, f -> id, NULL, & ignore );
1588 VectorSwap ( & self -> func, f -> id = exist -> id, f, & ignore );
1589 SFunctionWhack ( exist, NULL );
1590 return 0;
1591 }
1592
1593 /* exists is not an error */
1594 rc = 0;
1595 }
1596
1597 VectorSwap ( & self -> func, f -> id, NULL, & ignore );
1598 }
1599 }
1600 }
1601 else if ( GetRCState ( rc ) == rcExists )
1602 {
1603 rc = 0;
1604 }
1605
1606 SFunctionWhack ( f, NULL );
1607 return rc;
1608 }
1609
1610 /*
1611 * function-decl = 'function' <ext-func-decl> ';'
1612 * | 'function' <script-func-decl>
1613 */
function_declaration(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self)1614 rc_t function_declaration ( KSymTable *tbl, KTokenSource *src, KToken *t,
1615 const SchemaEnv *env, VSchema *self )
1616 {
1617 return function_decl ( tbl, src, t, env, self,
1618 env -> script_function_called_schema ? eFunction : 0, false );
1619 }
1620
1621 /*
1622 * extern-func = 'extern' 'function' <ext-function-decl> ';'
1623 */
extfunc_declaration(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self)1624 rc_t extfunc_declaration ( KSymTable *tbl, KTokenSource *src, KToken *t,
1625 const SchemaEnv *env, VSchema *self )
1626 {
1627 return function_decl ( tbl, src, t, env, self, eFunction, false );
1628 }
1629
1630 /*
1631 * validate-func = 'validate' 'function' <validate-function-decl> ';'
1632 */
valfunc_declaration(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self)1633 rc_t valfunc_declaration ( KSymTable *tbl, KTokenSource *src, KToken *t,
1634 const SchemaEnv *env, VSchema *self )
1635 {
1636 return function_decl ( tbl, src, t, env, self, eFunction, true );
1637 }
1638
1639 #endif /* SLVL >= 3 */
1640
1641
1642 #if SLVL >= 4
1643
1644 /*
1645 * script-decl = 'schema' [ 'function' ] <script-func-decl>
1646 */
script_declaration(KSymTable * tbl,KTokenSource * src,KToken * t,const SchemaEnv * env,VSchema * self)1647 rc_t script_declaration ( KSymTable *tbl, KTokenSource *src, KToken *t,
1648 const SchemaEnv *env, VSchema *self )
1649 {
1650 if ( t -> id == kw_function )
1651 next_token ( tbl, src, t );
1652
1653 return function_decl ( tbl, src, t, env, self, eScriptFunc, false );
1654 }
1655
1656 #endif /* SLVL >= 4 */
1657