3 * by John Hodge (thePowersGang)
16 //#define DEBUG_F(v...) printf(v)
20 extern void AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
23 typedef struct sBC_StackEnt tBC_StackEnt;
24 typedef struct sBC_Stack tBC_Stack;
26 enum eBC_StackEntTypes
28 ET_NULL, // Start of the stack
30 ET_FUNCTION_START = NUM_SS_DATATYPES,
31 ET_REFERENCE // Reference to a tSpiderValue
40 tSpiderValue *Reference; // Used for everything else
41 tSpiderObject *Object;
42 tSpiderNamespace *Namespace;
50 tBC_StackEnt Entries[];
54 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
55 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
58 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
60 if( Stack->EntryCount == 0 ) return 1;
62 *Dest = Stack->Entries[Stack->EntryCount];
66 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
68 if( Stack->EntryCount == Stack->EntrySpace ) return 1;
69 Stack->Entries[Stack->EntryCount] = *Src;
74 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
78 case SS_DATATYPE_INTEGER:
79 return !!Ent->Integer;
80 case SS_DATATYPE_REAL:
81 return (-.5f < Ent->Real && Ent->Real < 0.5f);
82 case SS_DATATYPE_OBJECT:
83 return Ent->Object != NULL;
84 case ET_FUNCTION_START:
87 return SpiderScript_IsValueTrue(Ent->Reference);
91 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
95 case SS_DATATYPE_INTEGER:
96 case SS_DATATYPE_REAL:
97 case SS_DATATYPE_OBJECT:
99 tmp = malloc(sizeof(tSpiderValue));
100 tmp->ReferenceCount = 1;
102 tmp->ReferenceCount = 2;
110 case SS_DATATYPE_INTEGER:
111 tmp->Type = SS_DATATYPE_INTEGER;
112 tmp->Integer = Ent->Integer;
114 case SS_DATATYPE_REAL:
115 tmp->Type = SS_DATATYPE_REAL;
116 tmp->Real = Ent->Real;
118 case SS_DATATYPE_OBJECT:
119 tmp->Type = SS_DATATYPE_OBJECT;
120 tmp->Object = Ent->Object;
122 case ET_FUNCTION_START:
123 AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
126 return Ent->Reference;
130 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
133 Ent->Type = ET_REFERENCE;
134 Ent->Reference = NULL;
139 case SS_DATATYPE_INTEGER:
140 Ent->Type = SS_DATATYPE_INTEGER;
141 Ent->Integer = Value->Integer;
143 case SS_DATATYPE_REAL:
144 Ent->Type = SS_DATATYPE_REAL;
145 Ent->Real = Value->Real;
147 case SS_DATATYPE_OBJECT:
148 Ent->Type = SS_DATATYPE_OBJECT;
149 Ent->Object = Value->Object;
152 SpiderScript_ReferenceValue(Value);
153 Ent->Type = ET_REFERENCE;
154 Ent->Reference = Value;
159 void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
163 case SS_DATATYPE_INTEGER:
164 case SS_DATATYPE_REAL:
165 case SS_DATATYPE_OBJECT:
168 SpiderScript_DereferenceValue(Ent->Reference);
173 #define GET_STACKVAL(dst) if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
174 AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
177 #define PUT_STACKVAL(src) if((ret = Bytecode_int_StackPush(Stack, &src))) { \
178 AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
181 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
182 #define OP_STRING(op_ptr) ((op_ptr)->Content.StringInt.String)
184 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
186 const int stack_size = 100;
187 tSpiderValue *ret, tmpsval;
192 stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
193 stack->EntrySpace = stack_size;
194 stack->EntryCount = 0;
196 // Push arguments in order (so top is last arg)
197 for( i = 0; i < NArguments; i ++ )
199 Bytecode_int_SetSpiderValue(&val, Args[i]);
200 Bytecode_int_StackPush(stack, &val);
204 Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
207 if( Bytecode_int_StackPop(stack, &val) ) {
212 ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
213 // Ensure it's a heap value
214 if(ret == &tmpsval) {
215 ret = malloc(sizeof(tSpiderValue));
216 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
222 tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
225 tSpiderNamespace *ns = Start;
226 while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
228 int len = pos - Name;
229 for( ns = ns->FirstChild; ns; ns = ns->Next )
231 if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
239 if(FinalName) *FinalName = Name;
243 #define STATE_HDR() DEBUG_F("%p %2i ", op, Stack->EntryCount)
246 * \brief Execute a bytecode function with a stack
248 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
252 tBC_StackEnt val1, val2;
253 int local_var_count = Fcn->BCFcn->MaxVariableCount;
254 tBC_StackEnt local_vars[local_var_count]; // Includes arguments
255 tSpiderValue tmpVal1, tmpVal2; // temp storage
256 tSpiderValue *pval1, *pval2, *ret_val;
257 tSpiderNamespace *default_namespace = &Script->Variant->RootNamespace;
260 if( ArgCount > Fcn->ArgumentCount ) return -1;
261 DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
262 for( i = Fcn->ArgumentCount; i > ArgCount; )
265 local_vars[i].Integer = 0;
266 local_vars[i].Type = Fcn->Arguments[i].Type;
270 GET_STACKVAL(local_vars[i]);
271 // TODO: Type checks / enforcing
275 memset(&val1, 0, sizeof(val1));
276 val1.Type = ET_FUNCTION_START;
280 op = Fcn->BCFcn->Operations;
283 const char *opstr = "";
284 tBC_Op *nextop = op->Next, *jmp_target;
286 switch(op->Operation)
293 // NOTE: Evil, all jumps are off by -1, so fix that
294 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
295 DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
300 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
301 DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
303 if( Bytecode_int_IsStackEntTrue(&val1) )
306 case BC_OP_JUMPIFNOT:
308 jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
309 DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
311 if( !Bytecode_int_IsStackEntTrue(&val1) )
316 case BC_OP_DEFINEVAR: {
318 type = OP_INDX(op) & 0xFFFF;
319 slot = OP_INDX(op) >> 16;
320 if(slot < 0 || slot >= local_var_count) {
321 DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
325 DEBUG_F("DEFVAR %i of type %i\n", slot, type);
326 memset(&local_vars[slot], 0, sizeof(local_vars[0]));
327 local_vars[slot].Type = type;
330 // Enter/Leave context
332 case BC_OP_ENTERCONTEXT:
334 DEBUG_F("ENTERCONTEXT\n");
336 case BC_OP_LEAVECONTEXT:
338 DEBUG_F("LEAVECONTEXT\n");
344 DEBUG_F("LOADVAR %i\n", OP_INDX(op));
345 if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
346 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
349 PUT_STACKVAL(local_vars[OP_INDX(op)]);
350 // DUMP_STACKVAL(local_vars[OP_INDX(op)]);
354 DEBUG_F("SAVEVAR %i\n", OP_INDX(op));
355 if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
356 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
359 GET_STACKVAL(local_vars[OP_INDX(op)]);
365 DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
366 val1.Type = SS_DATATYPE_INTEGER;
367 val1.Integer = op->Content.Integer;
372 DEBUG_F("LOADREAL %lf\n", op->Content.Real);
373 val1.Type = SS_DATATYPE_REAL;
374 val1.Real = op->Content.Real;
379 DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
380 val1.Type = SS_DATATYPE_STRING;
381 val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
387 val2.Type = OP_INDX(op);
388 DEBUG_F("CAST to %i\n", val2.Type);
390 if(val1.Type == val2.Type) {
394 switch(val2.Type * 100 + val1.Type )
396 case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
397 val2.Integer = val1.Real;
400 case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
401 val2.Integer = val1.Real;
405 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
406 pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
407 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
408 Bytecode_int_SetSpiderValue(&val2, pval2);
409 SpiderScript_DereferenceValue(pval2);
417 DEBUG_F("DUPSTACK\n");
426 DEBUG_F("LOGICNOT\n");
429 val2.Type = SS_DATATYPE_INTEGER;
430 val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
431 Bytecode_int_StackPush(Stack, &val2);
432 Bytecode_int_DerefStackValue(&val1);
435 if(!ast_op) ast_op = NODETYPE_BWNOT;
438 DEBUG_F("UNIOP %i\n", ast_op);
441 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
442 ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
443 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
444 Bytecode_int_SetSpiderValue(&val1, ret_val);
445 if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
446 Bytecode_int_StackPush(Stack, &val1);
452 if(!ast_op) ast_op = NODETYPE_LOGICALAND, opstr = "LOGICAND";
454 if(!ast_op) ast_op = NODETYPE_LOGICALOR, opstr = "LOGICOR";
456 if(!ast_op) ast_op = NODETYPE_LOGICALXOR, opstr = "LOGICXOR";
459 if(!ast_op) ast_op = NODETYPE_BWAND, opstr = "BITAND";
461 if(!ast_op) ast_op = NODETYPE_BWOR, opstr = "BITOR";
463 if(!ast_op) ast_op = NODETYPE_BWXOR, opstr = "BITXOR";
465 case BC_OP_BITSHIFTLEFT:
466 if(!ast_op) ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
467 case BC_OP_BITSHIFTRIGHT:
468 if(!ast_op) ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
469 case BC_OP_BITROTATELEFT:
470 if(!ast_op) ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
473 if(!ast_op) ast_op = NODETYPE_ADD, opstr = "ADD";
475 if(!ast_op) ast_op = NODETYPE_SUBTRACT, opstr = "SUBTRACT";
477 if(!ast_op) ast_op = NODETYPE_MULTIPLY, opstr = "MULTIPLY";
479 if(!ast_op) ast_op = NODETYPE_DIVIDE, opstr = "DIVIDE";
481 if(!ast_op) ast_op = NODETYPE_MODULO, opstr = "MODULO";
484 if(!ast_op) ast_op = NODETYPE_EQUALS, opstr = "EQUALS";
486 if(!ast_op) ast_op = NODETYPE_LESSTHAN, opstr = "LESSTHAN";
487 case BC_OP_LESSTHANOREQUAL:
488 if(!ast_op) ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
489 case BC_OP_GREATERTHAN:
490 if(!ast_op) ast_op = NODETYPE_GREATERTHAN, opstr = "GREATERTHAN";
491 case BC_OP_GREATERTHANOREQUAL:
492 if(!ast_op) ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
495 DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
499 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
500 pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
501 ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
502 if(pval1 != &tmpVal1) SpiderScript_DereferenceValue(pval1);
503 if(pval2 != &tmpVal2) SpiderScript_DereferenceValue(pval2);
504 Bytecode_int_SetSpiderValue(&val1, ret_val);
505 if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
506 Bytecode_int_StackPush(Stack, &val1);
510 case BC_OP_CALLFUNCTION: {
511 tScript_Function *fcn;
512 const char *name = OP_STRING(op);
513 int arg_count = OP_INDX(op);
516 DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
518 // Check current script functions (for fast call)
519 for(fcn = Script->Functions; fcn; fcn = fcn->Next)
521 if(strcmp(name, fcn->Name) == 0) {
525 if(fcn && fcn->BCFcn)
527 DEBUG_F(" - Fast call\n");
528 Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
534 tSpiderNamespace *ns = NULL;
535 tSpiderValue *args[arg_count];
537 // for( i = 0; i < arg_count; i ++ )
538 for( i = arg_count; i --; )
541 args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
544 if( name[0] == BC_NS_SEPARATOR ) {
546 ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
549 // TODO: Support multiple default namespaces
550 ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
553 rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
555 AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
560 for( i = arg_count; i --; )
561 SpiderScript_DereferenceValue(args[i]);
562 // Get and push return
563 Bytecode_int_SetSpiderValue(&val1, rv);
566 SpiderScript_DereferenceValue(rv);
579 printf("Unknown operation %i\n", op->Operation);
587 // - Delete local vars
588 printf("TODO: Clean up local vars\n");
591 // printf("TODO: Roll back stack\n");
592 // while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
594 // Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );