SpiderScript - Moved header to directory, ready to remove from tree
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_bytecode.c
1 /*
2  * SpiderScript Library
3  * by John Hodge (thePowersGang)
4  * 
5  * exec_bytecode.c
6  * - Execute bytecode
7  */
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include "common.h"
11 #include "bytecode.h"
12 #include <stdio.h>
13 #include <string.h>
14 #include "ast.h"
15 #include <inttypes.h>
16
17 #define TRACE   0
18
19 #if TRACE
20 # define DEBUG_F(v...)  printf(v)
21 #else
22 # define DEBUG_F(v...)
23 #endif
24
25 // === IMPORTS ===
26 extern void     AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
27
28 // === TYPES ===
29 typedef struct sBC_StackEnt     tBC_StackEnt;
30 typedef struct sBC_Stack        tBC_Stack;
31
32 enum eBC_StackEntTypes
33 {
34         ET_NULL,        // Start of the stack
35         // SS_DATATYPE_*
36         ET_FUNCTION_START = NUM_SS_DATATYPES,
37         ET_REFERENCE    // Reference to a tSpiderValue
38 };
39
40 struct sBC_StackEnt
41 {
42         uint8_t Type;
43         union {
44                 int64_t Integer;
45                 double  Real;
46                 tSpiderValue    *Reference;     // Used for everything else
47                 tSpiderObject   *Object;
48                 tSpiderNamespace        *Namespace;
49         };
50 };
51
52 struct sBC_Stack
53 {
54          int    EntrySpace;
55          int    EntryCount;
56         tBC_StackEnt    Entries[];
57 };
58
59 // === PROTOTYPES ===
60 tSpiderValue    *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
61  int    Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
62
63 // === CODE ===
64 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
65 {
66         if( Stack->EntryCount == 0 )    return 1;
67         Stack->EntryCount --;
68         *Dest = Stack->Entries[Stack->EntryCount];
69         return 0;
70 }
71
72 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
73 {
74         if( Stack->EntryCount == Stack->EntrySpace )    return 1;
75         Stack->Entries[Stack->EntryCount] = *Src;
76         Stack->EntryCount ++;
77         return 0;
78 }
79
80 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
81 {
82         switch(Ent->Type)
83         {
84         case SS_DATATYPE_INTEGER:
85                 return !!Ent->Integer;
86         case SS_DATATYPE_REAL:
87                 return !(-.5f < Ent->Real && Ent->Real < 0.5f);
88         case SS_DATATYPE_OBJECT:
89                 return Ent->Object != NULL;
90         case ET_FUNCTION_START:
91                 return -1;
92         default:
93                 return SpiderScript_IsValueTrue(Ent->Reference);
94         }
95 }
96
97 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
98 {
99         switch(Ent->Type)
100         {
101         case SS_DATATYPE_INTEGER:
102         case SS_DATATYPE_REAL:
103         case SS_DATATYPE_OBJECT:
104                 if(!tmp) {
105                         tmp = malloc(sizeof(tSpiderValue));
106                         tmp->ReferenceCount = 1;
107                 } else {
108                         // Stops a stack value from having free() called on it
109                         tmp->ReferenceCount = 2;
110                 }
111                 break;
112         default:
113                 break;
114         }
115         switch(Ent->Type)
116         {
117         case SS_DATATYPE_INTEGER:
118                 tmp->Type = SS_DATATYPE_INTEGER;
119                 tmp->Integer = Ent->Integer;
120                 return tmp;
121         case SS_DATATYPE_REAL:
122                 tmp->Type = SS_DATATYPE_REAL;
123                 tmp->Real = Ent->Real;
124                 return tmp;
125         case SS_DATATYPE_OBJECT:
126                 tmp->Type = SS_DATATYPE_OBJECT;
127                 tmp->Object = Ent->Object;
128                 return tmp;
129         case ET_FUNCTION_START:
130                 AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
131                 return NULL;
132         default:
133                 SpiderScript_ReferenceValue(Ent->Reference);
134                 return Ent->Reference;
135         }
136 }
137
138 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
139 {
140         if(!Value) {
141                 Ent->Type = ET_REFERENCE;
142                 Ent->Reference = NULL;
143                 return ;
144         }
145         switch(Value->Type)
146         {
147         case SS_DATATYPE_INTEGER:
148                 Ent->Type = SS_DATATYPE_INTEGER;
149                 Ent->Integer = Value->Integer;
150                 break;
151         case SS_DATATYPE_REAL:
152                 Ent->Type = SS_DATATYPE_REAL;
153                 Ent->Real = Value->Real;
154                 break;
155         case SS_DATATYPE_OBJECT:
156                 Ent->Type = SS_DATATYPE_OBJECT;
157                 Ent->Object = Value->Object;
158                 Ent->Object->ReferenceCount ++;
159                 break;
160         default:
161                 SpiderScript_ReferenceValue(Value);
162                 Ent->Type = ET_REFERENCE;
163                 Ent->Reference = Value;
164                 break;
165         }
166 }
167
168 void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
169 {
170         switch(Ent->Type)
171         {
172         case SS_DATATYPE_INTEGER:
173         case SS_DATATYPE_REAL:
174                 break;
175         case SS_DATATYPE_OBJECT:
176                 if(Ent->Object) {
177                         Ent->Object->ReferenceCount --;
178                         if(Ent->Object->ReferenceCount == 0) {
179                                 Ent->Object->Type->Destructor( Ent->Object );
180                         }
181 //                      printf("Object %p derefed (obj refcount = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
182                 }
183                 Ent->Object = NULL;
184                 break;
185         default:
186                 if(Ent->Reference)
187                         SpiderScript_DereferenceValue(Ent->Reference);
188                 Ent->Reference = NULL;
189                 break;
190         }
191 }
192 void Bytecode_int_RefStackValue(tBC_StackEnt *Ent)
193 {
194         switch(Ent->Type)
195         {
196         case SS_DATATYPE_INTEGER:
197         case SS_DATATYPE_REAL:
198                 break;
199         case SS_DATATYPE_OBJECT:
200                 if(Ent->Object) {
201                         Ent->Object->ReferenceCount ++;
202 //                      printf("Object %p referenced (count = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
203                 }
204                 break;
205         default:
206                 if(Ent->Reference)
207                         SpiderScript_ReferenceValue(Ent->Reference);
208                 break;
209         }
210 }
211
212 void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent)
213 {
214         switch(Ent->Type)
215         {
216         case SS_DATATYPE_INTEGER:
217                 printf("0x%"PRIx64, Ent->Integer);
218                 break;
219         case SS_DATATYPE_REAL:
220                 printf("%lf", Ent->Real);
221                 break;
222         case SS_DATATYPE_OBJECT:
223                 printf("Obj %p", Ent->Object);
224                 break;
225         default:
226                 if( Ent->Reference )
227                         printf("*%p (%i refs)", Ent->Reference, Ent->Reference->ReferenceCount);
228                 else
229                         printf("NULL");
230                 break;
231         }
232 }
233
234 #if TRACE
235 # define PRINT_STACKVAL(val)    Bytecode_int_PrintStackValue(&val)
236 #else
237 # define PRINT_STACKVAL(val)
238 #endif
239
240 #define GET_STACKVAL(dst)       if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
241         AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
242         return ret; \
243 }
244 #define PUT_STACKVAL(src)       if((ret = Bytecode_int_StackPush(Stack, &src))) { \
245         AST_RuntimeError(NULL, "Stack push failed, full stack");\
246         return ret; \
247 }
248 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
249 #define OP_STRING(op_ptr)       ((op_ptr)->Content.StringInt.String)
250
251 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
252 {
253         const int       stack_size = 100;
254         tSpiderValue    *ret, tmpsval;
255         tBC_Stack       *stack;
256         tBC_StackEnt    val;
257          int    i;
258         
259         stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
260         stack->EntrySpace = stack_size;
261         stack->EntryCount = 0;
262
263         // Push arguments in order (so top is last arg)
264         for( i = 0; i < NArguments; i ++ )
265         {
266                 Bytecode_int_SetSpiderValue(&val, Args[i]);
267                 Bytecode_int_StackPush(stack, &val);
268         }
269
270         // Call
271         Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
272
273         // Get return value
274         if( Bytecode_int_StackPop(stack, &val) ) {
275                 free(stack);
276                 return NULL;
277         }
278         free(stack);
279         
280         ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
281         // Ensure it's a heap value
282         if(ret == &tmpsval) {
283                 ret = malloc(sizeof(tSpiderValue));
284                 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
285                 // Set to 2 in _GetSpiderValue, so stack doesn't have free() called
286                 ret->ReferenceCount = 1;
287         }
288
289         return ret;
290 }
291
292 tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
293 {
294         char    *pos;
295         tSpiderNamespace        *ns = Start;
296         while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
297         {
298                  int    len = pos - Name;
299                 for( ns = ns->FirstChild; ns; ns = ns->Next )
300                 {
301                         if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
302                         break;
303                 }
304                 if(!ns) {
305                         return NULL;
306                 }
307                 Name += len + 1;
308         }
309         if(FinalName)   *FinalName = Name;
310         return ns;
311 }
312
313 /**
314  * \brief Call an external function (may recurse into Bytecode_ExecuteFunction, but may not)
315  */
316 int Bytecode_int_CallExternFunction(tSpiderScript *Script, tBC_Stack *Stack, tSpiderNamespace *DefaultNS, tBC_Op *op )
317 {
318         const char      *name = OP_STRING(op);
319          int    arg_count = OP_INDX(op);
320          int    i, ret = 0;
321         tSpiderValue    *args[arg_count];
322         tSpiderValue    *rv;
323         tBC_StackEnt    val1;
324         const char      *namespaces[] = {NULL}; // TODO: Default/imported namespaces
325
326         DEBUG_F("CALL (general) %s %i args\n", name, arg_count);
327         
328         // Read arguments
329         for( i = arg_count; i --; )
330         {
331                 GET_STACKVAL(val1);
332                 args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
333                 Bytecode_int_DerefStackValue(&val1);
334         }
335         
336         // Call the function etc.
337         if( op->Operation == BC_OP_CALLFUNCTION )
338         {
339                 rv = SpiderScript_ExecuteFunction(Script, name, namespaces, arg_count, args, &op->CacheEnt);
340         }
341         else if( op->Operation == BC_OP_CREATEOBJ )
342         {
343                 rv = SpiderScript_CreateObject(Script, name, namespaces, arg_count, args);
344         }
345         else if( op->Operation == BC_OP_CALLMETHOD )
346         {
347                 tSpiderObject   *obj;
348                 GET_STACKVAL(val1);
349                 
350                 if(val1.Type == SS_DATATYPE_OBJECT)
351                         obj = val1.Object;
352                 else if(val1.Type == ET_REFERENCE && val1.Reference && val1.Reference->Type == SS_DATATYPE_OBJECT)
353                         obj = val1.Reference->Object;
354                 else {
355                         // Error
356                         AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
357                         return -1;
358                 }
359                 rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
360                 Bytecode_int_DerefStackValue(&val1);
361         }
362         else
363         {
364                 AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
365                 rv = ERRPTR;
366         }
367         if(rv == ERRPTR) {
368                 AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
369                 return -1;
370         }
371         // Clean up args
372         for( i = arg_count; i --; )
373                 SpiderScript_DereferenceValue(args[i]);
374         // Get and push return
375         Bytecode_int_SetSpiderValue(&val1, rv);
376         PUT_STACKVAL(val1);
377         // Deref return
378         SpiderScript_DereferenceValue(rv);
379
380         #if 0
381         if(!rv) {
382                 printf("%s returned NULL\n", name);
383         }
384         if( rv && rv != ERRPTR && rv->ReferenceCount != 1 ) {
385                 printf("Return value from %s reference count fail (%i)\n",
386                         name, rv->ReferenceCount);
387         }
388         #endif  
389
390         return 0;
391 }
392
393 int Bytecode_int_LocalBinOp_Integer(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
394 {
395         switch(Operation)
396         {
397         case BC_OP_ADD:         Val1->Integer = Val1->Integer + Val2->Integer;  break;
398         case BC_OP_SUBTRACT:    Val1->Integer = Val1->Integer - Val2->Integer;  break;
399         case BC_OP_MULTIPLY:    Val1->Integer = Val1->Integer * Val2->Integer;  break;
400         case BC_OP_DIVIDE:      Val1->Integer = Val1->Integer / Val2->Integer;  break;
401         
402         case BC_OP_EQUALS:              Val1->Integer = (Val1->Integer == Val2->Integer);       break;
403         case BC_OP_NOTEQUALS:           Val1->Integer = (Val1->Integer != Val2->Integer);       break;
404         case BC_OP_LESSTHAN:            Val1->Integer = (Val1->Integer <  Val2->Integer);       break;
405         case BC_OP_LESSTHANOREQUAL:     Val1->Integer = (Val1->Integer <= Val2->Integer);       break;
406         case BC_OP_GREATERTHAN:         Val1->Integer = (Val1->Integer >  Val2->Integer);       break;
407         case BC_OP_GREATERTHANOREQUAL:  Val1->Integer = (Val1->Integer >= Val2->Integer);       break;
408         
409         case BC_OP_BITAND:      Val1->Integer = Val1->Integer & Val2->Integer;  break;
410         case BC_OP_BITOR:       Val1->Integer = Val1->Integer | Val2->Integer;  break;
411         case BC_OP_BITXOR:      Val1->Integer = Val1->Integer ^ Val2->Integer;  break;
412         case BC_OP_MODULO:      Val1->Integer = Val1->Integer % Val2->Integer;  break;
413         default:        AST_RuntimeError(NULL, "Invalid operation on datatype Integer"); return -1;
414         }
415         return 0;
416 }
417
418 int Bytecode_int_LocalBinOp_Real(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
419 {
420         switch(Operation)
421         {
422         // Real = Real OP Real
423         case BC_OP_ADD:         Val1->Real = Val1->Real + Val2->Real;   return 0;
424         case BC_OP_SUBTRACT:    Val1->Real = Val1->Real - Val2->Real;   return 0;
425         case BC_OP_MULTIPLY:    Val1->Real = Val1->Real * Val2->Real;   return 0;
426         case BC_OP_DIVIDE:      Val1->Real = Val1->Real / Val2->Real;   return 0;
427
428         // Bool/Integer = Real OP Real
429         case BC_OP_EQUALS:              Val1->Integer = (Val1->Real == Val2->Real);     break;
430         case BC_OP_NOTEQUALS:           Val1->Integer = (Val1->Real != Val2->Real);     break;
431         case BC_OP_LESSTHAN:            Val1->Integer = (Val1->Real <  Val2->Real);     break;
432         case BC_OP_LESSTHANOREQUAL:     Val1->Integer = (Val1->Real <= Val2->Real);     break;
433         case BC_OP_GREATERTHAN:         Val1->Integer = (Val1->Real >  Val2->Real);     break;
434         case BC_OP_GREATERTHANOREQUAL:  Val1->Integer = (Val1->Real >= Val2->Real);     break;
435         
436         default:        AST_RuntimeError(NULL, "Invalid operation on datatype Real"); return -1;
437         }
438         Val1->Type = SS_DATATYPE_INTEGER;       // Becomes logical
439         return 0;
440 }
441
442 #define STATE_HDR()     DEBUG_F("%p %2i ", op, Stack->EntryCount)
443
444 /**
445  * \brief Execute a bytecode function with a stack
446  */
447 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
448 {
449          int    ret, ast_op, i;
450         tBC_Op  *op;
451         tBC_StackEnt    val1, val2;
452          int    local_var_count = Fcn->BCFcn->MaxVariableCount;
453         tBC_StackEnt    local_vars[local_var_count];    // Includes arguments
454         tSpiderValue    tmpVal1, tmpVal2;       // temp storage
455         tSpiderValue    *pval1, *pval2, *ret_val;
456         tSpiderNamespace        *default_namespace = &Script->Variant->RootNamespace;
457
458         // Initialise local vars
459         for( i = 0; i < local_var_count; i ++ )
460                 local_vars[i].Type = ET_NULL;
461         
462         // Pop off arguments
463         if( ArgCount > Fcn->ArgumentCount )     return -1;
464         DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
465         // - Handle optional arguments
466         for( i = Fcn->ArgumentCount; i > ArgCount; )
467         {
468                 i --;
469                 local_vars[i].Integer = 0;
470                 local_vars[i].Type = Fcn->Arguments[i].Type;
471         }
472         for( ; i --; )
473         {
474                 GET_STACKVAL(local_vars[i]);
475                 // TODO: Type checks / enforcing
476         }
477         
478         // Mark the start
479         memset(&val1, 0, sizeof(val1));
480         val1.Type = ET_FUNCTION_START;
481         PUT_STACKVAL(val1);
482
483         // Execute!
484         op = Fcn->BCFcn->Operations;
485         while(op)
486         {
487                 const char      *opstr = "";
488                 tBC_Op  *nextop = op->Next, *jmp_target;
489                 ast_op = 0;
490                 switch(op->Operation)
491                 {
492                 case BC_OP_NOP:
493                         STATE_HDR();
494                         DEBUG_F("NOP\n");
495                         break;
496                 // Jumps
497                 case BC_OP_JUMP:
498                         STATE_HDR();
499                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
500                         DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
501                         nextop = jmp_target;
502                         break;
503                 case BC_OP_JUMPIF:
504                         STATE_HDR();
505                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
506                         DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
507                         GET_STACKVAL(val1);
508                         if( Bytecode_int_IsStackEntTrue(&val1) )
509                                 nextop = jmp_target;
510                         break;
511                 case BC_OP_JUMPIFNOT:
512                         STATE_HDR();
513                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
514                         DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
515                         GET_STACKVAL(val1);
516                         if( !Bytecode_int_IsStackEntTrue(&val1) )
517                                 nextop = jmp_target;
518                         break;
519                 
520                 // Define variables
521                 case BC_OP_DEFINEVAR: {
522                          int    type, slot;
523                         type = OP_INDX(op) & 0xFFFF;
524                         slot = OP_INDX(op) >> 16;
525                         if(slot < 0 || slot >= local_var_count) {
526                                 DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
527                                 return -1;
528                         }
529                         STATE_HDR();
530                         DEBUG_F("DEFVAR %i of type %i\n", slot, type);
531                         if( local_vars[slot].Type != ET_NULL ) {
532                                 Bytecode_int_DerefStackValue( &local_vars[slot] );
533                                 local_vars[slot].Type = ET_NULL;
534                         }
535                         memset(&local_vars[slot], 0, sizeof(local_vars[0]));
536                         local_vars[slot].Type = type;
537                         } break;
538
539                 // Enter/Leave context
540                 // - NOP now            
541                 case BC_OP_ENTERCONTEXT:
542                         STATE_HDR();
543                         DEBUG_F("ENTERCONTEXT\n");
544                         break;
545                 case BC_OP_LEAVECONTEXT:
546                         STATE_HDR();
547                         DEBUG_F("LEAVECONTEXT\n");
548                         break;
549
550                 // Variables
551                 case BC_OP_LOADVAR: {
552                          int    slot = OP_INDX(op);
553                         STATE_HDR();
554                         DEBUG_F("LOADVAR %i ", slot);
555                         if( slot < 0 || slot >= local_var_count ) {
556                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
557                                 return -1;
558                         }
559                         DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n");
560                         PUT_STACKVAL(local_vars[slot]);
561                         Bytecode_int_RefStackValue( &local_vars[slot] );
562                         } break;
563                 case BC_OP_SAVEVAR: {
564                          int    slot = OP_INDX(op);
565                         STATE_HDR();
566                         DEBUG_F("SAVEVAR %i = ", slot);
567                         if( slot < 0 || slot >= local_var_count ) {
568                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
569                                 return -1;
570                         }
571                         // Remove whatever was in there before
572                         DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] ");
573                         Bytecode_int_DerefStackValue( &local_vars[slot] );
574                         // Place new in
575                         GET_STACKVAL(local_vars[slot]);
576                         PRINT_STACKVAL(local_vars[slot]);
577                         DEBUG_F("\n");
578                         } break;
579
580                 // Array index (get or set)
581                 case BC_OP_INDEX:
582                 case BC_OP_SETINDEX:
583                         STATE_HDR();
584                         GET_STACKVAL(val1);     // Index
585                         // TODO: Check that index is an integer
586                         if( val1.Type != SS_DATATYPE_INTEGER ) {
587                                 nextop = NULL;
588                                 break;
589                         }
590
591                         // Get array as raw spider value
592                         GET_STACKVAL(val2);     // Array
593                         pval1 = Bytecode_int_GetSpiderValue(&val2, &tmpVal1);
594                         Bytecode_int_DerefStackValue(&val2);
595
596                         if( op->Operation == BC_OP_SETINDEX ) {
597                                 GET_STACKVAL(val2);
598                                 pval2 = Bytecode_int_GetSpiderValue(&val2, NULL);
599                                 Bytecode_int_DerefStackValue(&val2);
600                                 
601                                 DEBUG_F("SETINDEX %i ", val1.Integer); PRINT_STACKVAL(val2); DEBUG_F("\n");
602                         
603                                 ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, pval2);
604                                 if(ret_val == ERRPTR) { nextop = NULL; break; }
605                                 SpiderScript_DereferenceValue(pval2);
606                         }
607                         else {
608                                 DEBUG_F("INDEX %i ", val1.Integer);
609                                 ret_val = AST_ExecuteNode_Index(Script, NULL, pval1, val1.Integer, ERRPTR);
610                                 if(ret_val == ERRPTR) { nextop = NULL; break; }
611                                 
612                                 Bytecode_int_SetSpiderValue(&val1, ret_val);
613                                 SpiderScript_DereferenceValue(ret_val);
614                                 PUT_STACKVAL(val1);
615
616                                 DEBUG_F("[Got "); PRINT_STACKVAL(val1); DEBUG_F("]\n");
617
618                         }
619                         // Dereference the array (or object, ...)
620                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
621                         break;
622                 
623                 // Object element (get or set)
624                 case BC_OP_ELEMENT:
625                 case BC_OP_SETELEMENT:
626                         STATE_HDR();
627                         
628                         GET_STACKVAL(val1);
629                         // - Integers/Reals can't have elements :)
630                         if( val1.Type != ET_REFERENCE ) {
631                                 nextop = NULL;
632                                 break;
633                         }
634
635                         pval1 = Bytecode_int_GetSpiderValue(&val1, NULL);
636                         Bytecode_int_DerefStackValue(&val1);
637
638                         if( op->Operation == BC_OP_SETELEMENT ) {
639                                 GET_STACKVAL(val2);
640                                 pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
641                                 Bytecode_int_DerefStackValue(&val2);
642                                 
643                                 DEBUG_F("SETELEMENT %s ", OP_STRING(op)); PRINT_STACKVAL(val2); DEBUG_F("\n");
644
645                                 ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), pval2);
646                                 if(ret_val == ERRPTR) { nextop = NULL; break; }
647                                 
648                                 if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
649                         }
650                         else {
651                                 DEBUG_F("ELEMENT %s ", OP_STRING(op));
652                                 
653                                 ret_val = AST_ExecuteNode_Element(Script, NULL, pval1, OP_STRING(op), ERRPTR);
654                                 if(ret_val == ERRPTR) { nextop = NULL; break; }
655
656                                 Bytecode_int_SetSpiderValue(&val2, ret_val);
657                                 SpiderScript_DereferenceValue(ret_val);
658                                 PUT_STACKVAL(val2);
659         
660                                 DEBUG_F("[Got "); PRINT_STACKVAL(val2); DEBUG_F("]\n");
661                         }
662                         
663                         SpiderScript_DereferenceValue(pval1);
664                         break;
665
666                 // Constants:
667                 case BC_OP_LOADINT:
668                         STATE_HDR();
669                         DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
670                         val1.Type = SS_DATATYPE_INTEGER;
671                         val1.Integer = op->Content.Integer;
672                         PUT_STACKVAL(val1);
673                         break;
674                 case BC_OP_LOADREAL:
675                         STATE_HDR();
676                         DEBUG_F("LOADREAL %lf\n", op->Content.Real);
677                         val1.Type = SS_DATATYPE_REAL;
678                         val1.Real = op->Content.Real;
679                         PUT_STACKVAL(val1);
680                         break;
681                 case BC_OP_LOADSTR:
682                         STATE_HDR();
683                         DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
684                         val1.Type = SS_DATATYPE_STRING;
685                         val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
686                         PUT_STACKVAL(val1);
687                         break;
688                 case BC_OP_LOADNULL:
689                         STATE_HDR();
690                         DEBUG_F("LOADNULL\n");
691                         val1.Type = ET_REFERENCE;
692                         val1.Reference = NULL;
693                         PUT_STACKVAL(val1);
694                         break;
695
696                 case BC_OP_CAST:
697                         STATE_HDR();
698                         val2.Type = OP_INDX(op);
699                         DEBUG_F("CAST to %i\n", val2.Type);
700                         GET_STACKVAL(val1);
701                         if(val1.Type == val2.Type) {
702                                 PUT_STACKVAL(val1);
703                                 break;
704                         }
705                         if( val2.Type == SS_DATATYPE_INTEGER && val1.Type == SS_DATATYPE_REAL ) {
706                                 val2.Integer = val1.Real;
707                         }
708                         else if( val2.Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_INTEGER ) {
709                                 val2.Real = val1.Integer;
710                         }
711                         else {
712                                 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
713                                 pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
714                                 
715                                 Bytecode_int_SetSpiderValue(&val2, pval2);
716                                 SpiderScript_DereferenceValue(pval2);
717                                 
718                                 if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
719                                 Bytecode_int_DerefStackValue(&val1);
720 //                              printf("CAST (%x->%x) - Original %i references remaining\n",
721 //                                      pval1->Type, OP_INDX(op),
722 //                                      pval1->ReferenceCount);
723                         }
724                         PUT_STACKVAL(val2);
725                         break;
726
727                 case BC_OP_DUPSTACK:
728                         STATE_HDR();
729                         DEBUG_F("DUPSTACK ");
730                         GET_STACKVAL(val1);
731                         PRINT_STACKVAL(val1);
732                         DEBUG_F("\n");
733                         PUT_STACKVAL(val1);
734                         PUT_STACKVAL(val1);
735                         Bytecode_int_RefStackValue(&val1);
736                         break;
737
738                 // Discard the top item from the stack
739                 case BC_OP_DELSTACK:
740                         STATE_HDR();
741                         DEBUG_F("DELSTACK\n");
742                         GET_STACKVAL(val1);
743                         break;
744
745                 // Unary Operations
746                 case BC_OP_LOGICNOT:
747                         STATE_HDR();
748                         DEBUG_F("LOGICNOT\n");
749                         
750                         GET_STACKVAL(val1);
751                         val2.Type = SS_DATATYPE_INTEGER;
752                         val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
753                         Bytecode_int_StackPush(Stack, &val2);
754                         Bytecode_int_DerefStackValue(&val1);
755                         break;
756                 
757                 case BC_OP_BITNOT:
758                         if(!ast_op)     ast_op = NODETYPE_BWNOT,        opstr = "BITNOT";
759                 case BC_OP_NEG:
760                         if(!ast_op)     ast_op = NODETYPE_NEGATE,       opstr = "NEG";
761
762                         STATE_HDR();
763                         DEBUG_F("%s\n", opstr);
764
765                         GET_STACKVAL(val1);
766                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
767                         Bytecode_int_DerefStackValue(&val1);                    
768
769                         ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
770                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
771                         Bytecode_int_SetSpiderValue(&val1, ret_val);
772                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
773                         Bytecode_int_StackPush(Stack, &val1);
774                         
775                         break;
776
777                 // Binary Operations
778                 case BC_OP_LOGICAND:
779                         if(!ast_op)     ast_op = NODETYPE_LOGICALAND,   opstr = "LOGICAND";
780                 case BC_OP_LOGICOR:
781                         if(!ast_op)     ast_op = NODETYPE_LOGICALOR,    opstr = "LOGICOR";
782                 case BC_OP_LOGICXOR:
783                         if(!ast_op)     ast_op = NODETYPE_LOGICALXOR,   opstr = "LOGICXOR";
784         
785                         STATE_HDR();
786                         DEBUG_F("%s\n", opstr);
787
788                         GET_STACKVAL(val1);
789                         GET_STACKVAL(val2);
790                         
791                         switch(op->Operation)
792                         {
793                         case BC_OP_LOGICAND:
794                                 i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
795                                 break;
796                         case BC_OP_LOGICOR:
797                                 i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
798                                 break;
799                         case BC_OP_LOGICXOR:
800                                 i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
801                                 break;
802                         }
803                         Bytecode_int_DerefStackValue(&val1);
804                         Bytecode_int_DerefStackValue(&val2);
805
806                         val1.Type = SS_DATATYPE_INTEGER;
807                         val1.Integer = i;
808                         Bytecode_int_StackPush(Stack, &val1);
809                         break;
810
811                 case BC_OP_BITAND:
812                         if(!ast_op)     ast_op = NODETYPE_BWAND,        opstr = "BITAND";
813                 case BC_OP_BITOR:
814                         if(!ast_op)     ast_op = NODETYPE_BWOR,         opstr = "BITOR";
815                 case BC_OP_BITXOR:
816                         if(!ast_op)     ast_op = NODETYPE_BWXOR,        opstr = "BITXOR";
817
818                 case BC_OP_BITSHIFTLEFT:
819                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
820                 case BC_OP_BITSHIFTRIGHT:
821                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
822                 case BC_OP_BITROTATELEFT:
823                         if(!ast_op)     ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
824
825                 case BC_OP_ADD:
826                         if(!ast_op)     ast_op = NODETYPE_ADD,  opstr = "ADD";
827                 case BC_OP_SUBTRACT:
828                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT,     opstr = "SUBTRACT";
829                 case BC_OP_MULTIPLY:
830                         if(!ast_op)     ast_op = NODETYPE_MULTIPLY,     opstr = "MULTIPLY";
831                 case BC_OP_DIVIDE:
832                         if(!ast_op)     ast_op = NODETYPE_DIVIDE,       opstr = "DIVIDE";
833                 case BC_OP_MODULO:
834                         if(!ast_op)     ast_op = NODETYPE_MODULO,       opstr = "MODULO";
835
836                 case BC_OP_EQUALS:
837                         if(!ast_op)     ast_op = NODETYPE_EQUALS,       opstr = "EQUALS";
838                 case BC_OP_NOTEQUALS:
839                         if(!ast_op)     ast_op = NODETYPE_NOTEQUALS,    opstr = "NOTEQUALS";
840                 case BC_OP_LESSTHAN:
841                         if(!ast_op)     ast_op = NODETYPE_LESSTHAN,     opstr = "LESSTHAN";
842                 case BC_OP_LESSTHANOREQUAL:
843                         if(!ast_op)     ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
844                 case BC_OP_GREATERTHAN:
845                         if(!ast_op)     ast_op = NODETYPE_GREATERTHAN,  opstr = "GREATERTHAN";
846                 case BC_OP_GREATERTHANOREQUAL:
847                         if(!ast_op)     ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
848
849                         STATE_HDR();
850                         DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
851
852                         GET_STACKVAL(val2);     // Right
853                         GET_STACKVAL(val1);     // Left
854
855                         DEBUG_F(" ("); PRINT_STACKVAL(val1); DEBUG_F(")");
856                         DEBUG_F(" ("); PRINT_STACKVAL(val2); DEBUG_F(")\n");
857
858                         // Perform integer operations locally
859                         if( val1.Type == SS_DATATYPE_INTEGER && val2.Type == SS_DATATYPE_INTEGER )
860                         {
861                                 if( Bytecode_int_LocalBinOp_Integer(op->Operation, &val1, &val2) ) {
862                                         nextop = NULL;
863                                         break;
864                                 }
865                                 PUT_STACKVAL(val1);
866                                 break;
867                         }
868
869                         if(val1. Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_REAL )
870                         {
871                                 if( Bytecode_int_LocalBinOp_Real(op->Operation, &val1, &val2) ) {
872                                         nextop = NULL;
873                                         break;
874                                 }
875                                 PUT_STACKVAL(val1);
876                                 break;
877                         }
878                 
879                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
880                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
881                         Bytecode_int_DerefStackValue(&val1);
882                         Bytecode_int_DerefStackValue(&val2);
883
884                         // Hand to AST execution code
885                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
886                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
887                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
888
889                         if(ret_val == ERRPTR) {
890                                 AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
891                                 nextop = NULL;
892                                 break;
893                         }
894                         Bytecode_int_SetSpiderValue(&val1, ret_val);
895                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
896                         PUT_STACKVAL(val1);
897                         break;
898
899                 // Functions etc
900                 case BC_OP_CREATEOBJ:
901                 case BC_OP_CALLFUNCTION:
902                 case BC_OP_CALLMETHOD:
903                         STATE_HDR();
904
905                         if( op->Operation == BC_OP_CALLFUNCTION )
906                         {
907                                 tScript_Function        *fcn = NULL;
908                                 const char      *name = OP_STRING(op);
909                                  int    arg_count = OP_INDX(op);
910                                 DEBUG_F("CALL (local) %s %i args\n", name, arg_count);
911                                 // Check current script functions (for fast call)
912                                 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
913                                 {
914                                         if(strcmp(name, fcn->Name) == 0) {
915                                                 break;
916                                         }
917                                 }
918                                 if(fcn && fcn->BCFcn)
919                                 {
920                                         DEBUG_F(" - Fast call\n");
921                                         Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
922                                         break;
923                                 }
924                         }
925                 
926                         // Slower call
927                         if( Bytecode_int_CallExternFunction( Script, Stack, default_namespace, op ) ) {
928                                 nextop = NULL;
929                                 break;
930                         }
931                         break;
932
933                 case BC_OP_RETURN:
934                         STATE_HDR();
935
936                         DEBUG_F("RETURN\n");
937                         nextop = NULL;
938                         break;
939
940                 default:
941                         // TODO:
942                         STATE_HDR();
943                         AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
944                         nextop = NULL;
945                         break;
946                 }
947                 op = nextop;
948         }
949         
950         // Clean up
951         // - Delete local vars
952         for( i = 0; i < local_var_count; i ++ )
953         {
954                 if( local_vars[i].Type != ET_NULL )
955                 {
956                         DEBUG_F("Var %i - ", i); 
957                         PRINT_STACKVAL(local_vars[i]);
958                         Bytecode_int_DerefStackValue(&local_vars[i]);
959                         DEBUG_F("\n");
960                 }
961                 else
962                         DEBUG_F("Var %i - empty\n", i);
963         }
964         
965         // - Restore stack
966         if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
967                 Stack->EntryCount --;
968         else
969         {
970                  int    n_rolled = 1;
971                 GET_STACKVAL(val1);
972                 while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
973                 {
974                         Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
975                         n_rolled ++;
976                 }
977                 PUT_STACKVAL(val1);
978                 DEBUG_F("Rolled back %i entries\n", n_rolled);
979         }
980         
981
982         return 0;
983 }
984

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