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.hpp"
28 
29 #include <klib/symbol.h>
30 
31 #include <kfs/directory.h>
32 #include <kfs/mmap.h>
33 
34 #include "../vdb/schema-parse.h"
35 #include "../vdb/dbmgr-priv.h"
36 #include "../vdb/schema-expr.h"
37 
38 #include "SchemaParser.hpp"
39 
40 using namespace ncbi::SchemaParser;
41 #define YYDEBUG 1
42 #include "schema-ast-tokens.h"
43 
44 using namespace std;
45 
46 // data types, constants, etc.
47 
48 void
DeclareType(const AST_FQN & p_fqn,const KSymbol & p_super,const AST_Expr * p_dimension)49 ASTBuilder :: DeclareType ( const AST_FQN& p_fqn, const KSymbol& p_super, const AST_Expr* p_dimension )
50 {
51     /* capture supertype */
52     assert ( p_super . type == eDatatype );
53     const SDatatype * super = static_cast < const SDatatype * > ( p_super . u . obj );
54 
55     /* allocate a datatype */
56     SDatatype * dt = Alloc < SDatatype > ();
57     if ( dt != 0 )
58     {
59         /* insert into type vector */
60         if ( VectorAppend ( m_schema -> dt, & dt -> id, dt ) )
61         {
62             // create a symtab entry
63             const KSymbol* symbol = CreateFqnSymbol ( p_fqn, eDatatype, dt ); // will add missing namespaces to symtab
64             if ( symbol != 0 )
65             {
66                 /* fill it out from super-type */
67                 dt -> super     = super;
68                 dt -> byte_swap = super -> byte_swap;
69                 dt -> name      = symbol;
70                 uint32_t dimension = p_dimension == 0 ? 1 : ( uint32_t ) EvalConstExpr ( * p_dimension );
71                 dt -> size      = super -> size * dimension;
72                 dt -> dim       = dimension;
73                 dt -> domain    = super -> domain;
74             }
75         }
76         else
77         {
78             SDatatypeWhack ( dt, 0 );
79         }
80     }
81 }
82 
83 static
84 void
TypeExprInit(STypeExpr & p_expr)85 TypeExprInit ( STypeExpr & p_expr )
86 {
87     p_expr . dad . var = eTypeExpr;
88     atomic32_set ( & p_expr . dad . refcount, 1 );
89     p_expr . fmt = 0;
90     p_expr . dt = 0;
91     p_expr . ts = 0;
92     p_expr . id = 0;
93     p_expr . dim = 0;
94     p_expr . fd . fmt = 0;
95     p_expr . resolved = true;
96 }
97 
98 static
99 void
TypeExprFillTypeId(ASTBuilder & p_builder,const AST & p_node,STypeExpr & p_expr,const KSymbol & p_sym)100 TypeExprFillTypeId ( ASTBuilder & p_builder, const AST & p_node, STypeExpr & p_expr, const KSymbol & p_sym )
101 {
102     switch ( p_sym . type )
103     {
104     case eDatatype:
105         p_expr . dt                   = static_cast < const SDatatype * > ( p_sym . u . obj );
106         p_expr . fd . td . type_id    = p_expr . dt -> id;
107         break;
108     case eTypeset:
109         p_expr . ts                   = static_cast < const STypeset * > ( p_sym . u . obj );
110         p_expr . fd . td . type_id    = p_expr . ts -> id;
111         break;
112     case eFormat:
113         p_expr . fmt                  = static_cast < const SFormat * > ( p_sym . u . obj );
114         p_expr . fd . fmt             = p_expr . fmt -> id;
115         break;
116     case eSchemaType:
117         p_expr . id                   = static_cast < const SIndirectType * > ( p_sym . u . obj );
118         p_expr . fd . td . type_id    = p_expr . id -> id;
119         p_expr . resolved             = false;
120         break;
121     default:
122         p_builder . ReportError ( p_node . GetLocation (), "Not a datatype", p_sym . name );
123         break;
124     }
125 }
126 
127 STypeExpr *
MakeTypeExpr(const AST & p_type)128 ASTBuilder :: MakeTypeExpr ( const AST & p_type )
129 {
130     STypeExpr * ret = Alloc < STypeExpr > ();
131     if ( ret == 0 )
132     {
133         return 0;
134     }
135     TypeExprInit ( * ret );
136 
137     const AST_FQN * fqn = 0;
138     switch ( p_type . GetTokenType () )
139     {
140     case PT_IDENT : // scalar
141         {
142             fqn = ToFQN ( & p_type );
143             ret -> fd . td . dim = 1;
144         }
145         break;
146     case PT_ARRAY : // fqn [ const-expr | * ]
147         {
148             const AST & arrayType = p_type;
149             assert ( arrayType . ChildrenCount () == 2 );
150             fqn = ToFQN ( arrayType . GetChild ( 0 ) );
151             const AST & dimension = * arrayType . GetChild ( 1 );
152             if ( dimension . GetTokenType() == PT_EMPTY )
153             {
154                 ret -> fd . td . dim = 0;
155             }
156             else
157             {
158                 SExpression * expr = ToExpr ( & dimension ) -> MakeExpression ( * this ); // will report problems
159                 if ( expr != 0 )
160                 {
161                     switch ( expr -> var )
162                     {
163                     case eConstExpr :
164                         {
165                             SConstExpr* cexpr = reinterpret_cast < SConstExpr* > ( expr );
166                             // this may change as more kinds of const expressions are supported
167                             assert ( cexpr -> td . type_id == IntrinsicTypeId ( "U64" ) );
168                             ret -> fd . td . dim = ( uint32_t ) cexpr -> u . u64 [ 0 ];
169                             ret -> dim = expr;
170                         }
171                         break;
172                     case eIndirectExpr:
173                         {
174                             ret -> fd . td . dim = 0;
175                             ret -> dim = expr;
176                             ret -> resolved = false;
177                             break;
178                         }
179                     default:
180                         ReportError ( dimension . GetLocation (), "Not allowed in array subscripts", expr -> var );
181                         SExpressionWhack ( expr );
182                         break;
183                     }
184                 }
185             }
186         }
187         break;
188     case PT_TYPEEXPR :  // fqn (format) / fqn (type)
189         {
190             fqn = ToFQN ( p_type . GetChild ( 0 ) );
191             const KSymbol * fmt = Resolve ( * fqn ); // will report unknown name
192             if ( fmt -> type != eFormat )
193             {
194                 ReportError ( "Not a format", *fqn );
195                 fqn = 0;
196             }
197             else
198             {
199                 ret -> fmt = static_cast < const SFormat * > ( fmt -> u . obj );
200                 ret -> fd . fmt = ret -> fmt -> id;
201                 ret -> fd . td . dim = 1;
202 
203                 fqn = ToFQN ( p_type . GetChild ( 1 ) ); // has to be a type!
204             }
205         }
206         break;
207     default:
208         assert ( false ); // should not happen
209         break;
210     }
211 
212     if ( fqn != 0 )
213     {
214         const KSymbol * type = Resolve ( * fqn ); // will report unknown name
215         if ( type != 0 )
216         {
217             TypeExprFillTypeId ( * this, * fqn, * ret, * type );
218         }
219     }
220 
221     return ret;
222 }
223 
224 bool
FillSchemaParms(const AST & p_parms,Vector & p_v)225 ASTBuilder :: FillSchemaParms ( const AST & p_parms, Vector & p_v )
226 {
227     uint32_t count = p_parms . ChildrenCount ();
228     for ( uint32_t i = 0; i < count; ++ i )
229     {
230         const AST & parm = * p_parms . GetChild ( i );
231         switch ( parm . GetTokenType () )
232         {
233         case PT_IDENT :
234             {
235                 const KSymbol * sym = Resolve ( * ToFQN ( & parm ) ); // will report unknown name
236                 if ( sym == 0 )
237                 {
238                     return false;
239                 }
240 
241                 switch ( sym -> type )
242                 {
243                 /* type parameter */
244                 case eFormat:
245                 case eDatatype:
246                 case eTypeset:
247                 case eSchemaType:
248                     {
249                         STypeExpr * ret = Alloc < STypeExpr > ();
250                         if ( ret == 0 )
251                         {
252                             return false;
253                         }
254                         TypeExprInit ( * ret );
255                         ret -> fd . td . dim = 1;
256                         TypeExprFillTypeId ( * this, parm, * ret, * sym );
257                         if ( ! VectorAppend ( p_v, 0, ret ) )
258                         {
259                             SExpressionWhack ( & ret -> dad );
260                             return false;
261                         }
262                     }
263                     break;
264 
265                 case eConstant:
266                     {
267                         const SConstant * cnst = static_cast < const SConstant * > ( sym -> u . obj );
268                         assert ( cnst -> expr != NULL );
269                         const SDatatype *dt = VSchemaFindTypeid ( m_schema, cnst -> td . type_id );
270                         assert ( dt != 0 );
271                         if ( dt -> domain == ddUint && dt -> dim == 1 )
272                         {
273                             atomic32_inc ( & ( ( SExpression* ) cnst -> expr ) -> refcount );
274                             if ( ! VectorAppend ( p_v, 0, cnst -> expr ) )
275                             {
276                                 atomic32_dec ( & ( ( SExpression* ) cnst -> expr ) -> refcount );
277                                 return false;
278                             }
279                         }
280                         else
281                         {
282                             ReportError ( parm . GetLocation (),
283                                           "Schema argument constant has to be an unsigned integer scalar",
284                                           sym -> name );
285                             return false;
286                         }
287                     }
288                     break;
289 
290                 /* schema or factory constant must be uint
291                 but may not yet be completely resolved */
292                 case eSchemaParam:
293                 case eFactParam:
294                     //TODO: return indirect_const_expr ( tbl, src, t, env, self, v );
295                     assert ( false );
296                     break;
297 
298                 default:
299                     ReportError ( parm. GetChild ( 0 ) -> GetLocation (), "Cannot be used as a schema parameter", sym -> name );
300                     return false;
301                 }
302             }
303             break;
304 
305         case PT_UINT :
306             VectorAppend ( p_v, 0, ToExpr ( & parm ) -> MakeUnsigned ( * this ) );
307             break;
308 
309         case PT_ARRAY:
310             VectorAppend ( p_v, 0, MakeTypeExpr ( parm ) );
311             break;
312 
313         default:
314             assert ( false );
315         }
316     }
317     return true;
318 }
319 
320 bool
FillFactoryParms(const AST & p_parms,Vector & p_v)321 ASTBuilder :: FillFactoryParms ( const AST & p_parms, Vector & p_v )
322 {
323     uint32_t count = p_parms . ChildrenCount ();
324     for ( uint32_t i = 0; i < count; ++ i )
325     {
326         SExpression * expr = ToExpr ( p_parms . GetChild ( i ) ) -> MakeExpression ( * this );
327         if ( expr != 0 )
328         {
329             // allowed:
330             // eConstExpr, eIndirectExpr, eVectorExpr, eCastExpr, eFuncParamExpr, eNegateExpr
331             switch ( expr -> var )
332             {
333             case eConstExpr:
334             case eIndirectExpr:
335             case eVectorExpr:
336             case eCastExpr:
337             case eFuncParamExpr:
338             case eNegateExpr:
339                 if ( ! VectorAppend ( p_v, 0, expr ) )
340                 {
341                     SExpressionWhack ( expr );
342                     return false;
343                 }
344                 break;
345             default:
346                 ReportError ( p_parms . GetChild ( i ) -> GetLocation (), "Cannot be used as a factory parameter" );
347                 break;
348             }
349         }
350         else
351         {
352             return false;
353         }
354     }
355     return true;
356 }
357 
358 bool
FillArguments(const AST & p_parms,Vector & p_v)359 ASTBuilder :: FillArguments ( const AST & p_parms, Vector & p_v )
360 {
361     uint32_t count = p_parms . ChildrenCount ();
362     for ( uint32_t i = 0; i < count; ++ i )
363     {
364         const AST_Expr * parm = ToExpr ( p_parms . GetChild ( i ) );
365         // allowed tags: PT_AT, PHYSICAL_IDENTIFIER_1_0, PT_CAST, PT_IDENT, PT_MEMBEREXPR
366         // for PT_IDENT, allowed object types: eFuncParam, eProduction, eIdent, eForward, eVirtual, eColumn, ePhysMember
367         SExpression * expr = 0;
368         switch ( parm -> GetTokenType () )
369         {
370         case '@':
371         case PT_IDENT:
372         case PHYSICAL_IDENTIFIER_1_0:
373         case PT_MEMBEREXPR:
374             expr = parm -> MakeExpression ( * this );
375             break;
376         default:
377             ReportError ( p_parms . GetChild ( i ) -> GetLocation (), "Cannot be used as a function call parameter" );
378             break;
379         }
380         if ( expr == 0 )
381         {
382             return false;
383         }
384         if ( ! VectorAppend ( p_v, 0, expr ) )
385         {
386             SExpressionWhack ( expr );
387             return false;
388         }
389     }
390     return true;
391 }
392 
393 /*--------------------------------------------------------------------------
394  * STypesetMbr
395  *  a typedecl that can be tested for uniqueness
396  */
397 typedef struct STypesetMbr STypesetMbr;
398 struct STypesetMbr
399 {
400     BSTNode n;
401     VTypedecl td;
402 };
403 
404 static
STypesetPopulate(BSTNode * n,void * data)405 void CC STypesetPopulate ( BSTNode *n, void *data )
406 {
407     const STypesetMbr *mbr = ( const STypesetMbr* ) n;
408     STypeset *ts = static_cast < STypeset * > ( data );
409     ts -> td [ ts -> count ++ ] = mbr -> td;
410 }
411 
412 /* Cmp
413  * Sort
414  */
415 static
VTypedeclCmp(const VTypedecl * a,const VTypedecl * b)416 int64_t VTypedeclCmp ( const VTypedecl *a, const VTypedecl *b )
417 {
418     if ( a -> type_id != b -> type_id )
419         return ( int64_t ) a -> type_id - ( int64_t ) b -> type_id;
420     return ( int64_t ) a -> dim - ( int64_t ) b -> dim;
421 }
422 
423 static
STypesetMbrSort(const BSTNode * item,const BSTNode * n)424 int64_t CC STypesetMbrSort ( const BSTNode *item, const BSTNode *n )
425 {
426     const STypesetMbr *a = ( const STypesetMbr* ) item;
427     const STypesetMbr *b = ( const STypesetMbr* ) n;
428     return VTypedeclCmp ( & a -> td, & b -> td );
429 }
430 
431 void
DeclareTypeSet(const AST_FQN & p_fqn,const BSTree & p_types,uint32_t p_typeCount)432 ASTBuilder :: DeclareTypeSet ( const AST_FQN & p_fqn, const BSTree & p_types, uint32_t p_typeCount )
433 {
434     STypeset *ts = Alloc < STypeset > ( sizeof * ts - sizeof ts -> td + p_typeCount * sizeof ts -> td [ 0 ] );
435     if ( ts != 0 )
436     {
437         ts -> count = 0;
438         BSTreeForEach ( & p_types, false, STypesetPopulate, ts );
439 
440         if ( VectorAppend ( m_schema -> ts, & ts -> id, ts ) )
441         {
442             const KSymbol* symbol = CreateFqnSymbol ( p_fqn, eTypeset, ts ); // will add missing namespaces to symtab
443             ts -> name = symbol;
444             ts -> count = p_typeCount;
445         }
446         else
447         {
448             STypesetWhack ( ts, 0 );
449         }
450     }
451 }
452 
453 AST *
TypeDef(const Token * p_token,AST_FQN * p_baseType,AST * p_newTypes)454 ASTBuilder :: TypeDef ( const Token * p_token, AST_FQN* p_baseType, AST* p_newTypes )
455 {   //TODO: do we need to keep all these subtrees beyond the population of symtab?
456     AST * ret = new AST ( p_token, p_baseType, p_newTypes );
457 
458     const KSymbol * baseType = Resolve ( * p_baseType ); // will report unknown name
459     if ( baseType != 0 )
460     {
461         if ( baseType -> type != eDatatype )
462         {
463             ReportError ( "Not a datatype", * p_baseType );
464         }
465         else
466         {
467             uint32_t count = p_newTypes -> ChildrenCount ();
468             for ( uint32_t i = 0; i < count; ++i )
469             {
470                 const AST * newType = p_newTypes -> GetChild ( i );
471                 if ( newType -> GetTokenType () == PT_IDENT )
472                 {
473                     DeclareType ( * ToFQN ( newType ), * baseType, 0 ); // will report duplicate definition
474                 }
475                 else // fqn [ const-expr ]
476                 {
477                     assert ( newType -> ChildrenCount () == 2 );
478                     DeclareType ( * ToFQN ( newType -> GetChild ( 0 ) ),
479                                   * baseType,
480                                   ToExpr ( newType -> GetChild ( 1 ) ) ); // will report duplicate definition
481                 }
482             }
483         }
484     }
485     return ret;
486 }
487 
488 static
489 bool
TypeSetAddType(ASTBuilder & p_builder,BSTree & p_tree,const VTypedecl & p_type,uint32_t & p_typeCount)490 TypeSetAddType ( ASTBuilder & p_builder, BSTree & p_tree, const VTypedecl & p_type, uint32_t & p_typeCount )
491 {
492     STypesetMbr * mbr = p_builder . Alloc < STypesetMbr > ();
493     if ( mbr == 0 )
494     {
495         return false;
496     }
497 
498     mbr -> td = p_type;
499 
500     /* ignore/allow duplicates */
501     BSTNode * exist;
502     if ( BSTreeInsertUnique ( & p_tree, & mbr -> n, & exist, STypesetMbrSort ) != 0 )
503     {
504         free ( mbr );
505     }
506     else
507     {
508         ++ p_typeCount;
509     }
510     return true;
511 }
512 
513 const KSymbol *
TypeSpec(const AST & p_spec,VTypedecl & p_td)514 ASTBuilder :: TypeSpec ( const AST & p_spec, VTypedecl & p_td )
515 {
516     const KSymbol * ret = 0;
517     if ( p_spec . GetTokenType () == PT_IDENT )
518     {   // scalar
519         const AST_FQN & fqn = * ToFQN ( & p_spec );
520         ret = Resolve ( fqn ); // will report unknown name
521         if ( ret != 0 )
522         {
523             switch ( ret -> type )
524             {
525             case eDatatype:
526                 {
527                     const SDatatype * typeDef = static_cast < const SDatatype * > ( ret -> u . obj );
528                     p_td . type_id = typeDef -> id;
529                     p_td . dim = 1;
530                 }
531                 break;
532             case eTypeset:
533                 {
534                     const STypeset * typeset = static_cast < const STypeset * > ( ret -> u . obj );
535                     p_td . type_id = typeset -> id;
536                     p_td . dim = 1;
537                 }
538                 break;
539             default:
540                 {
541                     ReportError ( "Not a datatype", fqn );
542                 }
543                 return 0;
544             }
545         }
546     }
547     else // fqn [ const-expr ]
548     {
549         assert ( p_spec . GetTokenType () == PT_ARRAY );
550         assert ( p_spec . ChildrenCount () == 2 ); // fqn expr
551         const AST_FQN & fqn = * ToFQN ( p_spec . GetChild ( 0 ) );
552         ret = Resolve ( fqn ); // will report unknown name
553         if ( ret != 0 )
554         {
555             if ( ret -> type != eDatatype )
556             {
557                 ReportError ( "Not a datatype", fqn );
558                 return 0;
559             }
560             const SDatatype * typeDef = static_cast < const SDatatype * > ( ret -> u . obj );
561             p_td . type_id    = typeDef -> id;
562             p_td.dim = (uint32_t) EvalConstExpr(*ToExpr(p_spec.GetChild(1)));
563         }
564     }
565     return ret;
566 }
567 
568 AST *
TypeSet(const Token * p_token,AST_FQN * p_name,AST * p_typeSpecs)569 ASTBuilder :: TypeSet ( const Token* p_token, AST_FQN * p_name, AST * p_typeSpecs )
570 {
571     AST * ret = new AST ( p_token, p_name, p_typeSpecs );
572 
573     const KSymbol * existing = Resolve ( * p_name, false );
574 
575     // traverse p_typeSpecs, add to tree
576     BSTree tree;
577     BSTreeInit ( & tree );
578 
579     uint32_t typeCount = 0;
580     uint32_t count = p_typeSpecs -> ChildrenCount ();
581     bool error = false;
582     for ( uint32_t i = 0; i < count; ++i )
583     {
584         const AST * spec = p_typeSpecs -> GetChild ( i );
585         VTypedecl td;
586         const KSymbol * type = TypeSpec ( * spec, td );
587         if ( type != 0  )
588         {
589             if ( type -> type == eDatatype )
590             {
591                 if ( ! TypeSetAddType ( * this, tree, td, typeCount ) )
592                 {
593                     error = true;
594                 }
595             }
596             else
597             {
598                 assert ( type -> type == eTypeset );
599                 const STypeset * typeset = static_cast < const STypeset * > ( type -> u . obj );
600                 for ( uint16_t j = 0; j < typeset -> count; ++j )
601                 {
602                     if ( ! TypeSetAddType ( *this, tree, typeset -> td [ j ], typeCount ) )
603                     {
604                         error = true;
605                     }
606                 }
607             }
608         }
609         else
610         {
611             error = true;
612         }
613     }
614 
615     if ( ! error && existing != 0 )
616     {
617         if ( existing -> type != eTypeset )
618         {
619             ReportError ( "Already declared and is not a typeset", * p_name );
620         }
621         else
622         {   // allow benign redefine
623             const STypeset * orig = static_cast < const STypeset * > ( existing -> u . obj );
624             if ( orig -> count != typeCount )
625             {
626                 ReportError ( "Typeset already declared differently", * p_name );
627             }
628             else
629             {
630                 BSTNode* node = BSTreeFirst ( &tree );
631                 for ( uint32_t i = 0; i < typeCount; ++ i )
632                 {
633                     assert ( node != 0 );
634                     STypesetMbr * mbr = reinterpret_cast < STypesetMbr * > ( node );
635                     if ( VTypedeclCmp ( & orig -> td [ i ], & mbr -> td ) != 0 )
636                     {
637                         ReportError ( "Typeset already declared differently", * p_name );
638                         break;
639                     }
640                     node = BSTNodeNext ( node );
641                 }
642             }
643         }
644     }
645     else
646     {
647         DeclareTypeSet ( * p_name, tree, typeCount );
648     }
649 
650     BSTreeWhack ( & tree, BSTreeMbrWhack, 0 );
651 
652     return ret;
653 }
654 
655 AST *
FmtDef(const Token * p_token,AST_FQN * p_fqn,AST_FQN * p_super_opt)656 ASTBuilder :: FmtDef ( const Token* p_token, AST_FQN* p_fqn, AST_FQN* p_super_opt )
657 {
658     AST * ret = new AST ( p_token, p_fqn );
659     if ( p_super_opt != 0 )
660     {
661         ret -> AddNode ( p_super_opt );
662     }
663 
664     SFormat * fmt = Alloc < SFormat > ();
665     if ( fmt != 0 )
666     {
667         // superfmt
668         fmt -> super = 0;
669         if ( p_super_opt != 0 )
670         {
671             const KSymbol* super = Resolve ( * p_super_opt ); // will report undefined
672             if ( super != 0 )
673             {
674                 if ( super -> type != eFormat )
675                 {
676                     ReportError ( "Not a format", * p_super_opt );
677                     SFormatWhack ( fmt, 0 );
678                     return ret;
679                 }
680                 fmt -> super = static_cast < const SFormat * > ( super -> u . obj );
681             }
682         }
683 
684         /* insert into vector */
685         if ( VectorAppend ( m_schema -> fmt, & fmt -> id, fmt ) )
686         {   // create a symtab entry, link fmt to it
687             fmt -> name = CreateFqnSymbol ( * p_fqn, eFormat, fmt ); // will add missing namespaces to symtab
688         }
689         else
690         {
691             SFormatWhack ( fmt, 0 );
692         }
693     }
694 
695     return ret;
696 }
697 
698 AST *
ConstDef(const Token * p_token,AST * p_type,AST_FQN * p_fqn,AST_Expr * p_expr)699 ASTBuilder :: ConstDef  ( const Token* p_token, AST* p_type, AST_FQN* p_fqn, AST_Expr* p_expr )
700 {
701     AST * ret = new AST ( p_token, p_type, p_fqn, p_expr );
702 
703     SConstant *cnst = Alloc < SConstant > ();
704     if ( cnst != 0 )
705     {
706         if ( p_type -> GetTokenType () == PT_IDENT )
707         {   // scalar
708             const KSymbol * type = Resolve ( * ToFQN ( p_type ) ); // will report unknown name
709             if ( type != 0 )
710             {
711                 if ( VectorAppend ( m_schema -> cnst, & cnst -> id, cnst ) )
712                 {
713                     cnst -> name = CreateFqnSymbol ( * p_fqn, eConstant, cnst );
714                     cnst -> expr = p_expr -> EvaluateConst ( *this ); // will report problems
715                     const SDatatype * typeDef = static_cast < const SDatatype * > ( type -> u . obj );
716                     cnst -> td . type_id = typeDef -> id;
717                     cnst -> td . dim = 1;
718                 }
719                 else
720                 {
721                     SConstantWhack ( cnst, 0 );
722                 }
723             }
724         }
725         else // fqn [ const-expr ]
726         {
727             assert ( p_type -> GetTokenType () == PT_ARRAY );
728             assert ( p_type -> ChildrenCount () == 2 ); // fqn expr
729             const AST_FQN & fqn = * ToFQN ( p_type -> GetChild ( 0 ) );
730             const KSymbol * sym = Resolve ( fqn ); // will report unknown name
731             if ( sym != 0 )
732             {
733                 if ( sym -> type != eDatatype )
734                 {
735                     ReportError ( "Not a datatype", fqn );
736                     return 0;
737                 }
738                 if ( VectorAppend ( m_schema -> cnst, & cnst -> id, cnst ) )
739                 {
740                     cnst -> name = CreateFqnSymbol ( * p_fqn, eConstant, cnst );
741                     cnst -> expr = p_expr -> EvaluateConst ( *this ); // will report problems
742                     const SDatatype * typeDef = static_cast < const SDatatype * > ( sym -> u . obj );
743                     cnst -> td . type_id    = typeDef -> id;
744                     cnst->td.dim = (uint32_t) EvalConstExpr(*ToExpr(p_type->GetChild(1)));
745                 }
746             }
747         }
748     }
749 
750     return ret;
751 }
752 
753 AST *
AliasDef(const Token * p_token,AST_FQN * p_name,AST_FQN * p_newName)754 ASTBuilder :: AliasDef  ( const Token* p_token, AST_FQN* p_name, AST_FQN* p_newName )
755 {
756     AST * ret = new AST ( p_token, p_name, p_newName );
757 
758     const KSymbol * sym = Resolve ( * p_name ); // will report unknown name
759     if ( sym != 0 )
760     {
761         VectorAppend ( m_schema -> alias, 0, CreateFqnSymbol ( * p_newName, sym -> type, sym -> u . obj ) );
762     }
763 
764     return ret;
765 }
766 
767 void
AddIncludePath(const char * path)768 ASTBuilder :: AddIncludePath ( const char * path )
769 {
770     rc_t rc = VSchemaAddIncludePath ( m_schema, "%s", path );
771     if ( rc != 0 )
772     {
773         ReportRc ( "VSchemaAddIncludePath", rc );
774     }
775 }
776 
777 const KFile *
OpenIncludeFile(const Token::Location & p_loc,const char * p_fmt,...)778 ASTBuilder :: OpenIncludeFile ( const Token :: Location & p_loc, const char * p_fmt, ... )
779 {
780     const KFile * ret = 0;
781     va_list args;
782     va_start ( args, p_fmt );
783 
784     char path [ 4096 ];
785     rc_t rc = 0;
786     /* open file using include paths */
787     rc = VSchemaOpenFile ( m_schema, & ret, path, sizeof path, p_fmt, args );
788 
789     if ( rc != 0 )
790     {   /* try to open the file according to current directory */
791         KDirectory *wd;
792         rc = KDirectoryNativeDir ( & wd );
793         if ( rc == 0 )
794         {
795             rc = VSchemaTryOpenFile ( m_schema, wd, & ret, path, sizeof path, p_fmt, args );
796             // ret == 0 if was included previously
797             KDirectoryRelease ( wd );
798         }
799         else
800         {
801             ReportRc ( "KDirectoryNativeDir", rc );
802         }
803     }
804 
805     // if the file was found ...
806     if ( rc == 0 )
807     {
808         if ( ret != 0 ) // file was included for the 1st time
809         {
810             const KMMap *mm;
811             rc = KMMapMakeRead ( & mm, ret );
812             if ( rc == 0 )
813             {
814                 size_t size;
815                 const void *addr;
816                 rc = KMMapAddrRead ( mm, & addr );
817                 if ( rc == 0 )
818                 {
819                     rc = KMMapSize ( mm, & size );
820                     if ( rc == 0 )
821                     {
822                         rc = VIncludedPathMake ( & m_schema -> paths, & m_schema -> file_count, path );
823                         if ( rc != 0 )
824                         {
825                             ReportRc ( "VIncludedPathMake", rc );
826                         }
827                     }
828                     else
829                     {
830                         ReportRc ( "KMMapSize", rc );
831                     }
832                 }
833                 else
834                 {
835                     ReportRc ( "KMMapAddrRead", rc );
836                 }
837 
838                 KMMapRelease ( mm );
839             }
840             else
841             {
842                 ReportRc ( "KMMapMakeRead", rc );
843             }
844         }
845         // else: file was included previously, now ignored
846     }
847     else
848     {
849         ReportError ( p_loc, "Could not open include file", path );
850     }
851 
852     va_end ( args );
853     return ret;
854 }
855 
856 AST *
Include(const Token * p_token,const Token * p_filename)857 ASTBuilder :: Include ( const Token * p_token, const Token * p_filename )
858 {
859     AST * ret = new AST ( p_token );
860     assert ( p_filename != 0 );
861     ret -> AddNode ( p_filename );
862 
863     const char * quoted = p_filename -> GetValue ();
864     char * unquoted = string_dup ( quoted + 1, string_size ( quoted ) - 2 );
865     if ( unquoted != 0 )
866     {
867         const KFile * f = OpenIncludeFile ( p_token -> GetLocation (), "%s", unquoted );
868         if ( f != 0 )
869         {
870             SchemaParser parser;
871             if ( parser . ParseFile ( f, unquoted ) )
872             {
873                 delete Build ( * parser . GetParseTree (), unquoted, false );
874             }
875             KFileRelease ( f );
876         }
877         free ( unquoted );
878     }
879     else
880     {
881         ReportInternalError ( "ASTBuilder :: Include () : string_dup() failed" );
882     }
883 
884     return ret;
885 }