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;
157 Ent->Object->ReferenceCount ++;
160 SpiderScript_ReferenceValue(Value);
161 Ent->Type = ET_REFERENCE;
162 Ent->Reference = Value;
167 void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
171 case SS_DATATYPE_INTEGER:
172 case SS_DATATYPE_REAL:
174 case SS_DATATYPE_OBJECT:
176 Ent->Object->ReferenceCount --;
177 if(Ent->Object->ReferenceCount == 0) {
178 Ent->Object->Type->Destructor( Ent->Object );
180 // printf("Object %p derefed (obj refcount = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
186 SpiderScript_DereferenceValue(Ent->Reference);
187 Ent->Reference = NULL;
191 void Bytecode_int_RefStackValue(tBC_StackEnt *Ent)
195 case SS_DATATYPE_INTEGER:
196 case SS_DATATYPE_REAL:
198 case SS_DATATYPE_OBJECT:
200 Ent->Object->ReferenceCount ++;
201 // printf("Object %p referenced (count = %i)\n", Ent->Object, Ent->Object->ReferenceCount);
206 SpiderScript_ReferenceValue(Ent->Reference);
211 void Bytecode_int_PrintStackValue(tBC_StackEnt *Ent)
215 case SS_DATATYPE_INTEGER:
216 printf("0x%"PRIx64, Ent->Integer);
218 case SS_DATATYPE_REAL:
219 printf("%lf", Ent->Real);
221 case SS_DATATYPE_OBJECT:
222 printf("Obj %p", Ent->Object);
225 printf("*%p", Ent->Reference);
231 # define PRINT_STACKVAL(val) Bytecode_int_PrintStackValue(&val)
233 # define PRINT_STACKVAL(val)
236 #define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
237 AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
240 #define PUT_STACKVAL(src) if((ret = Bytecode_int_StackPush(Stack, &src))) { \
241 AST_RuntimeError(NULL, "Stack push failed, full stack");\
244 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
245 #define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
247 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
249 const int stack_size = 100;
250 tSpiderValue *ret, tmpsval;
255 stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
256 stack->EntrySpace = stack_size;
257 stack->EntryCount = 0;
259 // Push arguments in order (so top is last arg)
260 for( i = 0; i < NArguments; i ++ )
262 Bytecode_int_SetSpiderValue(&val, Args[i]);
263 Bytecode_int_StackPush(stack, &val);
267 Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
270 if( Bytecode_int_StackPop(stack, &val) ) {
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));
285 tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
288 tSpiderNamespace *ns = Start;
289 while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
291 int len = pos - Name;
292 for( ns = ns->FirstChild; ns; ns = ns->Next )
294 if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
302 if(FinalName) *FinalName = Name;
306 #define STATE_HDR() DEBUG_F("%p %2i ", op, Stack->EntryCount)
309 * \brief Execute a bytecode function with a stack
311 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
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;
322 // Initialise local vars
323 for( i = 0; i < local_var_count; i ++ )
324 local_vars[i].Type = ET_NULL;
327 if( ArgCount > Fcn->ArgumentCount ) return -1;
328 DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
329 for( i = Fcn->ArgumentCount; i > ArgCount; )
332 local_vars[i].Integer = 0;
333 local_vars[i].Type = Fcn->Arguments[i].Type;
337 GET_STACKVAL(local_vars[i]);
338 // TODO: Type checks / enforcing
342 memset(&val1, 0, sizeof(val1));
343 val1.Type = ET_FUNCTION_START;
347 op = Fcn->BCFcn->Operations;
350 const char *opstr = "";
351 tBC_Op *nextop = op->Next, *jmp_target;
353 switch(op->Operation)
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);
369 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
370 DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
372 if( Bytecode_int_IsStackEntTrue(&val1) )
375 case BC_OP_JUMPIFNOT:
377 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
378 DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
380 if( !Bytecode_int_IsStackEntTrue(&val1) )
385 case BC_OP_DEFINEVAR: {
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);
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;
399 memset(&local_vars[slot], 0, sizeof(local_vars[0]));
400 local_vars[slot].Type = type;
403 // Enter/Leave context
405 case BC_OP_ENTERCONTEXT:
407 DEBUG_F("ENTERCONTEXT\n");
409 case BC_OP_LEAVECONTEXT:
411 DEBUG_F("LEAVECONTEXT\n");
415 case BC_OP_LOADVAR: {
416 int slot = OP_INDX(op);
418 DEBUG_F("LOADVAR %i ", slot);
419 if( slot < 0 || slot >= local_var_count ) {
420 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
423 DEBUG_F("("); PRINT_STACKVAL(local_vars[slot]); DEBUG_F(")\n");
424 PUT_STACKVAL(local_vars[slot]);
425 Bytecode_int_RefStackValue( &local_vars[slot] );
427 case BC_OP_SAVEVAR: {
428 int slot = OP_INDX(op);
430 DEBUG_F("SAVEVAR %i = ", slot);
431 if( slot < 0 || slot >= local_var_count ) {
432 AST_RuntimeError(NULL, "Loading from invalid slot %i", slot);
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]);
445 DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
446 val1.Type = SS_DATATYPE_INTEGER;
447 val1.Integer = op->Content.Integer;
452 DEBUG_F("LOADREAL %lf\n", op->Content.Real);
453 val1.Type = SS_DATATYPE_REAL;
454 val1.Real = op->Content.Real;
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));
467 val2.Type = OP_INDX(op);
468 DEBUG_F("CAST to %i\n", val2.Type);
470 if(val1.Type == val2.Type) {
474 switch(val2.Type * 100 + val1.Type )
476 case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
477 val2.Integer = val1.Real;
480 case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
481 val2.Real = val1.Integer;
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);
497 DEBUG_F("DUPSTACK ");
499 PRINT_STACKVAL(val1);
503 Bytecode_int_RefStackValue(&val1);
506 // Discard the top item from the stack
509 DEBUG_F("DELSTACK\n");
516 DEBUG_F("LOGICNOT\n");
519 val2.Type = SS_DATATYPE_INTEGER;
520 val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
521 Bytecode_int_StackPush(Stack, &val2);
522 Bytecode_int_DerefStackValue(&val1);
525 if(!ast_op) ast_op = NODETYPE_BWNOT;
528 DEBUG_F("UNIOP %i\n", ast_op);
531 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
532 Bytecode_int_DerefStackValue(&val1);
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);
544 if(!ast_op) ast_op = NODETYPE_LOGICALAND, opstr = "LOGICAND";
546 if(!ast_op) ast_op = NODETYPE_LOGICALOR, opstr = "LOGICOR";
548 if(!ast_op) ast_op = NODETYPE_LOGICALXOR, opstr = "LOGICXOR";
551 DEBUG_F("%s\n", opstr);
556 switch(op->Operation)
559 i = Bytecode_int_IsStackEntTrue(&val1) && Bytecode_int_IsStackEntTrue(&val2);
562 i = Bytecode_int_IsStackEntTrue(&val1) || Bytecode_int_IsStackEntTrue(&val2);
565 i = Bytecode_int_IsStackEntTrue(&val1) ^ Bytecode_int_IsStackEntTrue(&val2);
568 Bytecode_int_DerefStackValue(&val1);
569 Bytecode_int_DerefStackValue(&val2);
571 val1.Type = SS_DATATYPE_INTEGER;
573 Bytecode_int_StackPush(Stack, &val1);
577 if(!ast_op) ast_op = NODETYPE_BWAND, opstr = "BITAND";
579 if(!ast_op) ast_op = NODETYPE_BWOR, opstr = "BITOR";
581 if(!ast_op) ast_op = NODETYPE_BWXOR, opstr = "BITXOR";
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";
591 if(!ast_op) ast_op = NODETYPE_ADD, opstr = "ADD";
593 if(!ast_op) ast_op = NODETYPE_SUBTRACT, opstr = "SUBTRACT";
595 if(!ast_op) ast_op = NODETYPE_MULTIPLY, opstr = "MULTIPLY";
597 if(!ast_op) ast_op = NODETYPE_DIVIDE, opstr = "DIVIDE";
599 if(!ast_op) ast_op = NODETYPE_MODULO, opstr = "MODULO";
602 if(!ast_op) ast_op = NODETYPE_EQUALS, opstr = "EQUALS";
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";
613 DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
615 GET_STACKVAL(val2); // Right
616 GET_STACKVAL(val1); // Left
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; \
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;\
640 PERFORM_NUM_OP(SS_DATATYPE_INTEGER, Integer);
641 PERFORM_NUM_OP(SS_DATATYPE_REAL, Real);
643 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
644 pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
645 Bytecode_int_DerefStackValue(&val1);
646 Bytecode_int_DerefStackValue(&val2);
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);
652 if(ret_val == ERRPTR) {
653 AST_RuntimeError(NULL, "_BinOp returned ERRPTR");
657 Bytecode_int_SetSpiderValue(&val1, ret_val);
658 if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
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);
671 DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
673 if( op->Operation == BC_OP_CALLFUNCTION )
675 // Check current script functions (for fast call)
676 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
678 if(strcmp(name, fcn->Name) == 0) {
682 if(fcn && fcn->BCFcn)
684 DEBUG_F(" - Fast call\n");
685 Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
692 tSpiderNamespace *ns = NULL;
693 tSpiderValue *args[arg_count];
696 for( i = arg_count; i --; )
699 args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
700 Bytecode_int_DerefStackValue(&val1);
703 // Resolve namespace into pointer
704 if( op->Operation != BC_OP_CALLMETHOD ) {
705 if( name[0] == BC_NS_SEPARATOR ) {
707 ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
710 // TODO: Support multiple default namespaces
711 ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
715 // Call the function etc.
716 if( op->Operation == BC_OP_CALLFUNCTION )
718 rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
720 else if( op->Operation == BC_OP_CREATEOBJ )
722 rv = SpiderScript_CreateObject(Script, ns, name, arg_count, args);
724 else if( op->Operation == BC_OP_CALLMETHOD )
729 if(val1.Type == SS_DATATYPE_OBJECT)
731 else if(val1.Type == ET_REFERENCE && val1.Reference->Type == SS_DATATYPE_OBJECT)
732 obj = val1.Reference->Object;
735 AST_RuntimeError(NULL, "OP_CALLMETHOD on non object");
739 rv = SpiderScript_ExecuteMethod(Script, obj, name, arg_count, args);
740 Bytecode_int_DerefStackValue(&val1);
744 AST_RuntimeError(NULL, "BUG - Unknown operation for CALL/CREATEOBJ (%i)", op->Operation);
748 AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
753 for( i = arg_count; i --; )
754 SpiderScript_DereferenceValue(args[i]);
755 // Get and push return
756 Bytecode_int_SetSpiderValue(&val1, rv);
759 SpiderScript_DereferenceValue(rv);
772 AST_RuntimeError(NULL, "Unknown operation %i\n", op->Operation);
780 // - Delete local vars
781 for( i = 0; i < local_var_count; i ++ )
783 if( local_vars[i].Type != ET_NULL )
785 Bytecode_int_DerefStackValue(&local_vars[i]);
790 // printf("TODO: Roll back stack\n");
791 if( Stack->Entries[Stack->EntryCount - 1].Type == ET_FUNCTION_START )
792 Stack->EntryCount --;
796 while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
798 Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );