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

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