Kernel/armv7 - Task switching now supported
[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                 case BC_OP_BITNOT:
525                         if(!ast_op)     ast_op = NODETYPE_BWNOT;
526
527                         STATE_HDR();
528                         DEBUG_F("UNIOP %i\n", ast_op);
529
530                         GET_STACKVAL(val1);
531                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
532                         Bytecode_int_DerefStackValue(&val1);                    
533
534                         ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
535                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
536                         Bytecode_int_SetSpiderValue(&val1, ret_val);
537                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
538                         Bytecode_int_StackPush(Stack, &val1);
539                         
540                         break;
541
542                 // Binary Operations
543                 case BC_OP_LOGICAND:
544                         if(!ast_op)     ast_op = NODETYPE_LOGICALAND,   opstr = "LOGICAND";
545                 case BC_OP_LOGICOR:
546                         if(!ast_op)     ast_op = NODETYPE_LOGICALOR,    opstr = "LOGICOR";
547                 case BC_OP_LOGICXOR:
548                         if(!ast_op)     ast_op = NODETYPE_LOGICALXOR,   opstr = "LOGICXOR";
549         
550                         STATE_HDR();
551                         DEBUG_F("%s\n", opstr);
552
553                         GET_STACKVAL(val1);
554                         GET_STACKVAL(val2);
555                         
556                         switch(op->Operation)
557                         {
558                         case BC_OP_LOGICAND:
559                                 i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
560                                 break;
561                         case BC_OP_LOGICOR:
562                                 i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
563                                 break;
564                         case BC_OP_LOGICXOR:
565                                 i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
566                                 break;
567                         }
568                         Bytecode_int_DerefStackValue(&val1);
569                         Bytecode_int_DerefStackValue(&val2);
570
571                         val1.Type = SS_DATATYPE_INTEGER;
572                         val1.Integer = i;
573                         Bytecode_int_StackPush(Stack, &val1);
574                         break;
575
576                 case BC_OP_BITAND:
577                         if(!ast_op)     ast_op = NODETYPE_BWAND,        opstr = "BITAND";
578                 case BC_OP_BITOR:
579                         if(!ast_op)     ast_op = NODETYPE_BWOR,         opstr = "BITOR";
580                 case BC_OP_BITXOR:
581                         if(!ast_op)     ast_op = NODETYPE_BWXOR,        opstr = "BITXOR";
582
583                 case BC_OP_BITSHIFTLEFT:
584                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
585                 case BC_OP_BITSHIFTRIGHT:
586                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
587                 case BC_OP_BITROTATELEFT:
588                         if(!ast_op)     ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
589
590                 case BC_OP_ADD:
591                         if(!ast_op)     ast_op = NODETYPE_ADD,  opstr = "ADD";
592                 case BC_OP_SUBTRACT:
593                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT,     opstr = "SUBTRACT";
594                 case BC_OP_MULTIPLY:
595                         if(!ast_op)     ast_op = NODETYPE_MULTIPLY,     opstr = "MULTIPLY";
596                 case BC_OP_DIVIDE:
597                         if(!ast_op)     ast_op = NODETYPE_DIVIDE,       opstr = "DIVIDE";
598                 case BC_OP_MODULO:
599                         if(!ast_op)     ast_op = NODETYPE_MODULO,       opstr = "MODULO";
600
601                 case BC_OP_EQUALS:
602                         if(!ast_op)     ast_op = NODETYPE_EQUALS,       opstr = "EQUALS";
603                 case BC_OP_LESSTHAN:
604                         if(!ast_op)     ast_op = NODETYPE_LESSTHAN,     opstr = "LESSTHAN";
605                 case BC_OP_LESSTHANOREQUAL:
606                         if(!ast_op)     ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
607                 case BC_OP_GREATERTHAN:
608                         if(!ast_op)     ast_op = NODETYPE_GREATERTHAN,  opstr = "GREATERTHAN";
609                 case BC_OP_GREATERTHANOREQUAL:
610                         if(!ast_op)     ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
611
612                         STATE_HDR();
613                         DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
614
615                         GET_STACKVAL(val2);     // Right
616                         GET_STACKVAL(val1);     // Left
617
618                         #define PERFORM_NUM_OP(_type, _field) if(val1.Type == _type && val1.Type == val2.Type) { \
619                                 switch(op->Operation) { \
620                                 case BC_OP_ADD: val1._field = val1._field + val2._field;        break; \
621                                 case BC_OP_SUBTRACT:    val1._field = val1._field - val2._field;        break; \
622                                 case BC_OP_MULTIPLY:    val1._field = val1._field * val2._field;        break; \
623                                 case BC_OP_DIVIDE:      val1._field = val1._field / val2._field;        break; \
624                                 case BC_OP_EQUALS:      val1._field = val1._field == val2._field;       break; \
625                                 case BC_OP_LESSTHAN:    val1._field = val1._field < val2._field;        break; \
626                                 case BC_OP_LESSTHANOREQUAL:     val1._field = val1._field <= val2._field;       break; \
627                                 case BC_OP_GREATERTHAN: val1._field = val1._field > val2._field;        break; \
628                                 case BC_OP_GREATERTHANOREQUAL:  val1._field = val1._field >= val2._field;       break; \
629                                 \
630                                 case BC_OP_BITAND:      val1._field = (int64_t)val1._field & (int64_t)val2._field;      break; \
631                                 case BC_OP_BITOR:       val1._field = (int64_t)val1._field | (int64_t)val2._field;      break; \
632                                 case BC_OP_BITXOR:      val1._field = (int64_t)val1._field ^ (int64_t)val2._field;      break; \
633                                 case BC_OP_MODULO:      val1._field = (int64_t)val1._field % (int64_t)val2._field;      break; \
634                                 default:        AST_RuntimeError(NULL, "Invalid operation on datatype %i", _type); nextop = NULL; break;\
635                                 }\
636                                 PUT_STACKVAL(val1);\
637                                 break;\
638                         }
639
640                         PERFORM_NUM_OP(SS_DATATYPE_INTEGER, Integer);
641                         PERFORM_NUM_OP(SS_DATATYPE_REAL, Real);
642                 
643                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
644                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
645                         Bytecode_int_DerefStackValue(&val1);
646                         Bytecode_int_DerefStackValue(&val2);
647
648                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
649                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
650                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
651
652                         if(ret_val == ERRPTR) {
653                                 AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
654                                 nextop = NULL;
655                                 break;
656                         }
657                         Bytecode_int_SetSpiderValue(&val1, ret_val);
658                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
659                         PUT_STACKVAL(val1);
660                         break;
661
662                 // Functions etc
663                 case BC_OP_CREATEOBJ:
664                 case BC_OP_CALLFUNCTION:
665                 case BC_OP_CALLMETHOD: {
666                         tScript_Function        *fcn = NULL;
667                         const char      *name = OP_STRING(op);
668                          int    arg_count = OP_INDX(op);
669                         
670                         STATE_HDR();
671                         DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
672
673                         if( op->Operation == BC_OP_CALLFUNCTION )
674                         {
675                                 // Check current script functions (for fast call)
676                                 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
677                                 {
678                                         if(strcmp(name, fcn->Name) == 0) {
679                                                 break;
680                                         }
681                                 }
682                                 if(fcn && fcn->BCFcn)
683                                 {
684                                         DEBUG_F(" - Fast call\n");
685                                         Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
686                                         break;
687                                 }
688                         }
689                         
690                         // Slower call
691                         {
692                                 tSpiderNamespace        *ns = NULL;
693                                 tSpiderValue    *args[arg_count];
694                                 tSpiderValue    *rv;
695                                 // Read arguments
696                                 for( i = arg_count; i --; )
697                                 {
698                                         GET_STACKVAL(val1);
699                                         args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
700                                         Bytecode_int_DerefStackValue(&val1);
701                                 }
702                                 
703                                 // Resolve namespace into pointer
704                                 if( op->Operation != BC_OP_CALLMETHOD ) {
705                                         if( name[0] == BC_NS_SEPARATOR ) {
706                                                 name ++;
707                                                 ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
708                                         }
709                                         else {
710                                                 // TODO: Support multiple default namespaces
711                                                 ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
712                                         }
713                                 }
714                                 
715                                 // Call the function etc.
716                                 if( op->Operation == BC_OP_CALLFUNCTION )
717                                 {
718                                         rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
719                                 }
720                                 else if( op->Operation == BC_OP_CREATEOBJ )
721                                 {
722                                         rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args);
723                                 }
724                                 else if( op->Operation == BC_OP_CALLMETHOD )
725                                 {
726                                         tSpiderObject   *obj;
727                                         GET_STACKVAL(val1);
728                                         
729                                         if(val1.Type == SS_DATATYPE_OBJECT)
730                                                 obj = val1.Object;
731                                         else if(val1.Type == ET_REFERENCE && val1.Reference->Type == SS_DATATYPE_OBJECT)
732                                                 obj = val1.Reference->Object;
733                                         else {
734                                                 // Error
735                                                 AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
736                                                 nextop = NULL;
737                                                 break;
738                                         }
739                                         rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
740                                         Bytecode_int_DerefStackValue(&val1);
741                                 }
742                                 else
743                                 {
744                                         AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
745                                         rv = ERRPTR;
746                                 }
747                                 if(rv == ERRPTR) {
748                                         AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
749                                         nextop = NULL;
750                                         break;
751                                 }
752                                 // Clean up args
753                                 for( i = arg_count; i --; )
754                                         SpiderScript_DereferenceValue(args[i]);
755                                 // Get and push return
756                                 Bytecode_int_SetSpiderValue(&val1, rv);
757                                 PUT_STACKVAL(val1);
758                                 // Deref return
759                                 SpiderScript_DereferenceValue(rv);
760                         }
761                         } break;
762
763                 case BC_OP_RETURN:
764                         STATE_HDR();
765                         DEBUG_F("RETURN\n");
766                         nextop = NULL;
767                         break;
768
769                 default:
770                         // TODO:
771                         STATE_HDR();
772                         AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
773                         nextop = NULL;
774                         break;
775                 }
776                 op = nextop;
777         }
778         
779         // Clean up
780         // - Delete local vars
781         for( i = 0; i < local_var_count; i ++ )
782         {
783                 if( local_vars[i].Type != ET_NULL )
784                 {
785                         Bytecode_int_DerefStackValue(&local_vars[i]);
786                 }
787         }
788         
789         // - Restore stack
790 //      printf("TODO: Roll back stack\n");
791         if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
792                 Stack->EntryCount --;
793         else
794         {
795                 GET_STACKVAL(val1);
796                 while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
797                 {
798                         Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
799                 }
800                 PUT_STACKVAL(val1);
801         }
802         
803
804         return 0;
805 }
806

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