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

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