3 * by John Hodge (thePowersGang)
20 # define DEBUG_F(v...) printf(v)
22 # define DEBUG_F(v...)
26 extern void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
29 typedef struct sBC_StackEnt tBC_StackEnt;
30 typedef struct sBC_Stack tBC_Stack;
32 enum eBC_StackEntTypes
34 ET_NULL, // Start of the stack
36 ET_FUNCTION_START = NUM_SS_DATATYPES,
37 ET_REFERENCE // Reference to a tSpiderValue
46 tSpiderValue *Reference; // Used for everything else
47 tSpiderObject *Object;
48 tSpiderNamespace *Namespace;
56 tBC_StackEnt Entries[];
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);
64 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
66 if( Stack->EntryCount == 0 ) return 1;
68 *Dest = Stack->Entries[Stack->EntryCount];
72 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
74 if( Stack->EntryCount == Stack->EntrySpace ) return 1;
75 Stack->Entries[Stack->EntryCount] = *Src;
80 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
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:
93 return SpiderScript_IsValueTrue(Ent->Reference);
97 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
101 case SS_DATATYPE_INTEGER:
102 case SS_DATATYPE_REAL:
103 case SS_DATATYPE_OBJECT:
105 tmp = malloc(sizeof(tSpiderValue));
106 tmp->ReferenceCount = 1;
108 tmp->ReferenceCount = 2;
116 case SS_DATATYPE_INTEGER:
117 tmp->Type = SS_DATATYPE_INTEGER;
118 tmp->Integer = Ent->Integer;
120 case SS_DATATYPE_REAL:
121 tmp->Type = SS_DATATYPE_REAL;
122 tmp->Real = Ent->Real;
124 case SS_DATATYPE_OBJECT:
125 tmp->Type = SS_DATATYPE_OBJECT;
126 tmp->Object = Ent->Object;
128 case ET_FUNCTION_START:
129 AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
132 SpiderScript_ReferenceValue(Ent->Reference);
133 return Ent->Reference;
137 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
140 Ent->Type = ET_REFERENCE;
141 Ent->Reference = NULL;
146 case SS_DATATYPE_INTEGER:
147 Ent->Type = SS_DATATYPE_INTEGER;
148 Ent->Integer = Value->Integer;
150 case SS_DATATYPE_REAL:
151 Ent->Type = SS_DATATYPE_REAL;
152 Ent->Real = Value->Real;
154 case SS_DATATYPE_OBJECT:
155 Ent->Type = SS_DATATYPE_OBJECT;
156 Ent->Object = Value->Object;
159 SpiderScript_ReferenceValue(Value);
160 Ent->Type = ET_REFERENCE;
161 Ent->Reference = Value;
166 void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
170 case SS_DATATYPE_INTEGER:
171 case SS_DATATYPE_REAL:
172 case SS_DATATYPE_OBJECT:
175 SpiderScript_DereferenceValue(Ent->Reference);
179 void Bytecode_int_RefStackValue(tBC_StackEnt *Ent)
183 case SS_DATATYPE_INTEGER:
184 case SS_DATATYPE_REAL:
185 case SS_DATATYPE_OBJECT:
188 SpiderScript_ReferenceValue(Ent->Reference);
193 void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent)
197 case SS_DATATYPE_INTEGER:
198 printf("0x%"PRIx64, Ent->Integer);
200 case SS_DATATYPE_REAL:
201 printf("%lf", Ent->Real);
203 case SS_DATATYPE_OBJECT:
204 printf("Obj %p", Ent->Object);
207 printf("*%p", Ent->Reference);
213 # define PRINT_STACKVAL(val) Bytecode_int_PrintStackValue(&val)
215 # define PRINT_STACKVAL(val)
218 #define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
219 AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
222 #define PUT_STACKVAL(src) if((ret = Bytecode_int_StackPush(Stack, &src))) { \
223 AST_RuntimeError(NULL, "Stack push failed, full stack");\
226 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
227 #define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
229 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
231 const int stack_size = 100;
232 tSpiderValue *ret, tmpsval;
237 stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
238 stack->EntrySpace = stack_size;
239 stack->EntryCount = 0;
241 // Push arguments in order (so top is last arg)
242 for( i = 0; i < NArguments; i ++ )
244 Bytecode_int_SetSpiderValue(&val, Args[i]);
245 Bytecode_int_StackPush(stack, &val);
249 Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
252 if( Bytecode_int_StackPop(stack, &val) ) {
257 ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
258 // Ensure it's a heap value
259 if(ret == &tmpsval) {
260 ret = malloc(sizeof(tSpiderValue));
261 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
267 tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
270 tSpiderNamespace *ns = Start;
271 while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
273 int len = pos - Name;
274 for( ns = ns->FirstChild; ns; ns = ns->Next )
276 if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
284 if(FinalName) *FinalName = Name;
288 #define STATE_HDR() DEBUG_F("%p %2i ", op, Stack->EntryCount)
291 * \brief Execute a bytecode function with a stack
293 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
297 tBC_StackEnt val1, val2;
298 int local_var_count = Fcn->BCFcn->MaxVariableCount;
299 tBC_StackEnt local_vars[local_var_count]; // Includes arguments
300 tSpiderValue tmpVal1, tmpVal2; // temp storage
301 tSpiderValue *pval1, *pval2, *ret_val;
302 tSpiderNamespace *default_namespace = &Script->Variant->RootNamespace;
304 // Initialise local vars
305 for( i = 0; i < local_var_count; i ++ )
306 local_vars[i].Type = ET_NULL;
309 if( ArgCount > Fcn->ArgumentCount ) return -1;
310 DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
311 for( i = Fcn->ArgumentCount; i > ArgCount; )
314 local_vars[i].Integer = 0;
315 local_vars[i].Type = Fcn->Arguments[i].Type;
319 GET_STACKVAL(local_vars[i]);
320 // TODO: Type checks / enforcing
324 memset(&val1, 0, sizeof(val1));
325 val1.Type = ET_FUNCTION_START;
329 op = Fcn->BCFcn->Operations;
332 const char *opstr = "";
333 tBC_Op *nextop = op->Next, *jmp_target;
335 switch(op->Operation)
342 // NOTE: Evil, all jumps are off by -1, so fix that
343 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
344 DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
349 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
350 DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
352 if( Bytecode_int_IsStackEntTrue(&val1) )
355 case BC_OP_JUMPIFNOT:
357 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
358 DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
360 if( !Bytecode_int_IsStackEntTrue(&val1) )
365 case BC_OP_DEFINEVAR: {
367 type = OP_INDX(op) & 0xFFFF;
368 slot = OP_INDX(op) >> 16;
369 if(slot < 0 || slot >= local_var_count) {
370 DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
374 DEBUG_F("DEFVAR %i of type %i\n", slot, type);
375 if( local_vars[slot].Type != ET_NULL ) {
376 Bytecode_int_DerefStackValue( &local_vars[slot] );
377 local_vars[slot].Type = ET_NULL;
379 memset(&local_vars[slot], 0, sizeof(local_vars[0]));
380 local_vars[slot].Type = type;
383 // Enter/Leave context
385 case BC_OP_ENTERCONTEXT:
387 DEBUG_F("ENTERCONTEXT\n");
389 case BC_OP_LEAVECONTEXT:
391 DEBUG_F("LEAVECONTEXT\n");
397 DEBUG_F("LOADVAR %i ", OP_INDX(op));
398 if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
399 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
402 DEBUG_F("("); PRINT_STACKVAL(local_vars[OP_INDX(op)]); DEBUG_F(")\n");
403 PUT_STACKVAL(local_vars[OP_INDX(op)]);
404 Bytecode_int_RefStackValue( &local_vars[OP_INDX(op)] );
408 DEBUG_F("SAVEVAR %i = ", OP_INDX(op));
409 if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
410 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
413 PRINT_STACKVAL(local_vars[OP_INDX(op)]);
415 GET_STACKVAL(local_vars[OP_INDX(op)]);
421 DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
422 val1.Type = SS_DATATYPE_INTEGER;
423 val1.Integer = op->Content.Integer;
428 DEBUG_F("LOADREAL %lf\n", op->Content.Real);
429 val1.Type = SS_DATATYPE_REAL;
430 val1.Real = op->Content.Real;
435 DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
436 val1.Type = SS_DATATYPE_STRING;
437 val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
443 val2.Type = OP_INDX(op);
444 DEBUG_F("CAST to %i\n", val2.Type);
446 if(val1.Type == val2.Type) {
450 switch(val2.Type * 100 + val1.Type )
452 case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
453 val2.Integer = val1.Real;
456 case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
457 val2.Real = val1.Integer;
461 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
462 pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
463 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
464 Bytecode_int_SetSpiderValue(&val2, pval2);
465 SpiderScript_DereferenceValue(pval2);
473 DEBUG_F("DUPSTACK ");
475 PRINT_STACKVAL(val1);
479 Bytecode_int_RefStackValue(&val1);
482 // Discard the top item from the stack
485 DEBUG_F("DELSTACK\n");
492 DEBUG_F("LOGICNOT\n");
495 val2.Type = SS_DATATYPE_INTEGER;
496 val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
497 Bytecode_int_StackPush(Stack, &val2);
498 Bytecode_int_DerefStackValue(&val1);
501 if(!ast_op) ast_op = NODETYPE_BWNOT;
504 DEBUG_F("UNIOP %i\n", ast_op);
507 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
508 Bytecode_int_DerefStackValue(&val1);
510 ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
511 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
512 Bytecode_int_SetSpiderValue(&val1, ret_val);
513 if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
514 Bytecode_int_StackPush(Stack, &val1);
520 if(!ast_op) ast_op = NODETYPE_LOGICALAND, opstr = "LOGICAND";
522 if(!ast_op) ast_op = NODETYPE_LOGICALOR, opstr = "LOGICOR";
524 if(!ast_op) ast_op = NODETYPE_LOGICALXOR, opstr = "LOGICXOR";
527 if(!ast_op) ast_op = NODETYPE_BWAND, opstr = "BITAND";
529 if(!ast_op) ast_op = NODETYPE_BWOR, opstr = "BITOR";
531 if(!ast_op) ast_op = NODETYPE_BWXOR, opstr = "BITXOR";
533 case BC_OP_BITSHIFTLEFT:
534 if(!ast_op) ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
535 case BC_OP_BITSHIFTRIGHT:
536 if(!ast_op) ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
537 case BC_OP_BITROTATELEFT:
538 if(!ast_op) ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
541 if(!ast_op) ast_op = NODETYPE_ADD, opstr = "ADD";
543 if(!ast_op) ast_op = NODETYPE_SUBTRACT, opstr = "SUBTRACT";
545 if(!ast_op) ast_op = NODETYPE_MULTIPLY, opstr = "MULTIPLY";
547 if(!ast_op) ast_op = NODETYPE_DIVIDE, opstr = "DIVIDE";
549 if(!ast_op) ast_op = NODETYPE_MODULO, opstr = "MODULO";
552 if(!ast_op) ast_op = NODETYPE_EQUALS, opstr = "EQUALS";
554 if(!ast_op) ast_op = NODETYPE_LESSTHAN, opstr = "LESSTHAN";
555 case BC_OP_LESSTHANOREQUAL:
556 if(!ast_op) ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
557 case BC_OP_GREATERTHAN:
558 if(!ast_op) ast_op = NODETYPE_GREATERTHAN, opstr = "GREATERTHAN";
559 case BC_OP_GREATERTHANOREQUAL:
560 if(!ast_op) ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
563 DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
565 GET_STACKVAL(val2); // Right
566 GET_STACKVAL(val1); // Left
567 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
568 pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
569 Bytecode_int_DerefStackValue(&val1);
570 Bytecode_int_DerefStackValue(&val2);
572 ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
573 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
574 if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
575 Bytecode_int_SetSpiderValue(&val1, ret_val);
576 if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
581 case BC_OP_CALLFUNCTION: {
582 tScript_Function *fcn;
583 const char *name = OP_STRING(op);
584 int arg_count = OP_INDX(op);
587 DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
589 // Check current script functions (for fast call)
590 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
592 if(strcmp(name, fcn->Name) == 0) {
596 if(fcn && fcn->BCFcn)
598 DEBUG_F(" - Fast call\n");
599 Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
605 tSpiderNamespace *ns = NULL;
606 tSpiderValue *args[arg_count];
608 // for( i = 0; i < arg_count; i ++ )
609 for( i = arg_count; i --; )
612 args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
613 Bytecode_int_DerefStackValue(&val1);
616 if( name[0] == BC_NS_SEPARATOR ) {
618 ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
621 // TODO: Support multiple default namespaces
622 ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
625 rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
627 AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
632 for( i = arg_count; i --; )
633 SpiderScript_DereferenceValue(args[i]);
634 // Get and push return
635 Bytecode_int_SetSpiderValue(&val1, rv);
638 SpiderScript_DereferenceValue(rv);
651 printf("Unknown operation %i\n", op->Operation);
659 // - Delete local vars
660 for( i = 0; i < local_var_count; i ++ )
662 if( local_vars[i].Type != ET_NULL )
664 Bytecode_int_DerefStackValue(&local_vars[i]);
669 // printf("TODO: Roll back stack\n");
670 if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
671 Stack->EntryCount --;
675 while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
677 Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );