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