Usermode - Fixed GAS/NASM detection
[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( !op1 || op1->Type != SS_DATATYPE_ARRAY )
486                 {
487                         // TODO: Implement "operator []" on objects
488                         AST_RuntimeError(Node, "Indexing non-array");
489                         ret = ERRPTR;
490                         break;
491                 }
492                 
493                 if( (!op2 || op2->Type != SS_DATATYPE_INTEGER) && !Block->Script->Variant->bImplicitCasts ) {
494                         AST_RuntimeError(Node, "Array index is not an integer");
495                         ret = ERRPTR;
496                         break;
497                 }
498                 
499                 if( !op2 || op2->Type != SS_DATATYPE_INTEGER )
500                 {
501                         tmpobj = SpiderScript_CastValueTo(SS_DATATYPE_INTEGER, op2);
502                         SpiderScript_DereferenceValue(op2);
503                         op2 = tmpobj;
504                 }
505                 
506                 if( op2->Integer >= op1->Array.Length ) {
507                         AST_RuntimeError(Node, "Array index out of bounds %i >= %i",
508                                 op2->Integer, op1->Array.Length);
509                         ret = ERRPTR;
510                         break;
511                 }
512                 
513                 ret = op1->Array.Items[ op2->Integer ];
514                 SpiderScript_ReferenceValue(ret);
515                 
516                 SpiderScript_DereferenceValue(op1);
517                 SpiderScript_DereferenceValue(op2);
518                 break;
519
520         // TODO: Implement runtime constants
521         case NODETYPE_CONSTANT:
522                 // TODO: Scan namespace for constant name
523                 AST_RuntimeError(Node, "TODO - Runtime Constants");
524                 ret = ERRPTR;
525                 break;
526         
527         // Constant Values
528         case NODETYPE_STRING:
529         case NODETYPE_INTEGER:
530         case NODETYPE_REAL:
531                 ret = &Node->Constant;
532                 SpiderScript_ReferenceValue(ret);
533                 break;
534         
535         // --- Operations ---
536         // Boolean Operations
537         case NODETYPE_LOGICALNOT:       // Logical NOT (!)
538                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
539                 if(op1 == ERRPTR)       return ERRPTR;
540                 ret = SpiderScript_CreateInteger( !SpiderScript_IsValueTrue(op1) );
541                 SpiderScript_DereferenceValue(op1);
542                 break;
543         case NODETYPE_LOGICALAND:       // Logical AND (&&)
544         case NODETYPE_LOGICALOR:        // Logical OR (||)
545         case NODETYPE_LOGICALXOR:       // Logical XOR (^^)
546                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
547                 if(op1 == ERRPTR)       return ERRPTR;
548                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
549                 if(op2 == ERRPTR) {
550                         SpiderScript_DereferenceValue(op1);
551                         return ERRPTR;
552                 }
553                 
554                 switch( Node->Type )
555                 {
556                 case NODETYPE_LOGICALAND:
557                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) && SpiderScript_IsValueTrue(op2) );
558                         break;
559                 case NODETYPE_LOGICALOR:
560                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) || SpiderScript_IsValueTrue(op2) );
561                         break;
562                 case NODETYPE_LOGICALXOR:
563                         ret = SpiderScript_CreateInteger( SpiderScript_IsValueTrue(op1) ^ SpiderScript_IsValueTrue(op2) );
564                         break;
565                 default:        break;
566                 }
567                 
568                 // Free intermediate objects
569                 SpiderScript_DereferenceValue(op1);
570                 SpiderScript_DereferenceValue(op2);
571                 break;
572         
573         // General Unary Operations
574         case NODETYPE_BWNOT:    // Bitwise NOT (~)
575         case NODETYPE_NEGATE:   // Negation (-)
576                 op1 = AST_ExecuteNode(Block, Node->UniOp.Value);
577                 if(op1 == ERRPTR)       return ERRPTR;
578                 ret = AST_ExecuteNode_UniOp(Block->Script, Node, Node->Type, op1);
579                 SpiderScript_DereferenceValue(op1);
580                 break;
581         
582         // General Binary Operations
583         case NODETYPE_ADD:
584         case NODETYPE_SUBTRACT:
585         case NODETYPE_MULTIPLY:
586         case NODETYPE_DIVIDE:
587         case NODETYPE_MODULO:
588         case NODETYPE_BWAND:
589         case NODETYPE_BWOR:
590         case NODETYPE_BWXOR:
591         case NODETYPE_BITSHIFTLEFT:
592         case NODETYPE_BITSHIFTRIGHT:
593         case NODETYPE_BITROTATELEFT:
594         case NODETYPE_EQUALS:
595         case NODETYPE_LESSTHAN:
596         case NODETYPE_GREATERTHAN:
597         case NODETYPE_LESSTHANEQUAL:
598         case NODETYPE_GREATERTHANEQUAL:
599                 // Get operands
600                 op1 = AST_ExecuteNode(Block, Node->BinOp.Left);
601                 if(op1 == ERRPTR)       return ERRPTR;
602                 op2 = AST_ExecuteNode(Block, Node->BinOp.Right);
603                 if(op2 == ERRPTR) {
604                         SpiderScript_DereferenceValue(op1);
605                         return ERRPTR;
606                 }
607                 
608                 ret = AST_ExecuteNode_BinOp(Block->Script, Node, Node->Type, op1, op2);
609                 
610                 // Free intermediate objects
611                 SpiderScript_DereferenceValue(op1);
612                 SpiderScript_DereferenceValue(op2);
613                 break;
614         
615         //default:
616         //      ret = NULL;
617         //      AST_RuntimeError(Node, "BUG - SpiderScript AST_ExecuteNode Unimplemented %i", Node->Type);
618         //      break;
619         }
620 _return:
621         // Reset namespace when no longer needed
622         if( Node->Type != NODETYPE_SCOPE )
623                 Block->CurNamespace = NULL;
624
625         #if TRACE_NODE_RETURNS
626         if(ret && ret != ERRPTR) {
627                 AST_RuntimeError(Node, "Ret type of %p %i is %i", Node, Node->Type, ret->Type);
628         }
629         else {
630                 AST_RuntimeError(Node, "Ret type of %p %i is %p", Node, Node->Type, ret);
631         }
632         #endif
633
634         return ret;
635 }
636
637 tSpiderValue *AST_ExecuteNode_UniOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Value)
638 {
639         tSpiderValue    *ret;
640         #if 0
641         if( Value->Type == SS_DATATYPE_OBJECT )
642         {
643                 const char      *fcnname;
644                 switch(Operation)
645                 {
646                 case NODETYPE_NEGATE:   fcnname = "-ve";        break;
647                 case NODETYPE_BWNOT:    fcnname = "~";  break;
648                 default:        fcnname = NULL; break;
649                 }
650                 
651                 if( fcnname )
652                 {
653                         ret = Object_ExecuteMethod(Value->Object, fcnname, );
654                         if( ret != ERRPTR )
655                                 return ret;
656                 }
657         }
658         #endif
659         switch(Value->Type)
660         {
661         // Integer Operations
662         case SS_DATATYPE_INTEGER:
663                 if( Value->ReferenceCount == 1 )
664                         SpiderScript_ReferenceValue(ret = Value);
665                 else
666                         ret = SpiderScript_CreateInteger(0);
667                 switch(Operation)
668                 {
669                 case NODETYPE_NEGATE:   ret->Integer = -Value->Integer; break;
670                 case NODETYPE_BWNOT:    ret->Integer = ~Value->Integer; break;
671                 default:
672                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Integer unknown op %i", Operation);
673                         SpiderScript_DereferenceValue(ret);
674                         ret = ERRPTR;
675                         break;
676                 }
677                 break;
678         // Real number Operations
679         case SS_DATATYPE_REAL:
680                 switch(Operation)
681                 {
682                 case NODETYPE_NEGATE:   ret = SpiderScript_CreateInteger( -Value->Real );       break;
683                 default:
684                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,UniOP,Real unknown op %i", Operation);
685                         ret = ERRPTR;
686                         break;
687                 }
688                 break;
689         
690         default:
691                 AST_RuntimeError(NULL, "Invalid operation (%i) on type (%i)", Operation, Value->Type);
692                 ret = ERRPTR;
693                 break;
694         }
695         
696         return ret;
697 }
698
699 tSpiderValue *AST_ExecuteNode_BinOp(tSpiderScript *Script, tAST_Node *Node, int Operation, tSpiderValue *Left, tSpiderValue *Right)
700 {
701         tSpiderValue    *preCastValue = Right;
702         tSpiderValue    *ret;
703         
704         // Convert types
705         if( Left && Right && Left->Type != Right->Type )
706         {
707                 #if 0
708                 // Object types
709                 // - Operator overload functions
710                 if( Left->Type == SS_DATATYPE_OBJECT )
711                 {
712                         const char      *fcnname;
713                         switch(Operation)
714                         {
715                         case NODETYPE_ADD:      fcnname = "+";  break;
716                         case NODETYPE_SUBTRACT: fcnname = "-";  break;
717                         case NODETYPE_MULTIPLY: fcnname = "*";  break;
718                         case NODETYPE_DIVIDE:   fcnname = "/";  break;
719                         case NODETYPE_MODULO:   fcnname = "%";  break;
720                         case NODETYPE_BWAND:    fcnname = "&";  break;
721                         case NODETYPE_BWOR:     fcnname = "|";  break;
722                         case NODETYPE_BWXOR:    fcnname = "^";  break;
723                         case NODETYPE_BITSHIFTLEFT:     fcnname = "<<"; break;
724                         case NODETYPE_BITSHIFTRIGHT:fcnname = ">>";     break;
725                         case NODETYPE_BITROTATELEFT:fcnname = "<<<";    break;
726                         default:        fcnname = NULL; break;
727                         }
728                         
729                         if( fcnname )
730                         {
731                                 ret = Object_ExecuteMethod(Left->Object, fcnname, Right);
732                                 if( ret != ERRPTR )
733                                         return ret;
734                                 // Fall through and try casting (which will usually fail)
735                         }
736                 }
737                 #endif
738                 
739                 // If implicit casts are allowed, convert Right to Left's type
740                 if(Script->Variant->bImplicitCasts)
741                 {
742                         Right = SpiderScript_CastValueTo(Left->Type, Right);
743                         if(Right == ERRPTR)
744                                 return ERRPTR;
745                 }
746                 // If statically typed, this should never happen, but catch it anyway
747                 else {
748                         AST_RuntimeError(Node, "Implicit cast not allowed (from %i to %i)", Right->Type, Left->Type);
749                         return ERRPTR;
750                 }
751         }
752         
753         // NULL Check
754         if( Left == NULL || Right == NULL ) {
755                 if(Right && Right != preCastValue)      free(Right);
756                 return NULL;
757         }
758
759         // Catch comparisons
760         switch(Operation)
761         {
762         case NODETYPE_EQUALS:
763         case NODETYPE_LESSTHAN:
764         case NODETYPE_GREATERTHAN:
765         case NODETYPE_LESSTHANEQUAL:
766         case NODETYPE_GREATERTHANEQUAL: {
767                  int    cmp;
768                 ret = NULL;
769                 // Do operation
770                 switch(Left->Type)
771                 {
772                 // - String Compare (does a strcmp, well memcmp)
773                 case SS_DATATYPE_STRING:
774                         // Call memcmp to do most of the work
775                         cmp = memcmp(
776                                 Left->String.Data, Right->String.Data,
777                                 (Left->String.Length < Right->String.Length) ? Left->String.Length : Right->String.Length
778                                 );
779                         // Handle reaching the end of the string
780                         if( cmp == 0 ) {
781                                 if( Left->String.Length == Right->String.Length )
782                                         cmp = 0;
783                                 else if( Left->String.Length < Right->String.Length )
784                                         cmp = 1;
785                                 else
786                                         cmp = -1;
787                         }
788                         break;
789                 
790                 // - Integer Comparisons
791                 case SS_DATATYPE_INTEGER:
792                         if( Left->Integer == Right->Integer )
793                                 cmp = 0;
794                         else if( Left->Integer < Right->Integer )
795                                 cmp = -1;
796                         else
797                                 cmp = 1;
798                         break;
799                 // - Real Number Comparisons
800                 case SS_DATATYPE_REAL:
801                         cmp = (Left->Real - Right->Real) / Right->Real * 10000; // < 0.1% difference is equality
802                         break;
803                 default:
804                         AST_RuntimeError(Node, "TODO - Comparison of type %i", Left->Type);
805                         ret = ERRPTR;
806                         break;
807                 }
808                 
809                 // Error check
810                 if( ret != ERRPTR )
811                 {
812                         if(Left->ReferenceCount == 1 && Left->Type != SS_DATATYPE_STRING)
813                                 SpiderScript_ReferenceValue(ret = Left);
814                         else
815                                 ret = SpiderScript_CreateInteger(0);
816                         
817                         // Create return
818                         switch(Operation)
819                         {
820                         case NODETYPE_EQUALS:   ret->Integer = (cmp == 0);      break;
821                         case NODETYPE_LESSTHAN: ret->Integer = (cmp < 0);       break;
822                         case NODETYPE_GREATERTHAN:      ret->Integer = (cmp > 0);       break;
823                         case NODETYPE_LESSTHANEQUAL:    ret->Integer = (cmp <= 0);      break;
824                         case NODETYPE_GREATERTHANEQUAL: ret->Integer = (cmp >= 0);      break;
825                         default:
826                                 AST_RuntimeError(Node, "Exec,CmpOp unknown op %i", Operation);
827                                 SpiderScript_DereferenceValue(ret);
828                                 ret = ERRPTR;
829                                 break;
830                         }
831                 }
832                 if(Right && Right != preCastValue)      free(Right);
833                 return ret;
834                 }
835
836         // Fall through and sort by type instead
837         default:
838                 break;
839         }
840         
841         // Do operation
842         switch(Left->Type)
843         {
844         // String Concatenation
845         case SS_DATATYPE_STRING:
846                 switch(Operation)
847                 {
848                 case NODETYPE_ADD:      // Concatenate
849                         ret = SpiderScript_StringConcat(Left, Right);
850                         break;
851                 // TODO: Support python style 'i = %i' % i ?
852                 // Might do it via a function call
853                 // Implement it via % with an array, but getting past the cast will be fun
854 //              case NODETYPE_MODULUS:
855 //                      break;
856                 // TODO: Support string repititions
857 //              case NODETYPE_MULTIPLY:
858 //                      break;
859
860                 default:
861                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,String unknown op %i", Operation);
862                         ret = ERRPTR;
863                         break;
864                 }
865                 break;
866         // Integer Operations
867         case SS_DATATYPE_INTEGER:
868                 if( Left->ReferenceCount == 1 )
869                         SpiderScript_ReferenceValue(ret = Left);
870                 else
871                         ret = SpiderScript_CreateInteger(0);
872                 switch(Operation)
873                 {
874                 case NODETYPE_ADD:      ret->Integer = Left->Integer + Right->Integer;  break;
875                 case NODETYPE_SUBTRACT: ret->Integer = Left->Integer - Right->Integer;  break;
876                 case NODETYPE_MULTIPLY: ret->Integer = Left->Integer * Right->Integer;  break;
877                 case NODETYPE_DIVIDE:   ret->Integer = Left->Integer / Right->Integer;  break;
878                 case NODETYPE_MODULO:   ret->Integer = Left->Integer % Right->Integer;  break;
879                 case NODETYPE_BWAND:    ret->Integer = Left->Integer & Right->Integer;  break;
880                 case NODETYPE_BWOR:     ret->Integer = Left->Integer | Right->Integer;  break;
881                 case NODETYPE_BWXOR:    ret->Integer = Left->Integer ^ Right->Integer;  break;
882                 case NODETYPE_BITSHIFTLEFT: ret->Integer = Left->Integer << Right->Integer;     break;
883                 case NODETYPE_BITSHIFTRIGHT:ret->Integer = Left->Integer >> Right->Integer;     break;
884                 case NODETYPE_BITROTATELEFT:
885                         ret->Integer = (Left->Integer << Right->Integer) | (Left->Integer >> (64-Right->Integer));
886                         break;
887                 default:
888                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Integer unknown op %i", Operation);
889                         SpiderScript_DereferenceValue(ret);
890                         ret = ERRPTR;
891                         break;
892                 }
893                 break;
894         
895         // Real Numbers
896         case SS_DATATYPE_REAL:
897                 if( Left->ReferenceCount == 1 )
898                         SpiderScript_ReferenceValue(ret = Left);
899                 else
900                         ret = SpiderScript_CreateReal(0);
901                 switch(Operation)
902                 {
903                 case NODETYPE_ADD:      ret->Real = Left->Real + Right->Real;   break;
904                 case NODETYPE_SUBTRACT: ret->Real = Left->Real - Right->Real;   break;
905                 case NODETYPE_MULTIPLY: ret->Real = Left->Real * Right->Real;   break;
906                 case NODETYPE_DIVIDE:   ret->Real = Left->Real / Right->Real;   break;
907                 default:
908                         AST_RuntimeError(Node, "SpiderScript internal error: Exec,BinOP,Real unknown op %i", Operation);
909                         SpiderScript_DereferenceValue(ret);
910                         ret = ERRPTR;
911                         break;
912                 }
913                 break;
914         
915         default:
916                 AST_RuntimeError(Node, "BUG - Invalid operation (%i) on type (%i)", Operation, Left->Type);
917                 ret = ERRPTR;
918                 break;
919         }
920         
921         if(Right && Right != preCastValue)      free(Right);
922         
923         return ret;
924 }
925
926 /**
927  * \brief Define a variable
928  * \param Block Current block state
929  * \param Type  Type of the variable
930  * \param Name  Name of the variable
931  * \return Boolean Failure
932  */
933 tAST_Variable *Variable_Define(tAST_BlockState *Block, int Type, const char *Name, tSpiderValue *Value)
934 {
935         tAST_Variable   *var, *prev = NULL;
936         
937         for( var = Block->FirstVar; var; prev = var, var = var->Next )
938         {
939                 if( strcmp(var->Name, Name) == 0 ) {
940                         AST_RuntimeError(NULL, "Redefinition of variable '%s'", Name);
941                         return ERRPTR;
942                 }
943         }
944         
945         var = malloc( sizeof(tAST_Variable) + strlen(Name) + 1 );
946         var->Next = NULL;
947         var->Type = Type;
948         var->Object = Value;
949         if(Value)       SpiderScript_ReferenceValue(Value);
950         strcpy(var->Name, Name);
951         
952         if(prev)        prev->Next = var;
953         else    Block->FirstVar = var;
954         
955         //printf("Defined variable %s (%i)\n", Name, Type);
956         
957         return var;
958 }
959
960 tAST_Variable *Variable_Lookup(tAST_BlockState *Block, tAST_Node *VarNode, int CreateType)
961 {       
962         tAST_Variable   *var = NULL;
963         
964         // Speed hack
965         if( VarNode->BlockState == Block && VarNode->BlockIdent == Block->Ident ) {
966                 var = VarNode->ValueCache;
967                 #if TRACE_VAR_LOOKUPS
968                 AST_RuntimeMessage(VarNode, "debug", "Fast var fetch on '%s' %p (%p:%i)",
969                         VarNode->Variable.Name, var,
970                         VarNode->BlockState, VarNode->BlockIdent
971                         );
972                 #endif
973         }
974         else
975         {
976                 tAST_BlockState *bs;
977                 for( bs = Block; bs; bs = bs->Parent )
978                 {
979                         for( var = bs->FirstVar; var; var = var->Next )
980                         {
981                                 if( strcmp(var->Name, VarNode->Variable.Name) == 0 )
982                                         break;
983                         }
984                         if(var) break;
985                 }
986                 
987                 if( !var )
988                 {
989                         if( Block->Script->Variant->bDyamicTyped && CreateType != SS_DATATYPE_UNDEF ) {
990                                 // Define variable
991                                 var = Variable_Define(Block, CreateType, VarNode->Variable.Name, NULL);
992                         }
993                         else
994                         {
995                                 AST_RuntimeError(VarNode, "Variable '%s' is undefined", VarNode->Variable.Name);
996                                 return NULL;
997                         }
998                 }
999                 
1000                 #if TRACE_VAR_LOOKUPS
1001                 AST_RuntimeMessage(VarNode, "debug", "Saved variable lookup of '%s' %p (%p:%i)",
1002                         VarNode->Variable.Name, var,
1003                         Block, Block->Ident);
1004                 #endif
1005                 
1006                 VarNode->ValueCache = var;
1007                 VarNode->BlockState = Block;
1008                 VarNode->BlockIdent = Block->Ident;
1009         }
1010         
1011         return var;
1012 }
1013
1014 /**
1015  * \brief Set the value of a variable
1016  * \return Boolean Failure
1017  */
1018 int Variable_SetValue(tAST_BlockState *Block, tAST_Node *VarNode, tSpiderValue *Value)
1019 {
1020         tAST_Variable   *var;
1021         
1022         var = Variable_Lookup(Block, VarNode, (Value ? Value->Type : SS_DATATYPE_UNDEF));
1023         
1024         if( !var )      return -1;
1025         
1026         if( !Block->Script->Variant->bDyamicTyped && (Value && var->Type != Value->Type) )
1027         {
1028                 AST_RuntimeError(VarNode, "Type mismatch assigning to '%s'",
1029                         VarNode->Variable.Name);
1030                 return -2;
1031         }
1032
1033 //      printf("Assign %p to '%s'\n", Value, var->Name);
1034         SpiderScript_ReferenceValue(Value);
1035         SpiderScript_DereferenceValue(var->Object);
1036         var->Object = Value;
1037         return 0;
1038 }
1039
1040 /**
1041  * \brief Get the value of a variable
1042  */
1043 tSpiderValue *Variable_GetValue(tAST_BlockState *Block, tAST_Node *VarNode)
1044 {
1045         tAST_Variable   *var = Variable_Lookup(Block, VarNode, 0);
1046         
1047         if( !var )      return ERRPTR;
1048         
1049         SpiderScript_ReferenceValue(var->Object);
1050         return var->Object;
1051 }
1052
1053 /**
1054  * \brief Destorys a variable
1055  */
1056 void Variable_Destroy(tAST_Variable *Variable)
1057 {
1058 //      printf("Variable_Destroy: (%p'%s')\n", Variable, Variable->Name);
1059         SpiderScript_DereferenceValue(Variable->Object);
1060         free(Variable);
1061 }
1062

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