SpiderScript - Fixed array behaviour, removed memory leaks
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_ast.c
1 /*
2  * SpiderScript Library
3  *
4  * AST Execution
5  */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include "common.h"
11 #include "ast.h"
12
13 #define USE_AST_EXEC    1
14 #define TRACE_VAR_LOOKUPS       0
15 #define TRACE_NODE_RETURNS      0
16
17 // === IMPORTS ===
18
19 // === PROTOTYPES ===
20 // - Node Execution
21 tSpiderValue    *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node);
22 tSpiderValue    *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right);
23 tSpiderValue    *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value);
24 tSpiderValue    *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node, tSpiderValue *Array, int Index, tSpiderValue *SaveValue);
25 // - Variables
26 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value);
27  int    Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value);
28 tSpiderValue    *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode);
29 void    Variable_Destroy(tAST_Variable *Variable);
30 // - Errors
31 void    AST_RuntimeMessage(tAST_Node *Node, const char *Type, const char *Format, ...);
32 void    AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
33
34 // === GLOBALS ===
35  int    giNextBlockIdent = 1;
36
37 // === CODE ===
38 #if USE_AST_EXEC
39 tSpiderValue *AST_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Arguments)
40 {
41         tAST_BlockState bs;
42         tSpiderValue    *ret;
43          int    i = 0;
44         
45         // Build a block State
46         bs.FirstVar = NULL;
47         bs.RetVal = NULL;
48         bs.Parent = NULL;
49         bs.BaseNamespace = &Script->Variant->RootNamespace;
50         bs.CurNamespace = NULL;
51         bs.Script = Script;
52         bs.Ident = giNextBlockIdent ++;
53         
54         // Parse arguments
55         for( i = 0; i < Fcn->ArgumentCount; i ++ )
56         {
57                 if( i >= NArguments )   break;  // TODO: Return gracefully
58                 // TODO: Type checks
59                 Variable_Define(&bs,
60                         Fcn->Arguments[i].Type, Fcn->Arguments[i].Name,
61                         Arguments[i]);
62         }
63                         
64         // Execute function
65         ret = AST_ExecuteNode(&bs, Fcn->ASTFcn);
66         if(ret != ERRPTR)
67         {
68                 SpiderScript_DereferenceValue(ret);     // Dereference output of last block statement
69                 ret = bs.RetVal;        // Set to return value of block
70         }
71                         
72         while(bs.FirstVar)
73         {
74                 tAST_Variable   *nextVar = bs.FirstVar->Next;
75                 Variable_Destroy( bs.FirstVar );
76                 bs.FirstVar = nextVar;
77         }
78         return ret;
79 }
80
81 /**
82  * \brief Execute an AST node and return its value
83  * \param Block Execution context
84  * \param Node  Node to execute
85  */
86 tSpiderValue *AST_ExecuteNode(tAST_BlockState *Block, tAST_Node *Node)
87 {
88         tAST_Node       *node;
89         tSpiderValue    *ret = NULL, *tmpobj;
90         tSpiderValue    *op1, *op2;     // Binary operations
91          int    i;
92         
93         switch(Node->Type)
94         {
95         // No Operation
96         case NODETYPE_NOP:
97                 ret = NULL;
98                 break;
99         
100         // Code block
101         case NODETYPE_BLOCK:
102                 {
103                         tAST_BlockState blockInfo;
104                         blockInfo.Parent = Block;
105                         blockInfo.Script = Block->Script;
106                         blockInfo.FirstVar = NULL;
107                         blockInfo.RetVal = NULL;
108                         blockInfo.BaseNamespace = Block->BaseNamespace;
109                         blockInfo.CurNamespace = NULL;
110                         blockInfo.BreakTarget = NULL;
111                         blockInfo.Ident = giNextBlockIdent ++;
112                         ret = NULL;
113                         // Loop over all nodes, or until the return value is set
114                         for(node = Node->Block.FirstChild;
115                                 node && !blockInfo.RetVal && !blockInfo.BreakTarget;
116                                 node = node->NextSibling )
117                         {
118                                 ret = AST_ExecuteNode(&blockInfo, node);
119                                 if(ret == ERRPTR)       break;  // Error check
120                                 if(ret != NULL) SpiderScript_DereferenceValue(ret);     // Free unused value
121                         }
122                         // Clean up variables
123                         while(blockInfo.FirstVar)
124                         {
125                                 tAST_Variable   *nextVar = blockInfo.FirstVar->Next;
126                                 Variable_Destroy( blockInfo.FirstVar );
127                                 blockInfo.FirstVar = nextVar;
128                         }
129                         // Clear ret if not an error
130                         if(ret != ERRPTR)       ret = NULL;
131                         
132                         // Set parent's return value if needed
133                         if( blockInfo.RetVal )
134                                 Block->RetVal = blockInfo.RetVal;
135                         if( blockInfo.BreakTarget ) {
136                                 Block->BreakTarget = blockInfo.BreakTarget;
137                                 Block->BreakType = blockInfo.BreakType;
138                         }
139                         
140                         // TODO: Unset break if break type deontes a block break
141                 }
142                 
143                 break;
144         
145         // Assignment
146         case NODETYPE_ASSIGN:
147                 // TODO: Support assigning to object attributes
148                 if( Node->Assign.Dest->Type != NODETYPE_VARIABLE ) {
149                         AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
150                         return ERRPTR;
151                 }
152                 ret = AST_ExecuteNode(Block, Node->Assign.Value);
153                 if(ret == ERRPTR)       return ERRPTR;
154                 
155                 // Perform assignment operation
156                 if( Node->Assign.Operation != NODETYPE_NOP )
157                 {
158                         tSpiderValue    *varVal, *value;
159
160                         varVal = Variable_GetValue(Block, Node->Assign.Dest);
161                         if(varVal == ERRPTR)    return ERRPTR;
162                         #if 0
163                         #else
164                         if(varVal && varVal->ReferenceCount == 2) {
165                                 SpiderScript_DereferenceValue(varVal);
166 //                              printf("pre: (%s) varVal->ReferenceCount = %i\n",
167 //                                      Node->Assign.Dest->Variable.Name,
168 //                                      varVal->ReferenceCount);
169                         }
170                         #endif
171                         value = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Assign.Operation, varVal, ret);
172                         if(value == ERRPTR)     return ERRPTR;
173
174                         if(ret) SpiderScript_DereferenceValue(ret);
175                         #if 0
176                         if(varVal)      SpiderScript_DereferenceValue(varVal);
177                         #else
178                         if(varVal && varVal->ReferenceCount == 1) {
179                                 SpiderScript_ReferenceValue(varVal);
180 //                              printf("post: varVal->ReferenceCount = %i\n", varVal->ReferenceCount);
181                                 break;  // If varVal was non-null, it has been updated by _BinOp
182                         }
183                         #endif
184                         // Else, it was NULL, so has to be assigned
185                         ret = value;
186                 }
187                 
188                 // Set the variable value
189                 if( Variable_SetValue( Block, Node->Assign.Dest, ret ) ) {
190                         SpiderScript_DereferenceValue( ret );
191                         return ERRPTR;
192                 }
193                 break;
194         
195         // Post increment/decrement
196         case NODETYPE_POSTINC:
197         case NODETYPE_POSTDEC:
198                 {
199                         tSpiderValue    *varVal, *value;
200                         static tSpiderValue     one = {
201                                 .Type = SS_DATATYPE_INTEGER,
202                                 .ReferenceCount = 1,
203                                 {.Integer = 1}
204                                 };
205                         
206                         // TODO: Support assigning to object attributes
207                         if( Node->UniOp.Value->Type != NODETYPE_VARIABLE ) {
208                                 AST_RuntimeError(Node, "LVALUE of assignment is not a variable");
209                                 return ERRPTR;
210                         }
211                 
212                         // Get values (current variable contents and a static one)
213                         varVal = Variable_GetValue(Block, Node->UniOp.Value);
214                         
215                         if( Node->Type == NODETYPE_POSTDEC )
216                                 value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_SUBTRACT, varVal, &one);
217                         else
218                                 value = AST_ExecuteNode_BinOp(Block->Script, Node, NODETYPE_ADD, varVal, &one);
219                         if( value == ERRPTR )
220                                 return ERRPTR;
221                         
222                         ret = varVal;
223                 
224                         if( Variable_SetValue( Block, Node->UniOp.Value, value ) ) {
225                                 SpiderScript_DereferenceValue( ret );
226                                 return ERRPTR;
227                         }
228                         SpiderScript_DereferenceValue( value );
229                 }
230                 break;
231         
232         // Function Call
233         case NODETYPE_METHODCALL:
234         case NODETYPE_FUNCTIONCALL:
235         case NODETYPE_CREATEOBJECT:
236                 // Logical block (used to allocate `params`)
237                 {
238                         const char      *namespaces[] = {NULL}; // TODO: Default namespaces?
239                         tSpiderValue    *params[Node->FunctionCall.NumArgs];
240                         i = 0;
241                         
242                         // Get arguments
243                         for(node = Node->FunctionCall.FirstArg; node; node = node->NextSibling)
244                         {
245                                 params[i] = AST_ExecuteNode(Block, node);
246                                 if( params[i] == ERRPTR ) {
247                                         while(i--)      SpiderScript_DereferenceValue(params[i]);
248                                         ret = ERRPTR;
249                                         goto _return;
250                                 }
251                                 i ++;
252                         }
253
254                         // TODO: Check for cached function reference                    
255
256                         // Call the function
257                         if( Node->Type == NODETYPE_CREATEOBJECT )
258                         {
259                                 ret = SpiderScript_CreateObject(Block->Script,
260                                         Node->FunctionCall.Name,
261                                         namespaces,
262                                         Node->FunctionCall.NumArgs, params
263                                         );
264                         }
265                         else if( Node->Type == NODETYPE_METHODCALL )
266                         {
267                                 tSpiderValue *obj = AST_ExecuteNode(Block, Node->FunctionCall.Object);
268                                 if( !obj || obj == ERRPTR || obj->Type != SS_DATATYPE_OBJECT ) {
269                                         AST_RuntimeError(Node->FunctionCall.Object,
270                                                 "Type Mismatch - Required SS_DATATYPE_OBJECT for method call");
271                                         while(i--)      SpiderScript_DereferenceValue(params[i]);
272                                         ret = ERRPTR;
273                                         break;
274                                 }
275                                 ret = SpiderScript_ExecuteMethod(Block->Script,
276                                         obj->Object, Node->FunctionCall.Name,
277                                         Node->FunctionCall.NumArgs, params
278                                         );
279                                 SpiderScript_DereferenceValue(obj);
280                         }
281                         else
282                         {
283                                 ret = SpiderScript_ExecuteFunction(Block->Script,
284                                         Node->FunctionCall.Name,
285                                         namespaces,
286                                         Node->FunctionCall.NumArgs, params,
287                                         NULL
288                                         );
289                         }
290
291                         
292                         // Dereference parameters
293                         while(i--)      SpiderScript_DereferenceValue(params[i]);
294                         
295                         // falls out
296                 }
297                 break;
298         
299         // Conditional
300         case NODETYPE_IF:
301                 ret = AST_ExecuteNode(Block, Node->If.Condition);
302                 if( ret == ERRPTR )     break;
303                 if( SpiderScript_IsValueTrue(ret) ) {
304                         tmpobj = AST_ExecuteNode(Block, Node->If.True);
305                 }
306                 else {
307                         tmpobj = AST_ExecuteNode(Block, Node->If.False);
308                 }
309                 SpiderScript_DereferenceValue(ret);
310                 if( tmpobj == ERRPTR )  return ERRPTR;
311                 SpiderScript_DereferenceValue(tmpobj);
312                 ret = NULL;
313                 break;
314         
315         // Loop
316         case NODETYPE_LOOP:
317                 // Initialise
318                 ret = AST_ExecuteNode(Block, Node->For.Init);
319                 if(ret == ERRPTR)       break;
320                 
321                 // Check initial condition
322                 if( !Node->For.bCheckAfter )
323                 {
324                         SpiderScript_DereferenceValue(ret);
325                 
326                         ret = AST_ExecuteNode(Block, Node->For.Condition);
327                         if(ret == ERRPTR)       return ERRPTR;
328                         if(!SpiderScript_IsValueTrue(ret)) {
329                                 SpiderScript_DereferenceValue(ret);
330                                 ret = NULL;
331                                 break;
332                         }
333                 }
334         
335                 // Perform loop
336                 for( ;; )
337                 {
338                         SpiderScript_DereferenceValue(ret);
339                         
340                         // Code
341                         ret = AST_ExecuteNode(Block, Node->For.Code);
342                         if(ret == ERRPTR)       return ERRPTR;
343                         SpiderScript_DereferenceValue(ret);
344                         
345                         if(Block->BreakTarget)
346                         {
347                                 if( Block->BreakTarget[0] == '\0' || strcmp(Block->BreakTarget, Node->For.Tag) == 0 )
348                                 {
349                                         // Ours
350                                         free((void*)Block->BreakTarget);        Block->BreakTarget = NULL;
351                                         if( Block->BreakType == NODETYPE_CONTINUE ) {
352                                                 // Continue, just keep going
353                                         }
354                                         else
355                                                 break;
356                                 }
357                                 else
358                                         break;  // Break out of this loop
359                         }
360                         
361                         // Increment
362                         ret = AST_ExecuteNode(Block, Node->For.Increment);
363                         if(ret == ERRPTR)       return ERRPTR;
364                         SpiderScript_DereferenceValue(ret);
365                         
366                         // Check condition
367                         ret = AST_ExecuteNode(Block, Node->For.Condition);
368                         if(ret == ERRPTR)       return ERRPTR;
369                         if(!SpiderScript_IsValueTrue(ret))      break;
370                 }
371                 SpiderScript_DereferenceValue(ret);
372                 ret = NULL;
373                 break;
374         
375         // Return
376         case NODETYPE_RETURN:
377                 ret = AST_ExecuteNode(Block, Node->UniOp.Value);
378                 if(ret == ERRPTR)       break;
379                 Block->RetVal = ret;    // Return value set
380                 ret = NULL;     // the `return` statement does not return a value
381                 break;
382         
383         case NODETYPE_BREAK:
384         case NODETYPE_CONTINUE:
385                 Block->BreakTarget = strdup(Node->Variable.Name);
386                 Block->BreakType = Node->Type;
387                 break;
388         
389         // Define a variable
390         case NODETYPE_DEFVAR:
391                 if( Node->DefVar.InitialValue ) {
392                         tmpobj = AST_ExecuteNode(Block, Node->DefVar.InitialValue);
393                         if(tmpobj == ERRPTR)    return ERRPTR;
394                 }
395                 else {
396                         tmpobj = NULL;
397                 }
398                 // TODO: Handle arrays
399                 ret = NULL;
400                 if( Variable_Define(Block, Node->DefVar.DataType, Node->DefVar.Name, tmpobj) == ERRPTR )
401                         ret = ERRPTR;
402                 SpiderScript_DereferenceValue(tmpobj);
403                 break;
404         
405         // Scope
406         case NODETYPE_SCOPE:
407                 {
408                 tSpiderNamespace        *ns;
409                 
410                 // Set current namespace if unset
411                 if( !Block->CurNamespace )
412                         Block->CurNamespace = Block->BaseNamespace;
413                 
414                 // Empty string means use the root namespace
415                 if( Node->Scope.Name[0] == '\0' )
416                 {
417                         ns = &Block->Script->Variant->RootNamespace;
418                 }
419                 else
420                 {
421                         // Otherwise scan the current namespace for the element
422                         for( ns = Block->CurNamespace->FirstChild; ns; ns = ns->Next )
423                         {
424                                 if( strcmp(ns->Name, Node->Scope.Name) == 0 )
425                                         break;
426                         }
427                 }
428                 if(!ns) {
429                         AST_RuntimeError(Node, "Unknown namespace '%s'", Node->Scope.Name);
430                         ret = ERRPTR;
431                         break;
432                 }
433                 Block->CurNamespace = ns;
434         
435                 // TODO: Check type of child node (Scope, Constant or Function) 
436         
437                 ret = AST_ExecuteNode(Block, Node->Scope.Element);
438                 }
439                 break;
440         
441         // Variable
442         case NODETYPE_VARIABLE:
443                 ret = Variable_GetValue( Block, Node );
444                 break;
445         
446         // Element of an Object
447         case NODETYPE_ELEMENT:
448                 tmpobj = AST_ExecuteNode( Block, Node->Scope.Element );
449                 if(tmpobj == ERRPTR)    return ERRPTR;
450                 if( !tmpobj || tmpobj->Type != SS_DATATYPE_OBJECT )
451                 {
452                         AST_RuntimeError(Node->Scope.Element, "Unable to dereference a non-object");
453                         ret = ERRPTR;
454                         break ;
455                 }
456                 
457                 for( i = 0; i < tmpobj->Object->Type->NAttributes; i ++ )
458                 {
459                         if( strcmp(Node->Scope.Name, tmpobj->Object->Type->AttributeDefs[i].Name) == 0 )
460                         {
461                                 ret = tmpobj->Object->Attributes[i];
462                                 SpiderScript_ReferenceValue(ret);
463                                 break;
464                         }
465                 }
466                 if( i == tmpobj->Object->Type->NAttributes )
467                 {
468                         AST_RuntimeError(Node->Scope.Element, "Unknown attribute '%s' of class '%s'",
469                                 Node->Scope.Name, tmpobj->Object->Type->Name);
470                         ret = ERRPTR;
471                 }
472                 break;
473
474         // Cast a value to another
475         case NODETYPE_CAST:
476                 {
477                 tmpobj = AST_ExecuteNode(Block, Node->Cast.Value);
478                 if(tmpobj == ERRPTR) return ERRPTR;
479                 ret = SpiderScript_CastValueTo( Node->Cast.DataType, tmpobj );
480                 SpiderScript_DereferenceValue(tmpobj);
481                 }
482                 break;
483
484         // Index into an array
485         case NODETYPE_INDEX:
486                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left); // Array
487                 if(op1 == ERRPTR)       return ERRPTR;
488                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);        // Offset
489                 if(op2 == ERRPTR) {
490                         SpiderScript_DereferenceValue(op1);
491                         return ERRPTR;
492                 }
493                 
494                 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
495                 {
496                         if( !Block->Script->Variant->bImplicitCasts ) {
497                                 AST_RuntimeError(Node, "Array index is not an integer");
498                                 ret = ERRPTR;
499                                 break;
500                         }
501                         else {
502                                 tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
503                                 SpiderScript_DereferenceValue(op2);
504                                 op2 = tmpobj;
505                         }
506                 }
507         
508                 if( !op1 )
509                 {
510                         SpiderScript_DereferenceValue(op2);
511                         AST_RuntimeError(Node, "Indexing NULL value");
512                         ret = ERRPTR;
513                         break;
514                 }
515
516                 ret = AST_ExecuteNode_Index(Block->Script, Node, op1, op2->Integer, NULL);
517
518                 SpiderScript_DereferenceValue(op1);
519                 SpiderScript_DereferenceValue(op2);
520                 break;
521
522         // TODO: Implement runtime constants
523         case NODETYPE_CONSTANT:
524                 // TODO: Scan namespace for constant name
525                 AST_RuntimeError(Node, "TODO - Runtime Constants");
526                 ret = ERRPTR;
527                 break;
528         
529         // Constant Values
530         case NODETYPE_STRING:
531         case NODETYPE_INTEGER:
532         case NODETYPE_REAL:
533                 ret = &Node->Constant;
534                 SpiderScript_ReferenceValue(ret);
535                 break;
536         case NODETYPE_NULL:
537                 ret = NULL;
538                 break;
539         
540         // --- Operations ---
541         // Boolean Operations
542         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
543                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
544                 if(op1 == ERRPTR)       return ERRPTR;
545                 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
546                 SpiderScript_DereferenceValue(op1);
547                 break;
548         case NODETYPE_LOGICALAND:       // Logical AND (&&)
549         case NODETYPE_LOGICALOR:        // Logical OR (||)
550         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
551                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
552                 if(op1 == ERRPTR)       return ERRPTR;
553                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
554                 if(op2 == ERRPTR) {
555                         SpiderScript_DereferenceValue(op1);
556                         return ERRPTR;
557                 }
558                 
559                 switch( Node->Type )
560                 {
561                 case NODETYPE_LOGICALAND:
562                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
563                         break;
564                 case NODETYPE_LOGICALOR:
565                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
566                         break;
567                 case NODETYPE_LOGICALXOR:
568                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
569                         break;
570                 default:        break;
571                 }
572                 
573                 // Free intermediate objects
574                 SpiderScript_DereferenceValue(op1);
575                 SpiderScript_DereferenceValue(op2);
576                 break;
577         
578         // General Unary Operations
579         case NODETYPE_BWNOT:    // Bitwise NOT (~)
580         case NODETYPE_NEGATE:   // Negation (-)
581                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
582                 if(op1 == ERRPTR)       return ERRPTR;
583                 ret = AST_ExecuteNode_UniOp(Block->Script, Node, Node->Type, op1);
584                 SpiderScript_DereferenceValue(op1);
585                 break;
586         
587         // General Binary Operations
588         case NODETYPE_ADD:
589         case NODETYPE_SUBTRACT:
590         case NODETYPE_MULTIPLY:
591         case NODETYPE_DIVIDE:
592         case NODETYPE_MODULO:
593         case NODETYPE_BWAND:
594         case NODETYPE_BWOR:
595         case NODETYPE_BWXOR:
596         case NODETYPE_BITSHIFTLEFT:
597         case NODETYPE_BITSHIFTRIGHT:
598         case NODETYPE_BITROTATELEFT:
599         case NODETYPE_EQUALS:
600         case NODETYPE_NOTEQUALS:
601         case NODETYPE_LESSTHAN:
602         case NODETYPE_GREATERTHAN:
603         case NODETYPE_LESSTHANEQUAL:
604         case NODETYPE_GREATERTHANEQUAL:
605                 // Get operands
606                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
607                 if(op1 == ERRPTR)       return ERRPTR;
608                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
609                 if(op2 == ERRPTR) {
610                         SpiderScript_DereferenceValue(op1);
611                         return ERRPTR;
612                 }
613                 
614                 ret = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Type, op1, op2);
615                 
616                 // Free intermediate objects
617                 SpiderScript_DereferenceValue(op1);
618                 SpiderScript_DereferenceValue(op2);
619                 break;
620         
621         //default:
622         //      ret = NULL;
623         //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
624         //      break;
625         }
626 _return:
627         // Reset namespace when no longer needed
628         if( Node->Type != NODETYPE_SCOPE )
629                 Block->CurNamespace = NULL;
630
631         #if TRACE_NODE_RETURNS
632         if(ret && ret != ERRPTR) {
633                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
634         }
635         else {
636                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
637         }
638         #endif
639
640         return ret;
641 }
642 #endif
643
644 tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
645 {
646         tSpiderValue    *ret;
647         #if 0
648         if( Value->Type == SS_DATATYPE_OBJECT )
649         {
650                 const char      *fcnname;
651                 switch(Operation)
652                 {
653                 case NODETYPE_NEGATE:   fcnname = "-ve";        break;
654                 case NODETYPE_BWNOT:    fcnname = "~";  break;
655                 default:        fcnname = NULL; break;
656                 }
657                 
658                 if( fcnname )
659                 {
660                         ret = Object_ExecuteMethod(Value->Object, fcnname, );
661                         if( ret != ERRPTR )
662                                 return ret;
663                 }
664         }
665         #endif
666         switch(Value->Type)
667         {
668         // Integer Operations
669         case SS_DATATYPE_INTEGER:
670                 if( Value->ReferenceCount == 1 )
671                         SpiderScript_ReferenceValue(ret = Value);
672                 else
673                         ret = SpiderScript_CreateInteger(0);
674                 switch(Operation)
675                 {
676                 case NODETYPE_NEGATE:   ret->Integer = -Value->Integer; break;
677                 case NODETYPE_BWNOT:    ret->Integer = ~Value->Integer; break;
678                 default:
679                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
680                         SpiderScript_DereferenceValue(ret);
681                         ret = ERRPTR;
682                         break;
683                 }
684                 break;
685         // Real number Operations
686         case SS_DATATYPE_REAL:
687                 switch(Operation)
688                 {
689                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Real );       break;
690                 default:
691                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
692                         ret = ERRPTR;
693                         break;
694                 }
695                 break;
696         
697         default:
698                 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
699                 ret = ERRPTR;
700                 break;
701         }
702         
703         return ret;
704 }
705
706 tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
707 {
708         tSpiderValue    *preCastValue = Right;
709         tSpiderValue    *ret;
710         
711         // Convert types
712         if( Left && Right && Left->Type != Right->Type )
713         {
714                 #if 0
715                 // Object types
716                 // - Operator overload functions
717                 if( Left->Type == SS_DATATYPE_OBJECT )
718                 {
719                         const char      *fcnname;
720                         switch(Operation)
721                         {
722                         case NODETYPE_ADD:      fcnname = "+";  break;
723                         case NODETYPE_SUBTRACT: fcnname = "-";  break;
724                         case NODETYPE_MULTIPLY: fcnname = "*";  break;
725                         case NODETYPE_DIVIDE:   fcnname = "/";  break;
726                         case NODETYPE_MODULO:   fcnname = "%";  break;
727                         case NODETYPE_BWAND:    fcnname = "&";  break;
728                         case NODETYPE_BWOR:     fcnname = "|";  break;
729                         case NODETYPE_BWXOR:    fcnname = "^";  break;
730                         case NODETYPE_BITSHIFTLEFT:     fcnname = "<<"; break;
731                         case NODETYPE_BITSHIFTRIGHT:fcnname = ">>";     break;
732                         case NODETYPE_BITROTATELEFT:fcnname = "<<<";    break;
733                         default:        fcnname = NULL; break;
734                         }
735                         
736                         if( fcnname )
737                         {
738                                 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
739                                 if( ret != ERRPTR )
740                                         return ret;
741                                 // Fall through and try casting (which will usually fail)
742                         }
743                 }
744                 #endif
745                 
746                 // If implicit casts are allowed, convert Right to Left's type
747                 if(Script->Variant->bImplicitCasts)
748                 {
749                         Right = SpiderScript_CastValueTo(Left->Type, Right);
750                         if(Right == ERRPTR)
751                                 return ERRPTR;
752                 }
753                 // If statically typed, this should never happen, but catch it anyway
754                 else {
755                         AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
756                         return ERRPTR;
757                 }
758         }
759         
760         // NULL Check
761         if( Left == NULL || Right == NULL ) {
762                 if(Right && Right != preCastValue)      free(Right);
763                 return NULL;
764         }
765
766         // Catch comparisons
767         switch(Operation)
768         {
769         case NODETYPE_EQUALS:
770         case NODETYPE_NOTEQUALS:
771         case NODETYPE_LESSTHAN:
772         case NODETYPE_GREATERTHAN:
773         case NODETYPE_LESSTHANEQUAL:
774         case NODETYPE_GREATERTHANEQUAL: {
775                  int    cmp;
776                 ret = NULL;
777                 // Do operation
778                 switch(Left->Type)
779                 {
780                 // - String Compare (does a strcmp, well memcmp)
781                 case SS_DATATYPE_STRING:
782                         // Call memcmp to do most of the work
783                         cmp = memcmp(
784                                 Left->String.Data, Right->String.Data,
785                                 (Left->String.Length < Right->String.Length) ? Left->String.Length : Right->String.Length
786                                 );
787                         // Handle reaching the end of the string
788                         if( cmp == 0 ) {
789                                 if( Left->String.Length == Right->String.Length )
790                                         cmp = 0;
791                                 else if( Left->String.Length < Right->String.Length )
792                                         cmp = 1;
793                                 else
794                                         cmp = -1;
795                         }
796                         break;
797                 
798                 // - Integer Comparisons
799                 case SS_DATATYPE_INTEGER:
800                         if( Left->Integer == Right->Integer )
801                                 cmp = 0;
802                         else if( Left->Integer < Right->Integer )
803                                 cmp = -1;
804                         else
805                                 cmp = 1;
806                         break;
807                 // - Real Number Comparisons
808                 case SS_DATATYPE_REAL:
809                         cmp = (Left->Real - Right->Real) / Right->Real * 10000; // < 0.1% difference is equality
810                         break;
811                 default:
812                         AST_RuntimeError(Node, "TODO - Comparison of type %i", Left->Type);
813                         ret = ERRPTR;
814                         break;
815                 }
816                 
817                 // Error check
818                 if( ret != ERRPTR )
819                 {
820                         if(Left->ReferenceCount == 1 && Left->Type != SS_DATATYPE_STRING)
821                                 SpiderScript_ReferenceValue(ret = Left);
822                         else
823                                 ret = SpiderScript_CreateInteger(0);
824                         
825                         // Create return
826                         switch(Operation)
827                         {
828                         case NODETYPE_EQUALS:   ret->Integer = (cmp == 0);      break;
829                         case NODETYPE_NOTEQUALS:        ret->Integer = (cmp != 0);      break;
830                         case NODETYPE_LESSTHAN: ret->Integer = (cmp < 0);       break;
831                         case NODETYPE_GREATERTHAN:      ret->Integer = (cmp > 0);       break;
832                         case NODETYPE_LESSTHANEQUAL:    ret->Integer = (cmp <= 0);      break;
833                         case NODETYPE_GREATERTHANEQUAL: ret->Integer = (cmp >= 0);      break;
834                         default:
835                                 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Operation);
836                                 SpiderScript_DereferenceValue(ret);
837                                 ret = ERRPTR;
838                                 break;
839                         }
840                 }
841                 if(Right && Right != preCastValue)      free(Right);
842                 return ret;
843                 }
844
845         // Fall through and sort by type instead
846         default:
847                 break;
848         }
849         
850         // Do operation
851         switch(Left->Type)
852         {
853         // String Concatenation
854         case SS_DATATYPE_STRING:
855                 switch(Operation)
856                 {
857                 case NODETYPE_ADD:      // Concatenate
858                         ret = SpiderScript_StringConcat(Left, Right);
859                         break;
860                 // TODO: Support python style 'i = %i' % i ?
861                 // Might do it via a function call
862                 // Implement it via % with an array, but getting past the cast will be fun
863 //              case NODETYPE_MODULUS:
864 //                      break;
865                 // TODO: Support string repititions
866 //              case NODETYPE_MULTIPLY:
867 //                      break;
868
869                 default:
870                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
871                         ret = ERRPTR;
872                         break;
873                 }
874                 break;
875         // Integer Operations
876         case SS_DATATYPE_INTEGER:
877                 if( Left->ReferenceCount == 1 )
878                         SpiderScript_ReferenceValue(ret = Left);
879                 else
880                         ret = SpiderScript_CreateInteger(0);
881                 switch(Operation)
882                 {
883                 case NODETYPE_ADD:      ret->Integer = Left->Integer + Right->Integer;  break;
884                 case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer;  break;
885                 case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer;  break;
886                 case NODETYPE_DIVIDE:   ret->Integer = Left->Integer / Right->Integer;  break;
887                 case NODETYPE_MODULO:   ret->Integer = Left->Integer % Right->Integer;  break;
888                 case NODETYPE_BWAND:    ret->Integer = Left->Integer & Right->Integer;  break;
889                 case NODETYPE_BWOR:     ret->Integer = Left->Integer | Right->Integer;  break;
890                 case NODETYPE_BWXOR:    ret->Integer = Left->Integer ^ Right->Integer;  break;
891                 case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer;     break;
892                 case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer;     break;
893                 case NODETYPE_BITROTATELEFT:
894                         ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
895                         break;
896                 default:
897                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
898                         SpiderScript_DereferenceValue(ret);
899                         ret = ERRPTR;
900                         break;
901                 }
902                 break;
903         
904         // Real Numbers
905         case SS_DATATYPE_REAL:
906                 if( Left->ReferenceCount == 1 )
907                         SpiderScript_ReferenceValue(ret = Left);
908                 else
909                         ret = SpiderScript_CreateReal(0);
910                 switch(Operation)
911                 {
912                 case NODETYPE_ADD:      ret->Real = Left->Real + Right->Real;   break;
913                 case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real;   break;
914                 case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real;   break;
915                 case NODETYPE_DIVIDE:   ret->Real = Left->Real / Right->Real;   break;
916                 default:
917                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
918                         SpiderScript_DereferenceValue(ret);
919                         ret = ERRPTR;
920                         break;
921                 }
922                 break;
923         
924         default:
925                 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
926                 ret = ERRPTR;
927                 break;
928         }
929         
930         if(Right && Right != preCastValue)      free(Right);
931         
932         return ret;
933 }
934
935 tSpiderValue *AST_ExecuteNode_Index(tSpiderScript *Script, tAST_Node *Node,
936         tSpiderValue *Array, int Index, tSpiderValue *SaveValue)
937 {
938         // Quick sanity check
939         if( !Array )
940         {
941                 AST_RuntimeError(Node, "Indexing NULL, not a good idea");
942                 return ERRPTR;
943         }
944
945         // Array?
946         if( SS_GETARRAYDEPTH(Array->Type) )
947         {
948                 if( Index < 0 || Index >= Array->Array.Length ) {
949                         AST_RuntimeError(Node, "Array index out of bounds %i not in (0, %i]",
950                                 Index, Array->Array.Length);
951                         return ERRPTR;
952                 }
953                 
954                 if( SaveValue )
955                 {
956                         if( SaveValue->Type != SS_DOWNARRAY(Array->Type) ) {
957                                 // TODO: Implicit casting
958                                 AST_RuntimeError(Node, "Type mismatch assiging to array element");
959                                 return ERRPTR;
960                         }
961                         SpiderScript_DereferenceValue( Array->Array.Items[Index] );
962                         Array->Array.Items[Index] = SaveValue;
963                         SpiderScript_ReferenceValue( Array->Array.Items[Index] );
964                         return NULL;
965                 }
966                 else
967                 {
968                         SpiderScript_ReferenceValue( Array->Array.Items[Index] );
969                         return Array->Array.Items[Index];
970                 }
971         }
972         else
973         {
974                 AST_RuntimeError(Node, "TODO - Implement indexing on non-arrays (type = %x)",
975                         Array->Type);
976                 return ERRPTR;
977         }
978 }
979
980 #if USE_AST_EXEC
981 /**
982  * \brief Define a variable
983  * \param Block Current block state
984  * \param Type  Type of the variable
985  * \param Name  Name of the variable
986  * \return Boolean Failure
987  */
988 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
989 {
990         tAST_Variable   *var, *prev = NULL;
991         
992         for( var = Block->FirstVar; var; prev = var, var = var->Next )
993         {
994                 if( strcmp(var->Name, Name) == 0 ) {
995                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
996                         return ERRPTR;
997                 }
998         }
999         
1000         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
1001         var->Next = NULL;
1002         var->Type = Type;
1003         var->Object = Value;
1004         if(Value)       SpiderScript_ReferenceValue(Value);
1005         strcpy(var->Name, Name);
1006         
1007         if(prev)        prev->Next = var;
1008         else    Block->FirstVar = var;
1009         
1010         //printf("Defined variable %s (%i)\n", Name, Type);
1011         
1012         return var;
1013 }
1014
1015 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
1016 {       
1017         tAST_Variable   *var = NULL;
1018         
1019         // Speed hack
1020         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
1021                 var = VarNode->ValueCache;
1022                 #if TRACE_VAR_LOOKUPS
1023                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
1024                         VarNode->Variable.Name, var,
1025                         VarNode->BlockState, VarNode->BlockIdent
1026                         );
1027                 #endif
1028         }
1029         else
1030         {
1031                 tAST_BlockState *bs;
1032                 for( bs = Block; bs; bs = bs->Parent )
1033                 {
1034                         for( var = bs->FirstVar; var; var = var->Next )
1035                         {
1036                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
1037                                         break;
1038                         }
1039                         if(var) break;
1040                 }
1041                 
1042                 if( !var )
1043                 {
1044                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
1045                                 // Define variable
1046                                 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
1047                         }
1048                         else
1049                         {
1050                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
1051                                 return NULL;
1052                         }
1053                 }
1054                 
1055                 #if TRACE_VAR_LOOKUPS
1056                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1057                         VarNode->Variable.Name, var,
1058                         Block, Block->Ident);
1059                 #endif
1060                 
1061                 VarNode->ValueCache = var;
1062                 VarNode->BlockState = Block;
1063                 VarNode->BlockIdent = Block->Ident;
1064         }
1065         
1066         return var;
1067 }
1068
1069 /**
1070  * \brief Set the value of a variable
1071  * \return Boolean Failure
1072  */
1073 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1074 {
1075         tAST_Variable   *var;
1076         
1077         var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1078         
1079         if( !var )      return -1;
1080         
1081         if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1082         {
1083                 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1084                         VarNode->Variable.Name);
1085                 return -2;
1086         }
1087
1088 //      printf("Assign %p to '%s'\n", Value, var->Name);
1089         SpiderScript_ReferenceValue(Value);
1090         SpiderScript_DereferenceValue(var->Object);
1091         var->Object = Value;
1092         return 0;
1093 }
1094
1095 /**
1096  * \brief Get the value of a variable
1097  */
1098 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1099 {
1100         tAST_Variable   *var = Variable_Lookup(Block, VarNode, 0);
1101         
1102         if( !var )      return ERRPTR;
1103         
1104         SpiderScript_ReferenceValue(var->Object);
1105         return var->Object;
1106 }
1107
1108 /**
1109  * \brief Destorys a variable
1110  */
1111 void Variable_Destroy(tAST_Variable *Variable)
1112 {
1113 //      printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1114         SpiderScript_DereferenceValue(Variable->Object);
1115         free(Variable);
1116 }
1117 #endif
1118

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