Usermode/libspiderscript - Fixing a multitude of bugs
[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                         tmp->ReferenceCount = 2;
109                 }
110                 break;
111         default:
112                 break;
113         }
114         switch(Ent->Type)
115         {
116         case SS_DATATYPE_INTEGER:
117                 tmp->Type = SS_DATATYPE_INTEGER;
118                 tmp->Integer = Ent->Integer;
119                 return tmp;
120         case SS_DATATYPE_REAL:
121                 tmp->Type = SS_DATATYPE_REAL;
122                 tmp->Real = Ent->Real;
123                 return tmp;
124         case SS_DATATYPE_OBJECT:
125                 tmp->Type = SS_DATATYPE_OBJECT;
126                 tmp->Object = Ent->Object;
127                 return tmp;
128         case ET_FUNCTION_START:
129                 AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
130                 return NULL;
131         default:
132                 SpiderScript_ReferenceValue(Ent->Reference);
133                 return Ent->Reference;
134         }
135 }
136
137 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
138 {
139         if(!Value) {
140                 Ent->Type = ET_REFERENCE;
141                 Ent->Reference = NULL;
142                 return ;
143         }
144         switch(Value->Type)
145         {
146         case SS_DATATYPE_INTEGER:
147                 Ent->Type = SS_DATATYPE_INTEGER;
148                 Ent->Integer = Value->Integer;
149                 break;
150         case SS_DATATYPE_REAL:
151                 Ent->Type = SS_DATATYPE_REAL;
152                 Ent->Real = Value->Real;
153                 break;
154         case SS_DATATYPE_OBJECT:
155                 Ent->Type = SS_DATATYPE_OBJECT;
156                 Ent->Object = Value->Object;
157                 Ent->Object->ReferenceCount ++;
158                 break;
159         default:
160                 SpiderScript_ReferenceValue(Value);
161                 Ent->Type = ET_REFERENCE;
162                 Ent->Reference = Value;
163                 break;
164         }
165 }
166
167 void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
168 {
169         switch(Ent->Type)
170         {
171         case SS_DATATYPE_INTEGER:
172         case SS_DATATYPE_REAL:
173                 break;
174         case SS_DATATYPE_OBJECT:
175                 if(Ent->Object) {
176                         Ent->Object->ReferenceCount --;
177                         if(Ent->Object->ReferenceCount == 0) {
178                                 Ent->Object->Type->Destructor( Ent->Object );
179                         }
180 //                      printf("Object %p derefed (obj refcount = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
181                 }
182                 Ent->Object = NULL;
183                 break;
184         default:
185                 if(Ent->Reference)
186                         SpiderScript_DereferenceValue(Ent->Reference);
187                 Ent->Reference = NULL;
188                 break;
189         }
190 }
191 void Bytecode_int_RefStackValue(tBC_StackEnt *Ent)
192 {
193         switch(Ent->Type)
194         {
195         case SS_DATATYPE_INTEGER:
196         case SS_DATATYPE_REAL:
197                 break;
198         case SS_DATATYPE_OBJECT:
199                 if(Ent->Object) {
200                         Ent->Object->ReferenceCount ++;
201 //                      printf("Object %p referenced (count = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
202                 }
203                 break;
204         default:
205                 if(Ent->Reference)
206                         SpiderScript_ReferenceValue(Ent->Reference);
207                 break;
208         }
209 }
210
211 void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent)
212 {
213         switch(Ent->Type)
214         {
215         case SS_DATATYPE_INTEGER:
216                 printf("0x%"PRIx64, Ent->Integer);
217                 break;
218         case SS_DATATYPE_REAL:
219                 printf("%lf", Ent->Real);
220                 break;
221         case SS_DATATYPE_OBJECT:
222                 printf("Obj %p", Ent->Object);
223                 break;
224         default:
225                 printf("*%p", Ent->Reference);
226                 break;
227         }
228 }
229
230 #if TRACE
231 # define PRINT_STACKVAL(val)    Bytecode_int_PrintStackValue(&val)
232 #else
233 # define PRINT_STACKVAL(val)
234 #endif
235
236 #define GET_STACKVAL(dst)       if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
237         AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
238         return ret; \
239 }
240 #define PUT_STACKVAL(src)       if((ret = Bytecode_int_StackPush(Stack, &src))) { \
241         AST_RuntimeError(NULL, "Stack push failed, full stack");\
242         return ret; \
243 }
244 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
245 #define OP_STRING(op_ptr)       ((op_ptr)->Content.StringInt.String)
246
247 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
248 {
249         const int       stack_size = 100;
250         tSpiderValue    *ret, tmpsval;
251         tBC_Stack       *stack;
252         tBC_StackEnt    val;
253          int    i;
254         
255         stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
256         stack->EntrySpace = stack_size;
257         stack->EntryCount = 0;
258
259         // Push arguments in order (so top is last arg)
260         for( i = 0; i < NArguments; i ++ )
261         {
262                 Bytecode_int_SetSpiderValue(&val, Args[i]);
263                 Bytecode_int_StackPush(stack, &val);
264         }
265
266         // Call
267         Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
268
269         // Get return value
270         if( Bytecode_int_StackPop(stack, &val) ) {
271                 free(stack);
272                 return NULL;
273         }
274         free(stack);
275         ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
276         // Ensure it's a heap value
277         if(ret == &tmpsval) {
278                 ret = malloc(sizeof(tSpiderValue));
279                 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
280         }
281
282         return ret;
283 }
284
285 tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
286 {
287         char    *pos;
288         tSpiderNamespace        *ns = Start;
289         while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
290         {
291                  int    len = pos - Name;
292                 for( ns = ns->FirstChild; ns; ns = ns->Next )
293                 {
294                         if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
295                         break;
296                 }
297                 if(!ns) {
298                         return NULL;
299                 }
300                 Name += len + 1;
301         }
302         if(FinalName)   *FinalName = Name;
303         return ns;
304 }
305
306 #define STATE_HDR()     DEBUG_F("%p %2i ", op, Stack->EntryCount)
307
308 /**
309  * \brief Execute a bytecode function with a stack
310  */
311 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
312 {
313          int    ret, ast_op, i;
314         tBC_Op  *op;
315         tBC_StackEnt    val1, val2;
316          int    local_var_count = Fcn->BCFcn->MaxVariableCount;
317         tBC_StackEnt    local_vars[local_var_count];    // Includes arguments
318         tSpiderValue    tmpVal1, tmpVal2;       // temp storage
319         tSpiderValue    *pval1, *pval2, *ret_val;
320         tSpiderNamespace        *default_namespace = &Script->Variant->RootNamespace;
321
322         // Initialise local vars
323         for( i = 0; i < local_var_count; i ++ )
324                 local_vars[i].Type = ET_NULL;
325         
326         // Pop off arguments
327         if( ArgCount > Fcn->ArgumentCount )     return -1;
328         DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
329         for( i = Fcn->ArgumentCount; i > ArgCount; )
330         {
331                 i --;
332                 local_vars[i].Integer = 0;
333                 local_vars[i].Type = Fcn->Arguments[i].Type;
334         }
335         for( ; i --; )
336         {
337                 GET_STACKVAL(local_vars[i]);
338                 // TODO: Type checks / enforcing
339         }
340         
341         // Mark the start
342         memset(&val1, 0, sizeof(val1));
343         val1.Type = ET_FUNCTION_START;
344         PUT_STACKVAL(val1);
345
346         // Execute!
347         op = Fcn->BCFcn->Operations;
348         while(op)
349         {
350                 const char      *opstr = "";
351                 tBC_Op  *nextop = op->Next, *jmp_target;
352                 ast_op = 0;
353                 switch(op->Operation)
354                 {
355                 case BC_OP_NOP:
356                         STATE_HDR();
357                         DEBUG_F("NOP\n");
358                         break;
359                 // Jumps
360                 case BC_OP_JUMP:
361                         STATE_HDR();
362                         // NOTE: Evil, all jumps are off by -1, so fix that
363                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
364                         DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
365                         nextop = jmp_target;
366                         break;
367                 case BC_OP_JUMPIF:
368                         STATE_HDR();
369                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
370                         DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
371                         GET_STACKVAL(val1);
372                         if( Bytecode_int_IsStackEntTrue(&val1) )
373                                 nextop = jmp_target;
374                         break;
375                 case BC_OP_JUMPIFNOT:
376                         STATE_HDR();
377                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
378                         DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
379                         GET_STACKVAL(val1);
380                         if( !Bytecode_int_IsStackEntTrue(&val1) )
381                                 nextop = jmp_target;
382                         break;
383                 
384                 // Define variables
385                 case BC_OP_DEFINEVAR: {
386                          int    type, slot;
387                         type = OP_INDX(op) & 0xFFFF;
388                         slot = OP_INDX(op) >> 16;
389                         if(slot < 0 || slot >= local_var_count) {
390                                 DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
391                                 return -1;
392                         }
393                         STATE_HDR();
394                         DEBUG_F("DEFVAR %i of type %i\n", slot, type);
395                         if( local_vars[slot].Type != ET_NULL ) {
396                                 Bytecode_int_DerefStackValue( &local_vars[slot] );
397                                 local_vars[slot].Type = ET_NULL;
398                         }
399                         memset(&local_vars[slot], 0, sizeof(local_vars[0]));
400                         local_vars[slot].Type = type;
401                         } break;
402
403                 // Enter/Leave context
404                 // - NOP now            
405                 case BC_OP_ENTERCONTEXT:
406                         STATE_HDR();
407                         DEBUG_F("ENTERCONTEXT\n");
408                         break;
409                 case BC_OP_LEAVECONTEXT:
410                         STATE_HDR();
411                         DEBUG_F("LEAVECONTEXT\n");
412                         break;
413
414                 // Variables
415                 case BC_OP_LOADVAR: {
416                          int    slot = OP_INDX(op);
417                         STATE_HDR();
418                         DEBUG_F("LOADVAR %i ", slot);
419                         if( slot < 0 || slot >= local_var_count ) {
420                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
421                                 return -1;
422                         }
423                         DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n");
424                         PUT_STACKVAL(local_vars[slot]);
425                         Bytecode_int_RefStackValue( &local_vars[slot] );
426                         } break;
427                 case BC_OP_SAVEVAR: {
428                          int    slot = OP_INDX(op);
429                         STATE_HDR();
430                         DEBUG_F("SAVEVAR %i = ", slot);
431                         if( slot < 0 || slot >= local_var_count ) {
432                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
433                                 return -1;
434                         }
435                         DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] ");
436                         Bytecode_int_DerefStackValue( &local_vars[slot] );
437                         GET_STACKVAL(local_vars[slot]);
438                         PRINT_STACKVAL(local_vars[slot]);
439                         DEBUG_F("\n");
440                         } break;
441
442                 // Constants:
443                 case BC_OP_LOADINT:
444                         STATE_HDR();
445                         DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
446                         val1.Type = SS_DATATYPE_INTEGER;
447                         val1.Integer = op->Content.Integer;
448                         PUT_STACKVAL(val1);
449                         break;
450                 case BC_OP_LOADREAL:
451                         STATE_HDR();
452                         DEBUG_F("LOADREAL %lf\n", op->Content.Real);
453                         val1.Type = SS_DATATYPE_REAL;
454                         val1.Real = op->Content.Real;
455                         PUT_STACKVAL(val1);
456                         break;
457                 case BC_OP_LOADSTR:
458                         STATE_HDR();
459                         DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
460                         val1.Type = SS_DATATYPE_STRING;
461                         val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
462                         PUT_STACKVAL(val1);
463                         break;
464
465                 case BC_OP_CAST:
466                         STATE_HDR();
467                         val2.Type = OP_INDX(op);
468                         DEBUG_F("CAST to %i\n", val2.Type);
469                         GET_STACKVAL(val1);
470                         if(val1.Type == val2.Type) {
471                                 PUT_STACKVAL(val1);
472                                 break;
473                         }
474                         switch(val2.Type * 100 + val1.Type )
475                         {
476                         case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
477                                 val2.Integer = val1.Real;
478                                 PUT_STACKVAL(val2);
479                                 break;
480                         case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
481                                 val2.Real = val1.Integer;
482                                 PUT_STACKVAL(val2);
483                                 break;
484                         default: {
485                                 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
486                                 pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
487                                 if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
488                                 Bytecode_int_SetSpiderValue(&val2, pval2);
489                                 SpiderScript_DereferenceValue(pval2);
490                                 PUT_STACKVAL(val2);
491                                 } break;
492                         }
493                         break;
494
495                 case BC_OP_DUPSTACK:
496                         STATE_HDR();
497                         DEBUG_F("DUPSTACK ");
498                         GET_STACKVAL(val1);
499                         PRINT_STACKVAL(val1);
500                         DEBUG_F("\n");
501                         PUT_STACKVAL(val1);
502                         PUT_STACKVAL(val1);
503                         Bytecode_int_RefStackValue(&val1);
504                         break;
505
506                 // Discard the top item from the stack
507                 case BC_OP_DELSTACK:
508                         STATE_HDR();
509                         DEBUG_F("DELSTACK\n");
510                         GET_STACKVAL(val1);
511                         break;
512
513                 // Unary Operations
514                 case BC_OP_LOGICNOT:
515                         STATE_HDR();
516                         DEBUG_F("LOGICNOT\n");
517                         
518                         GET_STACKVAL(val1);
519                         val2.Type = SS_DATATYPE_INTEGER;
520                         val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
521                         Bytecode_int_StackPush(Stack, &val2);
522                         Bytecode_int_DerefStackValue(&val1);
523                         break;
524                 
525                 case BC_OP_BITNOT:
526                         if(!ast_op)     ast_op = NODETYPE_BWNOT,        opstr = "BITNOT";
527                 case BC_OP_NEG:
528                         if(!ast_op)     ast_op = NODETYPE_NEGATE,       opstr = "NEG";
529
530                         STATE_HDR();
531                         DEBUG_F("%s\n", opstr);
532
533                         GET_STACKVAL(val1);
534                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
535                         Bytecode_int_DerefStackValue(&val1);                    
536
537                         ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
538                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
539                         Bytecode_int_SetSpiderValue(&val1, ret_val);
540                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
541                         Bytecode_int_StackPush(Stack, &val1);
542                         
543                         break;
544
545                 // Binary Operations
546                 case BC_OP_LOGICAND:
547                         if(!ast_op)     ast_op = NODETYPE_LOGICALAND,   opstr = "LOGICAND";
548                 case BC_OP_LOGICOR:
549                         if(!ast_op)     ast_op = NODETYPE_LOGICALOR,    opstr = "LOGICOR";
550                 case BC_OP_LOGICXOR:
551                         if(!ast_op)     ast_op = NODETYPE_LOGICALXOR,   opstr = "LOGICXOR";
552         
553                         STATE_HDR();
554                         DEBUG_F("%s\n", opstr);
555
556                         GET_STACKVAL(val1);
557                         GET_STACKVAL(val2);
558                         
559                         switch(op->Operation)
560                         {
561                         case BC_OP_LOGICAND:
562                                 i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
563                                 break;
564                         case BC_OP_LOGICOR:
565                                 i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
566                                 break;
567                         case BC_OP_LOGICXOR:
568                                 i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
569                                 break;
570                         }
571                         Bytecode_int_DerefStackValue(&val1);
572                         Bytecode_int_DerefStackValue(&val2);
573
574                         val1.Type = SS_DATATYPE_INTEGER;
575                         val1.Integer = i;
576                         Bytecode_int_StackPush(Stack, &val1);
577                         break;
578
579                 case BC_OP_BITAND:
580                         if(!ast_op)     ast_op = NODETYPE_BWAND,        opstr = "BITAND";
581                 case BC_OP_BITOR:
582                         if(!ast_op)     ast_op = NODETYPE_BWOR,         opstr = "BITOR";
583                 case BC_OP_BITXOR:
584                         if(!ast_op)     ast_op = NODETYPE_BWXOR,        opstr = "BITXOR";
585
586                 case BC_OP_BITSHIFTLEFT:
587                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
588                 case BC_OP_BITSHIFTRIGHT:
589                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
590                 case BC_OP_BITROTATELEFT:
591                         if(!ast_op)     ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
592
593                 case BC_OP_ADD:
594                         if(!ast_op)     ast_op = NODETYPE_ADD,  opstr = "ADD";
595                 case BC_OP_SUBTRACT:
596                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT,     opstr = "SUBTRACT";
597                 case BC_OP_MULTIPLY:
598                         if(!ast_op)     ast_op = NODETYPE_MULTIPLY,     opstr = "MULTIPLY";
599                 case BC_OP_DIVIDE:
600                         if(!ast_op)     ast_op = NODETYPE_DIVIDE,       opstr = "DIVIDE";
601                 case BC_OP_MODULO:
602                         if(!ast_op)     ast_op = NODETYPE_MODULO,       opstr = "MODULO";
603
604                 case BC_OP_EQUALS:
605                         if(!ast_op)     ast_op = NODETYPE_EQUALS,       opstr = "EQUALS";
606                 case BC_OP_NOTEQUALS:
607                         if(!ast_op)     ast_op = NODETYPE_NOTEQUALS,    opstr = "NOTEQUALS";
608                 case BC_OP_LESSTHAN:
609                         if(!ast_op)     ast_op = NODETYPE_LESSTHAN,     opstr = "LESSTHAN";
610                 case BC_OP_LESSTHANOREQUAL:
611                         if(!ast_op)     ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
612                 case BC_OP_GREATERTHAN:
613                         if(!ast_op)     ast_op = NODETYPE_GREATERTHAN,  opstr = "GREATERTHAN";
614                 case BC_OP_GREATERTHANOREQUAL:
615                         if(!ast_op)     ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
616
617                         STATE_HDR();
618                         DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
619
620                         GET_STACKVAL(val2);     // Right
621                         GET_STACKVAL(val1);     // Left
622
623                         DEBUG_F(" ("); PRINT_STACKVAL(val1); DEBUG_F(")");
624                         DEBUG_F(" ("); PRINT_STACKVAL(val2); DEBUG_F(")\n");
625
626                         #define PERFORM_NUM_OP(_type, _field) if(val1.Type == _type && val1.Type == val2.Type) { \
627                                 switch(op->Operation) { \
628                                 case BC_OP_ADD: val1._field = val1._field + val2._field;        break; \
629                                 case BC_OP_SUBTRACT:    val1._field = val1._field - val2._field;        break; \
630                                 case BC_OP_MULTIPLY:    val1._field = val1._field * val2._field;        break; \
631                                 case BC_OP_DIVIDE:      val1._field = val1._field / val2._field;        break; \
632                                 \
633                                 case BC_OP_EQUALS:      val1.Type=SS_DATATYPE_INTEGER; val1.Integer = (val1._field == val2._field);     break; \
634                                 case BC_OP_NOTEQUALS:   val1.Type=SS_DATATYPE_INTEGER; val1.Integer = (val1._field != val2._field);     break; \
635                                 case BC_OP_LESSTHAN:    val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field < val2._field;        break; \
636                                 case BC_OP_LESSTHANOREQUAL:     val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field <= val2._field;       break; \
637                                 case BC_OP_GREATERTHAN: val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field > val2._field;        break; \
638                                 case BC_OP_GREATERTHANOREQUAL:  val1.Type=SS_DATATYPE_INTEGER; val1.Integer = val1._field >= val2._field;       break; \
639                                 \
640                                 case BC_OP_BITAND:      val1._field = (int64_t)val1._field & (int64_t)val2._field;      break; \
641                                 case BC_OP_BITOR:       val1._field = (int64_t)val1._field | (int64_t)val2._field;      break; \
642                                 case BC_OP_BITXOR:      val1._field = (int64_t)val1._field ^ (int64_t)val2._field;      break; \
643                                 case BC_OP_MODULO:      val1._field = (int64_t)val1._field % (int64_t)val2._field;      break; \
644                                 default:        AST_RuntimeError(NULL, "Invalid operation on datatype %i", _type); nextop = NULL; break;\
645                                 }\
646                                 DEBUG_F(" - Fast local op\n");\
647                                 PUT_STACKVAL(val1);\
648                                 break;\
649                         }
650
651                         PERFORM_NUM_OP(SS_DATATYPE_INTEGER, Integer);
652                         PERFORM_NUM_OP(SS_DATATYPE_REAL, Real);
653                 
654                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
655                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
656                         Bytecode_int_DerefStackValue(&val1);
657                         Bytecode_int_DerefStackValue(&val2);
658
659                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
660                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
661                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
662
663                         if(ret_val == ERRPTR) {
664                                 AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
665                                 nextop = NULL;
666                                 break;
667                         }
668                         Bytecode_int_SetSpiderValue(&val1, ret_val);
669                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
670                         PUT_STACKVAL(val1);
671                         break;
672
673                 // Functions etc
674                 case BC_OP_CREATEOBJ:
675                 case BC_OP_CALLFUNCTION:
676                 case BC_OP_CALLMETHOD: {
677                         tScript_Function        *fcn = NULL;
678                         const char      *name = OP_STRING(op);
679                          int    arg_count = OP_INDX(op);
680                         
681                         STATE_HDR();
682                         DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
683
684                         if( op->Operation == BC_OP_CALLFUNCTION )
685                         {
686                                 // Check current script functions (for fast call)
687                                 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
688                                 {
689                                         if(strcmp(name, fcn->Name) == 0) {
690                                                 break;
691                                         }
692                                 }
693                                 if(fcn && fcn->BCFcn)
694                                 {
695                                         DEBUG_F(" - Fast call\n");
696                                         Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
697                                         break;
698                                 }
699                         }
700                         
701                         // Slower call
702                         {
703                                 tSpiderNamespace        *ns = NULL;
704                                 tSpiderValue    *args[arg_count];
705                                 tSpiderValue    *rv;
706                                 // Read arguments
707                                 for( i = arg_count; i --; )
708                                 {
709                                         GET_STACKVAL(val1);
710                                         args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
711                                         Bytecode_int_DerefStackValue(&val1);
712                                 }
713                                 
714                                 // Resolve namespace into pointer
715                                 if( op->Operation != BC_OP_CALLMETHOD ) {
716                                         if( name[0] == BC_NS_SEPARATOR ) {
717                                                 name ++;
718                                                 ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
719                                         }
720                                         else {
721                                                 // TODO: Support multiple default namespaces
722                                                 ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
723                                         }
724                                 }
725                                 
726                                 // Call the function etc.
727                                 if( op->Operation == BC_OP_CALLFUNCTION )
728                                 {
729                                         rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
730                                 }
731                                 else if( op->Operation == BC_OP_CREATEOBJ )
732                                 {
733                                         rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args);
734                                 }
735                                 else if( op->Operation == BC_OP_CALLMETHOD )
736                                 {
737                                         tSpiderObject   *obj;
738                                         GET_STACKVAL(val1);
739                                         
740                                         if(val1.Type == SS_DATATYPE_OBJECT)
741                                                 obj = val1.Object;
742                                         else if(val1.Type == ET_REFERENCE && val1.Reference && val1.Reference->Type == SS_DATATYPE_OBJECT)
743                                                 obj = val1.Reference->Object;
744                                         else {
745                                                 // Error
746                                                 AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
747                                                 nextop = NULL;
748                                                 break;
749                                         }
750                                         rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
751                                         Bytecode_int_DerefStackValue(&val1);
752                                 }
753                                 else
754                                 {
755                                         AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
756                                         rv = ERRPTR;
757                                 }
758                                 if(rv == ERRPTR) {
759                                         AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
760                                         nextop = NULL;
761                                         break;
762                                 }
763                                 // Clean up args
764                                 for( i = arg_count; i --; )
765                                         SpiderScript_DereferenceValue(args[i]);
766                                 // Get and push return
767                                 Bytecode_int_SetSpiderValue(&val1, rv);
768                                 PUT_STACKVAL(val1);
769                                 // Deref return
770                                 SpiderScript_DereferenceValue(rv);
771                         }
772                         } break;
773
774                 case BC_OP_RETURN:
775                         STATE_HDR();
776                         DEBUG_F("RETURN\n");
777                         nextop = NULL;
778                         break;
779
780                 default:
781                         // TODO:
782                         STATE_HDR();
783                         AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
784                         nextop = NULL;
785                         break;
786                 }
787                 op = nextop;
788         }
789         
790         // Clean up
791         // - Delete local vars
792         for( i = 0; i < local_var_count; i ++ )
793         {
794                 if( local_vars[i].Type != ET_NULL )
795                 {
796                         Bytecode_int_DerefStackValue(&local_vars[i]);
797                 }
798         }
799         
800         // - Restore stack
801 //      printf("TODO: Roll back stack\n");
802         if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
803                 Stack->EntryCount --;
804         else
805         {
806                 GET_STACKVAL(val1);
807                 while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
808                 {
809                         Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
810                 }
811                 PUT_STACKVAL(val1);
812         }
813         
814
815         return 0;
816 }
817

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