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 #include <math.h>
39 
40 #define GET_VAR( var ) if( var && var->accessors && var->accessors->get ) (var->accessors->get)( script, var )
41 #define GET_A_VAR GET_VAR( a )
42 #define GET_B_VAR GET_VAR( b )
43 #define GET_INPUT_VARS GET_A_VAR; GET_B_VAR
44 
45 /*{{{ FeriteVariable *ferite_build_object( FeriteScript *script, FeriteClass *nclass) */
ferite_build_object(FeriteScript * script,FeriteClass * nclass)46 FeriteVariable *ferite_build_object( FeriteScript *script, FeriteClass *nclass)
47 {
48     FeriteVariable *ptr = NULL;
49 
50     FE_ENTER_FUNCTION;
51 
52     if( nclass != NULL )
53     {
54         FUD(("BUILDOBJECT: Creating an instance of %s\n", nclass->name ));
55         ptr = ferite_create_object_variable( script, nclass->name, FE_ALLOC );
56         if( script && script->objects->stack_ptr )
57             VAO(ptr) = ferite_stack_pop( script->objects );
58         else
59             VAO(ptr) = fmalloc( sizeof( FeriteObject ) );
60         VAO(ptr)->name = fstrdup( nclass->name );
61         VAO(ptr)->klass = nclass;
62 
63         FUD(("BUILDOBJECT: Creating a duplicate varaible hash\n"));
64         VAO(ptr)->variables = ferite_duplicate_object_variable_list( script, nclass );
65 
66         FUD(("BUILDOBJECT: Linking function list up\n"));
67         VAO(ptr)->functions = nclass->object_methods;
68 
69         VAO(ptr)->oid = nclass->id;
70         VAO(ptr)->odata = NULL;
71 
72         VAO(ptr)->refcount = 1;
73 
74         ferite_add_to_gc( script, VAO(ptr) );
75     }
76     FE_LEAVE_FUNCTION( ptr );
77 }
78 /*}}}*/
79 
80 /**
81  * @group Objects
82  */
83 /*{{{ FeriteVariable *ferite_new_object( FeriteScript *script, FeriteClass *nclass, FeriteVariable **plist ) */
84 /**
85  * @function ferite_new_object
86  * @declaration FeriteVariable *ferite_new_object( FeriteScript *script, FeriteClass *nclass, FeriteVariable **plist)
87  * @brief Create a new object - the C equivalent to the ferite 'new' keyword.
88  * @param FeriteScript *script The script to create the object within.
89  * @param FeriteClass *nclass The class to instantiate an object from
90  * @param FeriteVariable **plist The parameters to be passed to the objects constructor. This can be NULL for an empty
91           list.
92  * @return A variable that references the newly created object.
93  * @warning The return variable is marked as disposable. If you wish to retain a reference and return the object from a
94     native function you must 'UNMARK_VARIABLE_AS_DISPOSABLE'
95  */
ferite_new_object(FeriteScript * script,FeriteClass * nclass,FeriteVariable ** plist)96 FeriteVariable *ferite_new_object( FeriteScript *script, FeriteClass *nclass, FeriteVariable **plist)
97 {
98     FeriteVariable *ptr = NULL, *rval = NULL;
99     FeriteFunction *func = NULL;
100     FeriteVariable **params = NULL;
101 
102     FE_ENTER_FUNCTION;
103     if(nclass != NULL)
104     {
105         if( nclass->state == FE_ITEM_IS_ABSTRACT )
106         {
107             ferite_error( script, 0, "You can't create instances of the abstract class %s\n", nclass->name );
108             FE_LEAVE_FUNCTION( NULL );
109         }
110         else if( nclass->state == FE_ITEM_IS_PROTOCOL )
111         {
112             ferite_error( script, 0, "You can't create instances of the protocol %s\n", nclass->name );
113             FE_LEAVE_FUNCTION( NULL );
114         }
115 
116         if( plist != NULL )
117             params = plist;
118         else
119             params = ferite_create_parameter_list( 3 );
120 
121         ptr = ferite_build_object(script,nclass);
122 
123         FUD(("NEWOBJECT: Marking as disposable\n" ));
124         MARK_VARIABLE_AS_DISPOSABLE( ptr );
125 
126         FUD(("NEWOBJECT: Searching for constructor\n" ));
127         func = ferite_find_constructor( script, VAO(ptr), params );
128         if( func != NULL )
129         {
130             FUD(("OPS: Calling constructor in class %s\n", nclass->name ));
131 
132             if( func->type == FNC_IS_EXTRL )
133                 rval = (func->fncPtr)( script, VAO(ptr), NULL, func, params );
134             else
135                 rval = ferite_script_function_execute( script, VAO(ptr), NULL, func, params );
136 
137             if( rval == NULL || (rval != NULL && rval->type == F_VAR_OBJ && VAO(rval) == NULL) )
138             {
139                 if( rval == NULL )
140                     ferite_error( script, 0, "Unable to instantiate object from class '%s'\n", nclass->name );
141 
142                 /* clean up the class */
143                 ferite_delete_object_variable_list( script, VAO(ptr)->variables );
144                 VAO(ptr)->variables = NULL;
145                 VAO(ptr)->functions = NULL;
146                 VAO(ptr)->klass = NULL;
147                 ffree( VAO(ptr)->name );
148 
149                 /* set our return val to NULL */
150                 VAO(ptr) = NULL;
151             }
152             if( rval != NULL )
153                 ferite_variable_destroy( script, rval );
154         }
155         else
156             ferite_error( script, 0, "Unable to find constructor of the class '%s' for the given parameters\n", nclass->name );
157 
158         if( plist == NULL )
159             ferite_delete_parameter_list( script, params );
160     }
161     FE_LEAVE_FUNCTION( ptr );
162 }
163 /*}}}*/
164 /** @end */
165 
166 /*{{{ FERITE_UNARY_OP( left_incrc ) */
FERITE_UNARY_OP(left_incr)167 FERITE_UNARY_OP( left_incr )
168 {
169     FeriteVariable *ptr = NULL;
170 
171     FE_ENTER_FUNCTION;
172     LOCK_VARIABLE(a);
173     GET_A_VAR;
174 
175     if( !FE_VAR_IS_FINALSET( a ) )
176     {
177         switch( a->type )
178         {
179           case F_VAR_LONG:
180             FUD(("OPS: Incrementing %s from %ld to ", a->name, VAI( a ) ));
181             VAI( a ) += 1;
182             FUD(("%ld\n", VAI( a ) ));
183 /*            ptr = ferite_duplicate_variable( script, a, NULL );
184             MARK_VARIABLE_AS_DISPOSABLE( ptr ); */
185             break;
186           default:
187             ferite_error( script, 0, "Can't increment variables of type %s\n", ferite_variable_id_to_str( script,a->type) );
188         }
189         if( FE_VAR_IS_FINAL( a ) )
190           MARK_VARIABLE_AS_FINALSET( a );
191     }
192     UNLOCK_VARIABLE(a);
193     FE_LEAVE_FUNCTION( a/*ptr*/ );
194 }
195 /*}}}*/
196 
197 /*{{{ FERITE_UNARY_OP( right_incr ) */
FERITE_UNARY_OP(right_incr)198 FERITE_UNARY_OP( right_incr )
199 {
200     FeriteVariable *ptr = NULL;
201 
202     FE_ENTER_FUNCTION;
203     LOCK_VARIABLE(a);
204     GET_A_VAR;
205 
206     if( !FE_VAR_IS_FINALSET( a ) )
207     {
208         switch( a->type )
209         {
210           case F_VAR_LONG:
211             ptr = ferite_duplicate_variable( script, a, NULL );
212             FUD(("OPS: Incrementing %s from %ld to ", a->name, VAI( a ) ));
213             VAI( a ) += 1;
214             FUD(("%ld\n", VAI( a ) ));
215             MARK_VARIABLE_AS_DISPOSABLE( ptr );
216             break;
217           default:
218             ferite_error( script, 0,"Can't increment variables of type %s\n", ferite_variable_id_to_str( script,a->type) );
219         }
220         if( FE_VAR_IS_FINAL( a ) )
221           MARK_VARIABLE_AS_FINALSET( a );
222     }
223     UNLOCK_VARIABLE(a);
224     FE_LEAVE_FUNCTION( ptr );
225 }
226 /*}}}*/
227 
228 /*{{{ FERITE_UNARY_OP( left_decr ) */
FERITE_UNARY_OP(left_decr)229 FERITE_UNARY_OP( left_decr )
230 {
231     FeriteVariable *ptr = NULL;
232 
233     FE_ENTER_FUNCTION;
234     LOCK_VARIABLE(a);
235     GET_A_VAR;
236 
237     if( !FE_VAR_IS_FINALSET( a ) )
238     {
239         switch( a->type )
240         {
241           case F_VAR_LONG:
242             FUD(("OPS: Decrementing %s from %ld to ", a->name, VAI( a ) ));
243             VAI( a ) -= 1;
244             FUD(("%ld\n", VAI( a ) ));
245 /*            ptr = ferite_duplicate_variable( script, a, NULL );
246             MARK_VARIABLE_AS_DISPOSABLE( ptr );*/
247             break;
248           default:
249             ferite_error( script, 0,"Can't decrement variables of type %s\n", ferite_variable_id_to_str( script,a->type) );
250         }
251         if( FE_VAR_IS_FINAL( a ) )
252           MARK_VARIABLE_AS_FINALSET( a );
253     }
254     UNLOCK_VARIABLE(a);
255     FE_LEAVE_FUNCTION( a/*ptr*/ );
256 }
257 /*}}}*/
258 
259 /*{{{ FERITE_UNARY_OP( right_decr ) */
FERITE_UNARY_OP(right_decr)260 FERITE_UNARY_OP( right_decr )
261 {
262     FeriteVariable *ptr = NULL;
263 
264     FE_ENTER_FUNCTION;
265     LOCK_VARIABLE(a);
266     GET_A_VAR;
267 
268     if( !FE_VAR_IS_FINALSET( a ) )
269     {
270         switch( a->type )
271         {
272           case F_VAR_LONG:
273             ptr = ferite_duplicate_variable( script, a, NULL );
274             MARK_VARIABLE_AS_DISPOSABLE( ptr );
275             FUD(("OPS: Decrementing %s from %ld to ", a->name, VAI( a ) ));
276             VAI( a ) -= 1;
277             FUD(("%ld\n", VAI( a ) ));
278             break;
279           default:
280             ferite_error( script, 0, "Can't decrement variables of type %s\n", ferite_variable_id_to_str( script,a->type) );
281         }
282         if( FE_VAR_IS_FINAL( a ) )
283           MARK_VARIABLE_AS_FINALSET( a );
284     }
285     UNLOCK_VARIABLE(a);
286     FE_LEAVE_FUNCTION( ptr );
287 }
288 /*}}}*/
289 
290 /*{{{ FERITE_UNARY_OP( positive_var ) */
FERITE_UNARY_OP(positive_var)291 FERITE_UNARY_OP( positive_var )
292 {
293     FeriteVariable *ptr = NULL;
294 
295     FE_ENTER_FUNCTION;
296     LOCK_VARIABLE(a);
297     GET_A_VAR;
298 
299     switch( a->type )
300     {
301       case F_VAR_LONG:
302         ptr = ferite_duplicate_variable( script, a, NULL );
303         MARK_VARIABLE_AS_DISPOSABLE( ptr );
304         if( VAI(ptr) < 0 )
305         {
306             VAI(ptr) = 0 - VAI(ptr);
307         }
308         break;
309       case F_VAR_DOUBLE:
310         ptr = ferite_duplicate_variable( script, a, NULL );
311         MARK_VARIABLE_AS_DISPOSABLE( ptr );
312         if( VAF(ptr) < 0 )
313         {
314             VAF(ptr) = 0 - VAF(ptr);
315         }
316         break;
317       default:
318         ferite_error( script, 0, "Can't positise variables of type %s\n", ferite_variable_id_to_str( script,a->type) );
319     }
320     UNLOCK_VARIABLE(a);
321     FE_LEAVE_FUNCTION( ptr );
322 }
323 /*}}}*/
324 
325 /*{{{ FERITE_UNARY_OP( negative_var ) */
FERITE_UNARY_OP(negative_var)326 FERITE_UNARY_OP( negative_var )
327 {
328     FeriteVariable *ptr = NULL;
329 
330     FE_ENTER_FUNCTION;
331     LOCK_VARIABLE(a);
332     GET_A_VAR;
333 
334     switch( a->type )
335     {
336       case F_VAR_LONG:
337         ptr = ferite_duplicate_variable( script, a, NULL );
338         MARK_VARIABLE_AS_DISPOSABLE( ptr );
339         VAI(ptr) = 0 - VAI(ptr);
340         break;
341       case F_VAR_DOUBLE:
342         ptr = ferite_duplicate_variable( script, a, NULL );
343         MARK_VARIABLE_AS_DISPOSABLE( ptr );
344         VAF(ptr) = 0 - VAF(ptr);
345         break;
346       default:
347         ferite_error( script, 0, "Can't negatise variables of type %s\n", ferite_variable_id_to_str( script,a->type) );
348     }
349     UNLOCK_VARIABLE(a);
350     FE_LEAVE_FUNCTION( ptr );
351 }
352 /*}}}*/
353 
354 /*{{{ MACROS FOR WRITING CLEAN OPERATORS */
355 
356 #define RETVNAME( n ) "op-" n "-return-value"
357 
358 #define BEGIN_BLOCK( t, var ) \
359   case t: \
360     switch( var->type ) \
361       {
362 
363 #define END_BLOCK \
364     } \
365     break;
366 
367 #define BEGIN_OP( var ) \
368     FeriteVariable *retv = NULL; \
369     FE_ENTER_FUNCTION; \
370     LOCK_VARIABLE(a); \
371     LOCK_VARIABLE(b); \
372     GET_INPUT_VARS; \
373     switch( var->type ){
374 
375 #define BLOCK_DIE( t ) \
376   default: \
377     ferite_error( script, 1, "Can't %s variables of type %s and %s\n", t,  \
378                               ferite_variable_id_to_str( script,a->type),  ferite_variable_id_to_str( script,b->type) );
379 
380 #define END_OP( d ) \
381     BLOCK_DIE( d )\
382         } \
383     if( retv != NULL ) { MARK_VARIABLE_AS_DISPOSABLE( retv ); } \
384     UNLOCK_VARIABLE(a); \
385     UNLOCK_VARIABLE(b); \
386     FE_LEAVE_FUNCTION( retv );
387 
388 #define DO_OP( t, cv, c ) \
389   case t: \
390     cv; \
391     c; \
392     break;
393 
394 #define FE_VAR_TRUE( var, op ) var = ferite_create_number_long_variable( script, RETVNAME( op ), FE_TRUE, FE_STATIC )
395 #define FE_VAR_FALSE( var, op ) var = ferite_create_number_long_variable( script, RETVNAME( op ), FE_FALSE, FE_STATIC )
396 
397 #define FE_VAR_TEST( test, op ) \
398         if( test ) \
399             FE_VAR_TRUE( ptr, op ); \
400     else \
401       FE_VAR_FALSE( ptr, op );
402 
403 #define FE_OP_RETURN_VOID( var, op ) \
404     var = ferite_create_void_variable( script, RETVNAME( op ), FE_STATIC ); \
405     MARK_VARIABLE_AS_DISPOSABLE(var); \
406    FE_LEAVE_FUNCTION( var );
407 
408 #define TEST_ZERO( test ) \
409     if( test == 0 ){ \
410         ferite_error( script, 0, "Divide By Zero Error\n" ); \
411         FE_LEAVE_FUNCTION( NULL ); }
412 
413 /*}}}*/
414 
415 /*{{{ FERITE_UNARY_OP( not_op ) */
FERITE_UNARY_OP(not_op)416 FERITE_UNARY_OP( not_op )
417 {
418     FeriteVariable *ptr;
419 
420     FE_ENTER_FUNCTION;
421     LOCK_VARIABLE(a);
422     GET_A_VAR;
423 
424     if( !ferite_variable_is_false( script,a ) )
425       FE_VAR_FALSE( ptr, "not-op" );
426     else
427       FE_VAR_TRUE( ptr, "not-op" );
428     MARK_VARIABLE_AS_DISPOSABLE( ptr );
429     UNLOCK_VARIABLE(a);
430     FE_LEAVE_FUNCTION( ptr );
431 }
432 /*}}}*/
433 
434 /*{{{ FERITE_UNARY_OP( eval ) */
FERITE_UNARY_OP(eval)435 FERITE_UNARY_OP( eval )
436 {
437     FeriteVariable *new_script_return = NULL;
438 
439     FE_ENTER_FUNCTION;
440     GET_A_VAR;
441 
442     if( a->type != F_VAR_STR )
443     {
444         ferite_error( script, 0, "Can not eval variables of type %s\n", ferite_variable_id_to_str( script,a->type) );
445         new_script_return = ferite_create_number_long_variable( script, "eval-return", FE_FALSE, FE_STATIC );
446     }
447     else
448       new_script_return = ferite_script_eval( script, FE_STR2PTR(a) );
449 
450     if( new_script_return == NULL )
451       new_script_return = ferite_create_void_variable( script, "eval-gone-wrong", FE_STATIC );
452 
453     MARK_VARIABLE_AS_DISPOSABLE( new_script_return );
454     FE_LEAVE_FUNCTION( new_script_return );
455 }
456 /*}}}*/
457 
458 /*{{{ FERITE_UNARY_OP( include ) */
FERITE_UNARY_OP(include)459 FERITE_UNARY_OP( include )
460 {
461     FeriteVariable *ptr;
462 
463     FE_ENTER_FUNCTION;
464     GET_A_VAR;
465 
466     if( a->type != F_VAR_STR )
467       ferite_error( script, 0, "You must pass include a string\n" );
468 
469     ptr = ferite_script_include( script, FE_STR2PTR(a) );
470 
471     if( ptr == NULL )
472     {
473         ferite_error( script, 0, "Unable to include file '%s'\n", FE_STR2PTR(a) );
474         ptr = ferite_create_void_variable( script, "include-gone-wrong", FE_STATIC );
475     }
476 
477     MARK_VARIABLE_AS_DISPOSABLE( ptr );
478     FE_LEAVE_FUNCTION( ptr );
479 }
480 /*}}}*/
481 
482 /*{{{ FERITE_BINARY_OP( add ) */
FERITE_BINARY_OP(add)483 FERITE_BINARY_OP( add )
484 {
485     double dval = 0;
486     FeriteString *str = NULL;
487 
488     BEGIN_OP( a )
489       BEGIN_BLOCK( F_VAR_DOUBLE, b )
490         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "add" ), VAF(a) + VAI(b), FE_STATIC ) )
491         DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "add" ), VAF(a) + VAF(b), FE_STATIC ) )
492         BLOCK_DIE( "add" )
493       END_BLOCK
494       BEGIN_BLOCK( F_VAR_STR, b )
495   		default:
496     		retv = ferite_create_string_variable( script, "add", VAS(a), FE_STATIC );
497     		str = ferite_variable_to_str( script, b,0 );
498     		ferite_str_cat( VAS(retv), str );
499     		ferite_str_destroy( str );
500     		FUD(( "returning (str)\"%s\"\n", FE_STR2PTR(retv)));
501       END_BLOCK
502       BEGIN_BLOCK( F_VAR_LONG, b )
503         DO_OP( F_VAR_LONG,
504                dval = (double)VAI(a) + (double)VAI(b);
505                if( dval > (double)LONG_MAX )
506                retv = ferite_create_number_double_variable( script, RETVNAME( "add" ), dval, FE_STATIC );
507                else
508                retv = ferite_create_number_long_variable( script, RETVNAME( "add" ), VAI(a) + VAI(b), FE_STATIC ), NOWT )
509         DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "add" ), VAI(a)+VAF(b), FE_STATIC ); )
510         BLOCK_DIE( "add" );
511       END_BLOCK
512     END_OP( "add" )
513 }
514 /*}}}*/
515 
516 /*{{{ FERITE_BINARY_OP( minus ) */
FERITE_BINARY_OP(minus)517 FERITE_BINARY_OP( minus )
518 {
519     double dval = 0;
520     FeriteString *var = NULL, *tmp = NULL;
521 
522     BEGIN_OP( a )
523       BEGIN_BLOCK( F_VAR_DOUBLE, b )
524         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "minus" ), VAF(a) - VAI(b), FE_STATIC ) )
525         DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "minus" ), VAF(a) - VAF(b), FE_STATIC ) )
526         BLOCK_DIE( "minus" )
527       END_BLOCK
528       BEGIN_BLOCK( F_VAR_LONG, b )
529         DO_OP( F_VAR_LONG,
530                dval = (double)VAI(a) - (double)VAI(b);
531                if( dval < (double)LONG_MIN )
532                retv = ferite_create_number_double_variable( script, RETVNAME( "minus" ), (double)VAI(a) - (double)VAI(b), FE_STATIC );
533                else
534                retv = ferite_create_number_long_variable( script, RETVNAME( "minus" ), VAI(a)-VAI(b), FE_STATIC ) , NOWT )
535         DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "minus" ), VAI(a)-VAF(b), FE_STATIC ); )
536         BLOCK_DIE( "minus" );
537       END_BLOCK
538       BEGIN_BLOCK( F_VAR_STR, b )
539         DO_OP( F_VAR_STR,
540                NOWT,
541                tmp = ferite_str_new( "", 0, FE_CHARSET_DEFAULT );
542                var = ferite_str_replace( VAS(a), VAS(b), tmp );
543                retv = ferite_create_string_variable( script, RETVNAME( "minus" ), var, FE_STATIC );
544                ferite_str_destroy( tmp );
545                ferite_str_destroy( var ); )
546         BLOCK_DIE( "minus" )
547       END_BLOCK
548     END_OP( "minus" )
549 }
550 /*}}}*/
551 
552 /*{{{ FERITE_BINARY_OP( mult ) */
FERITE_BINARY_OP(mult)553 FERITE_BINARY_OP( mult )
554 {
555     double dval = 0;
556 
557     BEGIN_OP( a )
558       BEGIN_BLOCK( F_VAR_DOUBLE, b )
559         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "mult" ), VAF(a) * VAI(b), FE_STATIC ) )
560         DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "mult" ), VAF(a) * VAF(b), FE_STATIC ) )
561 		BLOCK_DIE( "mult" )
562       END_BLOCK
563       BEGIN_BLOCK( F_VAR_LONG, b )
564         DO_OP( F_VAR_LONG,
565                dval = (double)VAI(a) * (double)VAI(b);
566                if( dval > (double)LONG_MAX )
567                retv = ferite_create_number_double_variable( script, RETVNAME( "mult" ), dval, FE_STATIC );
568                else
569                retv = ferite_create_number_long_variable( script, RETVNAME( "mult" ), VAI(a) * VAI(b), FE_STATIC ); , NOWT)
570         DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_double_variable( script, RETVNAME( "mult" ), VAI(a)*VAF(b), FE_STATIC ); )
571         BLOCK_DIE( "mult" );
572       END_BLOCK
573     END_OP( "mult" )
574 }
575 /*}}}*/
576 
577 /*{{{ FERITE_BINARY_OP( divide ) */
FERITE_BINARY_OP(divide)578 FERITE_BINARY_OP( divide )
579 {
580     BEGIN_OP( a )
581       BEGIN_BLOCK( F_VAR_DOUBLE, b )
582         DO_OP( F_VAR_LONG, TEST_ZERO( VAI(b) ), retv = ferite_create_number_double_variable( script, RETVNAME( "divide" ), VAF(a) / VAI(b), FE_STATIC ) )
583           DO_OP( F_VAR_DOUBLE, TEST_ZERO( VAF(b) ), retv = ferite_create_number_double_variable( script, RETVNAME( "divide" ), VAF(a) / VAF(b), FE_STATIC ) )
584             BLOCK_DIE( "divide" )
585               END_BLOCK
586       BEGIN_BLOCK( F_VAR_LONG, b )
587         DO_OP( F_VAR_LONG, TEST_ZERO( VAI(b) ), retv = ferite_create_number_long_variable( script, RETVNAME( "divide" ), VAI(a)/VAI(b), FE_STATIC ); )
588           DO_OP( F_VAR_DOUBLE, TEST_ZERO( VAF(b) ), retv = ferite_create_number_double_variable( script, RETVNAME( "divide" ), VAI(a)/VAF(b), FE_STATIC ); )
589             BLOCK_DIE( "divide" );
590     END_BLOCK
591       END_OP( "divide" )
592 }
593 /*}}}*/
594 
595 /*{{{ FERITE_BINARY_OP( modulus ) */
FERITE_BINARY_OP(modulus)596 FERITE_BINARY_OP( modulus )
597 {
598     BEGIN_OP( a )
599       BEGIN_BLOCK( F_VAR_DOUBLE, b )
600         DO_OP( F_VAR_LONG, if( VAI(b) == 0 ) ferite_error( script, 0, "modulus By Zero Error\n" ); , retv = ferite_create_number_double_variable( script, RETVNAME( "modulus" ), (long)VAF(a) % VAI(b), FE_STATIC ) )
601           DO_OP( F_VAR_DOUBLE, if( VAF(b) == 0 ) ferite_error( script, 0, "modulus By Zero Error\n" ); , retv = ferite_create_number_double_variable( script, RETVNAME( "modulus" ), (long)VAF(a) % (long)VAF(b), FE_STATIC ) )
602             BLOCK_DIE( "modulus" )
603               END_BLOCK
604       BEGIN_BLOCK( F_VAR_LONG, b )
605         DO_OP( F_VAR_LONG, if( VAI(b) == 0 ) ferite_error( script, 0, "modulus By Zero Error\n" );, retv = ferite_create_number_long_variable( script, RETVNAME( "modulus" ), VAI(a)%VAI(b), FE_STATIC ); )
606           DO_OP( F_VAR_DOUBLE, if( VAF(b) == 0 ) ferite_error( script, 0, "modulus By Zero Error\n" );, retv = ferite_create_number_double_variable( script, RETVNAME( "modulus" ), VAI(a)%(long)VAF(b), FE_STATIC ); )
607             BLOCK_DIE( "modulus" );
608     END_BLOCK
609       END_OP( "modulus" )
610 }
611 /*}}}*/
612 
613 /*{{{ FERITE_BINARY_OP( assign ) */
FERITE_BINARY_OP(assign)614 FERITE_BINARY_OP( assign )
615 {
616     FeriteVariable *retv = NULL;
617 
618     FE_ENTER_FUNCTION;
619     LOCK_VARIABLE(a);
620     LOCK_VARIABLE(b);
621     GET_B_VAR;
622     if( !FE_VAR_IS_FINALSET( a ) )
623     {
624         switch( a->type )
625         {
626             BEGIN_BLOCK( F_VAR_LONG, b )
627               DO_OP( F_VAR_LONG, VAI(a) = VAI(b);, retv = ferite_create_number_long_variable( script, RETVNAME( "assign" ), VAI(a), FE_STATIC ); )
628               DO_OP( F_VAR_DOUBLE, a->type = F_VAR_DOUBLE; VAF(a) = VAF(b);, retv = ferite_create_number_double_variable( script, RETVNAME( "assign" ), VAF(a), FE_STATIC ); )
629               BLOCK_DIE( "assign" )
630             END_BLOCK
631 
632             BEGIN_BLOCK( F_VAR_STR, b )
633               DO_OP( F_VAR_STR, ferite_str_cpy(VAS(a), VAS(b));, retv = ferite_create_string_variable( script, RETVNAME( "assign" ), VAS(a), FE_STATIC ); )
634               BLOCK_DIE( "assign" )
635             END_BLOCK
636 
637             BEGIN_BLOCK( F_VAR_DOUBLE, b )
638               DO_OP( F_VAR_DOUBLE, VAF(a) = VAF(b);, retv = ferite_create_number_double_variable( script, RETVNAME( "assign" ), VAF(a), FE_STATIC ); )
639               DO_OP( F_VAR_LONG, a->type = F_VAR_LONG; VAI(a) = VAI(b);, retv = ferite_create_number_long_variable( script, RETVNAME( "assign" ), VAI(a), FE_STATIC ); )
640               BLOCK_DIE( "assign" )
641             END_BLOCK
642 
643             BEGIN_BLOCK( F_VAR_OBJ, b )
644               DO_OP( F_VAR_OBJ,
645                      if( VAO(a) != NULL )
646                      {
647                          VAO(a)->refcount -= a->refcount;
648                          if( VAO(a)->refcount <= 0 )
649                            FUD(("OPS: GC: Object \"%s\" Flagged for DELETION\n", a->name));
650                      }
651                      if( VAO(b) != NULL )
652 		     VAO(b)->refcount += a->refcount + 1;
653                      VAO(a) = VAO(b);,
654                      retv = ferite_create_object_variable( script, RETVNAME( "assign" ), FE_STATIC );
655                      VAO(retv) = VAO(b);
656                    )
657               BLOCK_DIE( "assign" );
658             END_BLOCK
659 
660             BEGIN_BLOCK( F_VAR_UARRAY, b )
661               DO_OP( F_VAR_UARRAY,
662                      ferite_uarray_destroy( script, VAUA(a));,
663                      VAUA(a) = ferite_uarray_dup( script, VAUA(b), (void *(*)(FeriteScript*,FeriteVariable *,void *))ferite_duplicate_variable );
664                      retv = ferite_duplicate_variable( script, a, NULL );
665                    )
666               BLOCK_DIE( "assign" );
667             END_BLOCK
668 
669             BEGIN_BLOCK( F_VAR_VOID, b )
670               DO_OP( F_VAR_LONG,
671                      a->type = F_VAR_LONG;
672                      VAI(a) = VAI(b);,
673 		     retv = ferite_create_number_long_variable( script, RETVNAME( "assign" ), VAI(a), FE_STATIC );
674                    )
675               DO_OP( F_VAR_DOUBLE,
676                      a->type = F_VAR_DOUBLE;
677                      VAF(a) = VAF(b);,
678                      retv = ferite_create_number_double_variable( script, RETVNAME( "assign" ), VAF(a), FE_STATIC );
679 		    )
680               DO_OP( F_VAR_STR,
681                      a->type = F_VAR_STR;
682                      VAS(a) = ferite_str_dup(VAS(b));,
683                      retv = ferite_create_string_variable( script, RETVNAME( "assign" ), VAS(a), FE_STATIC );
684                    )
685 	      DO_OP( F_VAR_OBJ,
686                      a->type = F_VAR_OBJ;
687                      if( VAO(b) != NULL )
688                        VAO(b)->refcount++;
689                      VAO(a) = VAO(b);,
690                      retv = ferite_create_number_long_variable( script, RETVNAME( "assign" ), 1, FE_STATIC );
691                    )
692               DO_OP( F_VAR_UARRAY,
693                      a->type = F_VAR_UARRAY;
694                      VAUA(a) = ferite_uarray_dup( script, VAUA(b), (void *(*)(FeriteScript*,FeriteVariable *,void*))ferite_duplicate_variable );,
695                      retv = ferite_duplicate_variable( script, a, NULL );
696                    )
697               DO_OP( F_VAR_VOID, NOWT,
698                      retv = ferite_create_void_variable( script, RETVNAME( "assign" ), FE_STATIC );
699                    )
700 	      DO_OP( F_VAR_NS, NOWT,
701 		     a->type = F_VAR_NS;
702 		     VAP(a) = VAN(b);
703 		     retv = ferite_create_void_variable( script, RETVNAME( "assign" ), FE_STATIC );
704 		     retv->type = F_VAR_NS;
705 		     VAP(retv) = VAN(b);
706 		   )
707 	      DO_OP( F_VAR_CLASS, NOWT,
708 		     a->type = F_VAR_CLASS;
709 		     VAP(a) = VAC(b);
710 		     retv = ferite_create_void_variable( script, RETVNAME( "assign" ), FE_STATIC );
711 		     retv->type = F_VAR_CLASS;
712 		     VAP(retv) = VAC(b);
713 		   )
714               BLOCK_DIE( "assign" );
715  	    END_BLOCK
716           BLOCK_DIE( "assign" );
717         }
718         if( FE_VAR_IS_FINAL( a ) )
719           MARK_VARIABLE_AS_FINALSET( a ); /* set it so that the variable is constant for forever and a day */
720 
721         /* call the set method */
722         if( a->accessors != NULL && a->accessors->set != NULL )
723         {
724             FUD(( "calling var->set()\n" ));
725             (a->accessors->set)( script, a, b );
726         }
727     }
728     else
729     {
730         ferite_error( script, 0, "Can not assign to a constant variable.\n" );
731         retv = ferite_create_void_variable( script, RETVNAME( "assign" ), FE_STATIC );
732     }
733     if( retv != NULL )
734       MARK_VARIABLE_AS_DISPOSABLE( retv );
735     UNLOCK_VARIABLE(a);
736     UNLOCK_VARIABLE(b);
737     FE_LEAVE_FUNCTION( retv );
738 }
739 /*}}}*/
740 
741 /*{{{ FERITE_BINARY_OP( add_assign ) */
FERITE_BINARY_OP(add_assign)742 FERITE_BINARY_OP( add_assign )
743 {
744     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
745 
746     FE_ENTER_FUNCTION;
747     LOCK_VARIABLE(a);
748     LOCK_VARIABLE(b);
749 
750     tmp_ptr = ferite_op_add( script, a, b );
751     if( tmp_ptr != NULL )
752     {
753         ptr = ferite_op_assign( script, a, tmp_ptr );
754         MARK_VARIABLE_AS_DISPOSABLE( ptr );
755         ferite_variable_destroy( script, tmp_ptr );
756     }
757 
758     UNLOCK_VARIABLE(a);
759     UNLOCK_VARIABLE(b);
760     FE_LEAVE_FUNCTION( ptr );
761 }
762 /*}}}*/
763 
764 /*{{{ FERITE_BINARY_OP( minus_assign ) */
FERITE_BINARY_OP(minus_assign)765 FERITE_BINARY_OP( minus_assign )
766 {
767     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
768 
769     FE_ENTER_FUNCTION;
770     LOCK_VARIABLE(a);
771     LOCK_VARIABLE(b);
772 
773     tmp_ptr = ferite_op_minus( script, a, b );
774     if( tmp_ptr != NULL )
775     {
776         ptr = ferite_op_assign( script, a, tmp_ptr );
777         MARK_VARIABLE_AS_DISPOSABLE( ptr );
778         ferite_variable_destroy( script, tmp_ptr );
779     }
780 
781     UNLOCK_VARIABLE(a);
782     UNLOCK_VARIABLE(b);
783     FE_LEAVE_FUNCTION( ptr );
784 }
785 /*}}}*/
786 
787 /*{{{ FERITE_BINARY_OP( mult_assign ) */
FERITE_BINARY_OP(mult_assign)788 FERITE_BINARY_OP( mult_assign )
789 {
790     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
791 
792     FE_ENTER_FUNCTION;
793     LOCK_VARIABLE(a);
794     LOCK_VARIABLE(b);
795 
796     tmp_ptr = ferite_op_mult( script, a, b );
797     if( tmp_ptr !=  NULL )
798     {
799         ptr = ferite_op_assign( script, a, tmp_ptr );
800         MARK_VARIABLE_AS_DISPOSABLE( ptr );
801         ferite_variable_destroy( script, tmp_ptr );
802     }
803 
804     UNLOCK_VARIABLE(a);
805     UNLOCK_VARIABLE(b);
806     FE_LEAVE_FUNCTION( ptr );
807 }
808 /*}}}*/
809 
810 /*{{{ FERITE_BINARY_OP( divide_assign ) */
FERITE_BINARY_OP(divide_assign)811 FERITE_BINARY_OP( divide_assign )
812 {
813     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
814 
815     FE_ENTER_FUNCTION;
816     LOCK_VARIABLE(a);
817     LOCK_VARIABLE(b);
818 
819     tmp_ptr = ferite_op_divide( script, a, b );
820     if( tmp_ptr != NULL )
821     {
822         ptr = ferite_op_assign( script, a, tmp_ptr );
823         MARK_VARIABLE_AS_DISPOSABLE( ptr );
824         ferite_variable_destroy( script, tmp_ptr );
825     }
826 
827     UNLOCK_VARIABLE(a);
828     UNLOCK_VARIABLE(b);
829     FE_LEAVE_FUNCTION( ptr );
830 }
831 /*}}}*/
832 
833 /*{{{ FERITE_BINARY_OP( logical_or ) */
FERITE_BINARY_OP(logical_or)834 FERITE_BINARY_OP( logical_or )
835 {
836     FeriteVariable *ptr;
837 
838     FE_ENTER_FUNCTION;
839     LOCK_VARIABLE(a);
840     LOCK_VARIABLE(b);
841     GET_INPUT_VARS;
842 
843     FE_VAR_TEST( (!ferite_variable_is_false( script,a) || !ferite_variable_is_false( script,b )), "logical_or" );
844     MARK_VARIABLE_AS_DISPOSABLE( ptr );
845 
846     UNLOCK_VARIABLE(a);
847     UNLOCK_VARIABLE(b);
848     FE_LEAVE_FUNCTION( ptr );
849 }
850 /*}}}*/
851 
852 /*{{{ FERITE_BINARY_OP( logical_and ) */
FERITE_BINARY_OP(logical_and)853 FERITE_BINARY_OP( logical_and )
854 {
855     FeriteVariable *ptr;
856 
857     FE_ENTER_FUNCTION;
858     LOCK_VARIABLE(a);
859     LOCK_VARIABLE(b);
860     GET_INPUT_VARS;
861 
862     FE_VAR_TEST( (!ferite_variable_is_false( script,a) && !ferite_variable_is_false( script,b )), "logical_and" );
863     MARK_VARIABLE_AS_DISPOSABLE( ptr );
864 
865     UNLOCK_VARIABLE(a);
866     UNLOCK_VARIABLE(b);
867     FE_LEAVE_FUNCTION( ptr );
868 }
869 /*}}}*/
870 
871 /*{{{ FERITE_BINARY_OP( equals ) */
872 /* binary operators that push a true or falsae value onto the stack */
FERITE_BINARY_OP(equals)873 FERITE_BINARY_OP( equals )
874 {
875     FeriteVariable *ptr = NULL;
876 
877     FE_ENTER_FUNCTION;
878     LOCK_VARIABLE(a);
879     LOCK_VARIABLE(b);
880     GET_INPUT_VARS;
881     if( a->type != b->type &&
882         !(a->type == F_VAR_LONG && b->type == F_VAR_DOUBLE) &&
883         !(a->type == F_VAR_DOUBLE && b->type == F_VAR_LONG) )
884     {
885         FUD(("OPS: Variable types do not match in equals( %s, %s )\nReturning false\n", a->name, b->name ));
886         ptr = ferite_create_number_long_variable( script, "equals", 0, FE_STATIC );
887         MARK_VARIABLE_AS_DISPOSABLE( ptr );
888         UNLOCK_VARIABLE(a);
889         UNLOCK_VARIABLE(b);
890         FE_LEAVE_FUNCTION( ptr );
891     }
892     /* we know that they are the same */
893     switch( a->type )
894     {
895       case F_VAR_LONG:
896       case F_VAR_DOUBLE:
897       {
898           double left = (a->type == F_VAR_LONG ? (double)VAI(a) : VAF(a));
899           double right = (b->type == F_VAR_LONG ? (double)VAI(b) : VAF(b));
900           double delta = left - right;
901           if( a->type == F_VAR_DOUBLE || b->type == F_VAR_DOUBLE )
902           {
903               FE_VAR_TEST( (delta < 0.000001 && delta > -0.000001), "equals" );
904           }
905           else
906           {
907               FE_VAR_TEST( (VAI(a) == VAI(b)), "equals" );
908           }
909           break;
910       }
911       case F_VAR_STR:
912           FE_VAR_TEST( (ferite_str_cmp( VAS(a), VAS(b) ) == 1), "equals" );
913         break;
914       case F_VAR_OBJ:
915           FE_VAR_TEST( (VAO(a) == VAO(b)), "equals" );
916           break;
917       case F_VAR_UARRAY:
918           FE_VAR_TEST( (ferite_uarray_cmp( script, VAUA(a), VAUA(b) ) == 1), "equals" );
919           break;
920       case F_VAR_VOID:
921           FE_VAR_TEST( FE_TRUE, "equals" );
922           break;
923       case F_VAR_CLASS:
924           FE_VAR_TEST( (VAC(a) == VAC(b)), "equals" );
925           break;
926       case F_VAR_NS:
927           FE_VAR_TEST( (VAN(a) == VAN(b)), "equals" );
928           break;
929       default:
930         ferite_error( script, 0, "EEEK: unknown type %s in equals()\n", ferite_variable_id_to_str( script,a->type ) );
931     }
932     if( ptr )
933       MARK_VARIABLE_AS_DISPOSABLE( ptr );
934     UNLOCK_VARIABLE(a);
935     UNLOCK_VARIABLE(b);
936     FE_LEAVE_FUNCTION( ptr );
937 }
938 /*}}}*/
939 
940 /*{{{ FERITE_BINARY_OP( case ) */
941 /* binary operators that push a true or falsae value onto the stack */
FERITE_BINARY_OP(case)942 FERITE_BINARY_OP( case )
943 {
944     FeriteVariable *ptr = NULL;
945 
946     FE_ENTER_FUNCTION;
947     LOCK_VARIABLE(a);
948     LOCK_VARIABLE(b);
949     GET_INPUT_VARS;
950 
951     if( a->type != b->type &&
952         !(a->type == F_VAR_LONG && b->type == F_VAR_DOUBLE) &&
953         !(a->type == F_VAR_DOUBLE && b->type == F_VAR_LONG) )
954     {
955         FUD(("OPS: Variable types do not match in equals( %s, %s )\nReturning false\n", a->name, b->name ));
956         ptr = ferite_create_number_long_variable( script, "equals", 0, FE_STATIC );
957         MARK_VARIABLE_AS_DISPOSABLE( ptr );
958         UNLOCK_VARIABLE(a);
959         UNLOCK_VARIABLE(b);
960         FE_LEAVE_FUNCTION( ptr );
961     }
962     /* we know that they are the same */
963     switch( a->type )
964     {
965         case F_VAR_LONG:
966         case F_VAR_DOUBLE:
967         {
968             double left = (a->type == F_VAR_LONG ? (double)VAI(a) : VAF(a));
969             double right = (b->type == F_VAR_LONG ? (double)VAI(b) : VAF(b));
970             double delta = left - right;
971             if( a->type == F_VAR_DOUBLE || b->type == F_VAR_DOUBLE )
972             {
973                 FE_VAR_TEST( (delta < 0.000001 && delta > -0.000001), "equals" );
974             }
975             else
976             {
977                 FE_VAR_TEST( (VAI(a) == VAI(b)), "equals" );
978             }
979             break;
980         }
981         case F_VAR_STR:
982             FE_VAR_TEST( (ferite_str_cmp( VAS(a), VAS(b) ) == 1), "equals" );
983             break;
984         case F_VAR_OBJ:
985             FE_VAR_TEST( (VAO(a) == VAO(b)), "equals" );
986             break;
987         default:
988             ferite_error( script, 0, "EEEK: unknown type %s in equals()\n", ferite_variable_id_to_str( script,a->type ) );
989     }
990     if( ptr )
991       MARK_VARIABLE_AS_DISPOSABLE( ptr );
992     UNLOCK_VARIABLE(a);
993     UNLOCK_VARIABLE(b);
994     FE_LEAVE_FUNCTION( ptr );
995 }
996 /*}}}*/
997 
998 /*{{{ FERITE_BINARY_OP( notequals ) */
FERITE_BINARY_OP(notequals)999 FERITE_BINARY_OP( notequals )
1000 {
1001     FeriteVariable *ptr, *tptr;
1002 
1003     FE_ENTER_FUNCTION;
1004     LOCK_VARIABLE(a);
1005     LOCK_VARIABLE(b);
1006     GET_INPUT_VARS;
1007     tptr = ferite_op_equals( script, a, b );
1008     FE_VAR_TEST( (ferite_variable_is_false( script,tptr )), "not_equals" );
1009     MARK_VARIABLE_AS_DISPOSABLE( ptr );
1010     ferite_variable_destroy( script, tptr );
1011     UNLOCK_VARIABLE(a);
1012     UNLOCK_VARIABLE(b);
1013     FE_LEAVE_FUNCTION( ptr );
1014 }
1015 /*}}}*/
1016 
1017 /*{{{ FERITE_BINARY_OP( less_than ) */
FERITE_BINARY_OP(less_than)1018 FERITE_BINARY_OP( less_than )
1019 {
1020     FeriteVariable *ptr = NULL;
1021 
1022     FE_ENTER_FUNCTION;
1023     LOCK_VARIABLE(a);
1024     LOCK_VARIABLE(b);
1025     GET_INPUT_VARS;
1026 
1027     switch( a->type )
1028     {
1029       case F_VAR_LONG:
1030       case F_VAR_DOUBLE:
1031       {
1032           switch( b->type )
1033           {
1034               case F_VAR_LONG:
1035               case F_VAR_DOUBLE:
1036               {
1037                   double left = (a->type == F_VAR_LONG ? (double)VAI(a) : VAF(a));
1038                   double right = (b->type == F_VAR_LONG ? (double)VAI(b) : VAF(b));
1039                   double delta = left - right;
1040                   if( a->type == F_VAR_DOUBLE || b->type == F_VAR_DOUBLE )
1041                   {
1042                       FE_VAR_TEST( (delta < 0.0), "less-than" );
1043                   }
1044                   else
1045                   {
1046                       FE_VAR_TEST( (VAI(a) < VAI(b)), "less-than" );
1047                   }
1048                   break;
1049               }
1050               default:
1051                   ferite_error( script, 0, "ERROR: can't compare values of type %s with integers\n", ferite_variable_id_to_str( script,b->type) );
1052           }
1053           break;
1054       }
1055       default:
1056           ferite_error( script, 0, "ERK, can't compare items of type %s and %s\n", ferite_variable_id_to_str( script,a->type), ferite_variable_id_to_str( script, b->type ));
1057     }
1058     if( ptr )
1059         MARK_VARIABLE_AS_DISPOSABLE( ptr );
1060     UNLOCK_VARIABLE(a);
1061     UNLOCK_VARIABLE(b);
1062     FE_LEAVE_FUNCTION( ptr );
1063 }
1064 /*}}}*/
1065 
1066 /*{{{ FERITE_BINARY_OP( less_than_equals ) */
FERITE_BINARY_OP(less_than_equals)1067 FERITE_BINARY_OP( less_than_equals )
1068 {
1069     FeriteVariable *ptr = NULL;
1070 
1071     FE_ENTER_FUNCTION;
1072     LOCK_VARIABLE(a);
1073     LOCK_VARIABLE(b);
1074     GET_INPUT_VARS;
1075 
1076     switch( a->type )
1077     {
1078         case F_VAR_LONG:
1079         case F_VAR_DOUBLE:
1080         {
1081             switch( b->type )
1082             {
1083                 case F_VAR_LONG:
1084                 case F_VAR_DOUBLE:
1085                 {
1086                     double left = (a->type == F_VAR_LONG ? (double)VAI(a) : VAF(a));
1087                     double right = (b->type == F_VAR_LONG ? (double)VAI(b) : VAF(b));
1088                     double delta = left - right;
1089                     if( a->type == F_VAR_DOUBLE || b->type == F_VAR_DOUBLE )
1090                     {
1091                         FE_VAR_TEST( (delta <= 0.0), "less-than-equals" );
1092                     }
1093                     else
1094                     {
1095                         FE_VAR_TEST( (VAI(a) <= VAI(b)), "less-than-equals" );
1096                     }
1097                     break;
1098                 }
1099                 default:
1100                     ferite_error( script, 0, "ERROR: can't compare values of type %s with integers\n", ferite_variable_id_to_str( script,b->type) );
1101             }
1102             break;
1103         }
1104         default:
1105             ferite_error( script, 0, "ERK, can't compare items of type %s and %s\n", ferite_variable_id_to_str( script,a->type), ferite_variable_id_to_str( script, b->type ));
1106     }
1107     if( ptr )
1108       MARK_VARIABLE_AS_DISPOSABLE( ptr );
1109 
1110     UNLOCK_VARIABLE(a);
1111     UNLOCK_VARIABLE(b);
1112     FE_LEAVE_FUNCTION( ptr );
1113 }
1114 /*}}}*/
1115 
1116 /*{{{ FERITE_BINARY_OP( greater_than ) */
FERITE_BINARY_OP(greater_than)1117 FERITE_BINARY_OP( greater_than )
1118 {
1119     FeriteVariable *ptr = NULL;
1120 
1121     FE_ENTER_FUNCTION;
1122     LOCK_VARIABLE(a);
1123     LOCK_VARIABLE(b);
1124     GET_INPUT_VARS;
1125 
1126     switch( a->type )
1127     {
1128         case F_VAR_LONG:
1129         case F_VAR_DOUBLE:
1130         {
1131             switch( b->type )
1132             {
1133                 case F_VAR_LONG:
1134                 case F_VAR_DOUBLE:
1135                 {
1136                     double left = (a->type == F_VAR_LONG ? (double)VAI(a) : VAF(a));
1137                     double right = (b->type == F_VAR_LONG ? (double)VAI(b) : VAF(b));
1138                     double delta = left - right;
1139                     if( a->type == F_VAR_DOUBLE || b->type == F_VAR_DOUBLE )
1140                     {
1141                         FE_VAR_TEST( (delta > 0.0), "greater-than" );
1142                     }
1143                     else
1144                     {
1145                         FE_VAR_TEST( (VAI(a) > VAI(b)), "greater-than" );
1146                     }
1147                     break;
1148                 }
1149                 default:
1150                     ferite_error( script, 0, "ERROR: can't compare values of type %s with integers\n", ferite_variable_id_to_str( script,b->type) );
1151             }
1152             break;
1153         }
1154         default:
1155             ferite_error( script, 0, "ERK, can't compare items of type %s and %s\n", ferite_variable_id_to_str( script,a->type), ferite_variable_id_to_str( script, b->type ));
1156     }
1157     if( ptr )
1158         MARK_VARIABLE_AS_DISPOSABLE( ptr );
1159 
1160     UNLOCK_VARIABLE(a);
1161     UNLOCK_VARIABLE(b);
1162     FE_LEAVE_FUNCTION( ptr );
1163 }
1164 /*}}}*/
1165 
1166 /*{{{ FERITE_BINARY_OP( greater_than_equals ) */
FERITE_BINARY_OP(greater_than_equals)1167 FERITE_BINARY_OP( greater_than_equals )
1168 {
1169     FeriteVariable *ptr = NULL;
1170 
1171     FE_ENTER_FUNCTION;
1172     LOCK_VARIABLE(a);
1173     LOCK_VARIABLE(b);
1174     GET_INPUT_VARS;
1175 
1176     switch( a->type )
1177     {
1178         case F_VAR_LONG:
1179         case F_VAR_DOUBLE:
1180         {
1181             switch( b->type )
1182             {
1183                 case F_VAR_LONG:
1184                 case F_VAR_DOUBLE:
1185                 {
1186                     double left = (a->type == F_VAR_LONG ? (double)VAI(a) : VAF(a));
1187                     double right = (b->type == F_VAR_LONG ? (double)VAI(b) : VAF(b));
1188                     double delta = left - right;
1189                     if( a->type == F_VAR_DOUBLE || b->type == F_VAR_DOUBLE )
1190                     {
1191                         FE_VAR_TEST( (delta >= 0.0), "greater-than-equals" );
1192                     }
1193                     else
1194                     {
1195                         FE_VAR_TEST( (VAI(a) >= VAI(b)), "greater-than-equals" );
1196                     }
1197                     break;
1198                 }
1199                 default:
1200                     ferite_error( script, 0, "ERROR: can't compare values of type %s with integers\n", ferite_variable_id_to_str( script,b->type) );
1201             }
1202             break;
1203         }
1204         default:
1205             ferite_error( script, 0, "ERK, can't compare items of type %s and %s\n", ferite_variable_id_to_str( script,a->type), ferite_variable_id_to_str( script, b->type ));
1206     }
1207     if( ptr )
1208       MARK_VARIABLE_AS_DISPOSABLE( ptr );
1209 
1210     UNLOCK_VARIABLE(a);
1211     UNLOCK_VARIABLE(b);
1212     FE_LEAVE_FUNCTION( ptr );
1213 }
1214 /*}}}*/
1215 
1216 /*{{{ FERITE_MANY_OP( array_slice ) */
FERITE_MANY_OP(array_slice)1217 FERITE_MANY_OP(array_slice)
1218 {
1219     FeriteVariable *result = NULL;
1220     FeriteVariable *array = NULL, *a = NULL, *b = NULL, *tmp = NULL;
1221     long size,lower,upper,ii,cal_lo,cal_up;
1222     char *buf = NULL;
1223     FeriteString *str = NULL;
1224 
1225     FE_ENTER_FUNCTION;
1226 
1227     /* FIXME: thread locking! */
1228 
1229     array = vars[2];
1230     a = vars[1]; /* the lower bound */
1231     b = vars[0]; /* the upper bound */
1232 
1233     GET_VAR( array );
1234     GET_INPUT_VARS;
1235 
1236     if(array->type != F_VAR_STR && array->type != F_VAR_UARRAY)
1237     {
1238         ferite_error(script, 0, "Slices only work on Arrays and Strings\n");
1239         FE_OP_RETURN_VOID( result, "array_slice" );
1240     }
1241 
1242     if(array->type == F_VAR_STR)
1243       size = FE_STRLEN(array);
1244     else
1245       size = VAUA(array)->size;
1246 
1247     if(a->type == F_VAR_LONG)
1248       lower = VAI(a);
1249     else if(a->type == F_VAR_DOUBLE)
1250       lower = (int)floor(VAF(a));
1251     else
1252     {
1253         ferite_error(script, 0, "Invalid lower slice bound type: %s\n", ferite_variable_id_to_str(script, a->type));
1254         FE_OP_RETURN_VOID( result, "array_slice" );
1255     }
1256 
1257     if(b->type == F_VAR_VOID && FE_VAR_IS_PLACEHOLDER( b ) )
1258       upper = size - 1;
1259     else if(b->type == F_VAR_LONG)
1260       upper = VAI(b);
1261     else if(b->type == F_VAR_DOUBLE)
1262       upper = (int)floor(VAF(b));
1263     else
1264     {
1265         ferite_error(script, 0, "Invalid upper slice bound type: %s\n", ferite_variable_id_to_str(script, b->type));
1266         FE_OP_RETURN_VOID( result, "array_slice" );
1267     }
1268 
1269     cal_lo = lower;
1270     if(lower < 0)
1271       cal_lo = size + lower;
1272 
1273     cal_up = upper;
1274     if( upper < 0 )
1275       cal_up = size + upper;
1276 
1277     if(cal_lo < 0 || cal_up < 0 || cal_lo > size - 1 || cal_up > size - 1)
1278     {
1279         ferite_error(script, 0, "Invalid slice bounds: %d (%d) to %d (%d)\n",lower,cal_lo,upper,cal_up);
1280         FE_OP_RETURN_VOID( result, "array_slice" );
1281     }
1282     if(array->type == F_VAR_STR)
1283     {
1284         str = ferite_str_new( NULL, FE_STRLEN(array), FE_CHARSET_DEFAULT );
1285         buf = str->data;
1286         ii = 0;
1287         if(cal_lo > cal_up)
1288         {
1289             for(size=cal_lo;size >= cal_up; size--)
1290             {
1291                 buf[ii] = FE_STR2PTR(array)[size];
1292                 ii++;
1293             }
1294         }
1295         else
1296         {
1297             for(size=cal_lo;size <= cal_up; size++)
1298             {
1299                 buf[ii] = FE_STR2PTR(array)[size];
1300                 ii++;
1301             }
1302         }
1303 
1304         buf[ii] = '\0';
1305         str->length = ii;
1306 
1307         result = ferite_create_string_variable( script, "spliced_content", str, FE_STATIC );
1308         ferite_str_destroy( str );
1309     }
1310     else
1311     {
1312         result = ferite_create_uarray_variable( script, "spliced_content", VAUA(array)->size, FE_STATIC );
1313         if(cal_lo > cal_up)
1314         {
1315             for(size=cal_lo;size >= cal_up; size--)
1316             {
1317                 tmp = ferite_uarray_get_index(script, VAUA(array),(int)size);
1318                 tmp = ferite_duplicate_variable(script, tmp, NULL);
1319                 ferite_uarray_add(script, VAUA(result), tmp, NULL, FE_ARRAY_ADD_AT_END);
1320             }
1321         }
1322         else
1323         {
1324             for(size=cal_lo;size <= cal_up; size++)
1325             {
1326                 tmp = ferite_uarray_get_index(script, VAUA(array),(int)size);
1327                 tmp = ferite_duplicate_variable(script, tmp, NULL);
1328                 ferite_uarray_add(script, VAUA(result), tmp, NULL, FE_ARRAY_ADD_AT_END);
1329             }
1330         }
1331     }
1332     MARK_VARIABLE_AS_DISPOSABLE( result );
1333     FE_LEAVE_FUNCTION( result );
1334 }
1335 /*}}}*/
1336 
1337 /*{{{ FERITE_BINARY_OP( array_index ) */
FERITE_BINARY_OP(array_index)1338 FERITE_BINARY_OP( array_index )
1339 {
1340    /* a = array variable */
1341    /* b = index */
1342     FeriteVariable *ptr = NULL;
1343     char *s;
1344 
1345     FE_ENTER_FUNCTION;
1346     LOCK_VARIABLE(a);
1347     LOCK_VARIABLE(b);
1348     GET_INPUT_VARS;
1349 
1350     if( a->type != F_VAR_STR && a->type != F_VAR_UARRAY)
1351     {
1352         ferite_error( script, 0, "OPS: array_index: First Variable is not an Array or String\n" );
1353         UNLOCK_VARIABLE(a);
1354         UNLOCK_VARIABLE(b);
1355         FE_LEAVE_FUNCTION(ptr);
1356     }
1357 
1358     switch( a->type )
1359     {
1360       case F_VAR_STR:
1361         {
1362             switch( b->type )
1363             {
1364               case F_VAR_LONG:
1365                 {
1366                     size_t offset;
1367                     if( VAI(b) > (signed)FE_STRLEN( a ) )
1368                     {
1369                         ferite_error( script, 0, "String index out of range [%d]\n", VAI(b) );
1370                         break;
1371                     }
1372                     s = fmalloc(sizeof(char) * 2);
1373                     if(VAI(b) < 0)
1374                     {
1375                         offset = FE_STRLEN( a ) + VAI( b );
1376                         // printf("grabbing index %d (%d)\n",offset,strlen(VAS(a)) -1 );
1377                     }
1378                     else
1379                     {
1380                         offset = VAI(b);
1381                     }
1382                     s[0] = FE_STR2PTR(a)[offset];
1383                     s[1] = '\0';
1384                     ptr = ferite_create_string_variable_from_ptr( script, "array_String_return", s, 1, FE_CHARSET_DEFAULT, FE_STATIC );
1385                     MARK_VARIABLE_AS_DISPOSABLE( ptr );
1386                     ffree(s);
1387                 }
1388 
1389                 break;
1390               case F_VAR_DOUBLE:
1391                 {
1392                     size_t index = (size_t)VAF(b);
1393                     if( VAI(b) > (signed)FE_STRLEN( a ) )
1394                     {
1395                         ferite_error( script, 0, "String index out of range [%d]\n", index );
1396                         break;
1397                     }
1398                     s = fmalloc(sizeof(char) * 2);
1399                     if(index < 0)
1400                     {
1401                         index = FE_STRLEN( a ) + index;
1402                     }
1403                     s[0] = FE_STR2PTR( a )[index];
1404                     s[1] = '\0';
1405                     ptr = ferite_create_string_variable_from_ptr( script, "array_String_return", s, 1, FE_CHARSET_DEFAULT, FE_STATIC );
1406                     MARK_VARIABLE_AS_DISPOSABLE( ptr );
1407                     ffree(s);
1408                 }
1409                 break;
1410               default:
1411                 ferite_error( script, 0, "Other index methods not implemented in strings (%s)\n", ferite_variable_id_to_str( script, b->type ) );
1412             }
1413             break;
1414         }
1415       case F_VAR_UARRAY:
1416         {
1417             if( b->type == F_VAR_STR && VAS(b)->length == 0 )
1418                 ptr = ferite_create_void_variable( script, "array_void_variable", FE_STATIC );
1419             else
1420                 ptr = ferite_uarray_op( script, VAUA(a), b, NULL );
1421             break;
1422         }
1423     }
1424     UNLOCK_VARIABLE(a);
1425     UNLOCK_VARIABLE(b);
1426     FE_LEAVE_FUNCTION( ptr );
1427 }
1428 /*}}}*/
1429 
1430 /*{{{ FERITE_UNARY_OP( array_clear ) */
FERITE_UNARY_OP(array_clear)1431 FERITE_UNARY_OP( array_clear )
1432 {
1433     FeriteVariable *ptr = NULL;
1434     long iteration = 0, iteration_type = 0;
1435 
1436     FE_ENTER_FUNCTION;
1437     LOCK_VARIABLE(a);
1438     GET_A_VAR;
1439 
1440     if( a->type == F_VAR_UARRAY && VAUA(a)->size > 0 )
1441     {
1442 	iteration = VAUA(a)->iteration;
1443 	iteration_type = VAUA(a)->iterator_type;
1444 
1445         ferite_uarray_destroy( script, VAUA(a) );
1446         VAUA(a) = ferite_uarray_create();
1447 
1448 	VAUA(a)->iteration = iteration;
1449 	VAUA(a)->iterator_type = iteration_type;
1450     }
1451     UNLOCK_VARIABLE(a);
1452     FE_OP_RETURN_VOID( ptr, "array_clear" );
1453 }
1454 /*}}}*/
1455 
1456 /*{{{ FERITE_BINARY_OP( left_shift ) */
FERITE_BINARY_OP(left_shift)1457 FERITE_BINARY_OP( left_shift )
1458 {
1459     BEGIN_OP( a )
1460       BEGIN_BLOCK( F_VAR_LONG, b )
1461         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "left_shift" ), VAI(a) << VAI(b), FE_STATIC ); )
1462           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "left_shift" ), VAI(a) << (long)VAF(b), FE_STATIC ); )
1463             BLOCK_DIE( "left_shift" );
1464     END_BLOCK
1465       BEGIN_BLOCK( F_VAR_DOUBLE, b )
1466         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "left_shift" ), (long)VAF(a) << VAI(b), FE_STATIC ); )
1467           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "left_shift" ), (long)VAF(a) << (long)VAF(b), FE_STATIC ); )
1468             BLOCK_DIE( "left_shift" );
1469     END_BLOCK
1470       END_OP( "left_shift" )
1471 }
1472 /*}}}*/
1473 
1474 /*{{{ FERITE_BINARY_OP( right_shift ) */
FERITE_BINARY_OP(right_shift)1475 FERITE_BINARY_OP( right_shift )
1476 {
1477     BEGIN_OP( a )
1478       BEGIN_BLOCK( F_VAR_LONG, b )
1479         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "right_shift" ), VAI(a) >> VAI(b), FE_STATIC ); )
1480           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "right_shift" ), VAI(a) >> (long)VAF(b), FE_STATIC ); )
1481             BLOCK_DIE( "right_shift" );
1482     END_BLOCK
1483       BEGIN_BLOCK( F_VAR_DOUBLE, b )
1484         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "right_shift" ), (long)VAF(a) >> VAI(b), FE_STATIC ); )
1485           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "right_shift" ), (long)VAF(a) >> (long)VAF(b), FE_STATIC ); )
1486             BLOCK_DIE( "right_shift" );
1487     END_BLOCK
1488       END_OP( "right_shift" )
1489 }
1490 /*}}}*/
1491 
1492 /*{{{ FERITE_BINARY_OP( binary_or ) */
FERITE_BINARY_OP(binary_or)1493 FERITE_BINARY_OP( binary_or )
1494 {
1495     BEGIN_OP( a )
1496       BEGIN_BLOCK( F_VAR_LONG, b )
1497         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_or" ), VAI(a) | VAI(b), FE_STATIC ); )
1498           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_or" ), VAI(a) | (long)VAF(b), FE_STATIC ); )
1499             BLOCK_DIE( "binary_or" );
1500     END_BLOCK
1501       BEGIN_BLOCK( F_VAR_DOUBLE, b )
1502         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_or" ), (long)VAF(a) | VAI(b), FE_STATIC ); )
1503           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_or" ), (long)VAF(a) | (long)VAF(b), FE_STATIC ); )
1504             BLOCK_DIE( "binary_or" );
1505     END_BLOCK
1506       END_OP( "binary_or" )
1507 }
1508 /*}}}*/
1509 
1510 /*{{{ FERITE_BINARY_OP( binary_and ) */
FERITE_BINARY_OP(binary_and)1511 FERITE_BINARY_OP( binary_and )
1512 {
1513     BEGIN_OP( a )
1514       BEGIN_BLOCK( F_VAR_LONG, b )
1515         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_and" ), VAI(a) & VAI(b), FE_STATIC ); )
1516           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_and" ), VAI(a) & (long)VAF(b), FE_STATIC ); )
1517             BLOCK_DIE( "binary_and" );
1518     END_BLOCK
1519       BEGIN_BLOCK( F_VAR_DOUBLE, b )
1520         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_and" ), (long)VAF(a) & VAI(b), FE_STATIC ); )
1521           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_and" ), (long)VAF(a) & (long)VAF(b), FE_STATIC ); )
1522             BLOCK_DIE( "binary_and" );
1523     END_BLOCK
1524       END_OP( "binary_and" )
1525 }
1526 /*}}}*/
1527 
1528 /*{{{ FERITE_BINARY_OP( binary_xor ) */
FERITE_BINARY_OP(binary_xor)1529 FERITE_BINARY_OP( binary_xor )
1530 {
1531     BEGIN_OP( a )
1532       BEGIN_BLOCK( F_VAR_LONG, b )
1533         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_xor" ), VAI(a) ^ VAI(b), FE_STATIC ); )
1534           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_xor" ), VAI(a) ^ (long)VAF(b), FE_STATIC ); )
1535             BLOCK_DIE( "binary_xor" );
1536     END_BLOCK
1537       BEGIN_BLOCK( F_VAR_DOUBLE, b )
1538         DO_OP( F_VAR_LONG, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_xor" ), (long)VAF(a) ^ VAI(b), FE_STATIC ); )
1539           DO_OP( F_VAR_DOUBLE, NOWT, retv = ferite_create_number_long_variable( script, RETVNAME( "binary_xor" ), (long)VAF(a) ^ (long)VAF(b), FE_STATIC ); )
1540             BLOCK_DIE( "binary_xor" );
1541     END_BLOCK
1542       END_OP( "binary_xor" )
1543 }
1544 /*}}}*/
1545 
1546 /*{{{ FERITE_BINARY_OP( left_shift_assign ) */
FERITE_BINARY_OP(left_shift_assign)1547 FERITE_BINARY_OP( left_shift_assign )
1548 {
1549     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
1550 
1551     FE_ENTER_FUNCTION;
1552     LOCK_VARIABLE(a);
1553     LOCK_VARIABLE(b);
1554     tmp_ptr = ferite_op_left_shift( script, a, b );
1555     if( tmp_ptr != NULL )
1556     {
1557         ptr = ferite_op_assign( script, a, tmp_ptr );
1558         MARK_VARIABLE_AS_DISPOSABLE( ptr );
1559         ferite_variable_destroy( script, tmp_ptr );
1560     }
1561     UNLOCK_VARIABLE(a);
1562     UNLOCK_VARIABLE(b);
1563     FE_LEAVE_FUNCTION( ptr );
1564 }
1565 /*}}}*/
1566 
1567 /*{{{ FERITE_BINARY_OP( right_shift_assign ) */
FERITE_BINARY_OP(right_shift_assign)1568 FERITE_BINARY_OP( right_shift_assign )
1569 {
1570     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
1571 
1572     FE_ENTER_FUNCTION;
1573     LOCK_VARIABLE(a);
1574     LOCK_VARIABLE(b);
1575     tmp_ptr = ferite_op_right_shift( script, a, b );
1576     if( tmp_ptr != NULL )
1577     {
1578         ptr = ferite_op_assign( script, a, tmp_ptr );
1579         MARK_VARIABLE_AS_DISPOSABLE( ptr );
1580         ferite_variable_destroy( script, tmp_ptr );
1581     }
1582     UNLOCK_VARIABLE(a);
1583     UNLOCK_VARIABLE(b);
1584     FE_LEAVE_FUNCTION( ptr );
1585 }
1586 /*}}}*/
1587 
1588 /*{{{ FERITE_BINARY_OP( binary_and_assign ) */
FERITE_BINARY_OP(binary_and_assign)1589 FERITE_BINARY_OP( binary_and_assign )
1590 {
1591     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
1592 
1593     FE_ENTER_FUNCTION;
1594     LOCK_VARIABLE(a);
1595     LOCK_VARIABLE(b);
1596     tmp_ptr = ferite_op_binary_and( script, a, b );
1597     if( tmp_ptr != NULL )
1598     {
1599         ptr = ferite_op_assign( script, a, tmp_ptr );
1600         MARK_VARIABLE_AS_DISPOSABLE( ptr );
1601         ferite_variable_destroy( script, tmp_ptr );
1602     }
1603     UNLOCK_VARIABLE(a);
1604     UNLOCK_VARIABLE(b);
1605     FE_LEAVE_FUNCTION( ptr );
1606 }
1607 /*}}}*/
1608 
1609 /*{{{ FERITE_BINARY_OP( binary_or_assign ) */
FERITE_BINARY_OP(binary_or_assign)1610 FERITE_BINARY_OP( binary_or_assign )
1611 {
1612     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
1613 
1614     FE_ENTER_FUNCTION;
1615     LOCK_VARIABLE(a);
1616     LOCK_VARIABLE(b);
1617     tmp_ptr = ferite_op_binary_or( script, a, b );
1618     if( tmp_ptr != NULL )
1619     {
1620         ptr = ferite_op_assign( script, a, tmp_ptr );
1621         MARK_VARIABLE_AS_DISPOSABLE( ptr );
1622         ferite_variable_destroy( script, tmp_ptr );
1623     }
1624     UNLOCK_VARIABLE(a);
1625     UNLOCK_VARIABLE(b);
1626     FE_LEAVE_FUNCTION( ptr );
1627 }
1628 /*}}}*/
1629 
1630 /*{{{ FERITE_BINARY_OP( binary_xor_assign ) */
FERITE_BINARY_OP(binary_xor_assign)1631 FERITE_BINARY_OP( binary_xor_assign )
1632 {
1633     FeriteVariable *ptr = NULL, *tmp_ptr = NULL;
1634 
1635     FE_ENTER_FUNCTION;
1636     LOCK_VARIABLE(a);
1637     LOCK_VARIABLE(b);
1638     tmp_ptr = ferite_op_binary_xor( script, a, b );
1639     if( tmp_ptr != NULL )
1640     {
1641         ptr = ferite_op_assign( script, a, tmp_ptr );
1642         MARK_VARIABLE_AS_DISPOSABLE( ptr );
1643         ferite_variable_destroy( script, tmp_ptr );
1644     }
1645     UNLOCK_VARIABLE(a);
1646     UNLOCK_VARIABLE(b);
1647     FE_LEAVE_FUNCTION( ptr );
1648 }
1649 /*}}}*/
1650 
1651 /*{{{ FERITE_BINARY_OP( isa ) */
FERITE_BINARY_OP(isa)1652 FERITE_BINARY_OP( isa )
1653 {
1654     FeriteVariable *ptr = NULL;
1655 
1656     FE_ENTER_FUNCTION;
1657     LOCK_VARIABLE(a);
1658     LOCK_VARIABLE(b);
1659     GET_INPUT_VARS;
1660     FE_VAR_TEST( (strcmp( VAS(b)->data, ferite_variable_id_to_str(script,a->type) ) == 0), "isa" );
1661     UNLOCK_VARIABLE(a);
1662     UNLOCK_VARIABLE(b);
1663     if( ptr != NULL )
1664       MARK_VARIABLE_AS_DISPOSABLE( ptr );
1665     FE_LEAVE_FUNCTION( ptr );
1666 }
1667 /*}}}*/
1668 
1669 /*{{{ FERITE_BINARY_OP( instanceof ) */
FERITE_BINARY_OP(instanceof)1670 FERITE_BINARY_OP( instanceof )
1671 {
1672     FeriteVariable *ptr = NULL;
1673 
1674     FE_ENTER_FUNCTION;
1675     LOCK_VARIABLE(a);
1676     LOCK_VARIABLE(b);
1677     GET_INPUT_VARS;
1678     if( a->type == F_VAR_OBJ && b->type == F_VAR_CLASS && VAO(a) != NULL && VAO(a)->klass == b->data.pval )
1679       FE_VAR_TRUE( ptr, "instanceof" );
1680     else
1681       FE_VAR_FALSE( ptr, "instanceof" );
1682     UNLOCK_VARIABLE(a);
1683     UNLOCK_VARIABLE(b);
1684     if( ptr != NULL )
1685       MARK_VARIABLE_AS_DISPOSABLE( ptr );
1686     FE_LEAVE_FUNCTION( ptr );
1687 }
1688 /*}}}*/
1689 
1690 FeriteOpTable ferite_op_table[] =
1691 {
1692     { FERITE_OPCODE_not_op,              "not_op",              FERITE_OP_CALL( not_op ) },
1693     { FERITE_OPCODE_left_incr,           "left_incr",           FERITE_OP_CALL( left_incr ) },
1694     { FERITE_OPCODE_right_incr,          "right_incr",          FERITE_OP_CALL( right_incr ) },
1695     { FERITE_OPCODE_left_decr,           "left_decr",           FERITE_OP_CALL( left_decr ) },
1696     { FERITE_OPCODE_right_decr,          "right_decr",          FERITE_OP_CALL( right_decr ) },
1697     { FERITE_OPCODE_positive_var,        "positive_var",        FERITE_OP_CALL( positive_var ) },
1698     { FERITE_OPCODE_negative_var,        "negative_var",        FERITE_OP_CALL( negative_var ) },
1699     { FERITE_OPCODE_eval,                "eval",                FERITE_OP_CALL( eval ) },
1700     { FERITE_OPCODE_include,             "include",             FERITE_OP_CALL( include ) },
1701     { FERITE_OPCODE_add,                 "add",                 FERITE_OP_CALL( add ) },
1702     { FERITE_OPCODE_minus,               "minus",               FERITE_OP_CALL( minus ) },
1703     { FERITE_OPCODE_mult,                "mult",                FERITE_OP_CALL( mult ) },
1704     { FERITE_OPCODE_divide,              "divide",              FERITE_OP_CALL( divide ) },
1705     { FERITE_OPCODE_modulus,             "modulus",             FERITE_OP_CALL( modulus ) },
1706     { FERITE_OPCODE_assign,              "assign",              FERITE_OP_CALL( assign ) },
1707     { FERITE_OPCODE_add_assign,          "add_assign",          FERITE_OP_CALL( add_assign ) },
1708     { FERITE_OPCODE_minus_assign,        "minus_assign",        FERITE_OP_CALL( minus_assign ) },
1709     { FERITE_OPCODE_mult_assign,         "mult_assign",         FERITE_OP_CALL( mult_assign ) },
1710     { FERITE_OPCODE_divide_assign,       "divide_assign",       FERITE_OP_CALL( divide_assign ) },
1711     { FERITE_OPCODE_binary_or,           "binary_or",           FERITE_OP_CALL( binary_or ) },
1712     { FERITE_OPCODE_binary_and,          "binary_and",          FERITE_OP_CALL( binary_and ) },
1713     { FERITE_OPCODE_binary_xor,          "binary_xor",          FERITE_OP_CALL( binary_xor ) },
1714     { FERITE_OPCODE_logical_or,          "logical_or",          FERITE_OP_CALL( logical_or ) },
1715     { FERITE_OPCODE_logical_and,         "logical_and",         FERITE_OP_CALL( logical_and ) },
1716     { FERITE_OPCODE_equals,              "equals",              FERITE_OP_CALL( equals ) },
1717     { FERITE_OPCODE_case,                "case",                FERITE_OP_CALL( case ) },
1718     { FERITE_OPCODE_notequals,           "notequals",           FERITE_OP_CALL( notequals ) },
1719     { FERITE_OPCODE_less_than,           "less_than",           FERITE_OP_CALL( less_than ) },
1720     { FERITE_OPCODE_less_than_equals,    "less_than_equals",    FERITE_OP_CALL( less_than_equals ) },
1721     { FERITE_OPCODE_greater_than,        "greater_than",        FERITE_OP_CALL( greater_than ) },
1722     { FERITE_OPCODE_greater_than_equals, "greater_than_equals", FERITE_OP_CALL( greater_than_equals ) },
1723     { FERITE_OPCODE_array_index,         "array_index",         FERITE_OP_CALL( array_index ) },
1724     { FERITE_OPCODE_array_slice,         "array_slice",         FERITE_OP_CALL( array_slice ) },
1725     { FERITE_OPCODE_left_shift,          "left_shift",          FERITE_OP_CALL( left_shift ) },
1726     { FERITE_OPCODE_right_shift,         "right_shift",         FERITE_OP_CALL( right_shift ) },
1727     { FERITE_OPCODE_left_shift_assign,   "left_shift_assign",   FERITE_OP_CALL( left_shift_assign ) },
1728     { FERITE_OPCODE_right_shift_assign,  "right_shift_assign",  FERITE_OP_CALL( right_shift_assign ) },
1729     { FERITE_OPCODE_binary_and_assign,   "binary_and_assign",   FERITE_OP_CALL( binary_and_assign ) },
1730     { FERITE_OPCODE_binary_or_assign,    "binary_or_assign",    FERITE_OP_CALL( binary_or_assign ) },
1731     { FERITE_OPCODE_binary_xor_assign,   "binary_xor_assign",   FERITE_OP_CALL( binary_xor_assign ) },
1732     { FERITE_OPCODE_isa,                 "isa",                 FERITE_OP_CALL( isa ) },
1733     { FERITE_OPCODE_instanceof,          "instanceof",          FERITE_OP_CALL( instanceof ) },
1734     { FERITE_OPCODE_array_clear,         "array_clear",         FERITE_OP_CALL( array_clear ) }
1735 };
1736