3e93113ef831d629bfcfe802d5e1e7b98a9a735f
[sdk] / compiler / libec / src / dbpass.ec
1 import "ecdefs"
2
3 #define YYLTYPE Location
4 #include "grammar.h"
5
6 static OldList * tableStatements, * indexStatements, * addFieldStatements/*, * findFieldStatements*/;
7 static int numIndexes;
8 static External addAfter;
9
10 static void ProcessSpecifier(Specifier spec)
11 {
12    switch(spec.type)
13    {
14       case enumSpecifier:
15       case structSpecifier:
16       case unionSpecifier:
17       {
18          if(spec.definitions)
19          {
20             ClassDef def;
21             for(def = spec.definitions->first; def; def = def.next)
22             {
23                // TODO: Should use the ProcessClassDef function here right?
24
25                //if(def.type == ClassDefDeclaration && def.decl && def.decl.type == DeclarationStruct)
26                //   ProcessDeclaration(def.decl);
27                switch(def.type)
28                {
29                   case declarationClassDef:
30                      ProcessDeclaration(def.decl);
31                      break;
32                   case defaultPropertiesClassDef:
33                   {
34                      MemberInit init;
35                      for(init = def.defProperties->first; init; init = init.next)
36                      {
37                         Class oldThisClass = thisClass;
38                         ProcessMemberInit(init);
39                      }
40                      break;
41                   }
42                   case functionClassDef:
43                      ProcessClassFunction(def.function);
44                      break;
45                   case propertyClassDef:
46                      if(def.propertyDef)
47                      {
48                         ProcessProperty(def.propertyDef);
49                      }
50                      break;
51                   case propertyWatchClassDef:
52                      if(def.propertyWatch && def.propertyWatch.compound)
53                      {
54                         ProcessStatement(def.propertyWatch.compound);
55                      }
56                      break;
57                }
58             }
59          }
60          break;
61       }
62    }
63 }
64
65 static void ProcessIdentifier(Identifier id)
66 {
67
68 }
69
70 static void ProcessExpression(Expression exp)
71 {
72    switch(exp.type)
73    {
74       case newExp:
75          ProcessExpression(exp._new.size);
76          break;
77       case renewExp:
78          ProcessExpression(exp._renew.exp);
79          ProcessExpression(exp._renew.size);
80          break;
81       case constantExp:
82          break;
83       case identifierExp:
84          ProcessIdentifier(exp.identifier);
85          break;
86       case instanceExp:
87          ProcessInstance(exp.instance);
88          break;
89       case stringExp:
90          break;
91       case opExp:
92          if(exp.op.exp1)
93          {
94             ProcessExpression(exp.op.exp1);
95          }
96          if(exp.op.exp2)
97          {
98             ProcessExpression(exp.op.exp2);
99          }
100          break;
101       case bracketsExp:
102       {
103          Expression expression;
104          for(expression = exp.list->first; expression; expression = expression.next)
105          {
106             ProcessExpression(expression);
107          }
108          break;
109       }
110       case indexExp:
111       {
112          Expression expression;
113          ProcessExpression(exp.index.exp);
114          
115          for(expression = exp.index.index->first; expression; expression = expression.next)
116          {
117             ProcessExpression(expression);
118          }
119          break;
120       }
121       case callExp:
122       {
123          ProcessExpression(exp.call.exp);
124          
125          if(exp.call.arguments)
126          {
127             Expression expression;
128
129             for(expression = exp.call.arguments->first; expression; expression = expression.next)
130             {
131                ProcessExpression(expression);
132             }
133          }
134          break;
135       }
136       case memberExp:
137          ProcessExpression(exp.member.exp);
138          break;
139       case pointerExp:
140          ProcessExpression(exp.member.exp);
141          break;
142       case typeSizeExp:
143          break;
144       case castExp:
145          ProcessExpression(exp.cast.exp);
146          break;
147       case conditionExp:
148          ProcessExpression(exp.cond.cond);
149
150          {
151             Expression expression;
152             for(expression = exp.cond.exp->first; expression; expression = expression.next)
153             {
154                ProcessExpression(expression);
155             }
156          }
157          ProcessExpression(exp.cond.elseExp);
158          break;
159       case dummyExp:
160          break;
161       case dbfieldExp:
162       {
163          char tableName[1024];
164          char name[1024];
165          int len = strlen(exp.db.table);
166          memcpy(tableName, exp.db.table+1, len-2);
167          tableName[len-2] = 0;
168          ChangeCh(tableName, ' ', '_');
169          sprintf(name, "__ecereDBField_%s_%s", tableName, exp.db.id.string);
170          FreeExpContents(exp);
171          exp.type = identifierExp;
172          exp.identifier = MkIdentifier(name);                          
173          break;
174       }
175       case dbtableExp:
176       {
177          char tableName[1024];
178          char name[1024];
179          int len = strlen(exp.db.table);
180          memcpy(tableName, exp.db.table+1, len-2);
181          tableName[len-2] = 0;
182          ChangeCh(tableName, ' ', '_');
183          sprintf(name, "__ecereDBTable_%s", tableName);
184          FreeExpContents(exp);
185          exp.type = identifierExp;
186          exp.identifier = MkIdentifier(name);                          
187          break;
188       }
189       case dbindexExp:
190       {
191          char tableName[1024];
192          char name[1024];
193          int len = strlen(exp.db.table);
194          memcpy(tableName, exp.db.table+1, len-2);
195          tableName[len-2] = 0;
196          ChangeCh(tableName, ' ', '_');
197          sprintf(name, "__ecereDBIndex_%s_%s", tableName, exp.db.id.string);
198          FreeExpContents(exp);
199          exp.type = identifierExp;
200          exp.identifier = MkIdentifier(name);                          
201          break;
202       }
203       case dbopenExp:
204       {
205          if(tableStatements)
206          {
207             Statement databaseOpenStmt = MkCompoundStmt(MkList(), MkList());
208             Statement compound, compound2;
209             Statement ifDBStmt;
210             OldList * args;
211             char numIndexesString[16];
212
213             databaseOpenStmt.compound.context = Context { parent = curContext };
214
215             databaseOpenStmt.compound.declarations->Add(MkDeclaration(MkListOne(MkSpecifierName("Database")), 
216                MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("db")), null))));
217
218             // bool createNow = false;
219             databaseOpenStmt.compound.declarations->Add(MkDeclaration(MkListOne(MkSpecifierName("bool")), 
220                MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("createNow")), MkInitializerAssignment(MkExpIdentifier(MkIdentifier("false")))))));
221
222             // static bool initialized = false;
223             args = MkList();
224             args->Add(MkSpecifier(STATIC));
225             args->Add(MkSpecifierName("bool"));
226             databaseOpenStmt.compound.declarations->Add(MkDeclaration(args, 
227                MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("initialized")), MkInitializerAssignment(MkExpIdentifier(MkIdentifier("false")))))));
228
229             // if(initialized) return;
230             databaseOpenStmt.compound.statements->Add(MkIfStmt(MkListOne(MkExpIdentifier(MkIdentifier("initialized"))), MkReturnStmt(MkListOne(MkExpIdentifier(MkIdentifier("null")))), null));
231
232             // initialized = true;
233             databaseOpenStmt.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier("initialized")), '=', MkExpIdentifier(MkIdentifier("true"))))));
234
235             // db = ds.OpenDatabase("med", no);
236             args = MkList();
237             args->Add(CopyExpression(exp.dbopen.name));
238             args->Add(MkExpIdentifier(MkIdentifier("no")));
239             databaseOpenStmt.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier("db")), '=', 
240                MkExpCall(MkExpMember(CopyExpression(exp.dbopen.ds), MkIdentifier("OpenDatabase")), args)))));
241             
242             /*if(!db)
243             {
244                db = ds.OpenDatabase("med", create);
245                createNow = true;
246             }
247             */
248             databaseOpenStmt.compound.statements->Add(MkIfStmt(MkListOne(MkExpOp(null, '!', MkExpIdentifier(MkIdentifier("db")))), 
249                compound = MkCompoundStmt(null, MkList()), null));
250             compound.compound.context = Context { parent = databaseOpenStmt.compound.context };
251             
252             args = MkList();
253             args->Add(exp.dbopen.name);
254             args->Add(MkExpIdentifier(MkIdentifier("create")));
255             compound.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier("db")), '=', 
256                MkExpCall(MkExpMember(exp.dbopen.ds, MkIdentifier("OpenDatabase")), args)))));
257             compound.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier("createNow")), '=', 
258                MkExpIdentifier(MkIdentifier("true"))))));
259
260             exp.dbopen.name = null;
261             exp.dbopen.ds = null;
262
263             // if(db)
264             databaseOpenStmt.compound.statements->Add(MkIfStmt(MkListOne(MkExpIdentifier(MkIdentifier("db"))), 
265                ifDBStmt = MkCompoundStmt(MkList(), MkList()), null));
266
267             ifDBStmt.compound.context = Context { parent = databaseOpenStmt.compound.context };
268
269             // FieldIndex indexes[numIndexes] = { null };
270             sprintf(numIndexesString, "%d", numIndexes);
271             ifDBStmt.compound.declarations->Add(MkDeclaration(MkListOne(MkSpecifierName("FieldIndex")), MkListOne(MkInitDeclarator(MkDeclaratorArray(MkDeclaratorIdentifier(MkIdentifier("indexes")), 
272                MkExpConstant(numIndexesString)), MkInitializerList(MkListOne(MkInitializerList(MkListOne(MkInitializerAssignment(MkExpIdentifier(MkIdentifier("null")))))))))));
273             
274             ifDBStmt.compound.statements->Add(compound = MkCompoundStmt(null, tableStatements));
275             compound.compound.context = Context { parent = ifDBStmt.compound.context };
276             /*
277             ifDBStmt.compound.statements->Add(MkIfStmt(MkListOne(MkExpIdentifier(MkIdentifier("createNow"))), 
278                (compound = MkCompoundStmt(null, addFieldStatements), compound.compound.context = Context { parent = ifDBStmt.compound.context }, compound), 
279                (compound2 = MkCompoundStmt(null, findFieldStatements), compound2.compound.context = Context { parent = ifDBStmt.compound.context }, compound2)));
280             */
281             ifDBStmt.compound.statements->Add(
282                (compound = MkCompoundStmt(null, addFieldStatements), compound.compound.context = Context { parent = ifDBStmt.compound.context }, compound)
283                );
284
285             ifDBStmt.compound.statements->Add(compound = MkCompoundStmt(null, indexStatements));
286             compound.compound.context = Context { parent = ifDBStmt.compound.context };
287
288             // TODO: Don't make use of extension
289             exp.type = extensionCompoundExp;
290             exp.compound = databaseOpenStmt;
291
292             databaseOpenStmt.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpIdentifier(MkIdentifier("db")))));
293
294             tableStatements = null;
295          }
296          else
297          {
298             FreeExpContents(exp);
299             Compiler_Error($"No database table defined in this module or database_open already used.\n");
300             exp.type = dummyExp;
301          }
302          break;
303       }
304    }
305 }
306
307 static void ProcessStatement(Statement stmt)
308 {
309    switch(stmt.type)
310    {
311       case labeledStmt:
312          ProcessStatement(stmt.labeled.stmt);
313          break;
314       case caseStmt:
315          if(stmt.caseStmt.exp)
316          {
317             ProcessExpression(stmt.caseStmt.exp);
318          }
319
320          if(stmt.caseStmt.stmt)
321          {
322             ProcessStatement(stmt.caseStmt.stmt);
323          }
324          break;
325       case badDeclarationStmt:
326       {
327          ProcessDeclaration(stmt.decl);
328          break;
329       }
330       case compoundStmt:
331       {
332          Context oldContext = curContext;
333          curContext = stmt.compound.context;
334          if(stmt.compound.declarations)
335          {
336             Declaration decl;
337             for(decl = stmt.compound.declarations->first; decl; decl = decl.next)
338             {
339                ProcessDeclaration(decl);
340             }
341          }
342          if(stmt.compound.statements)
343          {
344             Statement statement;
345             for(statement = stmt.compound.statements->first; statement; statement = statement.next)
346             {
347                ProcessStatement(statement);
348             }
349          }
350          curContext = oldContext;
351          break;
352       }
353       case expressionStmt:
354       {
355          if(stmt.expressions)
356          {
357             Expression exp;
358             for(exp = stmt.expressions->first; exp; exp = exp.next)
359             {
360                ProcessExpression(exp);
361             }
362          }
363          break;
364       }
365       case ifStmt:
366       {
367          Expression exp;
368          for(exp = stmt.ifStmt.exp->first; exp; exp = exp.next)
369          {
370             ProcessExpression(exp);
371          }
372          if(stmt.ifStmt.stmt)
373          {
374             ProcessStatement(stmt.ifStmt.stmt);
375          }
376          if(stmt.ifStmt.elseStmt)
377          {
378             ProcessStatement(stmt.ifStmt.elseStmt);
379          }
380          break;
381       }
382       case switchStmt:
383       {
384          Expression exp;
385          for(exp = stmt.switchStmt.exp->first; exp; exp = exp.next)
386          {
387             ProcessExpression(exp);
388          }
389          ProcessStatement(stmt.switchStmt.stmt);
390          break;
391       }
392       case whileStmt:
393       {
394          Expression exp;
395          if(stmt.whileStmt.exp)
396          {
397             for(exp = stmt.whileStmt.exp->first; exp; exp = exp.next)
398             {
399                ProcessExpression(exp);
400             }
401          }
402          if(stmt.whileStmt.stmt)
403             ProcessStatement(stmt.whileStmt.stmt);
404          break;
405       }
406       case doWhileStmt:
407       {
408          ProcessStatement(stmt.doWhile.stmt);
409
410          if(stmt.doWhile.exp)
411          {
412             Expression exp;
413             for(exp = stmt.doWhile.exp->first; exp; exp = exp.next)
414             {
415                ProcessExpression(exp);
416             }
417          }
418          break;
419       }
420       case forStmt:
421       {
422          Expression exp;
423
424          if(stmt.forStmt.init)
425          {
426             ProcessStatement(stmt.forStmt.init);
427          }
428          
429          if(stmt.forStmt.check)
430          {
431             ProcessStatement(stmt.forStmt.check);
432          }
433          
434          if(stmt.forStmt.increment)
435          {
436             for(exp = stmt.forStmt.increment->first; exp; exp = exp.next)
437             {
438                ProcessExpression(exp);
439             }
440          }
441
442          if(stmt.forStmt.stmt)
443             ProcessStatement(stmt.forStmt.stmt);
444          break;
445       }
446       case gotoStmt:
447          break;
448       case continueStmt:
449          break;
450       case breakStmt:
451          break;
452       case returnStmt:
453          if(stmt.expressions)
454          {
455             Expression exp;
456             
457             for(exp = stmt.expressions->first; exp; exp = exp.next)
458             {
459                ProcessExpression(exp);
460             }
461          }
462          break;
463       case fireWatchersStmt:
464       case stopWatchingStmt:
465       {
466          Identifier _watch;
467          if(stmt._watch.watcher)
468          {
469             ProcessExpression(stmt._watch.watcher);
470          }
471          if(stmt._watch.object)
472          {
473             ProcessExpression(stmt._watch.object);
474          }
475          if(stmt._watch.watches)
476          {
477             for(_watch = stmt._watch.watches->first; _watch; _watch = _watch.next)
478             {
479                ProcessIdentifier(_watch);
480             }
481          }
482          break;
483       }
484       case watchStmt:
485       {
486          PropertyWatch _watch;
487          if(stmt._watch.watcher)
488          {
489             ProcessExpression(stmt._watch.watcher);
490          }
491          if(stmt._watch.object)
492          {
493             ProcessExpression(stmt._watch.object);
494          }
495          if(stmt._watch.watches)
496          {
497             for(_watch = stmt._watch.watches->first; _watch; _watch = _watch.next)
498             {
499                if(_watch.compound)
500                {
501                   ProcessStatement(_watch.compound);
502                }
503             }
504          }
505          break;
506       }
507    }
508 }
509
510 static void ProcessInitializer(Initializer initializer)
511 {
512    switch(initializer.type)
513    {
514       case listInitializer:
515       {
516          Initializer init;
517          
518          for(init = initializer.list->first; init; init = init.next)
519          {
520             ProcessInitializer(init);
521          }
522          break;
523       }
524       case expInitializer:
525          ProcessExpression(initializer.exp);
526          break;
527    }
528 }
529
530 static void ProcessInitDeclarator(InitDeclarator decl)
531 {
532    if(decl.initializer)
533       ProcessInitializer(decl.initializer);
534 }
535
536 static void ProcessDeclaration(Declaration decl)
537 {
538    switch(decl.type)
539    {
540       case structDeclaration:
541       {
542          Specifier spec;
543          if(decl.specifiers)
544          {
545             for(spec = decl.specifiers->first; spec; spec = spec.next)
546             {
547                ProcessSpecifier(spec);
548             }
549          }
550          break;
551       }
552       case initDeclaration:
553       {
554          // Need to loop through specifiers to look for :: completion
555          if(decl.specifiers)
556          {
557             Specifier s;
558
559             for(s = decl.specifiers->first; s; s = s.next)
560             {
561                ProcessSpecifier(s);
562             }
563          }
564
565          if(decl.declarators && decl.declarators->first)
566          {
567             InitDeclarator d;
568             for(d = decl.declarators->first; d; d = d.next)
569             {
570                ProcessInitDeclarator(d);
571             }   
572          }
573          break;
574       }
575       case instDeclaration:
576          ProcessInstance(decl.inst);
577          break;
578    }
579 }
580
581 static void ProcessFunction(FunctionDefinition func)
582 {
583    if(func.body)
584    {
585       ProcessStatement(func.body);
586    }
587 }
588
589 static void ProcessMemberInit(MemberInit init)
590 {
591    if(init.initializer)
592    {
593       ProcessInitializer(init.initializer);
594    }
595 }
596
597 static void ProcessInstance(Instantiation inst)
598 {
599    if(inst.members)
600    {
601       MembersInit init;
602       MemberInit memberInit;
603       for(init = inst.members->first; init; init = init.next)
604       {         
605          if(init.type == dataMembersInit && init.dataMembers)
606          {
607             for(memberInit = init.dataMembers->first; memberInit; memberInit = memberInit.next)
608             {
609                ProcessMemberInit(memberInit);
610             }
611          }
612
613          if(init.type == methodMembersInit)
614          {
615             ProcessClassFunction(init.function);
616          }
617       }
618    }
619 }
620
621 static void ProcessClassFunction(ClassFunction func)
622 {
623    if(func.body)
624    {
625       ProcessStatement(func.body);
626    }
627 }
628
629 static void ProcessProperty(PropertyDef def)
630 {
631    if(def.getStmt)
632    {
633       ProcessStatement(def.getStmt);
634    }
635    if(def.setStmt)
636    {
637       ProcessStatement(def.setStmt);
638    }
639 }
640
641 static void ProcessClassDef(ClassDef def)
642 {
643    switch(def.type)
644    {
645       case declarationClassDef:
646          ProcessDeclaration(def.decl);
647          break;
648       case defaultPropertiesClassDef:
649       {
650          MemberInit init;
651          for(init = def.defProperties->first; init; init = init.next)
652          {
653             ProcessMemberInit(init);
654          }
655          break;
656       }
657       case functionClassDef:
658          ProcessClassFunction(def.function);
659          break;
660       case propertyClassDef:
661          if(def.propertyDef)
662          {
663             ProcessProperty(def.propertyDef);
664          }
665          break;
666       case propertyWatchClassDef:
667          if(def.propertyWatch && def.propertyWatch.compound)
668          {
669             ProcessStatement(def.propertyWatch.compound);
670          }
671          break;
672    }
673 }
674
675 static void ProcessClass(ClassDefinition _class)
676 {
677    if(_class.definitions)
678    {
679       ClassDef def;
680       for(def = _class.definitions->first; def; def = def.next)
681       {
682          ProcessClassDef(def);
683       }
684    }
685 }
686
687 static void ProcessDBTable(DBTableDef table)
688 {
689    OldList * rowClassDefs = MkList(), * idClassDefs = null;
690    char tableName[1024];
691    char rowClassName[1024];
692    int len = strlen(table.name);
693    bool indexed = false;
694    char tableID[1024];
695    char nameField[1024];
696    OldList * args;
697    OldList * members;
698    int symbolID = 0; //MAXINT; //globalContext.nextID++;
699    if(table.symbol)
700       idClassDefs = MkList();
701
702    nameField[0] = 0;
703    memcpy(tableName, table.name+1, len-2);
704    tableName[len-2] = 0;
705    ChangeCh(tableName, ' ', '_');
706
707    sprintf(tableID, "__ecereDBTable_%s", tableName);
708
709    sprintf(rowClassName, "Row%s", tableName);
710    ChangeCh(rowClassName, ' ', '_');
711       
712    if(!tableStatements)
713    {
714       tableStatements = MkList();
715       indexStatements = MkList();
716       addFieldStatements = MkList();
717       // findFieldStatements = MkList();
718    }
719
720
721    {
722       External external;
723       external = MkExternalDeclaration(MkDeclaration(
724          MkListOne(MkSpecifierName("Table")),
725          MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(tableID)), null))));
726       external.declaration.declMode = table.declMode;
727       ast->Insert(addAfter, external);
728   
729       // tClasses          = db.OpenTable("Classes",        { tableRows, create });
730       args = MkList();
731       tableStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(tableID)), '=', MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier("db")), MkIdentifier("OpenTable")),
732          args)))));
733       args->Add(MkExpString(table.name));
734       members = MkList();
735       args->Add(MkExpInstance(MkInstantiation(null, null, MkListOne(MkMembersInitList(members)))));
736       members->Add(MkMemberInit(null, MkInitializerAssignment(MkExpIdentifier(MkIdentifier("tableRows")))));
737       members->Add(MkMemberInit(null, MkInitializerAssignment(MkExpIdentifier(MkIdentifier("create")))));
738    }
739
740    // Row Class
741    {
742       ClassDefinition _class;
743       ClassDef def;
744       External external;
745       OldList * inheritanceSpecs = MkList();
746       inheritanceSpecs->Add(MkSpecifier(PRIVATE));
747       inheritanceSpecs->Add(MkSpecifierName("Row"));
748       PushContext();
749       _class = MkClass(DeclClass(globalContext.nextID++, rowClassName), inheritanceSpecs, rowClassDefs);
750       PopContext(curContext);
751
752       def = MkClassDefDefaultProperty(MkListOne(MkMemberInitExp(MkExpIdentifier(MkIdentifier("tbl")), MkInitializerAssignment(MkExpIdentifier(MkIdentifier(tableID))))));
753       rowClassDefs->Add(def);
754
755        _class.symbol.idCode = symbolID;
756       _class.declMode = table.declMode;
757       external = MkExternalClass(_class);
758       ast->Insert(addAfter, external);
759       addAfter = external;
760    }
761
762    if(table.definitions)
763    {
764       DBTableEntry entry;
765
766       for(entry = table.definitions->first; entry; entry = entry.next)
767       {
768          switch(entry.type)
769          {
770             case fieldEntry:
771             {
772                bool isIndex = false;
773                char fieldID[1024];
774                OldList * args;
775                Specifier spec = entry.dataType.qualifiers ? (Specifier)entry.dataType.qualifiers->first : null;
776
777                sprintf(fieldID, "__ecereDBField_%s_%s", tableName, entry.id.string);
778
779                if(idClassDefs)
780                {
781                   if(!nameField[0] && spec.type == nameSpecifier && (!strcmp(spec.name, "String") || !strcmp(spec.name, "eda::CIString")))
782                   {
783                      // strcpy(nameField, entry.name);
784                      strcpy(nameField, entry.id.string);
785                   }
786                   if(!indexed && spec.type == nameSpecifier && !strcmp(spec.name, table.symbol.string))
787                   {
788                      Statement rowSet = MkCompoundStmt(MkList(), MkList());
789                      char name[1024];
790                      ClassDef def;
791
792                      numIndexes = Max(numIndexes, 1);
793                      isIndex = true;
794                      indexed = true;
795                      sprintf(name, "_%s", entry.id.string);
796                      curContext = rowSet.compound.context = Context { parent = globalContext };
797
798                      // Find(fieldSECid, middle, nil, value);
799                      rowSet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpCall(MkExpIdentifier(MkIdentifier("Find")), 
800                         args = MkList()))));
801                      args->Add(MkExpIdentifier(MkIdentifier(fieldID)));
802                      args->Add(MkExpIdentifier(MkIdentifier("middle")));
803                      args->Add(MkExpIdentifier(MkIdentifier("nil")));
804                      args->Add(MkExpIdentifier(MkIdentifier("value")));
805
806                      curContext = globalContext;
807
808                      def = MkClassDefProperty(MkProperty(
809                         CopyList(entry.dataType.qualifiers, CopySpecifier), CopyDeclarator(entry.dataType.declarator), 
810                            MkIdentifier(name), rowSet, null));
811                      def.propertyDef.symbol.id = def.propertyDef.symbol.idCode = symbolID;
812                      def.memberAccess = publicAccess;
813                      rowClassDefs->Add(def);
814                   }
815                }
816                if(rowClassDefs)
817                {
818                   Statement rowSet = MkCompoundStmt(MkList(), MkList()), rowGet = MkCompoundStmt(MkList(), MkList());
819                   ClassDef def;
820                   
821                   curContext = rowGet.compound.context = Context { parent = globalContext };
822
823                   // *** GET ***
824                   // Contact d = null;
825                   if(spec.type == nameSpecifier && spec.symbol && spec.symbol.registered && spec.symbol.registered.type == structClass)
826                   {
827                      rowGet.compound.declarations->Add(MkDeclarationInst(MkInstantiation(MkSpecifierName(spec.name), MkExpIdentifier(MkIdentifier("d")), null)));
828                   }
829                   else
830                   {
831                      Expression exp;
832                      rowGet.compound.declarations->Add(MkDeclaration(CopyList(entry.dataType.qualifiers, CopySpecifier), 
833                         MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("d")), MkInitializerAssignment(exp = MkExpConstant("0"))))));
834                      exp.destType = Type { kind = intType, refCount = 1 };
835                   }
836
837                   // GetData(fieldCNTid, d);
838                   rowGet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpCall(MkExpIdentifier(MkIdentifier("GetData")), 
839                      args = MkList()))));
840                   args->Add(MkExpIdentifier(MkIdentifier(fieldID)));
841                   /*if(spec.type == nameSpecifier && spec.symbol && spec.symbol.registered && spec.symbol.registered.type == structClass)
842                      args->Add(MkExpIdentifier(MkIdentifier("value")));
843                   else*/
844                      args->Add(MkExpIdentifier(MkIdentifier("d")));
845
846                   // return d;
847                   if(spec.type == nameSpecifier && spec.symbol && spec.symbol.registered && spec.symbol.registered.type == structClass)
848                   {
849                      rowGet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier("value")), '=', 
850                         MkExpIdentifier(MkIdentifier("d"))))));
851                   }
852                   else
853                      rowGet.compound.statements->Add(MkReturnStmt(MkListOne(MkExpIdentifier(MkIdentifier("d")))));
854
855                   // *** SET ***
856                   curContext = rowSet.compound.context = Context { parent = globalContext };
857                   
858                   // SetData(fieldCNTid, value);
859                   rowSet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpCall(MkExpIdentifier(MkIdentifier("SetData")), 
860                      args = MkList()))));
861                   args->Add(MkExpIdentifier(MkIdentifier(fieldID)));
862                   args->Add(MkExpIdentifier(MkIdentifier("value")));
863
864                   curContext = globalContext;
865                   def = MkClassDefProperty(MkProperty(CopyList(entry.dataType.qualifiers, CopySpecifier), entry.dataType.declarator, CopyIdentifier(entry.id), rowSet, rowGet));
866                   def.propertyDef.symbol.id = def.propertyDef.symbol.idCode = symbolID;
867                   def.memberAccess = publicAccess;
868                   rowClassDefs->Add(def);
869                }
870                {
871                   External external;
872
873                   external = MkExternalDeclaration(MkDeclaration(
874                      MkListOne(MkSpecifierName("Field")),
875                      MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(fieldID)), null))));
876                   ast->Add(external);
877                   external.declaration.declMode = table.declMode;
878                
879                   // fieldCLSname      = tClasses.AddField("name", class(String), 0 );
880                   args = MkList();
881                   addFieldStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(fieldID)), '=', MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier(tableID)), MkIdentifier("FindField")),
882                      args)))));
883                   args->Add(MkExpString(entry.name));
884
885                   args = MkList();
886                   addFieldStatements->Add(
887                      MkIfStmt(MkListOne(MkExpOp(null, '!', MkExpIdentifier(MkIdentifier(fieldID)))), 
888                         MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(fieldID)), '=', MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier(tableID)), MkIdentifier("AddField")),
889                      args)))), null));
890                   args->Add(MkExpString(entry.name));
891                   args->Add(MkExpClass(CopyList(entry.dataType.qualifiers, CopySpecifier), CopyDeclarator(entry.dataType.declarator)));
892                   args->Add(MkExpConstant("0"));
893
894                   // fieldCLSname      = tClasses.FindField("name");
895                   /*
896                   args = MkList();
897                   findFieldStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(fieldID)), '=', MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier(tableID)), MkIdentifier("FindField")),
898                      args)))));
899                   args->Add(MkExpString(entry.name));
900                   */
901                }
902                if(isIndex)
903                {
904                   // indexes[0].field = fieldCLSid;
905                   indexStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIndex(MkExpIdentifier(MkIdentifier("indexes")), 
906                      MkListOne(MkExpConstant("0"))), MkIdentifier("field")),  '=', MkExpIdentifier(MkIdentifier(fieldID))))));
907
908                   // indexes[0].order = ascending;
909                   indexStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIndex(MkExpIdentifier(MkIdentifier("indexes")), 
910                      MkListOne(MkExpConstant("0"))), MkIdentifier("order")),  '=', MkExpIdentifier(MkIdentifier("ascending"))))));
911
912                   // tClasses.Index(1, indexes);
913                   args = MkList();
914                   indexStatements->Add(MkExpressionStmt(MkListOne(MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier(tableID)), MkIdentifier("Index")), args))));
915                   args->Add(MkExpConstant("1"));
916                   args->Add(MkExpIdentifier(MkIdentifier("indexes")));
917                }
918                break;
919             }
920          }
921       }
922    }
923
924    // ID Class
925    if(table.symbol)
926    {
927       ClassDefinition _class;
928       External external;
929       ClassDef def;
930       Expression exp;
931
932       // table.symbol.id = table.symbol.idCode = globalContext.nextID++;
933       PushContext();
934       _class = MkClass(table.symbol, MkListOne(MkSpecifierName("Id")), idClassDefs);
935       PopContext(curContext);
936       _class.declMode = table.declMode;
937       external = MkExternalClass(_class);
938       ast->Insert(addAfter, external);
939       addAfter = external;
940
941       def = MkClassDefClassPropertyValue(MkIdentifier("table"), MkInitializerAssignment(exp = MkExpOp(null, '&', MkExpDBTable(CopyString(table.name)))));
942       ProcessExpression(exp);
943       idClassDefs->Add(def);
944       if(nameField[0])
945       {
946          def = MkClassDefClassPropertyValue(MkIdentifier("nameField"), MkInitializerAssignment(exp = MkExpOp(null, '&', MkExpDBField(CopyString(table.name), MkIdentifier(nameField)))));
947          ProcessExpression(exp);
948          idClassDefs->Add(def);
949       }      
950       // indexed = true;
951    }
952
953    if(table.definitions)
954    {
955       DBTableEntry entry;
956
957       for(entry = table.definitions->first; entry; entry = entry.next)
958       {
959          switch(entry.type)
960          {
961             case fieldEntry:
962             {
963                char fieldID[1024];
964                OldList * args;
965                Specifier spec = entry.dataType.qualifiers ? (Specifier)entry.dataType.qualifiers->first : null;
966
967                sprintf(fieldID, "__ecereDBField_%s_%s", tableName, entry.id.string);
968
969                if(idClassDefs && spec)
970                {
971                   Statement idSet = MkCompoundStmt(MkList(), MkList()), idGet = MkCompoundStmt(MkList(), MkList());
972                   ClassDef def;
973
974                   curContext = idGet.compound.context = Context { parent = globalContext };
975
976                   // *** GET ***
977                   // RowContacts r { this };
978                   idGet.compound.declarations->Add(MkDeclarationInst(MkInstantiation(MkSpecifierName(rowClassName), MkExpIdentifier(MkIdentifier("r")), 
979                      MkListOne(MkMembersInitList(MkListOne(MkMemberInit(null, MkInitializerAssignment(MkExpIdentifier(MkIdentifier("this"))))))))));
980                   
981                   // Contact d = null;
982                   if(spec.type == nameSpecifier && spec.symbol && spec.symbol.registered && spec.symbol.registered.type == structClass)
983                   {
984                      idGet.compound.declarations->Add(MkDeclarationInst(MkInstantiation(MkSpecifierName(spec.name), MkExpIdentifier(MkIdentifier("d")), null)));
985                   }
986                   else
987                   {
988                      Expression exp;
989                      idGet.compound.declarations->Add(MkDeclaration(CopyList(entry.dataType.qualifiers, CopySpecifier), 
990                         MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier("d")), MkInitializerAssignment(exp = MkExpConstant("0"))))));
991                      exp.destType = Type { kind = intType, refCount = 1 };
992                   }
993
994                   // r.GetData(fieldCNTid, d);
995                   idGet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier("r")), MkIdentifier("GetData")), 
996                      args = MkList()))));
997                   args->Add(MkExpIdentifier(MkIdentifier(fieldID)));
998                   /*if(spec.type == nameSpecifier && spec.symbol && spec.symbol.registered && spec.symbol.registered.type == structClass)
999                      args->Add(MkExpIdentifier(MkIdentifier("value")));
1000                   else*/
1001                      args->Add(MkExpIdentifier(MkIdentifier("d")));
1002
1003                   // delete r;
1004                   idGet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(null, DELETE, MkExpIdentifier(MkIdentifier("r"))))));
1005
1006                   // return d;
1007                   if(spec.type == nameSpecifier && spec.symbol && spec.symbol.registered && spec.symbol.registered.type == structClass)
1008                   {
1009                      idGet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier("value")), '=', 
1010                         MkExpIdentifier(MkIdentifier("d"))))));
1011                   }
1012                   else
1013                      idGet.compound.statements->Add(MkReturnStmt(MkListOne(MkExpIdentifier(MkIdentifier("d")))));
1014
1015                   // *** SET ***
1016                   curContext = idSet.compound.context = Context { parent = globalContext };
1017                   
1018                   // RowContacts r { this };
1019
1020                   idSet.compound.declarations->Add(MkDeclarationInst(MkInstantiation(MkSpecifierName(rowClassName), MkExpIdentifier(MkIdentifier("r")), 
1021                      MkListOne(MkMembersInitList(MkListOne(MkMemberInit(null, MkInitializerAssignment(MkExpIdentifier(MkIdentifier("this"))))))))));
1022
1023                   // r.SetData(fieldCNTid, value);
1024                   idSet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier("r")), MkIdentifier("SetData")), 
1025                      args = MkList()))));
1026                   args->Add(MkExpIdentifier(MkIdentifier(fieldID)));
1027                   args->Add(MkExpIdentifier(MkIdentifier("value")));
1028
1029                   // delete r;
1030                   idSet.compound.statements->Add(MkExpressionStmt(MkListOne(MkExpOp(null, DELETE, MkExpIdentifier(MkIdentifier("r"))))));
1031
1032                   curContext = globalContext;
1033                   
1034                   def = MkClassDefProperty(MkProperty(
1035                      CopyList(entry.dataType.qualifiers, CopySpecifier), CopyDeclarator(entry.dataType.declarator), 
1036                         CopyIdentifier(entry.id), idSet, idGet));
1037                   def.propertyDef.symbol.id = def.propertyDef.symbol.idCode = symbolID;
1038                   def.memberAccess = publicAccess;
1039                   idClassDefs->Add(def);
1040                }
1041
1042                /*
1043                entry.dataType.qualifiers = null;
1044                entry.dataType.declarator = null;
1045                entry.id = null;
1046                */
1047                break;
1048             }
1049             case indexEntry:
1050             {
1051                if(entry.items && entry.items->count)
1052                {
1053                   char indexID[1024];
1054                   DBIndexItem item;
1055                   int c;
1056                   bool needTable = false;
1057                   char num[16];
1058                   if(entry.id || indexed)
1059                   {
1060                      if(entry.id || entry.items->count == 1)
1061                      {
1062                         External external;
1063                         Identifier id = entry.id ? entry.id : ((DBIndexItem)entry.items->first).id;
1064                         sprintf(indexID, "__ecereDBIndex_%s_%s", tableName, id.string);
1065                         external = MkExternalDeclaration(MkDeclaration(
1066                            MkListOne(MkSpecifierName("Table")),
1067                            MkListOne(MkInitDeclarator(MkDeclaratorIdentifier(MkIdentifier(indexID)), null))));
1068                         ast->Add(external);
1069                         external.declaration.declMode = table.declMode;
1070                         needTable = true;
1071                      }
1072                      else
1073                         Compiler_Error($"Multiple field index requires a name\n");
1074                   }
1075                   else
1076                   {
1077                      indexed = true;
1078                      strcpy(indexID, tableID);
1079                   }
1080
1081                   for(c = 0, item = entry.items->first; item; item = item.next, c++)
1082                   {
1083                      char fieldID[1024];
1084                      // indexes[c].field = fieldCLSid;
1085                      sprintf(num, "%d", c);
1086                      sprintf(fieldID, "__ecereDBField_%s_%s", tableName, item.id.string);
1087
1088                      indexStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIndex(MkExpIdentifier(MkIdentifier("indexes")), 
1089                         MkListOne(MkExpConstant(num))), MkIdentifier("field")),  '=', MkExpIdentifier(MkIdentifier(fieldID))))));
1090                      indexStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpMember(MkExpIndex(MkExpIdentifier(MkIdentifier("indexes")), 
1091                         MkListOne(MkExpConstant(num))), MkIdentifier("order")),  '=', MkExpIdentifier(MkIdentifier((item.order == ascending) ? "ascending" : "descending"))))));
1092                   }
1093                   sprintf(num, "%d", c);
1094                   numIndexes = Max(numIndexes, c);
1095                   if(needTable)
1096                   {
1097                      // index          = db.OpenTable("Classes",        { tableRows });
1098                      args = MkList();
1099                      indexStatements->Add(MkExpressionStmt(MkListOne(MkExpOp(MkExpIdentifier(MkIdentifier(indexID)), '=', MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier("db")), MkIdentifier("OpenTable")),
1100                         args)))));
1101                      args->Add(MkExpString(table.name));
1102                      members = MkList();
1103                      args->Add(MkExpInstance(MkInstantiation(null, null, MkListOne(MkMembersInitList(members)))));
1104                      members->Add(MkMemberInit(null, MkInitializerAssignment(MkExpIdentifier(MkIdentifier("tableRows")))));
1105                   }
1106                   // tClasses.Index(1, indexes);
1107                   args = MkList();
1108                   indexStatements->Add(MkExpressionStmt(MkListOne(MkExpCall(MkExpMember(MkExpIdentifier(MkIdentifier(indexID)), MkIdentifier("Index")), args))));
1109                   args->Add(MkExpConstant(num));
1110                   args->Add(MkExpIdentifier(MkIdentifier("indexes")));
1111                }
1112                break;
1113             }
1114          }
1115       }
1116    }
1117 }
1118
1119 public void ProcessDBTableDefinitions()
1120 {
1121    External external;
1122    addAfter = null;
1123
1124    curContext = globalContext;
1125    if(inCompiler)
1126       PrePreProcessClassDefinitions();
1127
1128    DeclClass(0, "Field");
1129    DeclClass(0, "Table");
1130    DeclClass(0, "Row");
1131    DeclClass(0, "Id");
1132    numIndexes = 0;
1133    if(ast != null)
1134    {
1135       for(external = ast->first; external; external = external.next)
1136       {
1137          curExternal = external;
1138          switch(external.type)
1139          {
1140             case dbtableExternal:
1141                ProcessDBTable(external.table);
1142                break;
1143          }
1144       }
1145
1146       for(external = ast->first; external; external = external.next)
1147       {
1148          curExternal = external;
1149          switch(external.type)
1150          {
1151             case functionExternal: 
1152                ProcessFunction(external.function);
1153                break;
1154             case declarationExternal: 
1155                ProcessDeclaration(external.declaration);
1156                break;
1157             case classExternal: 
1158                ProcessClass(external._class);
1159                break;
1160          }
1161       }
1162    }
1163    curContext = globalContext;
1164 }