SpiderScript - More changes, cleaning up
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / exec_bytecode.c
1 /*
2  * SpiderScript Library
3  * by John Hodge (thePowersGang)
4  * 
5  * bytecode_makefile.c
6  * - Generate a bytecode file
7  */
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include <spiderscript.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 // === CODE ===
45 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
46 {
47         if( Stack->EntryCount == 0 )    return 1;
48         Stack->EntryCount --;
49         *Dest = Stack->Entries[Stack->EntryCount];
50         return 0;
51 }
52
53 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
54 {
55         if( Stack->EntryCount == Stack->EntrySpace )    return 1;
56         Stack->Entries[Stack->EntryCount] = *Src;
57         Stack->EntryCount ++;
58         return 0;
59 }
60
61 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
62 {
63         switch(Ent->Type)
64         {
65         case SS_DATATYPE_INTEGER:
66                 return !!Ent->Integer;
67         case SS_DATATYPE_REAL:
68                 return (-.5f < Ent->Real && Ent->Real < 0.5f);
69         case SS_DATATYPE_OBJECT:
70                 return Ent->Object != NULL;
71         case ET_FUNCTION_START:
72                 return -1;
73         default:
74                 return SpiderScript_IsValueTrue(Ent->Reference);
75         }
76 }
77
78 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
79 {
80         switch(Ent->Type)
81         {
82         case SS_DATATYPE_INTEGER:
83                 tmp->Type = SS_DATATYPE_INTEGER;
84                 tmp->ReferenceCount = 2;        // Stops it being freed
85                 tmp->Integer = Ent->Integer;
86                 return tmp;
87         case SS_DATATYPE_REAL:
88                 tmp->Type = SS_DATATYPE_REAL;
89                 tmp->ReferenceCount = 2;        // Stops it being freed
90                 tmp->Real = Ent->Real;
91                 return tmp;
92         case SS_DATATYPE_OBJECT:
93                 tmp->Type = SS_DATATYPE_OBJECT;
94                 tmp->ReferenceCount = 2;
95                 tmp->Object = Ent->Object;
96                 return tmp;
97         case ET_FUNCTION_START:
98                 return NULL;
99         default:
100                 return Ent->Reference;
101         }
102 }
103
104 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
105 {
106         switch(Value->Type)
107         {
108         case SS_DATATYPE_INTEGER:
109                 Ent->Type = SS_DATATYPE_INTEGER;
110                 Ent->Integer = Value->Integer;
111                 break;
112         case SS_DATATYPE_REAL:
113                 Ent->Type = SS_DATATYPE_REAL;
114                 Ent->Real = Value->Real;
115                 break;
116         case SS_DATATYPE_OBJECT:
117                 Ent->Type = SS_DATATYPE_OBJECT;
118                 Ent->Object = Value->Object;
119                 break;
120         default:
121                 SpiderScript_ReferenceValue(Value);
122                 Ent->Reference = Value;
123                 break;
124         }
125 }
126
127 #define GET_STACKVAL(dst)       if((ret = Bytecode_int_StackPop(Stack, &dst)))    return ret;
128 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
129 #define OP_STRING(op_ptr)       ((op_ptr)->Content.StringInt.String)
130
131 int Bytecode_ExecuteFunction(tSpiderScript *Script, tBC_Function *Fcn, tBC_Stack *Stack, int ArgCount)
132 {
133          int    ret, ast_op, i;
134         tBC_Op  *op;
135         tBC_StackEnt    val1, val2;
136         tBC_StackEnt    local_vars[Fcn->MaxVariableCount];      // Includes arguments
137         tSpiderValue    tmpVal1, tmpVal2;       // temp storage
138         tSpiderValue    *pval1, *pval2, *ret_val;
139         
140         // Pop off arguments
141         if( ArgCount > Fcn->ArgumentCount )     return -1;
142         for( i = Fcn->ArgumentCount; --i != ArgCount; )
143         {
144                 local_vars[i].Integer = 0;
145                 local_vars[i].Type = Fcn->Arguments[i].Type;
146         }
147         for( ; i --; )
148         {
149                 GET_STACKVAL(local_vars[i]);
150                 // TODO: Type checks / enforcing
151         }
152         
153         // Mark the start
154         memset(&val1, 0, sizeof(val1));
155         val1.Type = ET_FUNCTION_START;
156         Bytecode_int_StackPush(Stack, &val1);
157
158         // Execute!
159         op = Fcn->Operations;
160         while(op)
161         {
162                 tBC_Op  *nextop = op->Next;
163                 ast_op = 0;
164                 switch(op->Operation)
165                 {
166                 // Jumps
167                 case BC_OP_JUMP:
168                         nextop = Fcn->Labels[ OP_INDX(op) ];
169                         break;
170                 case BC_OP_JUMPIF:
171                         GET_STACKVAL(val1);
172                         if( Bytecode_int_IsStackEntTrue(&val1) )
173                                 nextop = Fcn->Labels[op->Content.StringInt.Integer];
174                         break;
175                 case BC_OP_JUMPIFNOT:
176                         GET_STACKVAL(val1);
177                         if( !Bytecode_int_IsStackEntTrue(&val1) )
178                                 nextop = Fcn->Labels[op->Content.StringInt.Integer];
179                         break;
180                 
181                 // Define variables
182                 case BC_OP_DEFINEVAR: {
183                          int    type, slot;
184                         type = OP_INDX(op) & 0xFFFF;
185                         slot = OP_INDX(op) >> 16;
186                         if(slot < 0 || slot >= sizeof(local_vars)/sizeof(local_vars[0]))        return -1;
187                         memset(&local_vars[slot], 0, sizeof(local_vars[0]));
188                         local_vars[slot].Type = type;
189                         } break;
190                 
191                 // Operations
192                 case BC_OP_ADD:
193                         ast_op = NODETYPE_ADD;
194                 case BC_OP_SUBTRACT:
195                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT;
196                         
197                         GET_STACKVAL(val2);
198                         GET_STACKVAL(val1);
199                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
200                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
201                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
202                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
203                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
204                         Bytecode_int_SetSpiderValue(&val1, ret_val);
205                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
206                         break;
207
208                 default:
209                         // TODO:
210                         break;
211                 }
212                 op = nextop;
213         }
214         
215         // Clean up
216         // - Delete local vars
217
218         
219         // - Restore stack
220         
221
222         return 0;
223 }
224

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