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