SpiderScript - More changes, cleaning up
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / bytecode_gen.c
1 /*
2  * SpiderScript Library
3  * by John Hodge (thePowersGang)
4  * 
5  * bytecode_gen.c
6  * - Generate bytecode
7  */
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include "bytecode_ops.h"
11 #include <stdio.h>
12 #include "bytecode_gen.h"
13 #include <string.h>
14 #include "bytecode.h"
15
16 // === IMPORTS ===
17
18 // === STRUCTURES ===
19
20 // === PROTOTYPES ===
21 tBC_Op  *Bytecode_int_AllocateOp(int Operation);
22  int    Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name);
23
24 // === GLOBALS ===
25
26 // === CODE ===
27 tBC_Op *Bytecode_int_AllocateOp(int Operation)
28 {
29         tBC_Op  *ret;
30
31         ret = malloc(sizeof(tBC_Op));
32         if(!ret)        return NULL;
33
34         ret->Next = NULL;
35         ret->Operation = Operation;
36         ret->bUseInteger = 0;
37
38         return ret;
39 }
40
41 tBC_Function *Bytecode_CreateFunction(const char *Name, int ArgCount, char **ArgNames, int *ArgTypes)
42 {
43         tBC_Function *ret;
44          int    i;
45
46         ret = malloc(sizeof(tBC_Function) + ArgCount*sizeof(ret->Arguments[0]));
47         if(!ret)        return NULL;
48         
49         ret->Name = Name;
50         ret->LabelSpace = ret->LabelCount = 0;
51         ret->Labels = NULL;
52
53         ret->MaxVariableCount = 0;
54         ret->CurContextDepth = 0;       
55         ret->VariableCount = ret->VariableSpace = 0;
56         ret->VariableNames = NULL;
57
58         ret->OperationCount = 0;
59         ret->Operations = NULL;
60         ret->OperationsEnd = (void*)&ret->Operations;
61
62         ret->ArgumentCount = ArgCount;
63         for( i = 0; i < ArgCount; i ++ )
64         {
65                 ret->Arguments[i].Name = strdup(ArgNames[i]);
66                 ret->Arguments[i].Type = ArgTypes[i];
67                 Bytecode_int_AddVariable(ret, ret->Arguments[i].Name);
68         }
69
70         return ret;
71 }
72
73 void Bytecode_DeleteFunction(tBC_Function *Fcn)
74 {
75         tBC_Op  *op;
76          int    i;
77         for( i = 0; i < Fcn->ArgumentCount; i ++ )
78         {
79                 free(Fcn->Arguments[i].Name);
80         }
81         for( op = Fcn->Operations; op; )
82         {
83                 tBC_Op  *nextop = op->Next;
84                 free(op);
85                 op = nextop;
86         }
87         free(Fcn->VariableNames);
88         free(Fcn->Labels);
89         free(Fcn);
90 }
91
92 int StringList_GetString(tStringList *List, const char *String, int Length)
93 {
94          int    strIdx = 0;
95         tString *ent;
96         for(ent = List->Head; ent; ent = ent->Next, strIdx ++)
97         {
98                 if(ent->Length == Length && memcmp(ent->Data, String, Length) == 0)     break;
99         }
100         if( ent ) {
101                 ent->RefCount ++;
102         }
103         else {
104                 ent = malloc(sizeof(tString) + Length + 1);
105                 if(!ent)        return -1;
106                 ent->Next = NULL;
107                 ent->Length = Length;
108                 ent->RefCount = 1;
109                 memcpy(ent->Data, String, Length);
110                 ent->Data[Length] = '\0';
111                 
112                 if(List->Head)
113                         List->Tail->Next = ent;
114                 else
115                         List->Head = ent;
116                 List->Tail = ent;
117                 List->Count ++;
118         }
119         return strIdx;
120 }
121
122 int Bytecode_int_Serialize(const tBC_Function *Function, void *Output, int *LabelOffsets, tStringList *Strings)
123 {
124         tBC_Op  *op;
125          int    len = 0, idx = 0;
126          int    i;
127
128         void _put_byte(uint8_t byte)
129         {
130                 uint8_t *buf = Output;
131                 if(Output)      buf[len] = byte;
132                 len ++;
133         }
134
135         void _put_dword(uint32_t value)
136         {
137                 uint8_t *buf = Output;
138                 if(Output) {
139                         buf[len+0] = value & 0xFF;
140                         buf[len+1] = value >> 8;
141                         buf[len+2] = value >> 16;
142                         buf[len+3] = value >> 24;
143                 }
144                 len += 4;
145         }
146         
147         void _put_qword(uint64_t value)
148         {
149                 _put_dword(value & 0xFFFFFFFF);
150                 _put_dword(value >> 32);
151         }
152
153         void _put_double(double value)
154         {
155                 // TODO: Machine agnostic
156                 if(Output) {
157                         *(double*)( (char*)Output + len ) = value;
158                 }
159                 len += sizeof(double);
160         }
161
162         void _put_string(const char *str, int len)
163         {
164                  int    strIdx = 0;
165                 if( Output ) {
166                         strIdx = StringList_GetString(Strings, str, len);
167                 }
168         
169                 // TODO: Relocations    
170                 _put_dword(strIdx);
171         }
172
173         for( op = Function->Operations; op; op = op->Next, idx ++ )
174         {
175                 // If first run, convert labels into byte offsets
176                 if( !Output )
177                 {
178                         for( i = 0; i < Function->LabelCount; i ++ )
179                         {
180                                 if(LabelOffsets[i])     continue;
181                                 if(op != Function->Labels[i])   continue;
182                                 
183                                 LabelOffsets[i] = len;
184                         }
185                 }
186
187                 _put_byte(op->Operation);
188                 switch(op->Operation)
189                 {
190                 // Relocate jumps (the value only matters if `Output` is non-NULL)
191                 case BC_OP_JUMP:
192                 case BC_OP_JUMPIF:
193                 case BC_OP_JUMPIFNOT:
194                         // TODO: Relocations?
195                         _put_dword( LabelOffsets[op->Content.StringInt.Integer] );
196                         break;
197                 // Special case for inline values
198                 case BC_OP_LOADINT:
199                         _put_qword(op->Content.Integer);
200                         break;
201                 case BC_OP_LOADREAL:
202                         _put_double(op->Content.Real);
203                         break;
204                 case BC_OP_LOADSTR:
205                         _put_string(op->Content.StringInt.String, op->Content.StringInt.Integer);
206                         break;
207                 // Everthing else just gets handled nicely
208                 default:
209                         if( op->Content.StringInt.String )
210                                 _put_string(op->Content.StringInt.String, strlen(op->Content.StringInt.String));
211                         if( op->bUseInteger )
212                                 _put_dword(op->Content.StringInt.Integer);
213                         break;
214                 }
215         }
216
217         return len;
218 }
219
220 char *Bytecode_SerialiseFunction(const tBC_Function *Function, int *Length, tStringList *Strings)
221 {
222          int    len;
223          int    *label_offsets;
224         char    *code;
225
226         label_offsets = calloc( sizeof(int), Function->LabelCount );
227         if(!label_offsets)      return NULL;
228
229         len = Bytecode_int_Serialize(Function, NULL, label_offsets, Strings);
230
231         code = malloc(len);
232         
233         Bytecode_int_Serialize(Function, code, label_offsets, Strings);
234
235         free(label_offsets);
236
237         *Length = len;
238
239         return code;
240 }
241
242 int Bytecode_AllocateLabel(tBC_Function *Handle)
243 {
244          int    ret;
245         
246         if( Handle->LabelCount == Handle->LabelSpace ) {
247                 void *tmp;
248                 Handle->LabelSpace += 20;       // TODO: Don't hardcode increment
249                 tmp = realloc(Handle->Labels, Handle->LabelSpace * sizeof(Handle->Labels[0]));
250                 if( !tmp ) {
251                         Handle->LabelSpace -= 20;
252                         return -1;
253                 }
254                 Handle->Labels = tmp;
255         }
256         ret = Handle->LabelCount ++;
257         Handle->Labels[ret] = 0;
258         return ret;
259 }
260
261 void Bytecode_SetLabel(tBC_Function *Handle, int Label)
262 {
263         if(Label < 0)   return ;
264         
265         if(Label >= Handle->LabelCount) return ;
266
267         Handle->Labels[Label] = Handle->OperationsEnd;
268         return ;
269 }
270
271 void Bytecode_int_AppendOp(tBC_Function *Fcn, tBC_Op *Op)
272 {
273         Op->Next = NULL;
274         if( Fcn->Operations )
275                 Fcn->OperationsEnd->Next = Op;
276         else
277                 Fcn->Operations = Op;
278         Fcn->OperationsEnd = Op;
279 }
280
281 int Bytecode_int_AddVariable(tBC_Function *Handle, const char *Name)
282 {
283         if(Handle->VariableCount == Handle->VariableSpace) {
284                 void    *tmp;
285                 Handle->VariableSpace += 10;
286                 tmp = realloc(Handle->VariableNames, Handle->VariableSpace * sizeof(Handle->VariableNames[0]));
287                 if(!tmp)        return -1;      // TODO: Error
288                 Handle->VariableNames = tmp;
289         }
290         Handle->VariableNames[Handle->VariableCount] = Name;
291         Handle->VariableCount ++;
292         // Get max count (used when executing to get the frame size)
293         if(Handle->VariableCount - Handle->CurContextDepth >= Handle->MaxVariableCount)
294                 Handle->MaxVariableCount = Handle->VariableCount - Handle->CurContextDepth;
295         return Handle->VariableCount - 1;
296 }
297
298 int Bytecode_int_GetVarIndex(tBC_Function *Handle, const char *Name)
299 {
300          int    i;
301         // Get the start of this context
302         for( i = Handle->VariableCount; i --; )
303         {
304                 if( Handle->VariableNames[i] && strcmp(Name, Handle->VariableNames[i]) == 0 )
305                         return i;
306         }
307         return -1;
308 }
309
310 #define DEF_BC_NONE(_op) { \
311         tBC_Op *op = Bytecode_int_AllocateOp(_op); \
312         op->Content.Integer = 0; \
313         op->bUseInteger = 0; \
314         Bytecode_int_AppendOp(Handle, op);\
315 }
316
317 #define DEF_BC_STRINT(_op, _str, _int) { \
318         tBC_Op *op = Bytecode_int_AllocateOp(_op);\
319         op->Content.StringInt.Integer = _int;\
320         op->Content.StringInt.String = _str;\
321         op->bUseInteger = 1;\
322         Bytecode_int_AppendOp(Handle, op);\
323 }
324 #define DEF_BC_STR(_op, _str) {\
325         tBC_Op *op = Bytecode_int_AllocateOp(_op);\
326         op->Content.StringInt.String = _str;\
327         op->bUseInteger = 0;\
328         Bytecode_int_AppendOp(Handle, op);\
329 }
330
331 // --- Flow Control
332 void Bytecode_AppendJump(tBC_Function *Handle, int Label)
333         DEF_BC_STRINT(BC_OP_JUMP, NULL, Label)
334 void Bytecode_AppendCondJump(tBC_Function *Handle, int Label)
335         DEF_BC_STRINT(BC_OP_JUMPIF, NULL, Label)
336 void Bytecode_AppendReturn(tBC_Function *Handle)
337         DEF_BC_NONE(BC_OP_RETURN);
338
339 // --- Variables
340 void Bytecode_AppendLoadVar(tBC_Function *Handle, const char *Name)
341         DEF_BC_STRINT(BC_OP_LOADVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
342 //      DEF_BC_STR(BC_OP_LOADVAR, Name)
343 void Bytecode_AppendSaveVar(tBC_Function *Handle, const char *Name)     // (Obj->)?var = 
344         DEF_BC_STRINT(BC_OP_SAVEVAR, NULL, Bytecode_int_GetVarIndex(Handle, Name))
345 //      DEF_BC_STR(BC_OP_SAVEVAR, Name)
346
347 // --- Constants
348 void Bytecode_AppendConstInt(tBC_Function *Handle, uint64_t Value)
349 {
350         tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADINT);
351         op->Content.Integer = Value;
352         Bytecode_int_AppendOp(Handle, op);
353 }
354 void Bytecode_AppendConstReal(tBC_Function *Handle, double Value)
355 {
356         tBC_Op *op = Bytecode_int_AllocateOp(BC_OP_LOADREAL);
357         op->Content.Real = Value;
358         Bytecode_int_AppendOp(Handle, op);
359 }
360 void Bytecode_AppendConstString(tBC_Function *Handle, const void *Data, size_t Length)
361         DEF_BC_STRINT(BC_OP_LOADSTR, Data, Length)
362
363 // --- Indexing / Scoping
364 void Bytecode_AppendSubNamespace(tBC_Function *Handle, const char *Name)
365         DEF_BC_STR(BC_OP_SCOPE, Name)
366 void Bytecode_AppendElement(tBC_Function *Handle, const char *Name)
367         DEF_BC_STR(BC_OP_ELEMENT, Name)
368 void Bytecode_AppendIndex(tBC_Function *Handle)
369         DEF_BC_NONE(BC_OP_INDEX)
370
371 void Bytecode_AppendCreateObj(tBC_Function *Handle, const char *Name, int ArgumentCount)
372         DEF_BC_STRINT(BC_OP_CREATEOBJ, Name, ArgumentCount)
373 void Bytecode_AppendMethodCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
374         DEF_BC_STRINT(BC_OP_CALLMETHOD, Name, ArgumentCount)
375 void Bytecode_AppendFunctionCall(tBC_Function *Handle, const char *Name, int ArgumentCount)
376         DEF_BC_STRINT(BC_OP_CALLFUNCTION, Name, ArgumentCount)
377
378 void Bytecode_AppendBinOp(tBC_Function *Handle, int Operation)
379         DEF_BC_NONE(Operation)
380 void Bytecode_AppendUniOp(tBC_Function *Handle, int Operation)
381         DEF_BC_NONE(Operation)
382 void Bytecode_AppendCast(tBC_Function *Handle, int Type)
383         DEF_BC_STRINT(BC_OP_CAST, NULL, Type)
384
385 // Does some bookeeping to allocate variable slots at compile time
386 void Bytecode_AppendEnterContext(tBC_Function *Handle)
387 {
388         Handle->CurContextDepth ++;
389         Bytecode_int_AddVariable(Handle, NULL); // NULL to record the extent of this    
390
391         DEF_BC_NONE(BC_OP_ENTERCONTEXT)
392 }
393 void Bytecode_AppendLeaveContext(tBC_Function *Handle)
394 {
395          int    i;
396         for( i = Handle->VariableCount; i --; )
397         {
398                 if( Handle->VariableNames[i] == NULL )  break;
399         }
400         Handle->CurContextDepth --;
401         Handle->VariableCount = i;
402
403         DEF_BC_NONE(BC_OP_LEAVECONTEXT)
404 }
405 //void Bytecode_AppendImportNamespace(tBC_Function *Handle, const char *Name);
406 //      DEF_BC_STRINT(BC_OP_IMPORTNS, Name, 0)
407 void Bytecode_AppendDefineVar(tBC_Function *Handle, const char *Name, int Type)
408 {
409          int    i;
410         #if 1
411         // Get the start of this context
412         for( i = Handle->VariableCount; i --; )
413         {
414                 if( Handle->VariableNames[i] == NULL )  break;
415         }
416         // Check for duplicate allocation
417         for( i ++; i < Handle->VariableCount; i ++ )
418         {
419                 if( strcmp(Name, Handle->VariableNames[i]) == 0 )
420                         return ;
421         }
422         #endif
423
424         i = Bytecode_int_AddVariable(Handle, Name);
425         
426         DEF_BC_STRINT(BC_OP_DEFINEVAR, Name, (Type&0xFFFF) | (i << 16))
427 }

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