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

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