1a74d4c2eae7222a1fce73e1e602ce2bf938c803
[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 //#define DEBUG_F(v...) printf(v)
17 #define DEBUG_F(v...)
18
19 // === IMPORTS ===
20 extern void     AST_RuntimeError(tAST_Node *Node, const char *Format, ...);
21
22 // === TYPES ===
23 typedef struct sBC_StackEnt     tBC_StackEnt;
24 typedef struct sBC_Stack        tBC_Stack;
25
26 enum eBC_StackEntTypes
27 {
28         ET_NULL,        // Start of the stack
29         // SS_DATATYPE_*
30         ET_FUNCTION_START = NUM_SS_DATATYPES,
31         ET_REFERENCE    // Reference to a tSpiderValue
32 };
33
34 struct sBC_StackEnt
35 {
36         uint8_t Type;
37         union {
38                 uint64_t        Integer;
39                 double          Real;
40                 tSpiderValue    *Reference;     // Used for everything else
41                 tSpiderObject   *Object;
42                 tSpiderNamespace        *Namespace;
43         };
44 };
45
46 struct sBC_Stack
47 {
48          int    EntrySpace;
49          int    EntryCount;
50         tBC_StackEnt    Entries[];
51 };
52
53 // === PROTOTYPES ===
54 tSpiderValue    *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args);
55  int    Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount);
56
57 // === CODE ===
58 int Bytecode_int_StackPop(tBC_Stack *Stack, tBC_StackEnt *Dest)
59 {
60         if( Stack->EntryCount == 0 )    return 1;
61         Stack->EntryCount --;
62         *Dest = Stack->Entries[Stack->EntryCount];
63         return 0;
64 }
65
66 int Bytecode_int_StackPush(tBC_Stack *Stack, tBC_StackEnt *Src)
67 {
68         if( Stack->EntryCount == Stack->EntrySpace )    return 1;
69         Stack->Entries[Stack->EntryCount] = *Src;
70         Stack->EntryCount ++;
71         return 0;
72 }
73
74 int Bytecode_int_IsStackEntTrue(tBC_StackEnt *Ent)
75 {
76         switch(Ent->Type)
77         {
78         case SS_DATATYPE_INTEGER:
79                 return !!Ent->Integer;
80         case SS_DATATYPE_REAL:
81                 return (-.5f < Ent->Real && Ent->Real < 0.5f);
82         case SS_DATATYPE_OBJECT:
83                 return Ent->Object != NULL;
84         case ET_FUNCTION_START:
85                 return -1;
86         default:
87                 return SpiderScript_IsValueTrue(Ent->Reference);
88         }
89 }
90
91 tSpiderValue *Bytecode_int_GetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *tmp)
92 {
93         switch(Ent->Type)
94         {
95         case SS_DATATYPE_INTEGER:
96         case SS_DATATYPE_REAL:
97         case SS_DATATYPE_OBJECT:
98                 if(!tmp) {
99                         tmp = malloc(sizeof(tSpiderValue));
100                         tmp->ReferenceCount = 1;
101                 } else {
102                         tmp->ReferenceCount = 2;
103                 }
104                 break;
105         default:
106                 break;
107         }
108         switch(Ent->Type)
109         {
110         case SS_DATATYPE_INTEGER:
111                 tmp->Type = SS_DATATYPE_INTEGER;
112                 tmp->Integer = Ent->Integer;
113                 return tmp;
114         case SS_DATATYPE_REAL:
115                 tmp->Type = SS_DATATYPE_REAL;
116                 tmp->Real = Ent->Real;
117                 return tmp;
118         case SS_DATATYPE_OBJECT:
119                 tmp->Type = SS_DATATYPE_OBJECT;
120                 tmp->Object = Ent->Object;
121                 return tmp;
122         case ET_FUNCTION_START:
123                 AST_RuntimeError(NULL, "_GetSpiderValue on ET_FUNCTION_START");
124                 return NULL;
125         default:
126                 return Ent->Reference;
127         }
128 }
129
130 void Bytecode_int_SetSpiderValue(tBC_StackEnt *Ent, tSpiderValue *Value)
131 {
132         if(!Value) {
133                 Ent->Type = ET_REFERENCE;
134                 Ent->Reference = NULL;
135                 return ;
136         }
137         switch(Value->Type)
138         {
139         case SS_DATATYPE_INTEGER:
140                 Ent->Type = SS_DATATYPE_INTEGER;
141                 Ent->Integer = Value->Integer;
142                 break;
143         case SS_DATATYPE_REAL:
144                 Ent->Type = SS_DATATYPE_REAL;
145                 Ent->Real = Value->Real;
146                 break;
147         case SS_DATATYPE_OBJECT:
148                 Ent->Type = SS_DATATYPE_OBJECT;
149                 Ent->Object = Value->Object;
150                 break;
151         default:
152                 SpiderScript_ReferenceValue(Value);
153                 Ent->Type = ET_REFERENCE;
154                 Ent->Reference = Value;
155                 break;
156         }
157 }
158
159 void Bytecode_int_DerefStackValue(tBC_StackEnt *Ent)
160 {
161         switch(Ent->Type)
162         {
163         case SS_DATATYPE_INTEGER:
164         case SS_DATATYPE_REAL:
165         case SS_DATATYPE_OBJECT:
166                 break;
167         default:
168                 SpiderScript_DereferenceValue(Ent->Reference);
169                 break;
170         }
171 }
172
173 #define GET_STACKVAL(dst)       if((ret = Bytecode_int_StackPop(Stack, &dst))) { \
174         AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
175         return ret; \
176 }
177 #define PUT_STACKVAL(src)       if((ret = Bytecode_int_StackPush(Stack, &src))) { \
178         AST_RuntimeError(NULL, "Stack pop failed, empty stack");\
179         return ret; \
180 }
181 #define OP_INDX(op_ptr) ((op_ptr)->Content.StringInt.Integer)
182 #define OP_STRING(op_ptr)       ((op_ptr)->Content.StringInt.String)
183
184 tSpiderValue *Bytecode_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, int NArguments, tSpiderValue **Args)
185 {
186         const int       stack_size = 100;
187         tSpiderValue    *ret, tmpsval;
188         tBC_Stack       *stack;
189         tBC_StackEnt    val;
190          int    i;
191         
192         stack = malloc(sizeof(tBC_Stack) + stack_size*sizeof(tBC_StackEnt));
193         stack->EntrySpace = stack_size;
194         stack->EntryCount = 0;
195
196         // Push arguments in order (so top is last arg)
197         for( i = 0; i < NArguments; i ++ )
198         {
199                 Bytecode_int_SetSpiderValue(&val, Args[i]);
200                 Bytecode_int_StackPush(stack, &val);
201         }
202
203         // Call
204         Bytecode_int_ExecuteFunction(Script, Fcn, stack, NArguments);
205
206         // Get return value
207         if( Bytecode_int_StackPop(stack, &val) ) {
208                 free(stack);
209                 return NULL;
210         }
211         free(stack);
212         ret = Bytecode_int_GetSpiderValue(&val, &tmpsval);
213         // Ensure it's a heap value
214         if(ret == &tmpsval) {
215                 ret = malloc(sizeof(tSpiderValue));
216                 memcpy(ret, &tmpsval, sizeof(tSpiderValue));
217         }
218
219         return ret;
220 }
221
222 tSpiderNamespace *Bytecode_int_ResolveNamespace(tSpiderNamespace *Start, const char *Name, const char **FinalName)
223 {
224         char    *pos;
225         tSpiderNamespace        *ns = Start;
226         while( (pos = strchr(Name, BC_NS_SEPARATOR)) )
227         {
228                  int    len = pos - Name;
229                 for( ns = ns->FirstChild; ns; ns = ns->Next )
230                 {
231                         if(memcmp(ns->Name, Name, len) == 0 && ns->Name[len] == 0)
232                         break;
233                 }
234                 if(!ns) {
235                         return NULL;
236                 }
237                 Name += len + 1;
238         }
239         if(FinalName)   *FinalName = Name;
240         return ns;
241 }
242
243 #define STATE_HDR()     DEBUG_F("%p %2i ", op, Stack->EntryCount)
244
245 /**
246  * \brief Execute a bytecode function with a stack
247  */
248 int Bytecode_int_ExecuteFunction(tSpiderScript *Script, tScript_Function *Fcn, tBC_Stack *Stack, int ArgCount)
249 {
250          int    ret, ast_op, i;
251         tBC_Op  *op;
252         tBC_StackEnt    val1, val2;
253          int    local_var_count = Fcn->BCFcn->MaxVariableCount;
254         tBC_StackEnt    local_vars[local_var_count];    // Includes arguments
255         tSpiderValue    tmpVal1, tmpVal2;       // temp storage
256         tSpiderValue    *pval1, *pval2, *ret_val;
257         tSpiderNamespace        *default_namespace = &Script->Variant->RootNamespace;
258         
259         // Pop off arguments
260         if( ArgCount > Fcn->ArgumentCount )     return -1;
261         DEBUG_F("Fcn->ArgumentCount = %i\n", Fcn->ArgumentCount);
262         for( i = Fcn->ArgumentCount; i > ArgCount; )
263         {
264                 i --;
265                 local_vars[i].Integer = 0;
266                 local_vars[i].Type = Fcn->Arguments[i].Type;
267         }
268         for( ; i --; )
269         {
270                 GET_STACKVAL(local_vars[i]);
271                 // TODO: Type checks / enforcing
272         }
273         
274         // Mark the start
275         memset(&val1, 0, sizeof(val1));
276         val1.Type = ET_FUNCTION_START;
277         PUT_STACKVAL(val1);
278
279         // Execute!
280         op = Fcn->BCFcn->Operations;
281         while(op)
282         {
283                 const char      *opstr = "";
284                 tBC_Op  *nextop = op->Next, *jmp_target;
285                 ast_op = 0;
286                 switch(op->Operation)
287                 {
288                 case BC_OP_NOP:
289                         break;
290                 // Jumps
291                 case BC_OP_JUMP:
292                         STATE_HDR();
293                         // NOTE: Evil, all jumps are off by -1, so fix that
294                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
295                         DEBUG_F("JUMP #%i %p\n", OP_INDX(op), jmp_target);
296                         nextop = jmp_target;
297                         break;
298                 case BC_OP_JUMPIF:
299                         STATE_HDR();
300                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
301                         DEBUG_F("JUMPIF #%i %p\n", OP_INDX(op), jmp_target);
302                         GET_STACKVAL(val1);
303                         if( Bytecode_int_IsStackEntTrue(&val1) )
304                                 nextop = jmp_target;
305                         break;
306                 case BC_OP_JUMPIFNOT:
307                         STATE_HDR();
308                         jmp_target = Fcn->BCFcn->Labels[ OP_INDX(op) ]->Next;
309                         DEBUG_F("JUMPIFNOT #%i %p\n", OP_INDX(op), jmp_target);
310                         GET_STACKVAL(val1);
311                         if( !Bytecode_int_IsStackEntTrue(&val1) )
312                                 nextop = jmp_target;
313                         break;
314                 
315                 // Define variables
316                 case BC_OP_DEFINEVAR: {
317                          int    type, slot;
318                         type = OP_INDX(op) & 0xFFFF;
319                         slot = OP_INDX(op) >> 16;
320                         if(slot < 0 || slot >= local_var_count) {
321                                 DEBUG_F("ERROR: slot %i out of range (max %i)\n", slot, local_var_count);
322                                 return -1;
323                         }
324                         STATE_HDR();
325                         DEBUG_F("DEFVAR %i of type %i\n", slot, type);
326                         memset(&local_vars[slot], 0, sizeof(local_vars[0]));
327                         local_vars[slot].Type = type;
328                         } break;
329
330                 // Enter/Leave context
331                 // - NOP now            
332                 case BC_OP_ENTERCONTEXT:
333                         STATE_HDR();
334                         DEBUG_F("ENTERCONTEXT\n");
335                         break;
336                 case BC_OP_LEAVECONTEXT:
337                         STATE_HDR();
338                         DEBUG_F("LEAVECONTEXT\n");
339                         break;
340
341                 // Variables
342                 case BC_OP_LOADVAR:
343                         STATE_HDR();
344                         DEBUG_F("LOADVAR %i\n", OP_INDX(op));
345                         if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
346                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
347                                 return -1;
348                         }
349                         PUT_STACKVAL(local_vars[OP_INDX(op)]);
350 //                      DUMP_STACKVAL(local_vars[OP_INDX(op)]);
351                         break;
352                 case BC_OP_SAVEVAR:
353                         STATE_HDR();
354                         DEBUG_F("SAVEVAR %i\n", OP_INDX(op));
355                         if( OP_INDX(op) < 0 || OP_INDX(op) >= local_var_count ) {
356                                 AST_RuntimeError(NULL, "Loading from invalid slot %i", OP_INDX(op));
357                                 return -1;
358                         }
359                         GET_STACKVAL(local_vars[OP_INDX(op)]);
360                         break;
361
362                 // Constants:
363                 case BC_OP_LOADINT:
364                         STATE_HDR();
365                         DEBUG_F("LOADINT 0x%lx\n", op->Content.Integer);
366                         val1.Type = SS_DATATYPE_INTEGER;
367                         val1.Integer = op->Content.Integer;
368                         PUT_STACKVAL(val1);
369                         break;
370                 case BC_OP_LOADREAL:
371                         STATE_HDR();
372                         DEBUG_F("LOADREAL %lf\n", op->Content.Real);
373                         val1.Type = SS_DATATYPE_REAL;
374                         val1.Real = op->Content.Real;
375                         PUT_STACKVAL(val1);
376                         break;
377                 case BC_OP_LOADSTR:
378                         STATE_HDR();
379                         DEBUG_F("LOADSTR %i \"%s\"\n", OP_INDX(op), OP_STRING(op));
380                         val1.Type = SS_DATATYPE_STRING;
381                         val1.Reference = SpiderScript_CreateString(OP_INDX(op), OP_STRING(op));
382                         PUT_STACKVAL(val1);
383                         break;
384
385                 case BC_OP_CAST:
386                         STATE_HDR();
387                         val2.Type = OP_INDX(op);
388                         DEBUG_F("CAST to %i\n", val2.Type);
389                         GET_STACKVAL(val1);
390                         if(val1.Type == val2.Type) {
391                                 PUT_STACKVAL(val1);
392                                 break;
393                         }
394                         switch(val2.Type * 100 + val1.Type )
395                         {
396                         case SS_DATATYPE_INTEGER*100 + SS_DATATYPE_REAL:
397                                 val2.Integer = val1.Real;
398                                 PUT_STACKVAL(val2);
399                                 break;
400                         case SS_DATATYPE_REAL*100 + SS_DATATYPE_INTEGER:
401                                 val2.Integer = val1.Real;
402                                 PUT_STACKVAL(val2);
403                                 break;
404                         default: {
405                                 pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
406                                 pval2 = SpiderScript_CastValueTo(val2.Type, pval1);
407                                 if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
408                                 Bytecode_int_SetSpiderValue(&val2, pval2);
409                                 SpiderScript_DereferenceValue(pval2);
410                                 PUT_STACKVAL(val2);
411                                 } break;
412                         }
413                         break;
414
415                 case BC_OP_DUPSTACK:
416                         STATE_HDR();
417                         DEBUG_F("DUPSTACK\n");
418                         GET_STACKVAL(val1);
419                         PUT_STACKVAL(val1);
420                         PUT_STACKVAL(val1);
421                         break;
422
423                 // Unary Operations
424                 case BC_OP_LOGICNOT:
425                         STATE_HDR();
426                         DEBUG_F("LOGICNOT\n");
427                         
428                         GET_STACKVAL(val1);
429                         val2.Type = SS_DATATYPE_INTEGER;
430                         val2.Integer = !Bytecode_int_IsStackEntTrue(&val1);
431                         Bytecode_int_StackPush(Stack, &val2);
432                         Bytecode_int_DerefStackValue(&val1);
433                         break;
434                 case BC_OP_BITNOT:
435                         if(!ast_op)     ast_op = NODETYPE_BWNOT;
436
437                         STATE_HDR();
438                         DEBUG_F("UNIOP %i\n", ast_op);
439
440                         GET_STACKVAL(val1);
441                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
442                         ret_val = AST_ExecuteNode_UniOp(Script, NULL, ast_op, pval1);
443                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
444                         Bytecode_int_SetSpiderValue(&val1, ret_val);
445                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
446                         Bytecode_int_StackPush(Stack, &val1);
447                         
448                         break;
449
450                 // Binary Operations
451                 case BC_OP_LOGICAND:
452                         if(!ast_op)     ast_op = NODETYPE_LOGICALAND,   opstr = "LOGICAND";
453                 case BC_OP_LOGICOR:
454                         if(!ast_op)     ast_op = NODETYPE_LOGICALOR,    opstr = "LOGICOR";
455                 case BC_OP_LOGICXOR:
456                         if(!ast_op)     ast_op = NODETYPE_LOGICALXOR,   opstr = "LOGICXOR";
457
458                 case BC_OP_BITAND:
459                         if(!ast_op)     ast_op = NODETYPE_BWAND,        opstr = "BITAND";
460                 case BC_OP_BITOR:
461                         if(!ast_op)     ast_op = NODETYPE_BWOR,         opstr = "BITOR";
462                 case BC_OP_BITXOR:
463                         if(!ast_op)     ast_op = NODETYPE_BWXOR,        opstr = "BITXOR";
464
465                 case BC_OP_BITSHIFTLEFT:
466                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTLEFT, opstr = "BITSHIFTLEFT";
467                 case BC_OP_BITSHIFTRIGHT:
468                         if(!ast_op)     ast_op = NODETYPE_BITSHIFTRIGHT, opstr = "BITSHIFTRIGHT";
469                 case BC_OP_BITROTATELEFT:
470                         if(!ast_op)     ast_op = NODETYPE_BITROTATELEFT, opstr = "BITROTATELEFT";
471
472                 case BC_OP_ADD:
473                         if(!ast_op)     ast_op = NODETYPE_ADD,  opstr = "ADD";
474                 case BC_OP_SUBTRACT:
475                         if(!ast_op)     ast_op = NODETYPE_SUBTRACT,     opstr = "SUBTRACT";
476                 case BC_OP_MULTIPLY:
477                         if(!ast_op)     ast_op = NODETYPE_MULTIPLY,     opstr = "MULTIPLY";
478                 case BC_OP_DIVIDE:
479                         if(!ast_op)     ast_op = NODETYPE_DIVIDE,       opstr = "DIVIDE";
480                 case BC_OP_MODULO:
481                         if(!ast_op)     ast_op = NODETYPE_MODULO,       opstr = "MODULO";
482
483                 case BC_OP_EQUALS:
484                         if(!ast_op)     ast_op = NODETYPE_EQUALS,       opstr = "EQUALS";
485                 case BC_OP_LESSTHAN:
486                         if(!ast_op)     ast_op = NODETYPE_LESSTHAN,     opstr = "LESSTHAN";
487                 case BC_OP_LESSTHANOREQUAL:
488                         if(!ast_op)     ast_op = NODETYPE_LESSTHANEQUAL, opstr = "LESSTHANOREQUAL";
489                 case BC_OP_GREATERTHAN:
490                         if(!ast_op)     ast_op = NODETYPE_GREATERTHAN,  opstr = "GREATERTHAN";
491                 case BC_OP_GREATERTHANOREQUAL:
492                         if(!ast_op)     ast_op = NODETYPE_GREATERTHANEQUAL, opstr = "GREATERTHANOREQUAL";
493
494                         STATE_HDR();
495                         DEBUG_F("BINOP %i %s (bc %i)\n", ast_op, opstr, op->Operation);
496
497                         GET_STACKVAL(val2);
498                         GET_STACKVAL(val1);
499                         pval1 = Bytecode_int_GetSpiderValue(&val1, &tmpVal1);
500                         pval2 = Bytecode_int_GetSpiderValue(&val2, &tmpVal2);
501                         ret_val = AST_ExecuteNode_BinOp(Script, NULL, ast_op, pval1, pval2);
502                         if(pval1 != &tmpVal1)   SpiderScript_DereferenceValue(pval1);
503                         if(pval2 != &tmpVal2)   SpiderScript_DereferenceValue(pval2);
504                         Bytecode_int_SetSpiderValue(&val1, ret_val);
505                         if(ret_val != &tmpVal1) SpiderScript_DereferenceValue(ret_val);
506                         Bytecode_int_StackPush(Stack, &val1);
507                         break;
508
509                 // Functions etc
510                 case BC_OP_CALLFUNCTION: {
511                         tScript_Function        *fcn;
512                         const char      *name = OP_STRING(op);
513                          int    arg_count = OP_INDX(op);
514                         
515                         STATE_HDR();
516                         DEBUG_F("CALL FUNCTION %s %i args\n", name, arg_count);
517
518                         // Check current script functions (for fast call)
519                         for(fcn = Script->Functions; fcn; fcn = fcn->Next)
520                         {
521                                 if(strcmp(name, fcn->Name) == 0) {
522                                         break;
523                                 }
524                         }
525                         if(fcn && fcn->BCFcn)
526                         {
527                                 DEBUG_F(" - Fast call\n");
528                                 Bytecode_int_ExecuteFunction(Script, fcn, Stack, arg_count);
529                                 break;
530                         }
531                         
532                         // Slower call
533                         {
534                                 tSpiderNamespace        *ns = NULL;
535                                 tSpiderValue    *args[arg_count];
536                                 tSpiderValue    *rv;
537 //                              for( i = 0; i < arg_count; i ++ )
538                                 for( i = arg_count; i --; )
539                                 {
540                                         GET_STACKVAL(val1);
541                                         args[i] = Bytecode_int_GetSpiderValue(&val1, NULL);
542                                 }
543                                 
544                                 if( name[0] == BC_NS_SEPARATOR ) {
545                                         name ++;
546                                         ns = Bytecode_int_ResolveNamespace(&Script->Variant->RootNamespace, name, &name);
547                                 }
548                                 else {
549                                         // TODO: Support multiple default namespaces
550                                         ns = Bytecode_int_ResolveNamespace(default_namespace, name, &name);
551                                 }
552                                 
553                                 rv = SpiderScript_ExecuteFunction(Script, ns, name, arg_count, args);
554                                 if(rv == ERRPTR) {
555                                         AST_RuntimeError(NULL, "SpiderScript_ExecuteFunction returned ERRPTR");
556                                         nextop = NULL;
557                                         break;
558                                 }
559                                 // Clean up args
560                                 for( i = arg_count; i --; )
561                                         SpiderScript_DereferenceValue(args[i]);
562                                 // Get and push return
563                                 Bytecode_int_SetSpiderValue(&val1, rv);
564                                 PUT_STACKVAL(val1);
565                                 // Deref return
566                                 SpiderScript_DereferenceValue(rv);
567                         }
568                         } break;
569
570                 case BC_OP_RETURN:
571                         STATE_HDR();
572                         DEBUG_F("RETURN\n");
573                         nextop = NULL;
574                         break;
575
576                 default:
577                         // TODO:
578                         STATE_HDR();
579                         printf("Unknown operation %i\n", op->Operation);
580                         nextop = NULL;
581                         break;
582                 }
583                 op = nextop;
584         }
585         
586         // Clean up
587         // - Delete local vars
588         printf("TODO: Clean up local vars\n");
589         
590         // - Restore stack
591 //      printf("TODO: Roll back stack\n");
592 //      while( Stack->EntryCount && Stack->Entries[ --Stack->EntryCount ].Type != ET_FUNCTION_START )
593 //      {
594 //              Bytecode_int_DerefStackValue( &Stack->Entries[Stack->EntryCount] );
595 //      }
596         
597
598         return 0;
599 }
600

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