SpiderScript - Restructured to be able to keep bytecode and AST in memory at one...
[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 <string.h>
13 #include "ast.h"
14
15 typedef struct sBC_StackEnt     tBC_StackEnt;
16 typedef struct sBC_Stack        tBC_Stack;
17
18 enum eBC_StackEntTypes
19 {
20         ET_NULL,        // Start of the stack
21         // SS_DATATYPE_*
22         ET_FUNCTION_START = NUM_SS_DATATYPES,
23         ET_REFERENCE    // Reference to a tSpiderValue
24 };
25
26 struct sBC_StackEnt
27 {
28         uint8_t Type;
29         union {
30                 uint64_t        Integer;
31                 double          Real;
32                 tSpiderValue    *Reference;     // Used for everything else
33                 tSpiderObject   *Object;
34         };
35 };
36
37 struct sBC_Stack
38 {
39          int    EntrySpace;
40          int    EntryCount;
41         tBC_StackEnt    Entries[];
42 };
43
44 // === PROTOTYPES ===
45 tSpiderValue    *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
46  int    Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
47
48 // === CODE ===
49 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
50 {
51         if( Stack->EntryCount == 0 )    return 1;
52         Stack->EntryCount --;
53         *Dest = Stack->Entries[Stack->EntryCount];
54         return 0;
55 }
56
57 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
58 {
59         if( Stack->EntryCount == Stack->EntrySpace )    return 1;
60         Stack->Entries[Stack->EntryCount] = *Src;
61         Stack->EntryCount ++;
62         return 0;
63 }
64
65 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
66 {
67         switch(Ent->Type)
68         {
69         case SS_DATATYPE_INTEGER:
70                 return !!Ent->Integer;
71         case SS_DATATYPE_REAL:
72                 return (-.5f < Ent->Real && Ent->Real < 0.5f);
73         case SS_DATATYPE_OBJECT:
74                 return Ent->Object != NULL;
75         case ET_FUNCTION_START:
76                 return -1;
77         default:
78                 return SpiderScript_IsValueTrue(Ent->Reference);
79         }
80 }
81
82 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
83 {
84         switch(Ent->Type)
85         {
86         case SS_DATATYPE_INTEGER:
87                 tmp->Type = SS_DATATYPE_INTEGER;
88                 tmp->ReferenceCount = 2;        // Stops it being freed
89                 tmp->Integer = Ent->Integer;
90                 return tmp;
91         case SS_DATATYPE_REAL:
92                 tmp->Type = SS_DATATYPE_REAL;
93                 tmp->ReferenceCount = 2;        // Stops it being freed
94                 tmp->Real = Ent->Real;
95                 return tmp;
96         case SS_DATATYPE_OBJECT:
97                 tmp->Type = SS_DATATYPE_OBJECT;
98                 tmp->ReferenceCount = 2;
99                 tmp->Object = Ent->Object;
100                 return tmp;
101         case ET_FUNCTION_START:
102                 return NULL;
103         default:
104                 return Ent->Reference;
105         }
106 }
107
108 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
109 {
110         switch(Value->Type)
111         {
112         case SS_DATATYPE_INTEGER:
113                 Ent->Type = SS_DATATYPE_INTEGER;
114                 Ent->Integer = Value->Integer;
115                 break;
116         case SS_DATATYPE_REAL:
117                 Ent->Type = SS_DATATYPE_REAL;
118                 Ent->Real = Value->Real;
119                 break;
120         case SS_DATATYPE_OBJECT:
121                 Ent->Type = SS_DATATYPE_OBJECT;
122                 Ent->Object = Value->Object;
123                 break;
124         default:
125                 SpiderScript_ReferenceValue(Value);
126                 Ent->Reference = Value;
127                 break;
128         }
129 }
130
131 #define GET_STACKVAL(dst)       if((ret = Bytecode_int_StackPop(Stack, &dst)))    return ret;
132 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
133 #define OP_STRING(op_ptr)       ((op_ptr)->Content.StringInt.String)
134
135 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
136 {
137         const int       stack_size = 100;
138         tSpiderValue    *ret, tmpsval;
139         tBC_Stack       *stack;
140         tBC_StackEnt    val;
141          int    i;
142         
143         stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
144         stack->EntrySpace = stack_size;
145         stack->EntryCount = 0;
146
147         // Push arguments in order (so top is last arg)
148         for( i = 0; i < NArguments; i ++ )
149         {
150                 Bytecode_int_SetSpiderValue(&val, Args[i]);
151                 Bytecode_int_StackPush(stack, &val);
152         }
153
154         // Call
155         Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
156
157         // Get return value
158         Bytecode_int_StackPop(stack, &val);
159         ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
160         // Ensure it's a heap value
161         if(ret == &tmpsval) {
162                 ret = malloc(sizeof(tSpiderValue));
163                 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
164         }
165         return ret;
166 }
167
168 /**
169  * \brief Execute a bytecode function with a stack
170  */
171 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
172 {
173          int    ret, ast_op, i;
174         tBC_Op  *op;
175         tBC_StackEnt    val1, val2;
176         tBC_StackEnt    local_vars[Fcn->BCFcn->MaxVariableCount];       // Includes arguments
177         tSpiderValue    tmpVal1, tmpVal2;       // temp storage
178         tSpiderValue    *pval1, *pval2, *ret_val;
179         
180         // Pop off arguments
181         if( ArgCount > Fcn->ArgumentCount )     return -1;
182         for( i = Fcn->ArgumentCount; --i != ArgCount; )
183         {
184                 local_vars[i].Integer = 0;
185                 local_vars[i].Type = Fcn->Arguments[i].Type;
186         }
187         for( ; i --; )
188         {
189                 GET_STACKVAL(local_vars[i]);
190                 // TODO: Type checks / enforcing
191         }
192         
193         // Mark the start
194         memset(&val1, 0, sizeof(val1));
195         val1.Type = ET_FUNCTION_START;
196         Bytecode_int_StackPush(Stack, &val1);
197
198         // Execute!
199         op = Fcn->BCFcn->Operations;
200         while(op)
201         {
202                 tBC_Op  *nextop = op->Next;
203                 ast_op = 0;
204                 switch(op->Operation)
205                 {
206                 // Jumps
207                 case BC_OP_JUMP:
208                         nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
209                         break;
210                 case BC_OP_JUMPIF:
211                         GET_STACKVAL(val1);
212                         if( Bytecode_int_IsStackEntTrue(&val1) )
213                                 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
214                         break;
215                 case BC_OP_JUMPIFNOT:
216                         GET_STACKVAL(val1);
217                         if( !Bytecode_int_IsStackEntTrue(&val1) )
218                                 nextop = Fcn->BCFcn->Labels[ OP_INDX(op) ];
219                         break;
220                 
221                 // Define variables
222                 case BC_OP_DEFINEVAR: {
223                          int    type, slot;
224                         type = OP_INDX(op) & 0xFFFF;
225                         slot = OP_INDX(op) >> 16;
226                         if(slot < 0 || slot >= sizeof(local_vars)/sizeof(local_vars[0]))        return -1;
227                         memset(&local_vars[slot], 0, sizeof(local_vars[0]));
228                         local_vars[slot].Type = type;
229                         } break;
230                 
231                 // Operations
232                 case BC_OP_ADD:
233                         ast_op = NODETYPE_ADD;
234                 case BC_OP_SUBTRACT:
235                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT;
236                         
237                         GET_STACKVAL(val2);
238                         GET_STACKVAL(val1);
239                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
240                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
241                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
242                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
243                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
244                         Bytecode_int_SetSpiderValue(&val1, ret_val);
245                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
246                         break;
247
248                 default:
249                         // TODO:
250                         break;
251                 }
252                 op = nextop;
253         }
254         
255         // Clean up
256         // - Delete local vars
257
258         
259         // - Restore stack
260         
261
262         return 0;
263 }
264

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