Usermode/libspiderscript - Cleaning code, made bytecode dump smaller
[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 /**
307  * \brief Call an external function (may recurse into Bytecode_ExecuteFunction, but may not)
308  */
309 int Bytecode_int_CallExternFunction(tSpiderScript *Script, tBC_Stack *Stack, tSpiderNamespace *DefaultNS, tBC_Op *op )
310 {
311         const char      *name = OP_STRING(op);
312          int    arg_count = OP_INDX(op);
313          int    i, ret = 0;
314         tSpiderNamespace        *ns = NULL;
315         tSpiderValue    *args[arg_count];
316         tSpiderValue    *rv;
317         tBC_StackEnt    val1;   
318
319         DEBUG_F("CALL (general) %s %i args\n", name, arg_count);
320         
321         // Read arguments
322         for( i = arg_count; i --; )
323         {
324                 GET_STACKVAL(val1);
325                 args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
326                 Bytecode_int_DerefStackValue(&val1);
327         }
328         
329         // Resolve namespace into pointer
330         if( op->Operation != BC_OP_CALLMETHOD ) {
331                 const char *name_orig = name;
332                 if( name[0] == BC_NS_SEPARATOR ) {
333                         name ++;
334                         ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
335                 }
336                 else {
337                         // TODO: Support multiple default namespaces
338                         ns = Bytecode_int_ResolveNamespace(DefaultNS, name, &name);
339                 }
340                 if( !ns ) {
341                         AST_RuntimeError(NULL, "Namespace '%s' not found in '%s'", name, name_orig);
342                         return -1;
343                 }
344         }
345         
346         // Call the function etc.
347         if( op->Operation == BC_OP_CALLFUNCTION )
348         {
349                 rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
350         }
351         else if( op->Operation == BC_OP_CREATEOBJ )
352         {
353                 rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args);
354         }
355         else if( op->Operation == BC_OP_CALLMETHOD )
356         {
357                 tSpiderObject   *obj;
358                 GET_STACKVAL(val1);
359                 
360                 if(val1.Type == SS_DATATYPE_OBJECT)
361                         obj = val1.Object;
362                 else if(val1.Type == ET_REFERENCE && val1.Reference && val1.Reference->Type == SS_DATATYPE_OBJECT)
363                         obj = val1.Reference->Object;
364                 else {
365                         // Error
366                         AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
367                         return -1;
368                 }
369                 rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
370                 Bytecode_int_DerefStackValue(&val1);
371         }
372         else
373         {
374                 AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
375                 rv = ERRPTR;
376         }
377         if(rv == ERRPTR) {
378                 AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
379                 return -1;
380         }
381         // Clean up args
382         for( i = arg_count; i --; )
383                 SpiderScript_DereferenceValue(args[i]);
384         // Get and push return
385         Bytecode_int_SetSpiderValue(&val1, rv);
386         PUT_STACKVAL(val1);
387         // Deref return
388         SpiderScript_DereferenceValue(rv);
389         
390         return ret;
391 }
392
393 int Bytecode_int_LocalBinOp_Integer(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
394 {
395         switch(Operation)
396         {
397         case BC_OP_ADD:         Val1->Integer = Val1->Integer + Val2->Integer;  break;
398         case BC_OP_SUBTRACT:    Val1->Integer = Val1->Integer - Val2->Integer;  break;
399         case BC_OP_MULTIPLY:    Val1->Integer = Val1->Integer * Val2->Integer;  break;
400         case BC_OP_DIVIDE:      Val1->Integer = Val1->Integer / Val2->Integer;  break;
401         
402         case BC_OP_EQUALS:              Val1->Integer = (Val1->Integer == Val2->Integer);       break;
403         case BC_OP_NOTEQUALS:           Val1->Integer = (Val1->Integer != Val2->Integer);       break;
404         case BC_OP_LESSTHAN:            Val1->Integer = (Val1->Integer <  Val2->Integer);       break;
405         case BC_OP_LESSTHANOREQUAL:     Val1->Integer = (Val1->Integer <= Val2->Integer);       break;
406         case BC_OP_GREATERTHAN:         Val1->Integer = (Val1->Integer >  Val2->Integer);       break;
407         case BC_OP_GREATERTHANOREQUAL:  Val1->Integer = (Val1->Integer >= Val2->Integer);       break;
408         
409         case BC_OP_BITAND:      Val1->Integer = Val1->Integer & Val2->Integer;  break;
410         case BC_OP_BITOR:       Val1->Integer = Val1->Integer | Val2->Integer;  break;
411         case BC_OP_BITXOR:      Val1->Integer = Val1->Integer ^ Val2->Integer;  break;
412         case BC_OP_MODULO:      Val1->Integer = Val1->Integer % Val2->Integer;  break;
413         default:        AST_RuntimeError(NULL, "Invalid operation on datatype %i", Val1->Type); return -1;
414         }
415         return 0;
416 }
417
418 int Bytecode_int_LocalBinOp_Real(int Operation, tBC_StackEnt *Val1, tBC_StackEnt *Val2)
419 {
420         switch(Operation)
421         {
422         case BC_OP_ADD:         Val1->Real = Val1->Real + Val2->Real;   return 0;
423         case BC_OP_SUBTRACT:    Val1->Real = Val1->Real - Val2->Real;   return 0;
424         case BC_OP_MULTIPLY:    Val1->Real = Val1->Real * Val2->Real;   return 0;
425         case BC_OP_DIVIDE:      Val1->Real = Val1->Real / Val2->Real;   return 0;
426
427         case BC_OP_EQUALS:              Val1->Integer = (Val1->Real == Val2->Real);     break;
428         case BC_OP_NOTEQUALS:           Val1->Integer = (Val1->Real != Val2->Real);     break;
429         case BC_OP_LESSTHAN:            Val1->Integer = (Val1->Real <  Val2->Real);     break;
430         case BC_OP_LESSTHANOREQUAL:     Val1->Integer = (Val1->Real <= Val2->Real);     break;
431         case BC_OP_GREATERTHAN:         Val1->Integer = (Val1->Real >  Val2->Real);     break;
432         case BC_OP_GREATERTHANOREQUAL:  Val1->Integer = (Val1->Real >= Val2->Real);     break;
433         
434         default:        AST_RuntimeError(NULL, "Invalid operation on datatype %i", Val1->Type); return -1;
435         }
436         Val1->Type = SS_DATATYPE_INTEGER;       // Becomes logical
437         return 0;
438 }
439
440 #define STATE_HDR()     DEBUG_F("%p %2i ", op, Stack->EntryCount)
441
442 /**
443  * \brief Execute a bytecode function with a stack
444  */
445 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
446 {
447          int    ret, ast_op, i;
448         tBC_Op  *op;
449         tBC_StackEnt    val1, val2;
450          int    local_var_count = Fcn->BCFcn->MaxVariableCount;
451         tBC_StackEnt    local_vars[local_var_count];    // Includes arguments
452         tSpiderValue    tmpVal1, tmpVal2;       // temp storage
453         tSpiderValue    *pval1, *pval2, *ret_val;
454         tSpiderNamespace        *default_namespace = &Script->Variant->RootNamespace;
455
456         // Initialise local vars
457         for( i = 0; i < local_var_count; i ++ )
458                 local_vars[i].Type = ET_NULL;
459         
460         // Pop off arguments
461         if( ArgCount > Fcn->ArgumentCount )     return -1;
462         DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
463         // - Handle optional arguments
464         for( i = Fcn->ArgumentCount; i > ArgCount; )
465         {
466                 i --;
467                 local_vars[i].Integer = 0;
468                 local_vars[i].Type = Fcn->Arguments[i].Type;
469         }
470         for( ; i --; )
471         {
472                 GET_STACKVAL(local_vars[i]);
473                 // TODO: Type checks / enforcing
474         }
475         
476         // Mark the start
477         memset(&val1, 0, sizeof(val1));
478         val1.Type = ET_FUNCTION_START;
479         PUT_STACKVAL(val1);
480
481         // Execute!
482         op = Fcn->BCFcn->Operations;
483         while(op)
484         {
485                 const char      *opstr = "";
486                 tBC_Op  *nextop = op->Next, *jmp_target;
487                 ast_op = 0;
488                 switch(op->Operation)
489                 {
490                 case BC_OP_NOP:
491                         STATE_HDR();
492                         DEBUG_F("NOP\n");
493                         break;
494                 // Jumps
495                 case BC_OP_JUMP:
496                         STATE_HDR();
497                         // NOTE: Evil, all jumps are off by -1, so fix that
498                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
499                         DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
500                         nextop = jmp_target;
501                         break;
502                 case BC_OP_JUMPIF:
503                         STATE_HDR();
504                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
505                         DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
506                         GET_STACKVAL(val1);
507                         if( Bytecode_int_IsStackEntTrue(&val1) )
508                                 nextop = jmp_target;
509                         break;
510                 case BC_OP_JUMPIFNOT:
511                         STATE_HDR();
512                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
513                         DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
514                         GET_STACKVAL(val1);
515                         if( !Bytecode_int_IsStackEntTrue(&val1) )
516                                 nextop = jmp_target;
517                         break;
518                 
519                 // Define variables
520                 case BC_OP_DEFINEVAR: {
521                          int    type, slot;
522                         type = OP_INDX(op) & 0xFFFF;
523                         slot = OP_INDX(op) >> 16;
524                         if(slot < 0 || slot >= local_var_count) {
525                                 DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
526                                 return -1;
527                         }
528                         STATE_HDR();
529                         DEBUG_F("DEFVAR %i of type %i\n", slot, type);
530                         if( local_vars[slot].Type != ET_NULL ) {
531                                 Bytecode_int_DerefStackValue( &local_vars[slot] );
532                                 local_vars[slot].Type = ET_NULL;
533                         }
534                         memset(&local_vars[slot], 0, sizeof(local_vars[0]));
535                         local_vars[slot].Type = type;
536                         } break;
537
538                 // Enter/Leave context
539                 // - NOP now            
540                 case BC_OP_ENTERCONTEXT:
541                         STATE_HDR();
542                         DEBUG_F("ENTERCONTEXT\n");
543                         break;
544                 case BC_OP_LEAVECONTEXT:
545                         STATE_HDR();
546                         DEBUG_F("LEAVECONTEXT\n");
547                         break;
548
549                 // Variables
550                 case BC_OP_LOADVAR: {
551                          int    slot = OP_INDX(op);
552                         STATE_HDR();
553                         DEBUG_F("LOADVAR %i ", slot);
554                         if( slot < 0 || slot >= local_var_count ) {
555                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
556                                 return -1;
557                         }
558                         DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n");
559                         PUT_STACKVAL(local_vars[slot]);
560                         Bytecode_int_RefStackValue( &local_vars[slot] );
561                         } break;
562                 case BC_OP_SAVEVAR: {
563                          int    slot = OP_INDX(op);
564                         STATE_HDR();
565                         DEBUG_F("SAVEVAR %i = ", slot);
566                         if( slot < 0 || slot >= local_var_count ) {
567                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
568                                 return -1;
569                         }
570                         DEBUG_F("[Deref "); PRINT_STACKVAL(local_vars[slot]); DEBUG_F("] ");
571                         Bytecode_int_DerefStackValue( &local_vars[slot] );
572                         GET_STACKVAL(local_vars[slot]);
573                         PRINT_STACKVAL(local_vars[slot]);
574                         DEBUG_F("\n");
575                         } break;
576
577                 // Constants:
578                 case BC_OP_LOADINT:
579                         STATE_HDR();
580                         DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
581                         val1.Type = SS_DATATYPE_INTEGER;
582                         val1.Integer = op->Content.Integer;
583                         PUT_STACKVAL(val1);
584                         break;
585                 case BC_OP_LOADREAL:
586                         STATE_HDR();
587                         DEBUG_F("LOADREAL %lf\n", op->Content.Real);
588                         val1.Type = SS_DATATYPE_REAL;
589                         val1.Real = op->Content.Real;
590                         PUT_STACKVAL(val1);
591                         break;
592                 case BC_OP_LOADSTR:
593                         STATE_HDR();
594                         DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
595                         val1.Type = SS_DATATYPE_STRING;
596                         val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
597                         PUT_STACKVAL(val1);
598                         break;
599
600                 case BC_OP_CAST:
601                         STATE_HDR();
602                         val2.Type = OP_INDX(op);
603                         DEBUG_F("CAST to %i\n", val2.Type);
604                         GET_STACKVAL(val1);
605                         if(val1.Type == val2.Type) {
606                                 PUT_STACKVAL(val1);
607                                 break;
608                         }
609                         switch(val2.Type * 100 + val1.Type )
610                         {
611                         case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
612                                 val2.Integer = val1.Real;
613                                 PUT_STACKVAL(val2);
614                                 break;
615                         case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
616                                 val2.Real = val1.Integer;
617                                 PUT_STACKVAL(val2);
618                                 break;
619                         default: {
620                                 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
621                                 pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
622                                 if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
623                                 Bytecode_int_SetSpiderValue(&val2, pval2);
624                                 SpiderScript_DereferenceValue(pval2);
625                                 PUT_STACKVAL(val2);
626                                 } break;
627                         }
628                         break;
629
630                 case BC_OP_DUPSTACK:
631                         STATE_HDR();
632                         DEBUG_F("DUPSTACK ");
633                         GET_STACKVAL(val1);
634                         PRINT_STACKVAL(val1);
635                         DEBUG_F("\n");
636                         PUT_STACKVAL(val1);
637                         PUT_STACKVAL(val1);
638                         Bytecode_int_RefStackValue(&val1);
639                         break;
640
641                 // Discard the top item from the stack
642                 case BC_OP_DELSTACK:
643                         STATE_HDR();
644                         DEBUG_F("DELSTACK\n");
645                         GET_STACKVAL(val1);
646                         break;
647
648                 // Unary Operations
649                 case BC_OP_LOGICNOT:
650                         STATE_HDR();
651                         DEBUG_F("LOGICNOT\n");
652                         
653                         GET_STACKVAL(val1);
654                         val2.Type = SS_DATATYPE_INTEGER;
655                         val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
656                         Bytecode_int_StackPush(Stack, &val2);
657                         Bytecode_int_DerefStackValue(&val1);
658                         break;
659                 
660                 case BC_OP_BITNOT:
661                         if(!ast_op)     ast_op = NODETYPE_BWNOT,        opstr = "BITNOT";
662                 case BC_OP_NEG:
663                         if(!ast_op)     ast_op = NODETYPE_NEGATE,       opstr = "NEG";
664
665                         STATE_HDR();
666                         DEBUG_F("%s\n", opstr);
667
668                         GET_STACKVAL(val1);
669                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
670                         Bytecode_int_DerefStackValue(&val1);                    
671
672                         ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
673                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
674                         Bytecode_int_SetSpiderValue(&val1, ret_val);
675                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
676                         Bytecode_int_StackPush(Stack, &val1);
677                         
678                         break;
679
680                 // Binary Operations
681                 case BC_OP_LOGICAND:
682                         if(!ast_op)     ast_op = NODETYPE_LOGICALAND,   opstr = "LOGICAND";
683                 case BC_OP_LOGICOR:
684                         if(!ast_op)     ast_op = NODETYPE_LOGICALOR,    opstr = "LOGICOR";
685                 case BC_OP_LOGICXOR:
686                         if(!ast_op)     ast_op = NODETYPE_LOGICALXOR,   opstr = "LOGICXOR";
687         
688                         STATE_HDR();
689                         DEBUG_F("%s\n", opstr);
690
691                         GET_STACKVAL(val1);
692                         GET_STACKVAL(val2);
693                         
694                         switch(op->Operation)
695                         {
696                         case BC_OP_LOGICAND:
697                                 i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
698                                 break;
699                         case BC_OP_LOGICOR:
700                                 i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
701                                 break;
702                         case BC_OP_LOGICXOR:
703                                 i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
704                                 break;
705                         }
706                         Bytecode_int_DerefStackValue(&val1);
707                         Bytecode_int_DerefStackValue(&val2);
708
709                         val1.Type = SS_DATATYPE_INTEGER;
710                         val1.Integer = i;
711                         Bytecode_int_StackPush(Stack, &val1);
712                         break;
713
714                 case BC_OP_BITAND:
715                         if(!ast_op)     ast_op = NODETYPE_BWAND,        opstr = "BITAND";
716                 case BC_OP_BITOR:
717                         if(!ast_op)     ast_op = NODETYPE_BWOR,         opstr = "BITOR";
718                 case BC_OP_BITXOR:
719                         if(!ast_op)     ast_op = NODETYPE_BWXOR,        opstr = "BITXOR";
720
721                 case BC_OP_BITSHIFTLEFT:
722                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
723                 case BC_OP_BITSHIFTRIGHT:
724                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
725                 case BC_OP_BITROTATELEFT:
726                         if(!ast_op)     ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
727
728                 case BC_OP_ADD:
729                         if(!ast_op)     ast_op = NODETYPE_ADD,  opstr = "ADD";
730                 case BC_OP_SUBTRACT:
731                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT,     opstr = "SUBTRACT";
732                 case BC_OP_MULTIPLY:
733                         if(!ast_op)     ast_op = NODETYPE_MULTIPLY,     opstr = "MULTIPLY";
734                 case BC_OP_DIVIDE:
735                         if(!ast_op)     ast_op = NODETYPE_DIVIDE,       opstr = "DIVIDE";
736                 case BC_OP_MODULO:
737                         if(!ast_op)     ast_op = NODETYPE_MODULO,       opstr = "MODULO";
738
739                 case BC_OP_EQUALS:
740                         if(!ast_op)     ast_op = NODETYPE_EQUALS,       opstr = "EQUALS";
741                 case BC_OP_NOTEQUALS:
742                         if(!ast_op)     ast_op = NODETYPE_NOTEQUALS,    opstr = "NOTEQUALS";
743                 case BC_OP_LESSTHAN:
744                         if(!ast_op)     ast_op = NODETYPE_LESSTHAN,     opstr = "LESSTHAN";
745                 case BC_OP_LESSTHANOREQUAL:
746                         if(!ast_op)     ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
747                 case BC_OP_GREATERTHAN:
748                         if(!ast_op)     ast_op = NODETYPE_GREATERTHAN,  opstr = "GREATERTHAN";
749                 case BC_OP_GREATERTHANOREQUAL:
750                         if(!ast_op)     ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
751
752                         STATE_HDR();
753                         DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
754
755                         GET_STACKVAL(val2);     // Right
756                         GET_STACKVAL(val1);     // Left
757
758                         DEBUG_F(" ("); PRINT_STACKVAL(val1); DEBUG_F(")");
759                         DEBUG_F(" ("); PRINT_STACKVAL(val2); DEBUG_F(")\n");
760
761                         // Perform integer operations locally
762                         if( val1.Type == SS_DATATYPE_INTEGER && val2.Type == SS_DATATYPE_INTEGER )
763                         {
764                                 if( Bytecode_int_LocalBinOp_Integer(op->Operation, &val1, &val2) ) {
765                                         nextop = NULL;
766                                         break;
767                                 }
768                                 PUT_STACKVAL(val1);
769                                 break;
770                         }
771
772                         if(val1. Type == SS_DATATYPE_REAL && val2.Type == SS_DATATYPE_REAL )
773                         {
774                                 if( Bytecode_int_LocalBinOp_Real(op->Operation, &val1, &val2) ) {
775                                         nextop = NULL;
776                                         break;
777                                 }
778                                 PUT_STACKVAL(val1);
779                                 break;
780                         }
781                 
782                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
783                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
784                         Bytecode_int_DerefStackValue(&val1);
785                         Bytecode_int_DerefStackValue(&val2);
786
787                         // Hand to AST execution code
788                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
789                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
790                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
791
792                         if(ret_val == ERRPTR) {
793                                 AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
794                                 nextop = NULL;
795                                 break;
796                         }
797                         Bytecode_int_SetSpiderValue(&val1, ret_val);
798                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
799                         PUT_STACKVAL(val1);
800                         break;
801
802                 // Functions etc
803                 case BC_OP_CREATEOBJ:
804                 case BC_OP_CALLFUNCTION:
805                 case BC_OP_CALLMETHOD:
806                         STATE_HDR();
807
808                         if( op->Operation == BC_OP_CALLFUNCTION )
809                         {
810                                 tScript_Function        *fcn = NULL;
811                                 const char      *name = OP_STRING(op);
812                                  int    arg_count = OP_INDX(op);
813                                 DEBUG_F("CALL (local) %s %i args\n", name, arg_count);
814                                 // Check current script functions (for fast call)
815                                 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
816                                 {
817                                         if(strcmp(name, fcn->Name) == 0) {
818                                                 break;
819                                         }
820                                 }
821                                 if(fcn && fcn->BCFcn)
822                                 {
823                                         DEBUG_F(" - Fast call\n");
824                                         Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
825                                         break;
826                                 }
827                         }
828                 
829                         // Slower call
830                         if( Bytecode_int_CallExternFunction( Script, Stack, default_namespace, op ) ) {
831                                 nextop = NULL;
832                                 break;
833                         }
834                         break;
835
836                 case BC_OP_RETURN:
837                         STATE_HDR();
838
839                         DEBUG_F("RETURN\n");
840                         nextop = NULL;
841                         break;
842
843                 default:
844                         // TODO:
845                         STATE_HDR();
846                         AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
847                         nextop = NULL;
848                         break;
849                 }
850                 op = nextop;
851         }
852         
853         // Clean up
854         // - Delete local vars
855         for( i = 0; i < local_var_count; i ++ )
856         {
857                 if( local_vars[i].Type != ET_NULL )
858                 {
859                         Bytecode_int_DerefStackValue(&local_vars[i]);
860                 }
861         }
862         
863         // - Restore stack
864         if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
865                 Stack->EntryCount --;
866         else
867         {
868                  int    n_rolled = 1;
869                 GET_STACKVAL(val1);
870                 while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
871                 {
872                         Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
873                         n_rolled ++;
874                 }
875                 PUT_STACKVAL(val1);
876                 DEBUG_F("Rolled back %i entried\n", n_rolled);
877         }
878         
879
880         return 0;
881 }
882

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