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