SpiderScript - Fixes, SpiderWeb's print_test.sw works
[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                 uint64_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                         STATE_HDR();
417                         DEBUG_F("LOADVAR %i ", OP_INDX(op));
418                         if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
419                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
420                                 return -1;
421                         }
422                         DEBUG_F("("); PRINT_STACKVAL(local_vars[OP_INDX(op)]); DEBUG_F(")\n");
423                         PUT_STACKVAL(local_vars[OP_INDX(op)]);
424                         Bytecode_int_RefStackValue( &local_vars[OP_INDX(op)] );
425                         break;
426                 case BC_OP_SAVEVAR:
427                         STATE_HDR();
428                         DEBUG_F("SAVEVAR %i = ", OP_INDX(op));
429                         if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
430                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
431                                 return -1;
432                         }
433                         DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[OP_INDX(op)]); DEBUG_F("] ");
434                         Bytecode_int_DerefStackValue( &local_vars[OP_INDX(op)] );
435                         GET_STACKVAL(local_vars[OP_INDX(op)]);
436                         PRINT_STACKVAL(local_vars[OP_INDX(op)]);
437                         DEBUG_F("\n");
438                         break;
439
440                 // Constants:
441                 case BC_OP_LOADINT:
442                         STATE_HDR();
443                         DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
444                         val1.Type = SS_DATATYPE_INTEGER;
445                         val1.Integer = op->Content.Integer;
446                         PUT_STACKVAL(val1);
447                         break;
448                 case BC_OP_LOADREAL:
449                         STATE_HDR();
450                         DEBUG_F("LOADREAL %lf\n", op->Content.Real);
451                         val1.Type = SS_DATATYPE_REAL;
452                         val1.Real = op->Content.Real;
453                         PUT_STACKVAL(val1);
454                         break;
455                 case BC_OP_LOADSTR:
456                         STATE_HDR();
457                         DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
458                         val1.Type = SS_DATATYPE_STRING;
459                         val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
460                         PUT_STACKVAL(val1);
461                         break;
462
463                 case BC_OP_CAST:
464                         STATE_HDR();
465                         val2.Type = OP_INDX(op);
466                         DEBUG_F("CAST to %i\n", val2.Type);
467                         GET_STACKVAL(val1);
468                         if(val1.Type == val2.Type) {
469                                 PUT_STACKVAL(val1);
470                                 break;
471                         }
472                         switch(val2.Type * 100 + val1.Type )
473                         {
474                         case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
475                                 val2.Integer = val1.Real;
476                                 PUT_STACKVAL(val2);
477                                 break;
478                         case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
479                                 val2.Real = val1.Integer;
480                                 PUT_STACKVAL(val2);
481                                 break;
482                         default: {
483                                 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
484                                 pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
485                                 if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
486                                 Bytecode_int_SetSpiderValue(&val2, pval2);
487                                 SpiderScript_DereferenceValue(pval2);
488                                 PUT_STACKVAL(val2);
489                                 } break;
490                         }
491                         break;
492
493                 case BC_OP_DUPSTACK:
494                         STATE_HDR();
495                         DEBUG_F("DUPSTACK ");
496                         GET_STACKVAL(val1);
497                         PRINT_STACKVAL(val1);
498                         DEBUG_F("\n");
499                         PUT_STACKVAL(val1);
500                         PUT_STACKVAL(val1);
501                         Bytecode_int_RefStackValue(&val1);
502                         break;
503
504                 // Discard the top item from the stack
505                 case BC_OP_DELSTACK:
506                         STATE_HDR();
507                         DEBUG_F("DELSTACK\n");
508                         GET_STACKVAL(val1);
509                         break;
510
511                 // Unary Operations
512                 case BC_OP_LOGICNOT:
513                         STATE_HDR();
514                         DEBUG_F("LOGICNOT\n");
515                         
516                         GET_STACKVAL(val1);
517                         val2.Type = SS_DATATYPE_INTEGER;
518                         val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
519                         Bytecode_int_StackPush(Stack, &val2);
520                         Bytecode_int_DerefStackValue(&val1);
521                         break;
522                 case BC_OP_BITNOT:
523                         if(!ast_op)     ast_op = NODETYPE_BWNOT;
524
525                         STATE_HDR();
526                         DEBUG_F("UNIOP %i\n", ast_op);
527
528                         GET_STACKVAL(val1);
529                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
530                         Bytecode_int_DerefStackValue(&val1);                    
531
532                         ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
533                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
534                         Bytecode_int_SetSpiderValue(&val1, ret_val);
535                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
536                         Bytecode_int_StackPush(Stack, &val1);
537                         
538                         break;
539
540                 // Binary Operations
541                 case BC_OP_LOGICAND:
542                         if(!ast_op)     ast_op = NODETYPE_LOGICALAND,   opstr = "LOGICAND";
543                 case BC_OP_LOGICOR:
544                         if(!ast_op)     ast_op = NODETYPE_LOGICALOR,    opstr = "LOGICOR";
545                 case BC_OP_LOGICXOR:
546                         if(!ast_op)     ast_op = NODETYPE_LOGICALXOR,   opstr = "LOGICXOR";
547         
548                         STATE_HDR();
549                         DEBUG_F("%s\n", opstr);
550
551                         GET_STACKVAL(val1);
552                         GET_STACKVAL(val2);
553                         
554                         switch(op->Operation)
555                         {
556                         case BC_OP_LOGICAND:
557                                 i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
558                                 break;
559                         case BC_OP_LOGICOR:
560                                 i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
561                                 break;
562                         case BC_OP_LOGICXOR:
563                                 i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
564                                 break;
565                         }
566                         Bytecode_int_DerefStackValue(&val1);
567                         Bytecode_int_DerefStackValue(&val2);
568
569                         val1.Type = SS_DATATYPE_INTEGER;
570                         val1.Integer = i;
571                         Bytecode_int_StackPush(Stack, &val1);
572                         break;
573
574                 case BC_OP_BITAND:
575                         if(!ast_op)     ast_op = NODETYPE_BWAND,        opstr = "BITAND";
576                 case BC_OP_BITOR:
577                         if(!ast_op)     ast_op = NODETYPE_BWOR,         opstr = "BITOR";
578                 case BC_OP_BITXOR:
579                         if(!ast_op)     ast_op = NODETYPE_BWXOR,        opstr = "BITXOR";
580
581                 case BC_OP_BITSHIFTLEFT:
582                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
583                 case BC_OP_BITSHIFTRIGHT:
584                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
585                 case BC_OP_BITROTATELEFT:
586                         if(!ast_op)     ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
587
588                 case BC_OP_ADD:
589                         if(!ast_op)     ast_op = NODETYPE_ADD,  opstr = "ADD";
590                 case BC_OP_SUBTRACT:
591                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT,     opstr = "SUBTRACT";
592                 case BC_OP_MULTIPLY:
593                         if(!ast_op)     ast_op = NODETYPE_MULTIPLY,     opstr = "MULTIPLY";
594                 case BC_OP_DIVIDE:
595                         if(!ast_op)     ast_op = NODETYPE_DIVIDE,       opstr = "DIVIDE";
596                 case BC_OP_MODULO:
597                         if(!ast_op)     ast_op = NODETYPE_MODULO,       opstr = "MODULO";
598
599                 case BC_OP_EQUALS:
600                         if(!ast_op)     ast_op = NODETYPE_EQUALS,       opstr = "EQUALS";
601                 case BC_OP_LESSTHAN:
602                         if(!ast_op)     ast_op = NODETYPE_LESSTHAN,     opstr = "LESSTHAN";
603                 case BC_OP_LESSTHANOREQUAL:
604                         if(!ast_op)     ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
605                 case BC_OP_GREATERTHAN:
606                         if(!ast_op)     ast_op = NODETYPE_GREATERTHAN,  opstr = "GREATERTHAN";
607                 case BC_OP_GREATERTHANOREQUAL:
608                         if(!ast_op)     ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
609
610                         STATE_HDR();
611                         DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
612
613                         GET_STACKVAL(val2);     // Right
614                         GET_STACKVAL(val1);     // Left
615                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
616                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
617                         Bytecode_int_DerefStackValue(&val1);
618                         Bytecode_int_DerefStackValue(&val2);
619
620                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
621                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
622                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
623
624                         if(ret_val == ERRPTR) {
625                                 AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
626                                 nextop = NULL;
627                                 break;
628                         }
629                         Bytecode_int_SetSpiderValue(&val1, ret_val);
630                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
631                         PUT_STACKVAL(val1);
632                         break;
633
634                 // Functions etc
635                 case BC_OP_CREATEOBJ:
636                 case BC_OP_CALLFUNCTION:
637                 case BC_OP_CALLMETHOD: {
638                         tScript_Function        *fcn = NULL;
639                         const char      *name = OP_STRING(op);
640                          int    arg_count = OP_INDX(op);
641                         
642                         STATE_HDR();
643                         DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
644
645                         if( op->Operation == BC_OP_CALLFUNCTION )
646                         {
647                                 // Check current script functions (for fast call)
648                                 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
649                                 {
650                                         if(strcmp(name, fcn->Name) == 0) {
651                                                 break;
652                                         }
653                                 }
654                                 if(fcn && fcn->BCFcn)
655                                 {
656                                         DEBUG_F(" - Fast call\n");
657                                         Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
658                                         break;
659                                 }
660                         }
661                         
662                         // Slower call
663                         {
664                                 tSpiderNamespace        *ns = NULL;
665                                 tSpiderValue    *args[arg_count];
666                                 tSpiderValue    *rv;
667                                 // Read arguments
668                                 for( i = arg_count; i --; )
669                                 {
670                                         GET_STACKVAL(val1);
671                                         args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
672                                         Bytecode_int_DerefStackValue(&val1);
673                                 }
674                                 
675                                 // Resolve namespace into pointer
676                                 if( op->Operation != BC_OP_CALLMETHOD ) {
677                                         if( name[0] == BC_NS_SEPARATOR ) {
678                                                 name ++;
679                                                 ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
680                                         }
681                                         else {
682                                                 // TODO: Support multiple default namespaces
683                                                 ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
684                                         }
685                                 }
686                                 
687                                 // Call the function etc.
688                                 if( op->Operation == BC_OP_CALLFUNCTION )
689                                 {
690                                         rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
691                                 }
692                                 else if( op->Operation == BC_OP_CREATEOBJ )
693                                 {
694                                         rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args);
695                                 }
696                                 else if( op->Operation == BC_OP_CALLMETHOD )
697                                 {
698                                         tSpiderObject   *obj;
699                                         GET_STACKVAL(val1);
700                                         
701                                         if(val1.Type == SS_DATATYPE_OBJECT)
702                                                 obj = val1.Object;
703                                         else if(val1.Type == ET_REFERENCE && val1.Reference->Type == SS_DATATYPE_OBJECT)
704                                                 obj = val1.Reference->Object;
705                                         else {
706                                                 // Error
707                                                 AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
708                                                 nextop = NULL;
709                                                 break;
710                                         }
711                                         rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
712                                         Bytecode_int_DerefStackValue(&val1);
713                                 }
714                                 else
715                                 {
716                                         AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
717                                         rv = ERRPTR;
718                                 }
719                                 if(rv == ERRPTR) {
720                                         AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
721                                         nextop = NULL;
722                                         break;
723                                 }
724                                 // Clean up args
725                                 for( i = arg_count; i --; )
726                                         SpiderScript_DereferenceValue(args[i]);
727                                 // Get and push return
728                                 Bytecode_int_SetSpiderValue(&val1, rv);
729                                 PUT_STACKVAL(val1);
730                                 // Deref return
731                                 SpiderScript_DereferenceValue(rv);
732                         }
733                         } break;
734
735                 case BC_OP_RETURN:
736                         STATE_HDR();
737                         DEBUG_F("RETURN\n");
738                         nextop = NULL;
739                         break;
740
741                 default:
742                         // TODO:
743                         STATE_HDR();
744                         AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
745                         nextop = NULL;
746                         break;
747                 }
748                 op = nextop;
749         }
750         
751         // Clean up
752         // - Delete local vars
753         for( i = 0; i < local_var_count; i ++ )
754         {
755                 if( local_vars[i].Type != ET_NULL )
756                 {
757                         Bytecode_int_DerefStackValue(&local_vars[i]);
758                 }
759         }
760         
761         // - Restore stack
762 //      printf("TODO: Roll back stack\n");
763         if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
764                 Stack->EntryCount --;
765         else
766         {
767                 GET_STACKVAL(val1);
768                 while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
769                 {
770                         Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
771                 }
772                 PUT_STACKVAL(val1);
773         }
774         
775
776         return 0;
777 }
778

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