Improving the debug capabilities of the heap code, changed VFS to use const char...
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_ast.c
1 /*
2  */
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include "ast.h"
7
8 // === PROTOTYPES ===
9 void    Object_Dereference(tSpiderValue *Object);
10 void    Object_Reference(tSpiderValue *Object);
11 tSpiderValue    *Object_CreateInteger(uint64_t Value);
12 tSpiderValue    *Object_CreateReal(double Value);
13 tSpiderValue    *Object_CreateString(int Length, const char *Data);
14 tSpiderValue    *Object_CastTo(int Type, tSpiderValue *Source);
15  int    Object_IsTrue(tSpiderValue *Value);
16
17 tSpiderValue    *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
18
19 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
20 void    Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
21 tSpiderValue    *Variable_GetValue(tAST_BlockState *Block, const char *Name);
22 void    Variable_Destroy(tAST_Variable *Variable);
23
24 // === CODE ===
25 /**
26  * \brief Dereference a created object
27  */
28 void Object_Dereference(tSpiderValue *Object)
29 {
30         if(!Object)     return ;
31         Object->ReferenceCount --;
32         if( Object->ReferenceCount == 0 )       free(Object);
33 }
34
35 void Object_Reference(tSpiderValue *Object)
36 {
37         if(!Object)     return ;
38         Object->ReferenceCount ++;
39 }
40
41 /**
42  * \brief Create an integer object
43  */
44 tSpiderValue *Object_CreateInteger(uint64_t Value)
45 {
46         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
47         ret->Type = SS_DATATYPE_INTEGER;
48         ret->ReferenceCount = 1;
49         ret->Integer = Value;
50         return ret;
51 }
52
53 /**
54  * \brief Create an real number object
55  */
56 tSpiderValue *Object_CreateReal(double Value)
57 {
58         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
59         ret->Type = SS_DATATYPE_REAL;
60         ret->ReferenceCount = 1;
61         ret->Real = Value;
62         return ret;
63 }
64
65 /**
66  * \brief Create an string object
67  */
68 tSpiderValue *Object_CreateString(int Length, const char *Data)
69 {
70         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
71         ret->Type = SS_DATATYPE_STRING;
72         ret->ReferenceCount = 1;
73         ret->String.Length = Length;
74         memcpy(ret->String.Data, Data, Length);
75         ret->String.Data[Length] = '\0';
76         return ret;
77 }
78
79 /**
80  * \brief Concatenate two strings
81  */
82 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
83 {
84          int    newLen = 0;
85         tSpiderValue    *ret;
86         if(Str1)        newLen += Str1->String.Length;
87         if(Str2)        newLen += Str2->String.Length;
88         ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
89         ret->Type = SS_DATATYPE_STRING;
90         ret->ReferenceCount = 1;
91         ret->String.Length = newLen;
92         if(Str1)
93                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
94         if(Str2) {
95                 if(Str1)
96                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
97                 else
98                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
99         }
100         ret->String.Data[ newLen ] = '\0';
101         return ret;
102 }
103
104 /**
105  * \brief Cast one object to another
106  */
107 tSpiderValue *Object_CastTo(int Type, tSpiderValue *Source)
108 {
109         tSpiderValue    *ret = ERRPTR;
110         // Check if anything needs to be done
111         if( Source->Type == Type ) {
112                 Object_Reference(Source);
113                 return Source;
114         }
115         
116         switch(Type)
117         {
118         case SS_DATATYPE_UNDEF:
119         case SS_DATATYPE_NULL:
120         case SS_DATATYPE_ARRAY:
121                 fprintf(stderr, "Object_CastTo - Invalid cast to %i\n", Type);
122                 return ERRPTR;
123         
124         case SS_DATATYPE_INTEGER:
125                 ret = malloc(sizeof(tSpiderValue));
126                 ret->Type = SS_DATATYPE_INTEGER;
127                 ret->ReferenceCount = 1;
128                 switch(Source->Type)
129                 {
130                 case SS_DATATYPE_INTEGER:       break;  // Handled above
131                 case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
132                 case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
133                 default:
134                         fprintf(stderr, "Object_CastTo - Invalid cast from %i\n", Source->Type);
135                         free(ret);
136                         ret = ERRPTR;
137                         break;
138                 }
139                 break;
140         default:
141                 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
142                 break;
143         }
144         
145         return ret;
146 }
147
148 /**
149  * \brief Condenses a value down to a boolean
150  */
151 int Object_IsTrue(tSpiderValue *Value)
152 {
153         switch(Value->Type)
154         {
155         case SS_DATATYPE_UNDEF:
156         case SS_DATATYPE_NULL:
157                 return 0;
158         
159         case SS_DATATYPE_INTEGER:
160                 return !!Value->Integer;
161         
162         case SS_DATATYPE_REAL:
163                 return (-.5f < Value->Real && Value->Real < 0.5f);
164         
165         case SS_DATATYPE_STRING:
166                 return Value->String.Length > 0;
167         
168         case SS_DATATYPE_OBJECT:
169                 return Value->Object != NULL;
170         
171         case SS_DATATYPE_ARRAY:
172                 return Value->Array.Length > 0;
173         }
174         return 0;
175 }
176
177 /**
178  * \brief Execute an AST node and return its value
179  */
180 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
181 {
182         tAST_Node       *node;
183         tSpiderValue    *ret, *tmpobj;
184         tSpiderValue    *op1, *op2;     // Binary operations
185          int    cmp;    // Used in comparisons
186         
187         switch(Node->Type)
188         {
189         // No Operation
190         case NODETYPE_NOP:      ret = NULL;     break;
191         
192         // Code block
193         case NODETYPE_BLOCK:
194                 {
195                         tAST_BlockState blockInfo;
196                         blockInfo.FirstVar = NULL;
197                         blockInfo.Parent = Block;
198                         blockInfo.Script = Block->Script;
199                         ret = NULL;
200                         for(node = Node->Block.FirstChild; node; node = node->NextSibling )
201                         {
202                                 if(node->Type == NODETYPE_RETURN) {
203                                         ret = AST_ExecuteNode(&blockInfo, node);
204                                         break ;
205                                 }
206                                 else {
207                                         tmpobj = AST_ExecuteNode(&blockInfo, node);
208                                         if(tmpobj == ERRPTR) {  // Error check
209                                                 ret = ERRPTR;
210                                                 break ;
211                                         }
212                                         if(tmpobj)      Object_Dereference(tmpobj);     // Free unused value
213                                 }
214                         }
215                         // Clean up variables
216                         while(blockInfo.FirstVar)
217                         {
218                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
219                                 Variable_Destroy( blockInfo.FirstVar );
220                                 blockInfo.FirstVar = nextVar;
221                         }
222                 }
223                 
224                 break;
225         
226         // Assignment
227         case NODETYPE_ASSIGN:
228                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
229                         fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
230                         return ERRPTR;
231                 }
232                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
233                 if(ret != ERRPTR)
234                         Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret );
235                 break;
236         
237         // Function Call
238         case NODETYPE_FUNCTIONCALL:
239                 {
240                          int    nParams = 0;
241                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
242                                 nParams ++;
243                         }
244                         // Logical block (used to allocate `params`)
245                         {
246                                 tSpiderValue    *params[nParams];
247                                  int    i=0;
248                                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
249                                         params[i] = AST_ExecuteNode(Block, node);
250                                         if( params[i] == ERRPTR ) {
251                                                 while(i--)      Object_Dereference(params[i]);
252                                                 ret = ERRPTR;
253                                                 goto _return;
254                                         }
255                                         i ++;
256                                 }
257                                 
258                                 // Call the function (SpiderScript_ExecuteMethod does the
259                                 // required namespace handling)
260                                 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
261                                 
262                                 // Dereference parameters
263                                 while(i--)      Object_Dereference(params[i]);
264                                 
265                                 // falls out
266                         }
267                 }
268                 break;
269         
270         // Return's special handling happens elsewhere
271         case NODETYPE_RETURN:
272                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
273                 break;
274         
275         // Define a variable
276         case NODETYPE_DEFVAR:
277                 ret = NULL;
278                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
279                         ret = ERRPTR;
280                 break;
281         
282         // Variable
283         case NODETYPE_VARIABLE:
284                 ret = Variable_GetValue( Block, Node->Variable.Name );
285                 break;
286
287         // Cast a value to another
288         case NODETYPE_CAST:
289                 ret = Object_CastTo(
290                         Node->Cast.DataType,
291                         AST_ExecuteNode(Block, Node->Cast.Value)
292                         );
293                 break;
294
295         // Index into an array
296         case NODETYPE_INDEX:
297                 fprintf(stderr, "TODO: Array indexing\n");
298                 ret = ERRPTR;
299                 break;
300
301         // TODO: Implement runtime constants
302         case NODETYPE_CONSTANT:
303                 fprintf(stderr, "TODO: Runtime Constants\n");
304                 ret = ERRPTR;
305                 break;
306         // Constant Values
307         case NODETYPE_STRING:   ret = Object_CreateString( Node->String.Length, Node->String.Data );    break;
308         case NODETYPE_INTEGER:  ret = Object_CreateInteger( Node->Integer );    break;
309         case NODETYPE_REAL:     ret = Object_CreateReal( Node->Real );  break;
310         
311         // --- Operations ---
312         // Boolean Operations
313         case NODETYPE_LOGICALAND:       // Logical AND (&&)
314         case NODETYPE_LOGICALOR:        // Logical OR (||)
315         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
316                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
317                 if(op1 == ERRPTR)       return ERRPTR;
318                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
319                 if(op2 == ERRPTR) {
320                         Object_Dereference(op1);
321                         return ERRPTR;
322                 }
323                 
324                 switch( Node->Type )
325                 {
326                 case NODETYPE_LOGICALAND:
327                         ret = Object_CreateInteger( Object_IsTrue(op1) && Object_IsTrue(op2) );
328                         break;
329                 case NODETYPE_LOGICALOR:
330                         ret = Object_CreateInteger( Object_IsTrue(op1) || Object_IsTrue(op2) );
331                         break;
332                 case NODETYPE_LOGICALXOR:
333                         ret = Object_CreateInteger( Object_IsTrue(op1) ^ Object_IsTrue(op2) );
334                         break;
335                 default:        break;
336                 }
337                 
338                 // Free intermediate objects
339                 Object_Dereference(op1);
340                 Object_Dereference(op2);
341                 break;
342         
343         // Comparisons
344         case NODETYPE_EQUALS:
345         case NODETYPE_LESSTHAN:
346         case NODETYPE_GREATERTHAN:
347                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
348                 if(op1 == ERRPTR)       return ERRPTR;
349                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
350                 if(op2 == ERRPTR) {
351                         Object_Dereference(op1);
352                         return ERRPTR;
353                 }
354                 
355                 // No conversion done for NULL
356                 // TODO: Determine if this will ever be needed
357                 if( op1->Type == SS_DATATYPE_NULL )
358                 {
359                         // NULLs always typecheck
360                         ret = Object_CreateInteger(op2->Type == SS_DATATYPE_NULL);
361                         break;
362                 }
363                 
364                 // Convert types
365                 if( op1->Type != op2->Type ) {
366                         // If dynamically typed, convert op2 to op1's type
367                         if(Block->Script->Variant->bDyamicTyped)
368                         {
369                                 tmpobj = op2;
370                                 op2 = Object_CastTo(op1->Type, op2);
371                                 Object_Dereference(tmpobj);
372                                 if(op2 == ERRPTR) {
373                                         Object_Dereference(op1);
374                                         return ERRPTR;
375                                 }
376                         }
377                         // If statically typed, this should never happen, but catch it anyway
378                         else {
379                                 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
380                                 ret = ERRPTR;
381                                 break;
382                         }
383                 }
384                 // Do operation
385                 switch(op1->Type)
386                 {
387                 // - NULL
388                 case SS_DATATYPE_NULL:  break;
389                 // - String Compare (does a strcmp, well memcmp)
390                 case SS_DATATYPE_STRING:
391                         // Call memcmp to do most of the work
392                         cmp = memcmp(
393                                 op1->String.Data, op2->String.Data,
394                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
395                                 );
396                         // Handle reaching the end of the string
397                         if( cmp == 0 ) {
398                                 if( op1->String.Length == op2->String.Length )
399                                         cmp = 0;
400                                 else if( op1->String.Length < op2->String.Length )
401                                         cmp = 1;
402                                 else
403                                         cmp = -1;
404                         }
405                         break;
406                 }
407                 
408                 // Free intermediate objects
409                 Object_Dereference(op1);
410                 Object_Dereference(op2);
411                 
412                 // Create return
413                 switch(Node->Type)
414                 {
415                 case NODETYPE_EQUALS:   ret = Object_CreateInteger(cmp == 0);   break;
416                 case NODETYPE_LESSTHAN: ret = Object_CreateInteger(cmp < 0);    break;
417                 case NODETYPE_GREATERTHAN:      ret = Object_CreateInteger(cmp > 0);    break;
418                 default:
419                         fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
420                         ret = ERRPTR;
421                         break;
422                 }
423                 break;
424         
425         // General Binary Operations
426         case NODETYPE_ADD:
427         case NODETYPE_SUBTRACT:
428         case NODETYPE_MULTIPLY:
429         case NODETYPE_DIVIDE:
430         case NODETYPE_MODULO:
431         case NODETYPE_BWAND:
432         case NODETYPE_BWOR:
433         case NODETYPE_BWXOR:
434         case NODETYPE_BITSHIFTLEFT:
435         case NODETYPE_BITSHIFTRIGHT:
436         case NODETYPE_BITROTATELEFT:
437                 // Get operands
438                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
439                 if(op1 == ERRPTR)       return ERRPTR;
440                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
441                 if(op2 == ERRPTR) {
442                         Object_Dereference(op1);
443                         return ERRPTR;
444                 }
445                 
446                 // Convert types
447                 if( op1 && op2 && op1->Type != op2->Type ) {
448                         // If dynamically typed, convert op2 to op1's type
449                         if(Block->Script->Variant->bDyamicTyped)
450                         {
451                                 tmpobj = op2;
452                                 op2 = Object_CastTo(op1->Type, op2);
453                                 Object_Dereference(tmpobj);
454                                 if(op2 == ERRPTR) {
455                                         Object_Dereference(op1);
456                                         return ERRPTR;
457                                 }
458                         }
459                         // If statically typed, this should never happen, but catch it anyway
460                         else {
461                                 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast\n");
462                                 ret = ERRPTR;
463                                 break;
464                         }
465                 }
466                 
467                 // Do operation
468                 switch(op1->Type)
469                 {
470                 case SS_DATATYPE_NULL:  break;
471                 // String Concatenation
472                 case SS_DATATYPE_STRING:
473                         switch(Node->Type)
474                         {
475                         case NODETYPE_ADD:      // Concatenate
476                                 ret = Object_StringConcat(op1, op2);
477                                 break;
478                         default:
479                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
480                                 ret = ERRPTR;
481                                 break;
482                         }
483                         break;
484                 case SS_DATATYPE_INTEGER:
485                         switch(Node->Type)
486                         {
487                         case NODETYPE_ADD:      ret = Object_CreateInteger( op1->Integer + op2->Integer );      break;
488                         case NODETYPE_SUBTRACT: ret = Object_CreateInteger( op1->Integer - op2->Integer );      break;
489                         case NODETYPE_MULTIPLY: ret = Object_CreateInteger( op1->Integer * op2->Integer );      break;
490                         case NODETYPE_DIVIDE:   ret = Object_CreateInteger( op1->Integer / op2->Integer );      break;
491                         case NODETYPE_MODULO:   ret = Object_CreateInteger( op1->Integer % op2->Integer );      break;
492                         case NODETYPE_BWAND:    ret = Object_CreateInteger( op1->Integer & op2->Integer );      break;
493                         case NODETYPE_BWOR:     ret = Object_CreateInteger( op1->Integer | op2->Integer );      break;
494                         case NODETYPE_BWXOR:    ret = Object_CreateInteger( op1->Integer ^ op2->Integer );      break;
495                         case NODETYPE_BITSHIFTLEFT:     ret = Object_CreateInteger( op1->Integer << op2->Integer );     break;
496                         case NODETYPE_BITSHIFTRIGHT:ret = Object_CreateInteger( op1->Integer >> op2->Integer ); break;
497                         case NODETYPE_BITROTATELEFT:
498                                 ret = Object_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
499                                 break;
500                         default:
501                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Node->Type);
502                                 ret = ERRPTR;
503                                 break;
504                         }
505                         break;
506                 }
507                 
508                 // Free intermediate objects
509                 Object_Dereference(op1);
510                 Object_Dereference(op2);
511                 break;
512         
513         //default:
514         //      ret = NULL;
515         //      fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
516         //      break;
517         }
518 _return:
519         return ret;
520 }
521
522 /**
523  * \brief Define a variable
524  * \param Block Current block state
525  * \param Type  Type of the variable
526  * \param Name  Name of the variable
527  * \return Boolean Failure
528  */
529 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
530 {
531         tAST_Variable   *var, *prev = NULL;
532         
533         for( var = Block->FirstVar; var; prev = var, var = var->Next )
534         {
535                 if( strcmp(var->Name, Name) == 0 ) {
536                         fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
537                         return ERRPTR;
538                 }
539         }
540         
541         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
542         var->Next = NULL;
543         var->Type = Type;
544         var->Object = NULL;
545         strcpy(var->Name, Name);
546         
547         if(prev)        prev->Next = var;
548         else    Block->FirstVar = var;
549         
550         //printf("Defined variable %s (%i)\n", Name, Type);
551         
552         return var;
553 }
554
555 /**
556  * \brief Set the value of a variable
557  */
558 void Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
559 {
560         tAST_Variable   *var;
561         tAST_BlockState *bs;
562         
563         for( bs = Block; bs; bs = bs->Parent )
564         {
565                 for( var = bs->FirstVar; var; var = var->Next )
566                 {
567                         if( strcmp(var->Name, Name) == 0 ) {
568                                 if( !Block->Script->Variant->bDyamicTyped
569                                  && (Value && var->Type != Value->Type) ) {
570                                         fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
571                                         return ;
572                                 }
573                                 Object_Reference(Value);
574                                 Object_Dereference(var->Object);
575                                 var->Object = Value;
576                                 return ;
577                         }
578                 }
579         }
580         
581         if( Block->Script->Variant->bDyamicTyped )
582         {
583                 // Define variable
584                 var = Variable_Define(Block, Value->Type, Name);
585                 Object_Reference(Value);
586                 var->Object = Value;
587         }
588         else
589         {
590                 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
591         }
592 }
593
594 /**
595  * \brief Get the value of a variable
596  */
597 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
598 {
599         tAST_Variable   *var;
600         tAST_BlockState *bs;
601         
602         for( bs = Block; bs; bs = bs->Parent )
603         {
604                 for( var = bs->FirstVar; var; var = var->Next )
605                 {
606                         if( strcmp(var->Name, Name) == 0 ) {
607                                 Object_Reference(var->Object);
608                                 return var->Object;
609                         }
610                 }
611         }
612         
613         fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
614         
615         return ERRPTR;
616 }
617
618 /**
619  * \brief Destorys a variable
620  */
621 void Variable_Destroy(tAST_Variable *Variable)
622 {
623         Object_Dereference(Variable->Object);
624         free(Variable);
625 }

UCC git Repository :: git.ucc.asn.au