1 /* -*- mode: c; mode: fold; -*- */
2 /*
3  * Copyright (C) 2000-2005 Chris Ross and various contributors
4  * Copyright (C) 1999-2000 Chris Ross
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * o Redistributions of source code must retain the above copyright notice, this
11  *   list of conditions and the following disclaimer.
12  * o Redistributions in binary form must reproduce the above copyright notice,
13  *   this list of conditions and the following disclaimer in the documentation
14  *   and/or other materials provided with the distribution.
15  * o Neither the name of the ferite software nor the names of its contributors may
16  *   be used to endorse or promote products derived from this software without
17  *   specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifdef HAVE_CONFIG_HEADER
33 #include "../config.h"
34 #endif
35 
36 #include "ferite.h"
37 #include "aphex.h"
38 
39 extern FeriteOpTable ferite_op_table[];
40 
41 /**
42  * @group Executor
43  * @description These functions allow for the execution of code. The main interface is
44  *              ferite_script_execute(), but to execute individual functions there is
45  *              ferite_call_function(). There are other convinience functions.
46  */
47 
48 /**
49  * @function ferite_stop_execution
50  * @declaration void ferite_stop_execution( FeriteScript *script )
51  * @brief Stop the script executing
52  * @param FeriteScript *script The script to stop
53  */
ferite_stop_execution(FeriteScript * script,int return_value)54 void ferite_stop_execution( FeriteScript *script, int return_value )
55 {
56     FE_ENTER_FUNCTION;
57     script->keep_execution = FE_FALSE;
58     script->return_value = return_value;
59     FE_LEAVE_FUNCTION( NOWT );
60 }
61 
62 /**
63  * @function ferite_is_executing
64  * @declaration int ferite_is_executing( FeriteScript *script )
65  * @brief Return whether a script is executing
66  * @param FeriteScript *script The script to query
67  * @return FE_TRUE if the script is executing, FE_FALSE otherwise
68  */
ferite_is_executing(FeriteScript * script)69 int ferite_is_executing( FeriteScript *script )
70 {
71     FE_ENTER_FUNCTION;
72     FE_LEAVE_FUNCTION( (script && script->is_executing ? FE_TRUE : FE_FALSE) );
73 }
74 
75 /**
76  * @function ferite_script_execute
77  * @declaration int ferite_script_execute( FeriteScript *script )
78  * @brief Run a script
79  * @param FeriteScript *script The script to run
80  * @return FE_TRUE on successfull execution, FE_FALSE otherwise
81  */
ferite_script_execute(FeriteScript * script)82 int ferite_script_execute( FeriteScript *script )
83 {
84     FeriteNamespaceBucket *nsb = NULL;
85     FeriteFunction *func = NULL;
86     FeriteVariable *err = NULL, *errstr = NULL, *erno = NULL, *rval = NULL;
87 
88     FE_ENTER_FUNCTION;
89 
90     if( script->mainns != NULL )
91     {
92         script->error_state = 0;
93         script->is_executing = FE_TRUE;
94         nsb = ferite_namespace_element_exists( script, script->mainns, "!__start__" );
95 
96         if( nsb != NULL )
97         {
98             func = nsb->data;
99             rval = ferite_script_function_execute( script, script->mainns, NULL, func, NULL );
100 
101 #ifdef THREAD_SAFE
102             ferite_thread_group_wait( script, script->thread_group );
103 #endif
104 
105             /* clean up the system */
106             if( rval != NULL )
107             {
108                 if( rval->type == F_VAR_LONG && script->return_value == 0 )
109                 {
110                     script->return_value = VAI(rval);
111                 }
112                 ferite_variable_destroy( script, rval );
113             }
114 
115             nsb = ferite_namespace_element_exists( script, script->mainns, "err" );
116             if( script->error_state == FE_ERROR_THROWN ) /* error propogated up the system */
117             {
118                 err = nsb->data;
119                 errstr = ferite_object_get_var( script, VAO(err), "str" );
120                 erno = ferite_object_get_var( script, VAO(err), "num" );
121                 if( script->error == NULL )
122                 {
123                     script->error = ferite_buffer_new( 0 );
124                     ferite_buffer_printf( script->error, "\n\n[ferite] Fatal Error: Execution stopped: On line %d, in file '%s':\n%s\n", script->current_op_line, script->current_op_file, VAS(errstr)->data );
125                 }
126                 FE_LEAVE_FUNCTION( 0 );
127             }
128             script->is_executing = FE_FALSE;
129             FE_LEAVE_FUNCTION( FE_TRUE );
130         }
131     }
132     else
133       ferite_error( script, 0, "Fatal Error: Unable to execute script - looks like the compile failed.\n" );
134     FE_LEAVE_FUNCTION( FE_FALSE );
135 }
136 
137 /**
138  * @function ferite_script_function_execute
139  * @declaration int ferite_script_function_execute( FeriteScript *script, void *container, FeriteFunction *function, FeriteVariable **params )
140  * @brief Execute a function within a script
141  * @param FeriteScript *script The current script
142  * @param void *container The container the function is running from namespace/class/object
143  * @param FeriteFunction *function The function to execute
144  * @param FeriteVariable **params The calling arguments
145  * @return The variable returned from the function
146  */
FE_NATIVE_FUNCTION(ferite_script_function_execute)147 FE_NATIVE_FUNCTION( ferite_script_function_execute )
148 {
149     FeriteExecuteRec    exec;
150     FeriteStack    exec_stack;
151     void *    stack_array[32];
152     FeriteVariable      *targetvar = NULL, *rval = NULL;
153     int i = 0, stop_execute = 0;
154     int sig_count = function->arg_count;
155     int offset = 3;
156 
157     FE_ENTER_FUNCTION;
158 
159     /*{{{ Checks before we do anything */
160     FE_ASSERT( script != NULL && function != NULL );
161 
162     if( !script->is_executing )
163       stop_execute = FE_TRUE;
164 
165     script->keep_execution = FE_TRUE;
166     /*}}}*/
167 
168     /*{{{ Obtain function, and create local variable hash */
169     exec.function = function;
170     exec.variable_list = (FeriteVariable**)ferite_duplicate_stack_contents( script, function->localvars, (void*(*)(FeriteScript*,void*,void*))ferite_duplicate_variable, NULL );
171     exec.stack = &exec_stack;
172     exec.stack->stack = stack_array;
173     exec.stack->stack_ptr = 0;
174     exec.stack->size = 32;
175     exec.block_depth = 0;
176     /*}}}*/
177 
178     /*{{{ Copy parameter values over to the local variable stack */
179     if( params != NULL ) /* handle function parameters */
180     {
181         /*
182          * Go through at add the all variables to the local variables. We either want to jump out when we hit a '.' or when we hit
183          * the super/self variables.
184          */
185         for( i = 0; i < sig_count && function->signature[i] != NULL && function->signature[i]->variable->name[0] != '.'; i++ )
186         {
187             /* Assign and use the return to add to the fncArgs array */
188             if( function->signature[i]->pass_type == FE_BY_VALUE )
189             {
190                 targetvar = ferite_op_assign( script, exec.variable_list[i+offset], params[i] );
191                 ferite_variable_destroy( script, targetvar );
192             }
193             else
194             {
195                 if( !FE_VAR_IS_DISPOSABLE(params[i]) )
196                 {
197                     /* We delete the existing var and then replace with ours */
198                     ferite_variable_destroy( script, exec.variable_list[i+offset] );
199                     exec.variable_list[i+offset] = ferite_get_variable_ref( script, params[i] );
200                 }
201                 else
202                 {
203                     /* otherwise we just do a normal assignment because disposable == no variable attached */
204                     targetvar = ferite_op_assign( script, exec.variable_list[i+offset], params[i] );
205                     ferite_variable_destroy( script, targetvar );
206                 }
207             }
208         }
209 
210         /* We are now at the 'dot' if we have one, or at an object - we now pick up the self and super variables */
211         /* sort out super */
212         targetvar = exec.variable_list[2];
213         if( targetvar != NULL )
214         {
215             if( function->is_static )
216             {
217                 targetvar->type = F_VAR_CLASS;
218                 VAC(targetvar) = ((FeriteClass*)__container__)->parent;
219             }
220             else if( function->klass != NULL )
221             {
222                 targetvar->type = F_VAR_OBJ;
223                 VAO(targetvar) = __container__;
224                 VAO(targetvar)->refcount++;
225             }
226             else
227             {
228                 targetvar->type = F_VAR_NS;
229                 VAN(targetvar) = ((FeriteNamespace*)__container__)->container;
230             }
231         }
232 
233         /* sort out self */
234         targetvar = exec.variable_list[1];
235         if( targetvar != NULL )
236         {
237             if( function->is_static )
238             {
239                 targetvar->type = F_VAR_CLASS;
240                 VAC(targetvar) = __container__;
241             }
242             else if( function->klass != NULL )
243             {
244                 targetvar->type = F_VAR_OBJ;
245                 VAO(targetvar) = __container__;
246                 VAO(targetvar)->refcount++;
247             }
248             else
249             {
250                 targetvar->type = F_VAR_NS;
251                 VAN(targetvar) = __container__;
252             }
253         }
254     }
255     /*}}}*/
256 
257     FUD(("EXECUTOR: Executing function %s %p\n", function->name, function->ccode->list[1] ));
258 
259     script->stack_level++;
260 	if( script->stack_level > FE_DEEPEST_STACK_LEVEL )
261     {
262         ferite_error( script, 0, "Stack level too deep! (%d)\n", script->stack_level );
263         FE_LEAVE_FUNCTION( rval );
264     }
265 
266     rval = ferite_script_real_function_execute( script, __container__, current_yield_block, function, script->mainns, &exec, params );
267     script->stack_level--;
268 
269     ferite_clean_up_exec_rec( script, &exec );
270 
271     if( stop_execute )
272       script->is_executing = FE_FALSE;
273 
274     FE_LEAVE_FUNCTION( rval );
275 }
276 
277 #ifndef WIN32
278 #define HAVE_INLINE inline
279 #else
280 #define HAVE_INLINE
281 #endif
282 
283 #define INLINE_OP( NAME ) \
284 static HAVE_INLINE void *NAME( FeriteScript *script, void *container, FeriteObject *current_yield_block, FeriteObject *new_yield_block, \
285                   FeriteFunction *function, FeriteNamespace *mainns, FeriteExecuteRec *exec, \
286                   FeriteVariable **params, FeriteOp *current_op )
287 
288 #define CALL_INLINE_OP( NAME ) \
289 NAME( script, container, current_yield_block, new_yield_block, function, mainns, exec, params, current_op )
290 
ferite_parameters_to_string(FeriteScript * script,FeriteVariable ** param_list)291 char *ferite_parameters_to_string( FeriteScript *script, FeriteVariable **param_list )
292 {
293     static char buffer[1024];
294     int i = 0;
295 
296     memset( buffer, '\0', 1024 );
297     while( param_list[i] != NULL )
298     {
299         strcat( buffer, ferite_variable_id_to_str( script, param_list[i]->type ) );
300         if( param_list[i+1] != NULL )
301             strcat( buffer, "," );
302         i++;
303     }
304     return buffer;
305 }
306 
INLINE_OP(ferite_exec_funcall)307 INLINE_OP( ferite_exec_funcall )
308 {
309     FeriteNamespace       *ns = NULL;
310     FeriteNamespaceBucket *nsb = NULL;
311     FeriteVariable        *varone = NULL, *vartwo = NULL;
312     FeriteVariable        *param_list[FE_FUNCTION_PARAMETER_MAX_SIZE], *rval = NULL;
313     FeriteFunction        *trgt_function_call = NULL;
314     FeriteClass           *sclass = NULL;
315     int                    i, j;
316     char                  *method_name = NULL;
317     void                  *function_container = NULL;
318 
319     /*{{{ Create Parameter List */
320     FUD(("CREATING PARAMETER LIST.\n"));
321 
322     exec->stack->stack_ptr -= current_op->opdataf->argument_count;
323     for( i = exec->stack->stack_ptr + 1, j = 0; j < current_op->opdataf->argument_count; i++, j++ )
324     {
325         param_list[j] = exec->stack->stack[i];
326         LOCK_VARIABLE( param_list[j] );
327     }
328     param_list[j] = NULL;
329     FUD(("PARAMETER LIST CREATED.\n"));
330     /*}}}*/
331     switch( current_op->OP_TYPE )
332     {
333         case F_OP_DELIVER:
334         {
335             if( current_yield_block != NULL )
336             {
337                 FeriteFunction *f = ferite_object_get_function( script, current_yield_block, "invoke" );
338                 rval = ferite_call_function( script, current_yield_block, new_yield_block, f, param_list );
339             }
340             else
341                 ferite_error( script, 0, "Trying to call deliver when no block is supplied!\n" );
342             break;
343         }
344             /*{{{ F_OP_METHOD (object and namespace) */
345         case F_OP_METHOD:
346         {
347 
348             vartwo = ferite_stack_pop( exec->stack );
349             method_name = (char*)(current_op->opdata);
350             function_container = VAP(vartwo);
351 
352             if( current_op->opdataf->function == NULL )
353             {
354                 switch( vartwo->type )
355                 {
356                     case F_VAR_OBJ:
357                     {
358                         FUD(( "Trying to find '%s' in '%s'\n", method_name, vartwo->name ));
359                         /* what we do here is check to see if they are searching the super class, if so, we swap the objects           */
360                         /* template with that of it's parents - if it has no parent we don't bother..., we then look for the function  */
361                         /* that we are after..... i personally would consider this to be, as we english say, "dash cunning"            */
362                         if( VAO(vartwo) == NULL )
363                         {
364                             ferite_error( script, 0, "Trying to access method '%s' in a null object.\n", method_name );
365                             break;
366                         }
367 
368                         /* Supar class */
369                         sclass = VAO(vartwo)->klass;
370                         if( vartwo->name[0] == 's' && vartwo->name[1] == 'u' && strcmp( vartwo->name, "super" ) == 0 )
371                         {
372                             if( function->klass->parent != NULL )
373                                 VAO(vartwo)->klass = function->klass->parent;
374                         }
375                         trgt_function_call = ferite_object_get_function_for_params( script, VAO(vartwo), method_name, param_list );
376                         VAO(vartwo)->klass = sclass;
377 
378                         /* Check to see if we have a function using the std methods */
379                         if( trgt_function_call == NULL )
380                         {
381                             /* ok this is where we try and be dash cunning, fail miserably and settle for an autoload function. */
382                             trgt_function_call = ferite_object_get_function( script, VAO(vartwo), "method_missing" );
383                             if( trgt_function_call == NULL )
384                             {
385                                 ferite_error( script, 0, "Unable to find method '%s(%s)' in object created from class '%s' (it could be static)\n", method_name, ferite_parameters_to_string(script, param_list), VAO(vartwo)->klass->name );
386                                 break;
387                             }
388                             else
389                             {
390                                 /* we have an autoload function, soooooooo, what do we do? */
391                                 varone = ferite_create_string_variable_from_ptr( script, "function-name", method_name, 0, FE_CHARSET_DEFAULT, FE_STATIC );
392                                 ferite_add_to_parameter_list( param_list, varone );
393                                 MARK_VARIABLE_AS_DISPOSABLE( varone );
394                             }
395                         }
396 
397                         if( trgt_function_call != NULL )
398                         {
399                             /* Check the access controls on the function */
400                             switch( trgt_function_call->state )
401                             {
402                                 case FE_ITEM_IS_PRIVATE:
403                                     if( !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) && trgt_function_call->klass != function->klass )
404                                         ferite_error( script, 0, "Trying to access a private method '%s' in object created from class '%s'\n", trgt_function_call->name, VAO(vartwo)->klass->name );
405                                     break;
406                                 case FE_ITEM_IS_PROTECTED:
407                                     if( !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) && !ferite_class_is_subclass( trgt_function_call->klass, function->klass ) )
408                                         ferite_error( script, 0, "Trying to access a protected method '%s' in object created from class '%s'\n", trgt_function_call->name, VAO(vartwo)->klass->name );
409                                     break;
410                                 case FE_ITEM_IS_PUBLIC:
411                                 default:
412                                     /* Do Nothing */
413                                     break;
414                             }
415                         }
416                         break;
417                     }
418                     case F_VAR_NS:
419                     {
420                         nsb = ferite_namespace_element_exists( script, VAN(vartwo), method_name );
421                         if( nsb == NULL || nsb->type != FENS_FNC )
422                         {
423                             ferite_error( script, 0, "Unable to find method '%s(%s)' in namespace '%s'\n", method_name, ferite_parameters_to_string(script, param_list), vartwo->name );
424                             break;
425                         }
426                         trgt_function_call = nsb->data;
427                         if( trgt_function_call != NULL )
428                         {
429                             for( ; trgt_function_call != NULL; trgt_function_call = trgt_function_call->next )
430                             {
431                                 if( ferite_check_params( script, param_list, trgt_function_call ) != 0 )
432                                     break;
433                             }
434 
435                             if( trgt_function_call == NULL )
436                             {
437                                 ferite_error( script, 0, "Unable to find method %s.%s(%s) that accepts the parameters passed.\n",
438                                               vartwo->name, method_name, ferite_parameters_to_string(script, param_list) );
439                                 current_op->opdataf->function = NULL;
440                             }
441                         }
442                         break;
443                     }
444 #ifdef DEBUG
445                     case F_VAR_STR:
446                     case F_VAR_UARRAY:
447                     case F_VAR_DOUBLE:
448                     case F_VAR_LONG:
449                     {
450                         char *namespace_search = NULL;
451                         switch( vartwo->type )
452                         {
453                             case F_VAR_STR:
454                                 namespace_search = "String";
455                                 break;
456                             case F_VAR_UARRAY:
457                                 namespace_search = "Array";
458                                 break;
459                             case F_VAR_DOUBLE:
460                             case F_VAR_LONG:
461                                 namespace_search = "Math";
462                                 break;
463                         }
464                         nsb = ferite_namespace_element_exists( script, script->mainns, namespace_search );
465                         if( nsb != NULL )
466                         {
467                             function_container = ns = nsb->data;
468                             nsb = ferite_namespace_element_exists( script, ns, method_name );
469 
470                             param_list[current_op->opdataf->argument_count + 1] = NULL;
471                             for( i = current_op->opdataf->argument_count; i > 0; i++ )
472                                 param_list[i] = param_list[i-1];
473                             LOCK_VARIABLE(vartwo);
474                             param_list[0] = vartwo;
475 
476                             if( nsb == NULL || nsb->type != FENS_FNC )
477                             {
478                                 ferite_error( script, 0, "Unable to find method '%s(%s)' in %s namespace.\n",
479                                               method_name,
480                                               ferite_parameters_to_string(script, param_list),
481                                               namespace_search );
482                                 break;
483                             }
484                             trgt_function_call = nsb->data;
485                             if( trgt_function_call != NULL )
486                             {
487                                 for( ; trgt_function_call != NULL; trgt_function_call = trgt_function_call->next )
488                                 {
489                                     if( ferite_check_params( script, param_list, trgt_function_call ) != 0 )
490                                         break;
491                                 }
492 
493                                 if( trgt_function_call == NULL )
494                                 {
495                                     ferite_error( script, 0, "Unable to find method %s.%s(%s) that accepts the parameters passed.\n",
496                                                   namespace_search, method_name, ferite_parameters_to_string(script, param_list) );
497                                     current_op->opdataf->function = NULL;
498                                 }
499                             }
500                         }
501                         else
502                         {
503                             char *lowercase_namespace = fstrdup( namespace_search );
504                             ferite_lowercase( lowercase_namespace );
505                             ferite_error( script, 0,
506                                           "Unable to find the %s namespace, please add 'uses \"%s\";' to your script.\n",
507                                           namespace_search,
508                                           lowercase_namespace );
509                             ffree( lowercase_namespace );
510                         }
511                         break;
512                     }
513 #endif
514                     case F_VAR_CLASS:
515                     {
516                         trgt_function_call = ferite_class_get_function_for_params( script, VAC(vartwo), method_name, param_list );
517 
518                         /* Do we have it */
519                         if( trgt_function_call == NULL )
520                         {
521                             /* ok this is where we try and be dash cunning, fail miserably and settle for an autoload function. */
522                             trgt_function_call = ferite_class_get_function( script, VAC(vartwo), "method_missing" );
523                             if( trgt_function_call == NULL )
524                             {
525                                 ferite_error( script, 0, "Unable to find method '%s(%s)' in class '%s' (it could be static)\n", method_name, ferite_parameters_to_string(script, param_list), VAC(vartwo)->name );
526                                 break;
527                             }
528                             else
529                             {
530                                 /* we have an autoload function, soooooooo, what do we do? */
531                                 varone = ferite_create_string_variable_from_ptr( script, "function-name", method_name, 0, FE_CHARSET_DEFAULT, FE_STATIC );
532                                 ferite_add_to_parameter_list( param_list, varone );
533                                 MARK_VARIABLE_AS_DISPOSABLE( varone );
534                             }
535                         }
536 
537                         /* Check the access controls on the function */
538                         if( trgt_function_call != NULL )
539                         {
540                             switch( trgt_function_call->state )
541                             {
542                                 case FE_ITEM_IS_PRIVATE:
543                                     if( !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) && trgt_function_call->klass != function->klass )
544                                         ferite_error( script, 0, "Trying to access a private method '%s' in class '%s'\n", trgt_function_call->name, VAC(vartwo)->name );
545                                     break;
546                                 case FE_ITEM_IS_PROTECTED:
547                                     if( !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) &&
548                                         !ferite_class_is_subclass( trgt_function_call->klass, function->klass ) )
549                                         ferite_error( script, 0, "Trying to access a protected method '%s' in class '%s'\n", trgt_function_call->name, VAC(vartwo)->name );
550                                     break;
551                                 case FE_ITEM_IS_PUBLIC:
552                                 default:
553                                     /* Do Nothing */
554                                     break;
555                             }
556                         }
557                         break;
558                     }
559                     default:
560                     {
561                         ferite_error( script, 0, "Expecting container found %s when trying to call %s.%s()\n", ferite_variable_id_to_str( script, vartwo->type ), vartwo->name, method_name );
562                         if( vartwo && FE_VAR_IS_DISPOSABLE( vartwo ) ) /* the var was created */
563                             ferite_variable_destroy( script, vartwo );
564                         break;
565                     }
566                 }
567 
568                 /* make a quick gettaway */
569                 if( script->error_state == FE_ERROR_THROWN )
570                 {
571                     if( vartwo && FE_VAR_IS_DISPOSABLE( vartwo ) ) /* the var was created */
572                         ferite_variable_destroy( script, vartwo );
573                     break;
574                 }
575             }
576             else
577             {
578                 trgt_function_call = current_op->opdataf->function;
579             }
580 
581             if( trgt_function_call != NULL )
582             {
583                 LOCK_VARIABLE(trgt_function_call); /* lock the method */
584                 if( trgt_function_call->type == FNC_IS_EXTRL )
585                 {
586                     if( trgt_function_call->fncPtr != NULL )
587                     {
588                         if( trgt_function_call->native_information != NULL )
589                         {
590                             script->current_op_file = trgt_function_call->native_information->file;
591                             script->current_op_line = trgt_function_call->native_information->line;
592                         }
593                         rval = (trgt_function_call->fncPtr)( script, function_container, new_yield_block, trgt_function_call, param_list );
594                     }
595                     else
596                         ferite_error( script, 0, "Unable to execute external method %s.%s (does it exist?)\n", ( vartwo->type == F_VAR_OBJ ? VAO(vartwo)->klass->name : vartwo->name ), trgt_function_call->name );
597                 }
598                 else /* internal function call */
599                 {
600                     rval = ferite_script_function_execute( script, function_container, new_yield_block, trgt_function_call, param_list );
601                 }
602                 UNLOCK_VARIABLE(trgt_function_call); /* unlock the method */
603                 if( script->error_state != FE_ERROR_THROWN )
604                 {
605                     script->current_op_file = function->ccode->filename; /* we do this because the other function might cause it to change */
606                     script->current_op_line = current_op->line;
607                 }
608             }
609 
610             if( vartwo && FE_VAR_IS_DISPOSABLE( vartwo ) ) /* the var was created */
611                 ferite_variable_destroy( script, vartwo );
612             break;
613         }
614             /*}}}*/
615             /*{{{ F_OP_FUNCTION (script) */
616         case F_OP_FUNCTION:
617         {
618             trgt_function_call = NULL;
619 
620             if( current_op->opdataf->function == NULL )
621             {
622                 /* handle other functions */
623                 nsb = ferite_find_namespace( script, mainns, (char *)(current_op->opdata), FENS_FNC );
624                 if( nsb != NULL )
625                     trgt_function_call = nsb->data;
626                 if( trgt_function_call == NULL ) /* we are in an eval check parent script */
627                 {
628                     nsb = ferite_find_namespace( script, script->mainns, (char *)(current_op->opdata), FENS_FNC );
629                     if( nsb != NULL )
630                     {
631                         if( (trgt_function_call = nsb->data) == NULL )
632                         {
633                             ferite_raise_script_error( script, 0, "Can't find function '%s'\n", (char *)(current_op->opdata));
634                             break;
635                         }
636                     }
637                     else
638                     {
639                         ferite_error( script, 0, "Function '%s' doesn't exist\n", (char *)(current_op->opdata) );
640                         break;
641                     }
642                 }
643 
644                 for( ; trgt_function_call != NULL; trgt_function_call = trgt_function_call->next )
645                 {
646                     if( ferite_check_params( script, param_list, trgt_function_call ) )
647                         break;
648                 }
649 
650                 if( trgt_function_call == NULL )
651                 {
652                     ferite_error( script, 0, "Unable to find function %s(%s)\n", (char *)(current_op->opdata), ferite_parameters_to_string(script, param_list) );
653                     current_op->opdataf->function = NULL;
654                 }
655                 /*
656                  * Disable cache for now, we have side-effects.
657                  * Cached methods isn't that great since it will fuck up inheritance.
658                  * Sys.Stream that uses inheritance will call wrong methods at the wrong time:
659                  * If you have used a ProcessStream and opens up a FileStream, The __close__
660                  * method will be that of ProcessStream, resulting in less than expected behaivour
661                  *
662                  else
663                  current_op->opdataf->function = trgt_function_call;
664                  */
665             }
666             else
667                 trgt_function_call = current_op->opdataf->function;
668 
669             if( trgt_function_call != NULL )
670             {
671                 LOCK_VARIABLE(trgt_function_call); /* lock the method */
672                 if( trgt_function_call->type == FNC_IS_EXTRL )
673                 {
674                     if( trgt_function_call->fncPtr != NULL )
675                     {
676                         if( trgt_function_call->native_information != NULL )
677                         {
678                             script->current_op_file = trgt_function_call->native_information->file;
679                             script->current_op_line = trgt_function_call->native_information->line;
680                         }
681                         rval = (trgt_function_call->fncPtr)( script, script->mainns, new_yield_block, trgt_function_call, param_list );
682                     }
683                     else
684                         ferite_error( script, 0, "Unable to execute external method %s (does it exist?)\n", trgt_function_call->name );
685                 }
686                 else /* internal function call */
687                 {
688                     rval = ferite_script_function_execute( script, script->mainns, new_yield_block, trgt_function_call, param_list );
689                 }
690                 UNLOCK_VARIABLE(trgt_function_call); /* lock the method */
691                 if( script->error_state != FE_ERROR_THROWN )
692                 {
693                     script->current_op_file = function->ccode->filename; /* we do this because the other function might cause it to change */
694                     script->current_op_line = current_op->line;
695                 }
696             }
697 
698             break;
699         }
700             /*}}}*/
701             /*{{{ F_OP_NEWOBJ */
702         case F_OP_NEWOBJ:
703         {
704             FUD(("Creating new object\n"));
705             vartwo = ferite_stack_pop( exec->stack );
706             if( vartwo->type != F_VAR_CLASS )
707             {
708                 ferite_error( script, 0, "%s is not a class, bad luck, try again :)\n", vartwo->name );
709                 break;
710             }
711             rval = (void *)ferite_new_object( script, (FeriteClass *)(vartwo->data.pval), param_list );
712             if( script->error_state != FE_ERROR_THROWN )
713             {
714                 script->current_op_file = function->ccode->filename; /* we do this because the other function might cause it to change */
715                 script->current_op_line = current_op->line;
716             }
717             if( vartwo && FE_VAR_IS_DISPOSABLE( vartwo ) ) /* the var was created */
718                 ferite_variable_destroy( script, vartwo );
719             break;
720         }
721             /*}}}*/
722     }
723     for( i = 0; i < FE_FUNCTION_PARAMETER_MAX_SIZE; i++ )
724     {
725         if( param_list[i] != NULL )
726         {
727             UNLOCK_VARIABLE(param_list[i]);
728             if( FE_VAR_IS_DISPOSABLE( param_list[i] ) )
729                 ferite_variable_destroy( script, PTR2VAR(param_list[i]) );
730             param_list[i] = NULL;
731         }
732         else
733             break;
734     }
735     if( rval != NULL )
736         ferite_stack_push( exec->stack, rval );
737 
738     if( new_yield_block != NULL )
739     {
740         new_yield_block->refcount--;
741         new_yield_block = NULL;
742     }
743 
744     return NULL;
745 }
INLINE_OP(ferite_exec_pushattr)746 INLINE_OP( ferite_exec_pushattr )
747 {
748     FeriteNamespaceBucket *nsb = NULL;
749     FeriteVariable        *varone = NULL, *vartwo = NULL;
750     FeriteVariable        **pml = NULL;
751     FeriteString          *str = NULL;
752     FeriteFunction        *trgt_function_call = NULL;
753     FeriteObjectVariable  *ov = NULL;
754     char                  *var_name = NULL;
755 
756     var_name = (char *)(current_op->opdata);
757     vartwo = ferite_stack_pop( exec->stack );
758     switch( vartwo->type )
759     {
760         case F_VAR_OBJ:
761         {
762             FUD(( "Executing: Searching for '%s' in '%s'\n", var_name, vartwo->name ));
763             if( VAO(vartwo) != NULL )
764             {
765                 /* Setup the variables in case of super */
766                 ov = VAO(vartwo)->variables;
767                 if( vartwo->name[0] == 's' && vartwo->name[1] == 'u' && strcmp( vartwo->name, "super" ) == 0 )
768                     VAO(vartwo)->variables = VAO(vartwo)->variables->parent;
769 
770                 varone = ferite_object_get_var( script, VAO(vartwo), var_name );
771 
772                 /* Return to normal use */
773                 VAO(vartwo)->variables = ov;
774 
775                 if( varone == NULL )
776                 {
777                     /* we see if the object has a .attribute_missing method - and call it */
778                     trgt_function_call = ferite_object_get_function( script, VAO(vartwo), "attribute_missing" );
779                     if( trgt_function_call == NULL )
780                     {
781                         ferite_error( script, 0, "Trying to access non-existant variable '%s' in object created from class '%s' (it could be static)\n", var_name, VAO(vartwo)->klass->name );
782                         break;
783                     }
784                     else
785                     {
786                         str = ferite_str_new( var_name, strlen( var_name ), FE_CHARSET_DEFAULT );
787                         pml = ferite_create_parameter_list_from_data( script, "s", str );
788                         varone = ferite_call_function( script, VAP(vartwo), new_yield_block, trgt_function_call, pml );
789                         ferite_delete_parameter_list( script, pml );
790                         ferite_str_destroy( str );
791                     }
792                 }
793 
794                 if( varone != NULL )
795                 {
796                     switch( varone->state )
797                     {
798                         case FE_ITEM_IS_PRIVATE:
799                             if( ferite_object_variable_class( script, VAO(vartwo), var_name ) != function->klass &&
800                                 !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) )
801                                 ferite_error( script, 0, "Trying to access a private variable '%s' in object created from class '%s'\n", var_name, VAO(vartwo)->klass->name );
802                             break;
803                         case FE_ITEM_IS_PROTECTED:
804                             if( !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) &&
805                                 !ferite_class_is_subclass( ferite_object_variable_class( script, VAO(vartwo), var_name ), function->klass ) )
806                                 ferite_error( script, 0, "Trying to access a protected variable '%s' in object created from class '%s'\n", var_name, VAO(vartwo)->klass->name );
807                             break;
808                         case FE_ITEM_IS_PUBLIC:
809                         default:
810                             /* Do Nothing */
811                             break;
812                     }
813                 }
814             }
815             else
816                 ferite_error( script, 0, "Trying to access variable '%s' in object '%s' which is null\n", var_name, vartwo->name );
817             break;
818         }
819         case F_VAR_NS:
820         {
821             nsb = ferite_namespace_element_exists( script, VAN(vartwo), var_name );
822             if( nsb == NULL )
823             {
824                 ferite_error( script, 0, "Can't find '%s' in namespace '%s'\n", var_name, vartwo->name );
825                 break;
826             }
827             switch( nsb->type )
828             {
829                 case FENS_NS:
830                     varone = ferite_create_namespace_variable( script, var_name, nsb->data, FE_STATIC );
831                     MARK_VARIABLE_AS_DISPOSABLE( varone );
832                     break;
833                 case FENS_VAR:
834                     varone = nsb->data;
835                     break;
836                 case FENS_CLS:
837                     varone = ferite_create_class_variable( script, var_name, nsb->data, FE_STATIC );
838                     MARK_VARIABLE_AS_DISPOSABLE( varone );
839                     break;
840                 default:
841                     ferite_error( script, 0, "Expecting variable, class or namespace for '%s' in '%s'\n", var_name, vartwo->name );
842                     break;
843             }
844             break;
845         }
846         case F_VAR_CLASS:
847         {
848             varone = ferite_class_get_var( script, VAC(vartwo), var_name );
849             if( varone == NULL )
850             {
851                 /* we see if the object has a .attribute_missing method - and call it */
852                 trgt_function_call = ferite_class_get_function( script, VAC(vartwo), "attribute_missing" );
853                 if( trgt_function_call == NULL )
854                 {
855                     ferite_error( script, 0, "Trying to access non-existant variable '%s' in class '%s' (it could be NON-static)\n", var_name, VAC(vartwo)->name );
856                     break;
857                 }
858                 else
859                 {
860                     str = ferite_str_new( var_name, strlen( var_name ), FE_CHARSET_DEFAULT );
861                     pml = ferite_create_parameter_list_from_data( script, "s", str );
862                     varone = ferite_call_function( script, VAP(vartwo), new_yield_block, trgt_function_call, pml );
863                     ferite_delete_parameter_list( script, pml );
864                     ferite_str_destroy( str );
865                 }
866             }
867 
868             if( varone != NULL )
869             {
870                 switch( varone->state )
871                 {
872                     case FE_ITEM_IS_PRIVATE:
873                         if( !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) && ferite_class_variable_class( script, VAC(vartwo), var_name ) != function->klass )
874                             ferite_error( script, 0, "Trying to access a private variable '%s' in class '%s'\n", var_name, VAC(vartwo)->name );
875                         break;
876                     case FE_ITEM_IS_PROTECTED:
877                         if( !(strcmp(vartwo->name, "self") == 0 && function->klass != NULL && strncmp( function->klass->name, "!__clos", 7 ) == 0) && !ferite_class_is_subclass( ferite_class_variable_class( script, VAC(vartwo), var_name ), function->klass ) )
878                             ferite_error( script, 0, "Trying to access a protected variable '%s' in class '%s'\n", var_name, VAC(vartwo)->name );
879                         break;
880                     case FE_ITEM_IS_PUBLIC:
881                     default:
882                         /* Do Nothing */
883                         break;
884                 }
885             }
886             break;
887         }
888         default:
889         {
890             ferite_error( script, 0, "Can not get variable '%s' from '%s', expecting object/namespace/class but found a %s.\n",
891                           (char *)(current_op->opdata),
892                           vartwo->name,
893                           ferite_variable_id_to_str( script, vartwo->type ) );
894             break;
895         }
896     }
897     if( vartwo && FE_VAR_IS_DISPOSABLE( vartwo ) )
898         ferite_variable_destroy( script, vartwo );
899     if( script->error_state == FE_ERROR_THROWN )
900         return NULL;
901 
902     if( varone != NULL )
903         ferite_stack_push( exec->stack, varone );
904     else
905     {
906         ferite_error( script, 0, "Can't Find Variable '%s'\n",  (char *)(current_op->opdata) );
907         return NULL;
908     }
909 
910     return NULL;
911 }
INLINE_OP(ferite_exec_swaptop)912 INLINE_OP( ferite_exec_swaptop )
913 {
914     int sp = exec->stack->stack_ptr;
915     void *tmp = exec->stack->stack[sp];
916     exec->stack->stack[sp] = exec->stack->stack[sp - 1];
917     exec->stack->stack[sp - 1] = tmp;
918 
919     return NULL;
920 }
INLINE_OP(ferite_exec_binary)921 INLINE_OP( ferite_exec_binary )
922 {
923     FeriteVariable        *varone = NULL, *vartwo = NULL, *result = NULL;
924     FeriteVariable        *(*binaryop)( FeriteScript *s, FeriteVariable *a, FeriteVariable *b );
925 
926     FUD(("BINARY\n"));
927     vartwo = ferite_stack_pop( exec->stack );
928     varone = ferite_stack_pop( exec->stack );
929     binaryop = (FeriteVariable *(*)( FeriteScript *, FeriteVariable *, FeriteVariable * ))ferite_op_table[current_op->addr].ptr;
930     FUD(("Binary Op Parameters: %s, %s\n", varone->name, vartwo->name ));
931     if( (result =  binaryop( script, varone, vartwo )) )
932         ferite_stack_push( exec->stack, result );
933     if( FE_VAR_IS_DISPOSABLE( vartwo ) )
934     {
935         FUD(("Deleting Variable: %s\n", vartwo->name ));
936         ferite_variable_destroy( script, vartwo );
937     }
938     if( FE_VAR_IS_DISPOSABLE( varone ) )
939     {
940         FUD(("Deleting Variable: %s\n", varone->name ));
941         ferite_variable_destroy( script, varone );
942     }
943 
944     return NULL;
945 }
INLINE_OP(ferite_exec_push)946 INLINE_OP( ferite_exec_push )
947 {
948     FUD(("PUSH\n"));
949     ferite_stack_push( exec->stack, current_op->opdata );
950 
951     return NULL;
952 }
INLINE_OP(ferite_exec_pop)953 INLINE_OP( ferite_exec_pop )
954 {
955     FeriteVariable *varone = ferite_stack_pop( exec->stack );
956     FUD(("POP\n"));
957     if( varone && FE_VAR_IS_DISPOSABLE( varone ) )
958     {
959         FUD(("Deleting Variable: %s\n", varone->name ));
960         ferite_variable_destroy( script, varone );
961     }
962 
963     return NULL;
964 }
INLINE_OP(ferite_exec_args)965 INLINE_OP( ferite_exec_args )
966 {
967     int argcount = ferite_get_parameter_count( params ), i = 0;
968     FeriteVariable *varone = ferite_create_uarray_variable( script, "fncArgs", argcount+1, FE_STATIC ), *vartwo = NULL;
969 
970     for( i = 0; i < argcount; i++ )
971     {
972         vartwo = ferite_duplicate_variable( script, params[i], NULL );
973         ferite_uarray_add( script, VAUA(varone), vartwo, NULL, FE_ARRAY_ADD_AT_END );
974     }
975     MARK_VARIABLE_AS_DISPOSABLE( varone );
976     ferite_stack_push( exec->stack, varone );
977 
978     return NULL;
979 }
INLINE_OP(ferite_exec_get_deliver)980 INLINE_OP( ferite_exec_get_deliver )
981 {
982     FeriteVariable *vartwo = ferite_create_object_variable_with_data( script, "get-yield", current_yield_block, FE_STATIC );
983     MARK_VARIABLE_AS_DISPOSABLE( vartwo );
984     ferite_stack_push( exec->stack, vartwo );
985 
986     return NULL;
987 }
INLINE_OP(ferite_exec_set_deliver)988 INLINE_OP( ferite_exec_set_deliver )
989 {
990     FeriteVariable *vartwo = NULL;
991 
992     FUD(("SET YIELD\n"));
993     if( new_yield_block != NULL )
994         new_yield_block->refcount--;
995 
996     if( current_op->addr == FE_TRUE ) /* If true we use the current */
997         new_yield_block = current_yield_block;
998     else
999     {
1000         vartwo = ferite_stack_pop( exec->stack );
1001         new_yield_block = VAO(vartwo);
1002     }
1003     if( new_yield_block != NULL )
1004         new_yield_block->refcount++;
1005 
1006     if( vartwo != NULL && FE_VAR_IS_DISPOSABLE( vartwo ) )
1007         ferite_variable_destroy( script, vartwo );
1008 
1009     return new_yield_block;
1010 }
INLINE_OP(ferite_exec_clsre_assgn)1011 INLINE_OP( ferite_exec_clsre_assgn )
1012 {
1013     char *name = NULL;
1014     FeriteObject *self = (FeriteObject*)container;
1015     FeriteVariable *varone = ferite_stack_pop( exec->stack );
1016 
1017     name = varone->name;
1018     if( strcmp( name, "temporaryself" ) == 0 )
1019         name = "self";
1020     ferite_object_set_var( script, self, name, ferite_get_variable_ref( script, varone ) );
1021 
1022     return NULL;
1023 }
INLINE_OP(ferite_exec_pushvar)1024 INLINE_OP( ferite_exec_pushvar )
1025 {
1026     FeriteVariable *varone = NULL;
1027     FeriteNamespaceBucket *nsb = ferite_namespace_element_exists( script, mainns, (char *)(current_op->opdata) );
1028 
1029     FUD(("PUSHVAR\n"));
1030     /* try and get it from the local scoped variable hash */
1031     if( nsb != NULL )
1032     {
1033         switch( nsb->type )
1034         {
1035             case FENS_NS:
1036                 varone = ferite_create_namespace_variable( script, (char *)(current_op->opdata), nsb->data, FE_STATIC );
1037                 MARK_VARIABLE_AS_DISPOSABLE( varone );
1038                 break;
1039             case FENS_VAR:
1040                 varone = nsb->data;
1041                 break;
1042             case FENS_CLS:
1043                 varone = ferite_create_class_variable( script, (char *)(current_op->opdata), nsb->data, FE_STATIC );
1044                 MARK_VARIABLE_AS_DISPOSABLE( varone );
1045                 break;
1046             default:
1047                 ferite_error( script, 0, "PUSHVAR with wrong type\n" );
1048         }
1049     }
1050 
1051     if( script->error_state == FE_ERROR_THROWN )
1052         return NULL;
1053 
1054     if( varone != NULL )
1055         ferite_stack_push( exec->stack, varone );
1056     else
1057         ferite_error( script, 0, "Can't find item named '%s'\n",  (char *)(current_op->opdata) );
1058 
1059     return NULL;
1060 }
INLINE_OP(ferite_exec_pushindex)1061 INLINE_OP( ferite_exec_pushindex )
1062 {
1063     FeriteVariable *varone = exec->variable_list[current_op->addr];
1064     ferite_stack_push( exec->stack, varone );
1065 
1066     return NULL;
1067 }
INLINE_OP(ferite_exec_unary)1068 INLINE_OP( ferite_exec_unary )
1069 {
1070     FeriteVariable        *varone = NULL, *result = NULL;
1071     FeriteVariable        *(*unaryop)( FeriteScript *s, FeriteVariable *a );
1072 
1073     FUD(("UNARY\n"));
1074     varone = ferite_stack_pop( exec->stack );
1075     unaryop = (FeriteVariable *(*)( FeriteScript *, FeriteVariable * ))ferite_op_table[current_op->addr].ptr;
1076     FUD(("Unary Op Parameters: %s\n", varone->name ));
1077     if( (result = unaryop( script, varone )) )
1078         ferite_stack_push( exec->stack, result );
1079     if( FE_VAR_IS_DISPOSABLE( varone ) )
1080     {
1081         FUD(("Deleting Variable: %s\n", varone->name ));
1082         ferite_variable_destroy( script, varone );
1083     }
1084 
1085     return NULL;
1086 }
INLINE_OP(ferite_exec_many)1087 INLINE_OP( ferite_exec_many )
1088 {
1089     FeriteVariable *(*manyop)(FeriteScript *s, FeriteVariable **vars,int count);
1090     FeriteVariable **many = NULL, *result = NULL;
1091     int n, *count = NULL;
1092 
1093     FUD(("MANY\n"));
1094     count = (int*)(current_op->opdata);
1095     many = fmalloc(sizeof(FeriteVariable*) * *count);
1096     for( n = 0; n < *count; n++ )
1097     {
1098         many[n] = ferite_stack_pop( exec->stack );
1099         LOCK_VARIABLE( many[n] );
1100     }
1101     manyop = (FeriteVariable *(*)(FeriteScript *, FeriteVariable **,int))ferite_op_table[current_op->addr].ptr;
1102     if( (result = manyop(script, many, *count)) )
1103         ferite_stack_push( exec->stack, result );
1104     for( n = 0; n < *count; n++ )
1105     {
1106         UNLOCK_VARIABLE( many[n] );
1107         if( FE_VAR_IS_DISPOSABLE( many[n] ) )
1108         {
1109             FUD(("Deleting Variable: %s\n",many[n]->name));
1110             ferite_variable_destroy(script, many[n]);
1111         }
1112     }
1113     ffree(many);
1114 
1115     return NULL;
1116 }
INLINE_OP(ferite_exec_case)1117 INLINE_OP( ferite_exec_case )
1118 {
1119     FeriteVariable        *varone = NULL, *vartwo = NULL, *result = NULL;
1120     /*
1121      * This will simply take the first operand, duplicate it, and then push it back onto
1122      * the stack. It then lets the switch statement run into the next block.
1123      */
1124     vartwo = ferite_stack_pop( exec->stack );
1125     varone = ferite_stack_pop( exec->stack );
1126     result = ferite_duplicate_variable( script, varone, NULL );
1127     MARK_VARIABLE_AS_DISPOSABLE( result );
1128     ferite_stack_push( exec->stack, result );
1129     ferite_stack_push( exec->stack, varone );
1130     ferite_stack_push( exec->stack, vartwo );
1131 
1132     return NULL;
1133 }
1134 
1135 /**
1136  * @function ferite_script_real_function_execute
1137  * @declaration FeriteVariable *ferite_script_real_function_execute( FeriteScript *script, void *container, FeriteFunction *function, FeriteNamespace *ns, FeriteExecuteRec *exec, FeriteVariable **params )
1138  * @brief Execute a eval operator compiled script
1139  * @param FeriteScript *script The current script to run
1140  * @param void *container The container the function is running from namespace/class/object
1141  * @param FeriteFunction *function The function to execute
1142  * @param FeriteNamespace *ns The scripts main namespace
1143  * @param FeriteExecuteRec *exec The execute records for the current script
1144  * @param FeriteVariable **params The parameters passed to the function
1145  * @return The return value from the function on successfull execution, NULL otherwise
1146  */
ferite_script_real_function_execute(FeriteScript * script,void * container,FeriteObject * current_yield_block,FeriteFunction * function,FeriteNamespace * mainns,FeriteExecuteRec * exec,FeriteVariable ** params)1147 FeriteVariable *ferite_script_real_function_execute( FeriteScript *script, void *container, FeriteObject *current_yield_block, FeriteFunction *function, FeriteNamespace *mainns, FeriteExecuteRec *exec, FeriteVariable **params )
1148 {
1149     /*{{{ Variables */
1150     FeriteOp        *current_op = NULL;
1151     FeriteOp       **opcode_list = NULL;
1152     FeriteVariable  *varone = NULL, *vartwo = NULL, *rval = NULL, *return_val = NULL;
1153     FeriteObject    *new_yield_block = NULL;
1154     int              current_op_loc = 0, keep_function_running = FE_TRUE, error_op_location = 0, error_array[100];
1155     /*}}}*/
1156 
1157     FE_ENTER_FUNCTION;
1158 
1159     opcode_list = function->ccode->list;
1160     current_op = opcode_list[0];
1161     current_op_loc++;
1162 
1163     script->current_op_file = function->ccode->filename;
1164 
1165     FUD(("EXECUTION STARTING\n"));
1166     while( keep_function_running && script->keep_execution )
1167     {
1168         varone = NULL;
1169         vartwo = NULL;
1170         rval = NULL;
1171         FUD(("[%p] ", current_op ));
1172 
1173         script->current_op_line = current_op->line;
1174         exec->block_depth = current_op->block_depth;
1175         switch( current_op->OP_TYPE )
1176         {
1177             case F_OP_SWAP_TOP:
1178             {
1179                 CALL_INLINE_OP( ferite_exec_swaptop );
1180                 break;
1181             }
1182             case F_OP_PUSH:
1183             {
1184                 /*{{{ F_OP_PUSH      (push something onto the stack)    */
1185                 CALL_INLINE_OP( ferite_exec_push );
1186                 break;
1187             }
1188             case F_OP_POP:
1189             {
1190                 /*{{{ F_OP_POP       (pop something off the stack)      */
1191                 CALL_INLINE_OP( ferite_exec_pop );
1192                 break;
1193             }
1194             case F_OP_ARGS:
1195             {
1196                 /*{{{ F_OP_ARGS      (get the funtions parameters)      */
1197                 CALL_INLINE_OP( ferite_exec_args );
1198                 break;
1199             }
1200             case F_OP_GET_DELIVER:
1201             {
1202                 /* push the deliver object onto the stack */
1203                 CALL_INLINE_OP( ferite_exec_get_deliver );
1204                 break;
1205             }
1206             case F_OP_SET_DELIVER:
1207             {
1208                 /* Set the current yield block */
1209                 new_yield_block = CALL_INLINE_OP( ferite_exec_set_deliver );
1210                 break;
1211             }
1212             case F_OP_CLSRE_ASSGN:
1213             {
1214                 /* Only gets called within the constructor of a closure */
1215                 CALL_INLINE_OP( ferite_exec_clsre_assgn );
1216                 break;
1217             }
1218             case F_OP_PUSHVAR:
1219             {
1220                 /*{{{ F_OP_PUSHVAR   (get variable and put onto stack)  */
1221                 CALL_INLINE_OP( ferite_exec_pushvar );
1222                 break;
1223             }
1224             case F_OP_PUSHATTR:
1225             {
1226                 /*{{{ F_OP_PUSHATTR  (get variable from and object,class or namespace and put onto stack)  */
1227                 CALL_INLINE_OP( ferite_exec_pushattr );
1228                 break;
1229             }
1230             case F_OP_PUSHINDEX:
1231             {
1232                 /*{{{ F_OP_PUSHINDEX (get a variable from the local vars and push it onto the stack) */
1233                 CALL_INLINE_OP( ferite_exec_pushindex );
1234                 break;
1235             }
1236             case F_OP_UNARY:
1237             {
1238                 /*{{{ F_OP_UNARY     (do a unary operation)             */
1239                 CALL_INLINE_OP( ferite_exec_unary );
1240                 break;
1241             }
1242             case F_OP_MANY:
1243             {
1244                 /*{{{ F_OP_MANY      (do something requiring many args) */
1245                 CALL_INLINE_OP( ferite_exec_many );
1246                 break;
1247             }
1248             case F_OP_CASE:
1249             {
1250                 /*{{{ F_OP_CASE      (do a case statement)              */
1251                 CALL_INLINE_OP( ferite_exec_case );
1252                 /* NOTE!!!! THERE IS NO BREAK! THIS IS DELIBERATE!!!!! */
1253             }
1254             case F_OP_BINARY:
1255             {
1256                 /*{{{ F_OP_BINARY    (do a binary operation)            */
1257                 CALL_INLINE_OP( ferite_exec_binary );
1258                 break;
1259             }
1260             case F_OP_METHOD:
1261             case F_OP_FUNCTION:
1262             case F_OP_NEWOBJ:
1263             case F_OP_DELIVER:
1264             {
1265                 CALL_INLINE_OP( ferite_exec_funcall );
1266                 if( new_yield_block != NULL )
1267                 {
1268                     new_yield_block->refcount--;
1269                     new_yield_block = NULL;
1270                 }
1271                 break;
1272             }
1273             case F_OP_BNE:
1274             {
1275                 /*{{{ F_OP_BNE       (branch if not equal)              */
1276                 FUD(("BNE\n"));
1277                 varone = ferite_stack_pop( exec->stack );
1278                 if( ferite_variable_is_false( script, varone) )
1279                 {
1280                     FUD(("BNE: Branching\n" ));
1281                     current_op_loc = current_op->addr;
1282                 }
1283                 else
1284                 {
1285                     FUD(("BNE: Not Branching\n" ));
1286                 }
1287                 if( FE_VAR_IS_DISPOSABLE( varone ) ) /* the var was created */
1288                     ferite_variable_destroy( script, varone );
1289                 break;
1290             }
1291             case F_OP_BIE:
1292             {
1293                 /*{{{ F_OP_BIE       (branch if equal)                  */
1294                 FUD(("BIE\n"));
1295                 varone = ferite_stack_pop( exec->stack );
1296                 if( !ferite_variable_is_false( script, varone ) )
1297                 {
1298                     FUD(("BIE: Branching\n" ));
1299                     current_op_loc = current_op->addr;
1300                 }
1301                 else
1302                 {
1303                     FUD(("BIE: Not Branching\n" ));
1304                 }
1305                 if( varone != NULL && FE_VAR_IS_DISPOSABLE( varone ) ) /* the var was created */
1306                     ferite_variable_destroy( script, varone );
1307                 break;
1308             }
1309             case F_OP_JMP:
1310             {
1311                 /*{{{ F_OP_JMP       (jump to a address)                */
1312                 FUD(("JMP\n"));
1313                 current_op_loc = current_op->addr;
1314                 break;
1315             }
1316             case F_OP_NOP:
1317             {
1318                 /*{{{ F_OP_NOP       (do nothing)                       */
1319                 FUD(("NOP. Nothing Done :)\n"));
1320                 break;
1321             }
1322             case F_OP_EXIT:
1323             {
1324                 /*{{{ F_OP_EXIT      (exit and return from a function)  */
1325                 FUD(("Exiting\n"));
1326                 keep_function_running = FE_FALSE; /* quit the function */
1327                 varone = ferite_stack_pop( exec->stack );
1328                 return_val = ferite_duplicate_variable( script, varone, NULL );
1329                 MARK_VARIABLE_AS_DISPOSABLE( return_val );
1330                 if( varone && FE_VAR_IS_DISPOSABLE( varone ) )
1331                 {
1332                     FUD(("Deleting Variable: %s\n", varone->name ));
1333                     ferite_variable_destroy( script, varone );
1334                 }
1335                 break;
1336             }
1337             case F_OP_ERR:
1338             {
1339                 /*{{{ F_OP_ERR       (set an error handler)             */
1340                 if( current_op->addr == -1 )
1341                 {  /* reset the error counter */
1342                     script->error_state = FE_NO_ERROR;
1343                     error_array[error_op_location] = 0;
1344 		   error_op_location--;
1345                 }
1346                 else
1347                 {
1348                     FUD(("ERROR HANDLER: Setting Error location to %ld",  current_op->addr ));
1349                     error_array[error_op_location] = current_op->addr;
1350 					error_op_location++;
1351                 }
1352                 break;
1353             }
1354             case F_OP_VRST:
1355             {
1356                 varone = ferite_stack_pop( exec->stack );
1357                 ferite_variable_convert_to_type( script, varone, F_VAR_VOID );
1358                 break;
1359             }
1360             default:
1361                 ferite_error( script, 0, "Unknown op type [%d]\n", current_op->OP_TYPE );
1362         }
1363 
1364         /*{{{ error checking */
1365         FUD(( "ERROR STATE: %d\n", script->error_state ));
1366         switch( script->error_state )
1367         {
1368             case FE_ERROR_THROWN:
1369             {
1370                 FUD(( "ERROR STATE: reported...\n" ));
1371                 if( error_op_location < 1 || error_array[error_op_location-1] == 0 )
1372                 {
1373                     /* there is no error handler propogate upwards */
1374                     FUD(( "ERROR STATE: No error handler found... bombing out.\n" ));
1375                     FUD(( "EXEC: detected error - stoping execution\n" ));
1376                     ferite_error( script, 0, "    in %s:%d\n", function->ccode->filename, current_op->line );
1377                     keep_function_running = FE_FALSE;
1378                 }
1379                 else
1380                 {
1381                     FUD(( "ERROR STATE: Going to error handler code\n" ));
1382                     current_op_loc = error_array[error_op_location-1];
1383                     current_op = opcode_list[current_op_loc];
1384                     current_op_loc++;
1385 
1386                     /* We also need to reset the error log otherwise we will get errors we have caught */
1387                     ferite_reset_errors( script );
1388                 }
1389                 break;
1390             }
1391             default:
1392                 current_op = opcode_list[current_op_loc];
1393                 current_op_loc++;
1394         }
1395 
1396         if( !keep_function_running || !script->keep_execution )
1397         {
1398             break;
1399         }
1400 
1401         /*{{{ GARBAGE COLLECTOR */
1402 #ifndef FE_USE_GENERATIONAL_GC
1403         {
1404             FeriteStdGC *gc = script->gc;
1405             gc->count++;
1406             if( gc->count > FE_GC_RUN_AFTER_OPS )
1407             {
1408                 ferite_check_std_gc( script );
1409                 gc->count = 0;
1410             }
1411         }
1412 #endif
1413 
1414       /*}}}*/
1415     }
1416 
1417     FUD(("EXECUTION COMPLETE. Have a nice day :). (%s)\n", function->name));
1418     FE_LEAVE_FUNCTION( return_val );
1419 }
1420 
1421 /**
1422  * @function ferite_clean_up_exec_rec
1423  * @declaration void ferite_clean_up_exec_rec( FeriteScript *script, FeriteExecuteRec *exec )
1424  * @brief Clean up and Execution Record
1425  * @param FeriteScript *script The current script
1426  * @param FeriteExecuteRex *exec   Pointer to the execution record
1427  */
ferite_clean_up_exec_rec(FeriteScript * script,FeriteExecuteRec * exec)1428 void ferite_clean_up_exec_rec( FeriteScript *script, FeriteExecuteRec *exec )
1429 {
1430     int counter, i;
1431     FeriteVariable *targetvar;
1432 
1433     FE_ENTER_FUNCTION;
1434     /*{{{ Clean up local scope variables */
1435     FUD(("DELETING LOCAL VARIABLES\n" ));
1436     for( i = 1; i <= exec->function->localvars->stack_ptr; i++ )
1437     {
1438         if( exec->variable_list[i] != NULL )
1439           ferite_variable_destroy( script, exec->variable_list[i] );
1440     }
1441     ffree( exec->variable_list );
1442     /*}}}*/
1443 
1444     /*{{{ Clean up execution stack */
1445     counter = 0;
1446     for( i = 1; i <= exec->stack->stack_ptr; i++ )
1447     {
1448         targetvar = exec->stack->stack[i];
1449         if( targetvar && FE_VAR_IS_DISPOSABLE( targetvar ) )
1450         {
1451             FUD(("[%d/%d] DESTROYING STACK VARIABLE %s (%s)\n", i,
1452                  exec->stack->stack_ptr,
1453                  targetvar->name,
1454                  ferite_variable_id_to_str( script, targetvar->type) ));
1455             ferite_variable_destroy( script, targetvar );
1456             counter++;
1457         }
1458     }
1459     FUD(( "%d variables lefton stack\n", counter ));
1460     FUD(("IN TOTAL %d VARIABLES WHERE NOT DEALLOCATED\n", counter));
1461    /*}}}*/
1462     FE_LEAVE_FUNCTION( NOWT );
1463 }
1464 
1465 /**
1466  * @function ferite_create_parameter_list
1467  * @declaration FeriteVariable **ferite_create_parameter_list( int size )
1468  * @brief Create a parameter list, NULLify it and then return it
1469  * @param int size The number of parameters to hold
1470  * @return The created list
1471  */
ferite_create_parameter_list(int size)1472 FeriteVariable **ferite_create_parameter_list( int size )
1473 {
1474     FeriteVariable **list = NULL;
1475 
1476     FE_ENTER_FUNCTION;
1477     list = fcalloc( sizeof( FeriteVariable* ) * (size+1), sizeof(char) );
1478     FE_LEAVE_FUNCTION( list );
1479 }
1480 
1481 /**
1482  * @function ferite_add_to_parameter_list
1483  * @declaration FeriteVariable **ferite_add_to_parameter_list( FeriteVariable **list, FeriteVariable *var )
1484  * @brief Place a parameter within the next availible place within the parameter list
1485  * @param FeriteVariable **list The list to place it in
1486  * @param FeriteVariable *var  The variable to place within the list
1487  * @return The list passed to the function
1488  */
ferite_add_to_parameter_list(FeriteVariable ** list,FeriteVariable * var)1489 FeriteVariable **ferite_add_to_parameter_list( FeriteVariable **list, FeriteVariable *var )
1490 {
1491     int size = ferite_get_parameter_count( list );
1492 
1493     FE_ENTER_FUNCTION;
1494     list[size] = var;
1495     list[size+1] = NULL;
1496     FE_LEAVE_FUNCTION( list );
1497 }
1498 
1499 /**
1500  * @function ferite_delete_parameter_list
1501  * @declaration void ferite_delete_parameter_list( FeriteScript *script, FeriteVariable **list )
1502  * @brief Delete a parameter list, and destroy any disposable variables
1503  * @param FeriteScript *script The current script
1504  * @param FeriteVariable **list   The list to be deleted
1505  */
ferite_delete_parameter_list(FeriteScript * script,FeriteVariable ** list)1506 void ferite_delete_parameter_list( FeriteScript *script, FeriteVariable **list )
1507 {
1508     int i = 0;
1509     int size = ferite_get_parameter_count( list );
1510 
1511     FE_ENTER_FUNCTION;
1512     while( list[i] != NULL && i < size )
1513     {
1514         if( list[i] )
1515         {
1516             UNLOCK_VARIABLE(list[i]);
1517             if( FE_VAR_IS_DISPOSABLE( list[i] ) )
1518               ferite_variable_destroy( script, PTR2VAR(list[i]) );
1519         }
1520         i++;
1521     }
1522     ffree( list );
1523     FE_LEAVE_FUNCTION( NOWT );
1524 }
1525 
1526 /**
1527  * @function ferite_create_parameter_list_from_data
1528  * @declaration FeriteVariable **ferite_create_parameter_list_from_data( FeriteScript *script, char *format, ... )
1529  * @brief This function is used to make creating a parameter list very easy.
1530  * @param script The current script
1531  * @param format The signiture for the parameters
1532  * @description
1533  * This function makes the whole process of creating a parameter list very easy. It allows
1534  * you to create a list from the actual data and not have to worry about the finer details of
1535  * ferite variables. It returns a parameter list.<nl/>
1536  * <nl/>
1537  * e.g.:<nl/>
1538  * ferite_create_parameter_list_from_data( script, "nns", 2.3, 2, "Jello" );<nl/>
1539  * <nl/>
1540  * The formats are as follows:<nl/>
1541  *   n = number<nl/>
1542  *   s = string<nl/>
1543  *   o = object<nl/>
1544  *   a = array
1545  * @return The list that is created.
1546  */
ferite_create_parameter_list_from_data(FeriteScript * script,char * format,...)1547 FeriteVariable **ferite_create_parameter_list_from_data( FeriteScript *script, char *format, ... )
1548 {
1549     FeriteVariable **retval = NULL;
1550     FeriteVariable *var = NULL;
1551     va_list          ap;
1552     int              i = 0;
1553 
1554     retval = fmalloc( sizeof( FeriteVariable * ) * (strlen(format) + 3) );
1555     memset( retval, '\0', sizeof( FeriteVariable * ) * (strlen(format) + 3) );
1556 
1557     va_start( ap, format );
1558     for( i = 0; i < (signed)strlen(format); i++ )
1559     {
1560         switch( format[i] )
1561         {
1562           case 'n':
1563             var = ferite_create_number_double_variable( script, "list_from_data-number", va_arg( ap, double ), FE_STATIC );
1564             break;
1565           case 'l':
1566             var = ferite_create_number_long_variable( script, "list_from_data-number", va_arg( ap, long ), FE_STATIC );
1567             break;
1568           case 's':
1569             var = ferite_create_string_variable( script, "list_from_data-string", va_arg( ap, FeriteString * ), FE_STATIC );
1570             break;
1571           case 'o':
1572             var = ferite_create_object_variable( script, "list_from_data-object", FE_STATIC );
1573             VAO(var) = va_arg( ap, FeriteObject * );
1574             VAO(var)->refcount++;
1575             break;
1576           case 'a':
1577             var = ferite_create_uarray_variable( script, "list_from_data-array", 0, FE_STATIC );
1578             ferite_uarray_destroy( script, VAUA(var) );
1579             VAUA(var) = ferite_uarray_dup( script, va_arg( ap, FeriteUnifiedArray *), (void *(*)(FeriteScript*,FeriteVariable*,void*))ferite_duplicate_variable );
1580             break;
1581         }
1582         MARK_VARIABLE_AS_DISPOSABLE( var );
1583         retval[i] = var;
1584     }
1585     va_end( ap );
1586     return retval;
1587 }
1588 
1589 /**
1590  * @function ferite_call_function
1591  * @declaration FeriteVariable *ferite_call_function( FeriteScript *script, FeriteFunction *function, FeriteVariable **params )
1592  * @brief This will call any function from it's function pointer and a parameter list
1593  * @param FeriteScript *script The current script
1594  * @param FeriteFunction *function The function to be called
1595  * @param FeriteVariable **params The parameter list to be passed to the function
1596  * @description This function will work on either an internal or native function and will happily choose the correct function
1597  *              if it happens to be overloaded.
1598  */
ferite_call_function(FeriteScript * script,void * container,FeriteObject * block,FeriteFunction * orig_function,FeriteVariable ** params)1599 FeriteVariable *ferite_call_function( FeriteScript *script, void *container, FeriteObject *block, FeriteFunction *orig_function, FeriteVariable **params )
1600 {
1601     FeriteVariable *retval = NULL;
1602     FeriteFunction *function = NULL;
1603     FeriteVariable **plist = NULL;
1604     int script_exec_state = 0;
1605 
1606     FE_ENTER_FUNCTION;
1607 
1608     if( orig_function != NULL )
1609     {
1610         script_exec_state = script->is_executing;
1611         script->is_executing = FE_TRUE;
1612 
1613         plist = params;
1614         if( params == NULL )
1615         {
1616             plist = ferite_create_parameter_list( 1 );
1617             plist[0] = NULL;
1618         }
1619 
1620         for( function = orig_function; function != NULL; function = function->next )
1621         {
1622             if( ferite_check_params( script, plist, function ) == 1 )
1623             {
1624                 LOCK_VARIABLE( function );
1625                 if( function->type == FNC_IS_EXTRL )
1626                 {
1627                     if( function->fncPtr != NULL )
1628                         retval = (function->fncPtr)( script, container, block, function, plist );
1629                     else
1630                         retval = ferite_create_void_variable( script, "error...", FE_STATIC );
1631                 }
1632                 else
1633                 {
1634                     retval = ferite_script_function_execute( script, container, block, function, plist );
1635                     if( script->error_state == FE_ERROR_THROWN )
1636                         retval = ferite_create_void_variable( script, "error...", FE_STATIC );
1637                 }
1638                 UNLOCK_VARIABLE( function );
1639                 break;
1640             }
1641         }
1642         if( function == NULL )
1643             ferite_error( script, 0, "Incorrect parameters for function %s\n", orig_function->name );
1644 
1645         if( params == NULL )
1646             ffree( plist );
1647 
1648         script->is_executing = script_exec_state;
1649     }
1650     else
1651         ferite_error( script, 0, "Unable to execute NULL function\n" );
1652 
1653     FE_LEAVE_FUNCTION( retval );
1654 }
1655 
1656 /**
1657  * @end
1658  */
1659