Per-CPU task switch disable, minor spiderscript changes
[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    *SpiderScript_CreateInteger(uint64_t Value);
12 tSpiderValue    *SpiderScript_CreateReal(double Value);
13 tSpiderValue    *SpiderScript_CreateString(int Length, const char *Data);
14 tSpiderValue    *SpiderScript_CastValueTo(int Type, tSpiderValue *Source);
15  int    SpiderScript_IsValueTrue(tSpiderValue *Value);
16 char    *SpiderScript_DumpValue(tSpiderValue *Value);
17
18 tSpiderValue    *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
19
20 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name);
21  int    Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value);
22 tSpiderValue    *Variable_GetValue(tAST_BlockState *Block, const char *Name);
23 void    Variable_Destroy(tAST_Variable *Variable);
24
25 // === CODE ===
26 /**
27  * \brief Dereference a created object
28  */
29 void Object_Dereference(tSpiderValue *Object)
30 {
31         if(!Object)     return ;
32         if(Object == ERRPTR)    return ;
33         Object->ReferenceCount --;
34         if( Object->ReferenceCount == 0 ) {
35                 switch( (enum eSpiderScript_DataTypes) Object->Type )
36                 {
37                 case SS_DATATYPE_OBJECT:
38                         Object->Object->Type->Destructor( Object->Object );
39                         break;
40                 case SS_DATATYPE_OPAQUE:
41                         Object->Opaque.Destroy( Object->Opaque.Data );
42                         break;
43                 default:
44                         break;
45                 }
46                 free(Object);
47         }
48 }
49
50 void Object_Reference(tSpiderValue *Object)
51 {
52         if(!Object)     return ;
53         Object->ReferenceCount ++;
54 }
55
56 /**
57  * \brief Create an integer object
58  */
59 tSpiderValue *SpiderScript_CreateInteger(uint64_t Value)
60 {
61         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
62         ret->Type = SS_DATATYPE_INTEGER;
63         ret->ReferenceCount = 1;
64         ret->Integer = Value;
65         return ret;
66 }
67
68 /**
69  * \brief Create an real number object
70  */
71 tSpiderValue *SpiderScript_CreateReal(double Value)
72 {
73         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) );
74         ret->Type = SS_DATATYPE_REAL;
75         ret->ReferenceCount = 1;
76         ret->Real = Value;
77         return ret;
78 }
79
80 /**
81  * \brief Create an string object
82  */
83 tSpiderValue *SpiderScript_CreateString(int Length, const char *Data)
84 {
85         tSpiderValue    *ret = malloc( sizeof(tSpiderValue) + Length + 1 );
86         ret->Type = SS_DATATYPE_STRING;
87         ret->ReferenceCount = 1;
88         ret->String.Length = Length;
89         memcpy(ret->String.Data, Data, Length);
90         ret->String.Data[Length] = '\0';
91         return ret;
92 }
93
94 /**
95  * \brief Concatenate two strings
96  */
97 tSpiderValue *Object_StringConcat(tSpiderValue *Str1, tSpiderValue *Str2)
98 {
99          int    newLen = 0;
100         tSpiderValue    *ret;
101         if(Str1)        newLen += Str1->String.Length;
102         if(Str2)        newLen += Str2->String.Length;
103         ret = malloc( sizeof(tSpiderValue) + newLen + 1 );
104         ret->Type = SS_DATATYPE_STRING;
105         ret->ReferenceCount = 1;
106         ret->String.Length = newLen;
107         if(Str1)
108                 memcpy(ret->String.Data, Str1->String.Data, Str1->String.Length);
109         if(Str2) {
110                 if(Str1)
111                         memcpy(ret->String.Data+Str1->String.Length, Str2->String.Data, Str2->String.Length);
112                 else
113                         memcpy(ret->String.Data, Str2->String.Data, Str2->String.Length);
114         }
115         ret->String.Data[ newLen ] = '\0';
116         return ret;
117 }
118
119 /**
120  * \brief Cast one object to another
121  * \brief Type  Destination type
122  * \brief Source        Input data
123  */
124 tSpiderValue *SpiderScript_CastValueTo(int Type, tSpiderValue *Source)
125 {
126         tSpiderValue    *ret = ERRPTR;
127          int    len = 0;
128
129         if( !Source )   return NULL;
130         
131         // Check if anything needs to be done
132         if( Source->Type == Type ) {
133                 Object_Reference(Source);
134                 return Source;
135         }
136         
137         switch( (enum eSpiderScript_DataTypes)Type )
138         {
139         case SS_DATATYPE_UNDEF:
140         case SS_DATATYPE_ARRAY:
141         case SS_DATATYPE_OPAQUE:
142                 fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast to %i\n", Type);
143                 return ERRPTR;
144         
145         case SS_DATATYPE_INTEGER:
146                 ret = malloc(sizeof(tSpiderValue));
147                 ret->Type = SS_DATATYPE_INTEGER;
148                 ret->ReferenceCount = 1;
149                 switch(Source->Type)
150                 {
151                 case SS_DATATYPE_INTEGER:       break;  // Handled above
152                 case SS_DATATYPE_STRING:        ret->Integer = atoi(Source->String.Data);       break;
153                 case SS_DATATYPE_REAL:  ret->Integer = Source->Real;    break;
154                 default:
155                         fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
156                         free(ret);
157                         ret = ERRPTR;
158                         break;
159                 }
160                 break;
161         
162         case SS_DATATYPE_STRING:
163                 switch(Source->Type)
164                 {
165                 case SS_DATATYPE_INTEGER:       len = snprintf(NULL, 0, "%li", Source->Integer);        break;
166                 case SS_DATATYPE_REAL:  snprintf(NULL, 0, "%f", Source->Real);  break;
167                 default:        break;
168                 }
169                 ret = malloc(sizeof(tSpiderValue) + len + 1);
170                 ret->Type = SS_DATATYPE_STRING;
171                 ret->ReferenceCount = 1;
172                 ret->String.Length = len;
173                 switch(Source->Type)
174                 {
175                 case SS_DATATYPE_INTEGER:       sprintf(ret->String.Data, "%li", Source->Integer);      break;
176                 case SS_DATATYPE_REAL:  sprintf(ret->String.Data, "%f", Source->Real);  break;
177                 default:
178                         fprintf(stderr, "SpiderScript_CastValueTo - Invalid cast from %i\n", Source->Type);
179                         free(ret);
180                         ret = ERRPTR;
181                         break;
182                 }
183                 break;
184         
185         default:
186                 fprintf(stderr, "BUG REPORT: Unimplemented cast target\n");
187                 break;
188         }
189         
190         return ret;
191 }
192
193 /**
194  * \brief Condenses a value down to a boolean
195  */
196 int SpiderScript_IsValueTrue(tSpiderValue *Value)
197 {
198         if( Value == ERRPTR )   return 0;
199         if( Value == NULL )     return 0;
200         
201         switch( (enum eSpiderScript_DataTypes)Value->Type )
202         {
203         case SS_DATATYPE_UNDEF:
204                 return 0;
205         
206         case SS_DATATYPE_INTEGER:
207                 return !!Value->Integer;
208         
209         case SS_DATATYPE_REAL:
210                 return (-.5f < Value->Real && Value->Real < 0.5f);
211         
212         case SS_DATATYPE_STRING:
213                 return Value->String.Length > 0;
214         
215         case SS_DATATYPE_OBJECT:
216                 return Value->Object != NULL;
217         
218         case SS_DATATYPE_OPAQUE:
219                 return Value->Opaque.Data != NULL;
220         
221         case SS_DATATYPE_ARRAY:
222                 return Value->Array.Length > 0;
223         default:
224                 fprintf(stderr, "Spiderscript internal error: Unknown type %i in SpiderScript_IsValueTrue\n", Value->Type);
225                 return 0;
226         }
227         return 0;
228 }
229
230 /**
231  * \brief Dump a value into a string
232  * \return Heap string
233  */
234 char *SpiderScript_DumpValue(tSpiderValue *Value)
235 {
236         char    *ret;
237         if( Value == ERRPTR )
238                 return strdup("ERRPTR");
239         if( Value == NULL )
240                 return strdup("null");
241         
242         switch( (enum eSpiderScript_DataTypes)Value->Type )
243         {
244         case SS_DATATYPE_UNDEF: return strdup("undefined");
245         
246         case SS_DATATYPE_INTEGER:
247                 ret = malloc( sizeof(Value->Integer)*2 + 3 );
248                 sprintf(ret, "0x%lx", Value->Integer);
249                 return ret;
250         
251         case SS_DATATYPE_REAL:
252                 ret = malloc( sprintf(NULL, "%f", Value->Real) + 1 );
253                 sprintf(ret, "%f", Value->Real);
254                 return ret;
255         
256         case SS_DATATYPE_STRING:
257                 ret = malloc( Value->String.Length + 3 );
258                 ret[0] = '"';
259                 strcpy(ret+1, Value->String.Data);
260                 ret[Value->String.Length+1] = '"';
261                 ret[Value->String.Length+2] = '\0';
262                 return ret;
263         
264         case SS_DATATYPE_OBJECT:
265                 ret = malloc( sprintf(NULL, "{%s *%p}", Value->Object->Type->Name, Value->Object) + 1 );
266                 sprintf(ret, "{%s *%p}", Value->Object->Type->Name, Value->Object);
267                 return ret;
268         
269         case SS_DATATYPE_OPAQUE:
270                 ret = malloc( sprintf(NULL, "*%p", Value->Opaque.Data) + 1 );
271                 sprintf(ret, "*%p", Value->Opaque.Data);
272                 return ret;
273         
274         case SS_DATATYPE_ARRAY:
275                 return strdup("Array");
276         
277         default:
278                 fprintf(stderr, "Spiderscript internal error: Unknown type %i in Object_Dump\n", Value->Type);
279                 return NULL;
280         }
281         
282 }
283
284 /**
285  * \brief Execute an AST node and return its value
286  */
287 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
288 {
289         tAST_Node       *node;
290         tSpiderValue    *ret = NULL, *tmpobj;
291         tSpiderValue    *op1, *op2;     // Binary operations
292          int    cmp;    // Used in comparisons
293         
294         switch(Node->Type)
295         {
296         // No Operation
297         case NODETYPE_NOP:      ret = NULL;     break;
298         
299         // Code block
300         case NODETYPE_BLOCK:
301                 {
302                         tAST_BlockState blockInfo;
303                         blockInfo.FirstVar = NULL;
304                         blockInfo.RetVal = NULL;
305                         blockInfo.Parent = Block;
306                         blockInfo.Script = Block->Script;
307                         ret = NULL;
308                         for(node = Node->Block.FirstChild; node && !blockInfo.RetVal; node = node->NextSibling )
309                         {
310                                 tmpobj = AST_ExecuteNode(&blockInfo, node);
311                                 if(tmpobj == ERRPTR) {  // Error check
312                                         ret = ERRPTR;
313                                         break ;
314                                 }
315                                 if(tmpobj)      Object_Dereference(tmpobj);     // Free unused value
316                         }
317                         // Clean up variables
318                         while(blockInfo.FirstVar)
319                         {
320                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
321                                 Variable_Destroy( blockInfo.FirstVar );
322                                 blockInfo.FirstVar = nextVar;
323                         }
324                         
325                         if( blockInfo.RetVal )
326                                 Block->RetVal = blockInfo.RetVal;
327                 }
328                 
329                 break;
330         
331         // Assignment
332         case NODETYPE_ASSIGN:
333                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
334                         fprintf(stderr, "Syntax error: LVALUE of assignment is not a variable\n");
335                         return ERRPTR;
336                 }
337                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
338                 if(ret != ERRPTR)
339                 {
340                         if( Variable_SetValue( Block, Node->Assign.Dest->Variable.Name, ret ) ) {
341                                 Object_Dereference( ret );
342                                 fprintf(stderr, "on line %i\n", Node->Line);
343                                 return ERRPTR;
344                         }
345                 }
346                 break;
347         
348         // Function Call
349         case NODETYPE_FUNCTIONCALL:
350                 {
351                          int    nParams = 0;
352                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
353                                 nParams ++;
354                         }
355                         // Logical block (used to allocate `params`)
356                         {
357                                 tSpiderValue    *params[nParams];
358                                  int    i=0;
359                                 for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling) {
360                                         params[i] = AST_ExecuteNode(Block, node);
361                                         if( params[i] == ERRPTR ) {
362                                                 while(i--)      Object_Dereference(params[i]);
363                                                 ret = ERRPTR;
364                                                 goto _return;
365                                         }
366                                         i ++;
367                                 }
368                                 
369                                 // Call the function (SpiderScript_ExecuteMethod does the
370                                 // required namespace handling)
371                                 ret = SpiderScript_ExecuteMethod(Block->Script, Node->FunctionCall.Name, nParams, params);
372                                 
373                                 // Dereference parameters
374                                 while(i--)      Object_Dereference(params[i]);
375                                 
376                                 // falls out
377                         }
378                 }
379                 break;
380         
381         // Conditional
382         case NODETYPE_IF:
383                 ret = AST_ExecuteNode(Block, Node->If.Condition);
384                 if( SpiderScript_IsValueTrue(ret) ) {
385                         AST_ExecuteNode(Block, Node->If.True);
386                 }
387                 else {
388                         AST_ExecuteNode(Block, Node->If.False);
389                 }
390                 Object_Dereference(ret);
391                 break;
392         
393         // Loop
394         case NODETYPE_LOOP:
395                 ret = AST_ExecuteNode(Block, Node->For.Init);
396                 if( Node->For.bCheckAfter ) {
397                         do {
398                                 Object_Dereference(ret);
399                                 ret = AST_ExecuteNode(Block, Node->For.Code);
400                                 Object_Dereference(ret);
401                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
402                         } while( SpiderScript_IsValueTrue(ret) );
403                 }
404                 else {
405                         Object_Dereference(ret);
406                         ret = AST_ExecuteNode(Block, Node->For.Condition);
407                         while( SpiderScript_IsValueTrue(ret) ) {
408                                 Object_Dereference(ret);
409                                 ret = AST_ExecuteNode(Block, Node->For.Code);
410                                 Object_Dereference(ret);
411                                 ret = AST_ExecuteNode(Block, Node->For.Condition);
412                         }
413                         Object_Dereference(ret);
414                 }
415                 break;
416         
417         // Return
418         case NODETYPE_RETURN:
419                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
420                 Block->RetVal = ret;    // Return value set
421                 break;
422         
423         // Define a variable
424         case NODETYPE_DEFVAR:
425                 ret = NULL;
426                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name) == ERRPTR )
427                         ret = ERRPTR;
428                 break;
429         
430         // Variable
431         case NODETYPE_VARIABLE:
432                 ret = Variable_GetValue( Block, Node->Variable.Name );
433                 break;
434
435         // Cast a value to another
436         case NODETYPE_CAST:
437                 ret = SpiderScript_CastValueTo(
438                         Node->Cast.DataType,
439                         AST_ExecuteNode(Block, Node->Cast.Value)
440                         );
441                 break;
442
443         // Index into an array
444         case NODETYPE_INDEX:
445                 fprintf(stderr, "TODO: Array indexing\n");
446                 ret = ERRPTR;
447                 break;
448
449         // TODO: Implement runtime constants
450         case NODETYPE_CONSTANT:
451                 fprintf(stderr, "TODO: Runtime Constants\n");
452                 ret = ERRPTR;
453                 break;
454         // Constant Values
455         case NODETYPE_STRING:   ret = SpiderScript_CreateString( Node->String.Length, Node->String.Data );      break;
456         case NODETYPE_INTEGER:  ret = SpiderScript_CreateInteger( Node->Integer );      break;
457         case NODETYPE_REAL:     ret = SpiderScript_CreateReal( Node->Real );    break;
458         
459         // --- Operations ---
460         // Boolean Operations
461         case NODETYPE_LOGICALAND:       // Logical AND (&&)
462         case NODETYPE_LOGICALOR:        // Logical OR (||)
463         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
464                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
465                 if(op1 == ERRPTR)       return ERRPTR;
466                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
467                 if(op2 == ERRPTR) {
468                         Object_Dereference(op1);
469                         return ERRPTR;
470                 }
471                 
472                 switch( Node->Type )
473                 {
474                 case NODETYPE_LOGICALAND:
475                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
476                         break;
477                 case NODETYPE_LOGICALOR:
478                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
479                         break;
480                 case NODETYPE_LOGICALXOR:
481                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
482                         break;
483                 default:        break;
484                 }
485                 
486                 // Free intermediate objects
487                 Object_Dereference(op1);
488                 Object_Dereference(op2);
489                 break;
490         
491         // Comparisons
492         case NODETYPE_EQUALS:
493         case NODETYPE_LESSTHAN:
494         case NODETYPE_GREATERTHAN:
495                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
496                 if(op1 == ERRPTR)       return ERRPTR;
497                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
498                 if(op2 == ERRPTR) {
499                         Object_Dereference(op1);
500                         return ERRPTR;
501                 }
502                 
503                 // Convert types
504                 if( op1->Type != op2->Type ) {
505                         // If dynamically typed, convert op2 to op1's type
506                         if(Block->Script->Variant->bDyamicTyped)
507                         {
508                                 tmpobj = op2;
509                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
510                                 Object_Dereference(tmpobj);
511                                 if(op2 == ERRPTR) {
512                                         Object_Dereference(op1);
513                                         return ERRPTR;
514                                 }
515                         }
516                         // If statically typed, this should never happen, but catch it anyway
517                         else {
518                                 fprintf(stderr, "PARSER ERROR: Statically typed implicit cast (line %i)\n",
519                                         Node->Line);
520                                 ret = ERRPTR;
521                                 break;
522                         }
523                 }
524                 // Do operation
525                 switch(op1->Type)
526                 {
527                 // - String Compare (does a strcmp, well memcmp)
528                 case SS_DATATYPE_STRING:
529                         // Call memcmp to do most of the work
530                         cmp = memcmp(
531                                 op1->String.Data, op2->String.Data,
532                                 (op1->String.Length < op2->String.Length) ? op1->String.Length : op2->String.Length
533                                 );
534                         // Handle reaching the end of the string
535                         if( cmp == 0 ) {
536                                 if( op1->String.Length == op2->String.Length )
537                                         cmp = 0;
538                                 else if( op1->String.Length < op2->String.Length )
539                                         cmp = 1;
540                                 else
541                                         cmp = -1;
542                         }
543                         break;
544                 default:
545                         fprintf(stderr, "SpiderScript internal error: TODO: Comparison of type %i\n", op1->Type);
546                         ret = ERRPTR;
547                         break;
548                 }
549                 
550                 // Free intermediate objects
551                 Object_Dereference(op1);
552                 Object_Dereference(op2);
553                 
554                 // Error check
555                 if( ret == ERRPTR )
556                         break;
557                 
558                 // Create return
559                 switch(Node->Type)
560                 {
561                 case NODETYPE_EQUALS:   ret = SpiderScript_CreateInteger(cmp == 0);     break;
562                 case NODETYPE_LESSTHAN: ret = SpiderScript_CreateInteger(cmp < 0);      break;
563                 case NODETYPE_GREATERTHAN:      ret = SpiderScript_CreateInteger(cmp > 0);      break;
564                 default:
565                         fprintf(stderr, "SpiderScript internal error: Exec,CmpOp unknown op %i", Node->Type);
566                         ret = ERRPTR;
567                         break;
568                 }
569                 break;
570         
571         // General Binary Operations
572         case NODETYPE_ADD:
573         case NODETYPE_SUBTRACT:
574         case NODETYPE_MULTIPLY:
575         case NODETYPE_DIVIDE:
576         case NODETYPE_MODULO:
577         case NODETYPE_BWAND:
578         case NODETYPE_BWOR:
579         case NODETYPE_BWXOR:
580         case NODETYPE_BITSHIFTLEFT:
581         case NODETYPE_BITSHIFTRIGHT:
582         case NODETYPE_BITROTATELEFT:
583                 // Get operands
584                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
585                 if(op1 == ERRPTR)       return ERRPTR;
586                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
587                 if(op2 == ERRPTR) {
588                         Object_Dereference(op1);
589                         return ERRPTR;
590                 }
591                 
592                 // Convert types
593                 if( op1 && op2 && op1->Type != op2->Type ) {
594                         // If dynamically typed, convert op2 to op1's type
595                         if(Block->Script->Variant->bDyamicTyped)
596                         {
597                                 tmpobj = op2;
598                                 op2 = SpiderScript_CastValueTo(op1->Type, op2);
599                                 Object_Dereference(tmpobj);
600                                 if(op2 == ERRPTR) {
601                                         Object_Dereference(op1);
602                                         return ERRPTR;
603                                 }
604                         }
605                         // If statically typed, this should never happen, but catch it anyway
606                         else {
607                                 fprintf(stderr,
608                                         "PARSER ERROR: Statically typed implicit cast (from %i to %i)\n",
609                                         op2->Type, op1->Type
610                                         );
611                                 ret = ERRPTR;
612                                 break;
613                         }
614                 }
615                 
616                 // NULL Check
617                 if( op1 == NULL || op2 == NULL ) {
618                         ret = NULL;
619                         break;
620                 }
621                 
622                 // Do operation
623                 switch(op1->Type)
624                 {
625                 // String Concatenation
626                 case SS_DATATYPE_STRING:
627                         switch(Node->Type)
628                         {
629                         case NODETYPE_ADD:      // Concatenate
630                                 ret = Object_StringConcat(op1, op2);
631                                 break;
632                         default:
633                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,String unknown op %i\n", Node->Type);
634                                 ret = ERRPTR;
635                                 break;
636                         }
637                         break;
638                 // Integer Operations
639                 case SS_DATATYPE_INTEGER:
640                         switch(Node->Type)
641                         {
642                         case NODETYPE_ADD:      ret = SpiderScript_CreateInteger( op1->Integer + op2->Integer );        break;
643                         case NODETYPE_SUBTRACT: ret = SpiderScript_CreateInteger( op1->Integer - op2->Integer );        break;
644                         case NODETYPE_MULTIPLY: ret = SpiderScript_CreateInteger( op1->Integer * op2->Integer );        break;
645                         case NODETYPE_DIVIDE:   ret = SpiderScript_CreateInteger( op1->Integer / op2->Integer );        break;
646                         case NODETYPE_MODULO:   ret = SpiderScript_CreateInteger( op1->Integer % op2->Integer );        break;
647                         case NODETYPE_BWAND:    ret = SpiderScript_CreateInteger( op1->Integer & op2->Integer );        break;
648                         case NODETYPE_BWOR:     ret = SpiderScript_CreateInteger( op1->Integer | op2->Integer );        break;
649                         case NODETYPE_BWXOR:    ret = SpiderScript_CreateInteger( op1->Integer ^ op2->Integer );        break;
650                         case NODETYPE_BITSHIFTLEFT:     ret = SpiderScript_CreateInteger( op1->Integer << op2->Integer );       break;
651                         case NODETYPE_BITSHIFTRIGHT:ret = SpiderScript_CreateInteger( op1->Integer >> op2->Integer );   break;
652                         case NODETYPE_BITROTATELEFT:
653                                 ret = SpiderScript_CreateInteger( (op1->Integer << op2->Integer) | (op1->Integer >> (64-op2->Integer)) );
654                                 break;
655                         default:
656                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i\n", Node->Type);
657                                 ret = ERRPTR;
658                                 break;
659                         }
660                         break;
661                 
662                 // Real Numbers
663                 case SS_DATATYPE_REAL:
664                         switch(Node->Type)
665                         {
666                         default:
667                                 fprintf(stderr, "SpiderScript internal error: Exec,BinOP,Real unknown op %i\n", Node->Type);
668                                 ret = ERRPTR;
669                                 break;
670                         }
671                         break;
672                 
673                 default:
674                         fprintf(stderr, "SpiderScript error: Invalid operation (%i) on type (%i)\n", Node->Type, op1->Type);
675                         ret = ERRPTR;
676                         break;
677                 }
678                 
679                 // Free intermediate objects
680                 Object_Dereference(op1);
681                 Object_Dereference(op2);
682                 break;
683         
684         //default:
685         //      ret = NULL;
686         //      fprintf(stderr, "ERROR: SpiderScript AST_ExecuteNode Unimplemented %i\n", Node->Type);
687         //      break;
688         }
689 _return:
690         return ret;
691 }
692
693 /**
694  * \brief Define a variable
695  * \param Block Current block state
696  * \param Type  Type of the variable
697  * \param Name  Name of the variable
698  * \return Boolean Failure
699  */
700 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name)
701 {
702         tAST_Variable   *var, *prev = NULL;
703         
704         for( var = Block->FirstVar; var; prev = var, var = var->Next )
705         {
706                 if( strcmp(var->Name, Name) == 0 ) {
707                         fprintf(stderr, "ERROR: Redefinition of variable '%s'\n", Name);
708                         return ERRPTR;
709                 }
710         }
711         
712         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
713         var->Next = NULL;
714         var->Type = Type;
715         var->Object = NULL;
716         strcpy(var->Name, Name);
717         
718         if(prev)        prev->Next = var;
719         else    Block->FirstVar = var;
720         
721         //printf("Defined variable %s (%i)\n", Name, Type);
722         
723         return var;
724 }
725
726 /**
727  * \brief Set the value of a variable
728  * \return Boolean Failure
729  */
730 int Variable_SetValue(tAST_BlockState *Block, const char *Name, tSpiderValue *Value)
731 {
732         tAST_Variable   *var;
733         tAST_BlockState *bs;
734         
735         for( bs = Block; bs; bs = bs->Parent )
736         {
737                 for( var = bs->FirstVar; var; var = var->Next )
738                 {
739                         if( strcmp(var->Name, Name) == 0 ) {
740                                 if( !Block->Script->Variant->bDyamicTyped
741                                  && (Value && var->Type != Value->Type) ) {
742                                         fprintf(stderr, "ERROR: Type mismatch assigning to '%s'\n", Name);
743                                         return -2;
744                                 }
745                                 Object_Reference(Value);
746                                 Object_Dereference(var->Object);
747                                 var->Object = Value;
748                                 return 0;
749                         }
750                 }
751         }
752         
753         if( Block->Script->Variant->bDyamicTyped )
754         {
755                 // Define variable
756                 var = Variable_Define(Block, Value->Type, Name);
757                 Object_Reference(Value);
758                 var->Object = Value;
759                 return 0;
760         }
761         else
762         {
763                 fprintf(stderr, "ERROR: Variable '%s' set while undefined\n", Name);
764                 return -1;
765         }
766 }
767
768 /**
769  * \brief Get the value of a variable
770  */
771 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, const char *Name)
772 {
773         tAST_Variable   *var;
774         tAST_BlockState *bs;
775         
776         for( bs = Block; bs; bs = bs->Parent )
777         {
778                 for( var = bs->FirstVar; var; var = var->Next )
779                 {
780                         if( strcmp(var->Name, Name) == 0 ) {
781                                 Object_Reference(var->Object);
782                                 return var->Object;
783                         }
784                 }
785         }
786         
787         fprintf(stderr, "ERROR: Variable '%s' used undefined\n", Name);
788         
789         return ERRPTR;
790 }
791
792 /**
793  * \brief Destorys a variable
794  */
795 void Variable_Destroy(tAST_Variable *Variable)
796 {
797         Object_Dereference(Variable->Object);
798         free(Variable);
799 }

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