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

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