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 
27 #include "ASTBuilder-func.hpp"
28 
29 #include <klib/symbol.h>
30 #include <klib/printf.h>
31 
32 #include "../vdb/schema-parse.h"
33 #include "../vdb/dbmgr-priv.h"
34 #include "../vdb/schema-expr.h"
35 
36 using namespace ncbi::SchemaParser;
37 #define YYDEBUG 1
38 #include "schema-ast-tokens.h"
39 
40 using namespace std;
41 
FunctionDeclaration(ASTBuilder & p_builder)42 FunctionDeclaration :: FunctionDeclaration ( ASTBuilder & p_builder )
43 :   m_builder ( p_builder ),
44     m_self ( m_builder . Alloc < SFunction > () ),
45     m_destroy ( true )
46 {
47     if ( m_self != 0 )
48     {
49         VectorInit ( & m_self -> fact . parms, 0, 8 );
50     }
51 }
52 
FunctionDeclaration(ASTBuilder & p_builder,SFunction & p_func)53 FunctionDeclaration :: FunctionDeclaration ( ASTBuilder & p_builder, SFunction & p_func )
54 :   m_builder ( p_builder ),
55     m_self ( & p_func ),
56     m_destroy ( false )
57 {
58     memset ( m_self, 0, sizeof * m_self );
59     VectorInit ( & m_self -> fact . parms, 0, 8 );
60     m_self -> script        = true;
61 }
62 
~FunctionDeclaration()63 FunctionDeclaration :: ~FunctionDeclaration ()
64 {
65     if ( m_self != 0 && m_destroy )
66     {
67         SFunctionWhack ( m_self, 0 );
68     }
69 }
70 
71 bool
HandleOverload(const AST_FQN & p_fqn,const KSymbol * p_priorDecl)72 FunctionDeclaration :: HandleOverload ( const AST_FQN & p_fqn, const KSymbol *  p_priorDecl )
73 {
74     assert ( p_priorDecl != 0 );
75 
76     Vector & functions = m_builder . GetSchema () -> func;
77 
78     SNameOverload *name = ( SNameOverload* ) p_priorDecl -> u . obj;
79     assert ( name != 0 );
80 
81     SFunction *exist = static_cast < SFunction * > ( VectorGet ( & name -> items, 0 ) );
82     assert ( exist != 0 );
83     if ( exist -> script )
84     {
85         if ( ! m_self -> script)
86         {
87             m_builder . ReportError ( p_fqn . GetLocation (), "Overload has to have a body", p_priorDecl -> name );
88         }
89     }
90     else if ( m_self -> script)
91     {
92         m_builder . ReportError ( p_fqn . GetLocation (), "Overload cannot have a body", p_priorDecl -> name );
93     }
94 
95     uint32_t idx;
96     rc_t rc = VectorInsertUnique ( & name -> items, m_self, & idx, SFunctionSort );
97     if ( rc == 0 ) // overload added
98     {
99         return m_builder . VectorAppend ( functions, & m_self -> id, m_self );
100     }
101     if ( GetRCState ( rc ) == rcExists )
102     {   /* an overload with the same major version exists */
103         /* see if new function trumps old */
104         SFunction *exist = static_cast < SFunction * > ( VectorGet ( & name -> items, idx ) );
105         if ( m_self -> version > exist -> version )
106         {
107             /* insert our function in name overload */
108             void * prior;
109             VectorSwap ( & name -> items, idx, m_self, & prior );
110 
111             /* if existing is in the same schema... */
112             if ( ( const void* ) name == exist -> name -> u . obj )
113             {
114                 /* need to swap with old */
115                 assert ( exist -> id >= VectorStart ( & functions ) );
116                 VectorSwap ( & functions, exist -> id, m_self, & prior );
117                 m_self -> id = exist -> id;
118                 SFunctionWhack ( (SFunction*)prior, 0 );
119             }
120             return true;
121         }
122     }
123     else if ( rc != 0 )
124     {
125         m_builder . ReportRc ( "VectorInsertUnique", rc );
126     }
127     return false;
128 }
129 
130 bool
SetName(const AST_FQN & p_fqn,uint32_t p_type,bool p_canOverload,bool p_validate)131 FunctionDeclaration :: SetName ( const AST_FQN &  p_fqn,
132                                  uint32_t         p_type,
133                                  bool             p_canOverload,
134                                  bool             p_validate )
135 {
136     if ( m_self == 0 )
137     {
138         return false;
139     }
140 
141     m_self -> script        = p_type == eScriptFunc;
142     m_self -> untyped       = p_type == eUntypedFunc;
143     m_self -> row_length    = p_type == eRowLengthFunc;
144     m_self -> validate      = p_validate;
145 
146     const KSymbol * priorDecl = m_builder . Resolve ( p_fqn, false );
147 
148     m_self -> version = p_fqn . GetVersion ();
149     if ( ( m_self -> version & 0xFFFF ) != 0 && priorDecl != 0 && priorDecl -> type == eFunction )
150     {
151         m_builder . ReportError ( "Changing release number is not allowed", p_fqn );
152         return false;
153     }
154 
155     if ( priorDecl == 0 )
156     {
157         m_self -> name = m_builder . CreateFqnSymbol ( p_fqn, p_type, m_self );
158         if ( m_self -> name != 0 )
159         {
160             if ( m_builder . CreateOverload ( m_self -> name,
161                                               m_self,
162                                               SFunctionSort,
163                                               m_builder . GetSchema () -> func,
164                                               m_builder . GetSchema () -> fname,
165                                               & m_self -> id ) )
166             {
167                 m_destroy = false;
168                 return true;
169             }
170         }
171     }
172     else
173     {
174         if ( ! p_canOverload  || priorDecl -> type == eFactory )
175         {
176             m_builder . ReportError ( "Declared earlier and cannot be overloaded", p_fqn );
177             return false;
178         }
179 
180         if ( HandleOverload ( p_fqn, priorDecl ) )
181         {   // declared previously, this version not ignored
182             m_self -> name = priorDecl;
183             m_destroy = false;
184             return true;
185         }
186     }
187 
188     return false;
189 }
190 
191 void
SetReturnType(STypeExpr * p_retType)192 FunctionDeclaration :: SetReturnType ( STypeExpr * p_retType )
193 {
194     if ( m_self != 0 && p_retType != 0 )
195     {
196         m_self -> rt = & p_retType -> dad;
197     }
198 }
199 
200 void
AddFactoryParams(Vector & p_sig,const AST & p_params)201 FunctionDeclaration :: AddFactoryParams ( Vector& p_sig, const AST & p_params )
202 {
203     uint32_t count = p_params . ChildrenCount ();
204     for ( uint32_t i = 0; i < count; ++i )
205     {
206         SIndirectConst * param = m_builder . Alloc < SIndirectConst > ();
207         if ( param == 0 )
208         {
209             return;
210         }
211         const AST * p = p_params . GetChild ( i );
212         assert ( p != 0 );
213         assert ( p -> ChildrenCount () == 3 ); // type, ident, control or PT_EMPTY
214 
215         STypeExpr * type = m_builder . MakeTypeExpr ( * p -> GetChild ( 0 ) );
216         if ( type != 0 )
217         {
218             param -> td = & type -> dad;
219         }
220 
221         param -> name = m_builder . CreateLocalSymbol ( * p -> GetChild ( 1 ),
222                                                         p -> GetChild ( 1 ) -> GetTokenValue (),
223                                                         eFactParam,
224                                                         param );
225 
226         if ( m_builder . VectorAppend ( p_sig, & param -> pos, param ) )
227         {
228             param -> expr_id = ++ ( m_builder . GetSchema () -> num_indirect );
229         }
230         else
231         {
232             SIndirectConstWhack ( param, NULL );
233         }
234     }
235 }
236 
237 void
SetFactoryParams(const AST & p_sig)238 FunctionDeclaration :: SetFactoryParams ( const AST & p_sig )
239 {
240     if ( m_self != 0 && p_sig . GetTokenType () != PT_EMPTY )
241     {   // children: mandatory, optional, isVariadic
242         assert ( p_sig . ChildrenCount () == 3 );
243         m_self -> fact . mand = p_sig . GetChild ( 0 ) -> ChildrenCount ();
244         AddFactoryParams ( m_self -> fact . parms, * p_sig . GetChild ( 0 ) );
245         AddFactoryParams ( m_self -> fact . parms, * p_sig . GetChild ( 1 ) );
246         m_self -> fact . vararg = p_sig . GetChild ( 2 ) -> GetTokenType () != PT_EMPTY;
247     }
248 }
249 
250 void
AddFormalParams(Vector & p_sig,const AST & p_params)251 FunctionDeclaration :: AddFormalParams ( Vector& p_sig, const AST & p_params )
252 {
253     uint32_t count = p_params . ChildrenCount ();
254     for ( uint32_t i = 0; i < count; ++i )
255     {
256         SProduction * param = m_builder . Alloc < SProduction > ();
257         if ( param == 0 )
258         {
259             return;
260         }
261         const AST * p = p_params . GetChild ( i );
262         assert ( p != 0 );
263         assert ( p -> ChildrenCount () == 3 ); // type, ident, control or PT_EMPTY
264 
265         STypeExpr * type = m_builder . MakeTypeExpr ( * p -> GetChild ( 0 ) );
266         if ( type != 0 )
267         {
268             param -> fd = & type -> dad;
269         }
270 
271         param -> name = m_builder . CreateLocalSymbol ( * p -> GetChild ( 1 ),
272                                                         p -> GetChild ( 1 ) -> GetTokenValue (),
273                                                         eFuncParam,
274                                                         param );
275 
276         param -> control = p -> GetChild ( 2 ) -> GetTokenType () != PT_EMPTY;
277 
278         if ( ! m_builder . VectorAppend ( p_sig, & param -> cid . id, param ) )
279         {
280             SProductionWhack ( param, NULL );
281         }
282     }
283 }
284 
285 void
SetFormalParams(const AST & p_sig)286 FunctionDeclaration :: SetFormalParams ( const AST & p_sig )
287 {
288     if ( m_self != 0 && p_sig . GetTokenType () != PT_EMPTY )
289     {   // children: mandatory, optional, isVariadic
290         assert ( p_sig . ChildrenCount () == 3 );
291         m_self -> func . mand = p_sig . GetChild ( 0 ) -> ChildrenCount ();
292         AddFormalParams ( m_self -> func . parms, * p_sig . GetChild ( 0 ) );
293         AddFormalParams ( m_self -> func . parms, * p_sig . GetChild ( 1 ) );
294         m_self -> func . vararg = p_sig . GetChild ( 2 ) -> GetTokenType () != PT_EMPTY;
295     }
296 }
297 
298 void
SetPhysicalParams()299 FunctionDeclaration :: SetPhysicalParams ()
300 {
301     if ( m_self != 0 )
302     {
303         VectorInit ( & m_self -> func . parms, 0, 1 );
304         m_self -> func . mand     = 1;
305         m_self -> func . vararg   = false;
306 
307         /* create special input symbol */
308         SProduction * parm = m_builder . Alloc < SProduction > ();
309         if ( parm != 0 && m_builder . VectorAppend ( m_self -> func . parms, & parm -> cid . id, parm ) )
310         {
311             /* create special input symbol */
312             String symstr;
313             CONST_STRING ( & symstr, "@" );
314             rc_t rc = KSymTableCreateConstSymbol ( & m_builder . GetSymTab (), & parm -> name, & symstr, eFuncParam, parm );
315             if ( rc == 0 )
316             {
317                 VectorInit ( & m_self -> u . script . prod, 0, 8 );
318             }
319             else
320             {
321                 m_builder . ReportRc ( "KSymTableCreateConstSymbol", rc );
322             }
323         }
324         else
325         {
326             SProductionWhack ( parm, 0 );
327         }
328     }
329 }
330 
331 SIndirectType *
MakeSchemaParamType(const AST_FQN & p_name)332 FunctionDeclaration :: MakeSchemaParamType ( const AST_FQN & p_name )
333 {
334     SIndirectType *ret = m_builder . Alloc < SIndirectType > ();
335     if ( ret != 0 )
336     {   /* create symbol */
337         String nameStr;
338         p_name . GetIdentifier ( nameStr );
339         rc_t rc = KSymTableCreateConstSymbol ( & m_builder . GetSymTab (), & ret -> name, & nameStr, eSchemaType, ret );
340         if ( rc == 0 )
341         {
342             if ( m_builder . VectorAppend ( m_builder . GetSchema () -> pt, & ret -> id, ret ) )
343             {
344                 /* initialize to raw format,
345                 undefined type, and no dimension */
346                 ret -> type_id = ++ ( m_builder . GetSchema () -> num_indirect );
347                 return ret;
348             }
349         }
350         else
351         {
352             m_builder . ReportRc ( "KSymTableCreateConstSymbol", rc );
353         }
354         SIndirectTypeWhack ( ret, 0 );
355     }
356     return 0;
357 }
358 
359 SIndirectConst *
MakeSchemaParamConst(const AST_FQN & p_name)360 FunctionDeclaration :: MakeSchemaParamConst ( const AST_FQN & p_name )
361 {
362     SIndirectConst * ret = m_builder . Alloc < SIndirectConst > ();
363     if ( ret != 0 )
364     {   /* create symbol */
365         String nameStr;
366         p_name . GetIdentifier ( nameStr );
367         rc_t rc = KSymTableCreateConstSymbol ( & m_builder . GetSymTab (), & ret -> name, & nameStr, eSchemaParam, ret );
368         if ( rc == 0 )
369         {
370             ret -> expr_id = ++ ( m_builder . GetSchema () -> num_indirect );
371             return ret;
372         }
373         else
374         {
375             m_builder . ReportRc ( "KSymTableCreateConstSymbol", rc );
376         }
377         SIndirectConstWhack ( ret, 0 );
378     }
379     return 0;
380 }
381 
382 void
SetSchemaParams(const AST & p_sig)383 FunctionDeclaration :: SetSchemaParams ( const AST & p_sig )
384 {
385     uint32_t count = p_sig . ChildrenCount ();
386     for ( uint32_t i = 0; i < count; ++i )
387     {
388         const AST & p = * p_sig . GetChild ( i );
389         if ( p . ChildrenCount () == 1 ) // type
390         {
391             SIndirectType * formal = MakeSchemaParamType ( * ToFQN ( p . GetChild ( 0 ) ) );
392             if ( formal != 0 )
393             {
394                 /* record positional */
395                 if ( m_builder . VectorAppend ( m_self -> type, 0, formal ) )
396                 {
397                     formal -> pos = i;
398                     continue;
399                 }
400                 SIndirectTypeWhack ( formal, 0 );
401             }
402             break;
403         }
404         else // value
405         {
406             STypeExpr * type = m_builder . MakeTypeExpr ( * p . GetChild ( 0 ) );
407             if ( type != 0 )
408             {
409                 const AST_FQN & ident = * ToFQN ( p . GetChild ( 1 ) );
410                 // scalar unsigned int type required
411                 if ( type -> dt != 0 &&
412                     type -> dt -> domain == ddUint &&
413                     type -> fd . td. dim == 1 )
414                 {
415                     SIndirectConst * formal = MakeSchemaParamConst ( ident );
416                     if ( formal != 0 )
417                     {
418                         /* record positional */
419                         if ( m_builder . VectorAppend ( m_self -> schem, 0, formal ) )
420                         {
421                             formal -> td = & type -> dad;
422                             formal -> pos = i;
423                             continue; // success
424                         }
425                         SIndirectConstWhack ( formal, 0 );
426                     }
427                 }
428                 else
429                 {
430                     String nameStr;
431                     ident . GetIdentifier ( nameStr );
432                     m_builder . ReportError ( ident . GetLocation (), "Not a scalar unsigned integer", nameStr );
433                 }
434                 SExpressionWhack ( & type -> dad );
435             }
436             break;
437         }
438     }
439 }
440 
441 void
HandleStatement(const AST & p_stmt)442 FunctionDeclaration :: HandleStatement ( const AST & p_stmt )
443 {
444     switch ( p_stmt . GetTokenType () )
445     {
446     case KW_return:
447         {
448             if ( m_self -> u . script . rtn == 0 )
449             {
450                 assert ( p_stmt . ChildrenCount () == 1 );
451                 m_self -> u . script . rtn = ToExpr ( p_stmt . GetChild ( 0 ) ) -> MakeExpression ( m_builder );
452             }
453             else
454             {
455                 m_builder . ReportError ( p_stmt . GetLocation (),
456                                           "Multiple return statements in a function",
457                                           m_self -> name -> name );
458             }
459         }
460         break;
461     case PT_PRODSTMT:
462         {
463             assert ( p_stmt . ChildrenCount () == 3 );
464             const AST * ident = p_stmt . GetChild ( 1 );
465             assert ( ident -> ChildrenCount () == 1 );
466             m_builder . AddProduction ( * ident,
467                                         m_self -> u . script . prod,
468                                         ident -> GetChild ( 0 ) -> GetTokenValue (),
469                                         * ToExpr ( p_stmt . GetChild ( 2 ) ),
470                                         p_stmt . GetChild ( 0 ) );
471         }
472         break;
473     case PT_EMPTY:
474         break;
475     default:
476         m_builder . ReportError ( p_stmt . GetLocation (), "Unsupported statement type", p_stmt . GetTokenType () );
477         break;
478     }
479 }
480 
481 void
HandleScript(const AST & p_body,const String & p_funcName)482 FunctionDeclaration :: HandleScript ( const AST & p_body, const String & p_funcName )
483 {
484     uint32_t stmtCount = p_body . ChildrenCount ();
485     for ( uint32_t i = 0 ; i < stmtCount; ++ i )
486     {
487         HandleStatement ( * p_body . GetChild ( i ) );
488     }
489     if ( m_self -> script && m_self -> u . script . rtn == 0 )
490     {
491         m_builder . ReportError ( p_body . GetLocation (), "Schema function does not contain a return statement", p_funcName );
492     }
493 }
494 
495 void
SetPrologue(const AST & p_prologue)496 FunctionDeclaration :: SetPrologue ( const AST & p_prologue )
497 {
498     switch ( p_prologue . GetTokenType () )
499     {
500     case PT_IDENT:
501         {   // renaming
502             const AST_FQN & fqn = * ToFQN ( & p_prologue );
503             const KSymbol * priorDecl = m_builder . Resolve ( fqn, false );
504             if ( priorDecl != 0 )
505             {
506                 if ( priorDecl -> type == eFunction || priorDecl -> type == eFactory )
507                 {
508                     m_self -> u. ext . fact = priorDecl;
509                 }
510                 else
511                 {
512                     m_builder . ReportError ( "Cannot be used as factory", fqn );
513                 }
514             }
515             else
516             {
517                 m_self -> u. ext . fact = m_builder . CreateFqnSymbol ( fqn, eFactory, 0 );
518             }
519         }
520         break;
521     case PT_EMPTY:
522         {   // function body
523             if ( p_prologue . ChildrenCount () > 0 )
524             {
525                 if ( m_self -> fact . vararg )
526                 {
527                     m_builder . ReportError ( p_prologue . GetLocation (),
528                                               "Function with factory varargs cannot have a body",
529                                               m_self -> name -> name );
530                 }
531                 else
532                 {
533                     rc_t rc = KSymTablePushScope ( & m_builder . GetSymTab (), SchemaScope () );
534                     if ( rc == 0 )
535                     {
536                         rc = KSymTablePushScope ( & m_builder . GetSymTab (), FunctionScope () );
537                         if ( rc == 0 )
538                         {
539                             HandleScript ( p_prologue, m_self -> name -> name );
540                             KSymTablePopScope ( & m_builder . GetSymTab () );
541                         }
542                         else
543                         {
544                             m_builder . ReportRc ( "KSymTablePushScope", rc );
545                         }
546                         KSymTablePopScope ( & m_builder . GetSymTab () );
547                     }
548                     else
549                     {
550                         m_builder . ReportRc ( "KSymTablePushScope", rc );
551                     }
552                 }
553             }
554         }
555         break;
556     default:
557         assert (false);
558     }
559 }
560 
561 // Function-building methods from ASTBuilder
562 
563 AST *
UntypedFunctionDecl(const Token * p_token,AST_FQN * p_name)564 ASTBuilder :: UntypedFunctionDecl ( const Token* p_token, AST_FQN* p_name )
565 {
566     AST * ret = new AST ( p_token, p_name );
567     FunctionDeclaration ( *this ) . SetName ( * p_name, eUntypedFunc, false, false );
568     return ret;
569 }
570 
571 AST *
RowlenFunctionDecl(const Token * p_token,AST_FQN * p_name)572 ASTBuilder :: RowlenFunctionDecl ( const Token* p_token, AST_FQN* p_name )
573 {
574     AST * ret = new AST ( p_token, p_name );
575     FunctionDeclaration ( *this ) . SetName ( * p_name, eRowLengthFunc, false, false );
576     return ret;
577 }
578 
579 AST *
FunctionDecl(const Token * p_token,bool p_script,AST * p_schema,AST * p_returnType,AST_FQN * p_name,AST * p_fact,AST * p_params,AST * p_prologue)580 ASTBuilder :: FunctionDecl ( const Token *  p_token,
581                              bool           p_script,
582                              AST *          p_schema,
583                              AST *          p_returnType,
584                              AST_FQN *      p_name,
585                              AST *          p_fact,
586                              AST *          p_params,
587                              AST *          p_prologue )
588 {
589     AST * ret = new AST ( p_token, p_schema, p_returnType, p_name, p_fact, p_params, p_prologue );
590 
591     bool isValidate = p_token -> GetType () == PT_VALIDATE;
592 
593     FunctionDeclaration func ( *this );
594     if ( func . SetName ( * p_name,
595                           ( p_script || ( p_prologue -> GetTokenType () == PT_EMPTY && p_prologue -> ChildrenCount () > 0 ) )? eScriptFunc : eFunction,
596                           true,
597                           isValidate ) )
598     {
599         rc_t rc = 0;
600         bool hasSchemaParms = p_schema -> ChildrenCount () != 0;
601         if ( hasSchemaParms )
602         {
603             rc = KSymTablePushScope ( & m_symtab, func . SchemaScope () );
604             if ( rc == 0 )
605             {
606                 func . SetSchemaParams ( * p_schema );
607             }
608             else
609             {
610                 ReportRc ( "KSymTablePushScope", rc );
611                 hasSchemaParms = false; // do not pop later on
612             }
613         }
614 
615         // if hasSchemaParms, we are still in its scope, in order to evaluate the return type
616         bool isVoid = p_returnType -> ChildrenCount () == 0;
617         if ( isValidate )
618         {   // require return type to be void, 2 mandatory parameters, no optional or varargs
619             if ( ! isVoid )
620             {
621                 ReportError ( "Validate functions have to return void", * p_name );
622             }
623             if ( p_params -> GetChild ( 0 ) -> ChildrenCount () != 2 )
624             {
625                 ReportError ( "Validate functions have to have 2 mandatory parameters", * p_name);
626             }
627             if ( p_params -> GetChild ( 1 ) -> ChildrenCount () != 0 )
628             {
629                 ReportError ( "Validate functions cannot have optional parameters", * p_name);
630             }
631             if ( p_params -> GetChild ( 2 ) -> GetTokenType () != PT_EMPTY )
632             {
633                 ReportError ( "Validate functions cannot have variable parameters", * p_name);
634             }
635         }
636         else if ( isVoid )
637         {
638             ReportError ( "Only validate functions can return void", * p_name );
639         }
640         else
641         {
642             func . SetReturnType ( MakeTypeExpr ( * p_returnType ) );
643         }
644 
645         rc = KSymTablePushScope ( & m_symtab, func . FunctionScope () );
646         if ( rc == 0 )
647         {
648             if ( p_fact -> GetTokenType () != PT_EMPTY )
649             {
650                 func . SetFactoryParams ( * p_fact );
651             }
652 
653             func . SetFormalParams ( * p_params );
654 
655             KSymTablePopScope ( & m_symtab );
656         }
657         else
658         {
659             ReportRc ( "KSymTablePushScope", rc );
660         }
661 
662         if ( hasSchemaParms )
663         {   // now, can pop schema params' scope
664             KSymTablePopScope ( & m_symtab );
665         }
666 
667         if ( p_prologue != 0 )
668         {
669             func . SetPrologue ( * p_prologue );
670         }
671     }
672 
673     return ret;
674 }
675