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