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

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