1/*
2 * Copyright (C) 2001-2005 Evan Webb
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * o Redistributions of source code must retain the above copyright notice, this
9 *   list of conditions and the following disclaimer.
10 * o Redistributions in binary form must reproduce the above copyright notice,
11 *   this list of conditions and the following disclaimer in the documentation
12 *   and/or other materials provided with the distribution.
13 * o Neither the name of the ferite software nor the names of its contributors may
14 *   be used to endorse or promote products derived from this software without
15 *   specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30uses "reflection.lib";
31
32module-header
33{
34
35#include <string.h>
36
37#define ClassObj     ((FeriteClass*)(self->odata))
38#define ObjectObj    ((FeriteObject*)(self->odata))
39#define FunctionObj  ((FunctionHolder*)(self->odata))
40#define NSObj        ((FeriteNamespace*)(self->odata))
41
42#define ChkSelf \
43   if(ClassObj == NULL) { \
44      ferite_error(script, 0, "Undefined Class\n"); \
45   }
46
47    typedef struct __function_holder
48    {
49        FeriteFunction *func;
50        void *container;
51    }
52    FunctionHolder;
53
54    void reflection_variable_get( FeriteScript *script, FeriteVariable *var );
55    void reflection_variable_set( FeriteScript *script, FeriteVariable *var, FeriteVariable *newvalue );
56    void reflection_variable_cleanup( FeriteScript *script, void *odata );
57    char *reflection_generate_class_fqn( FeriteScript *script, FeriteClass *klass );
58    FeriteVariable *reflection_ns_get_list( FeriteScript *script, FeriteNamespace *space, int type );
59}
60
61/**
62 * @class Namespace
63 * @brief This class wraps a ferite namespace and provides mechanisms to query it's contents.
64 */
65class Namespace
66{
67    /**
68     * @function constructor
69     * @declaration function constructor( void ns )
70     * @brief This function taks a namespace and constructs a wrapper
71     * @description This function takes a namespace in the form of new Namespace(Sys)
72     * @param void ns The namespace to wrap
73     */
74    native function constructor( void ns )
75    {
76        if( ns->type != F_VAR_NS )
77        {
78            FE_RETURN_NULL_OBJECT;
79        }
80        self->odata = VAN(ns);
81    }
82    /**
83     * @function getVariables
84     * @declaration function getVariables()
85     * @brief Fetch an array containing names to types mapping of all the variables within the namespace
86     * @description This function allows you to inspect the contents of the namespace. The returned array
87       has the types as the elements with the names of the variables mapped ot the index. e.g. [ 'f' => 'string' ]
88     * @return An associative array
89     */
90    native function getVariables()
91    {
92        FeriteVariable *array = NULL, *var = NULL, *tmp = NULL;
93        FeriteHashBucket *buk = NULL;
94        FeriteIterator *iter = NULL;
95
96        ChkSelf;
97        array = ferite_create_uarray_variable(script, "ns::getVars", NSObj->data_fork->size, FE_STATIC);
98        iter = ferite_create_iterator(script);
99        while((buk = (FeriteHashBucket*)ferite_hash_walk(script, NSObj->data_fork,iter)) != NULL)
100        {
101            FeriteNamespaceBucket *b = buk->data;
102            if( b->type == FENS_VAR )
103            {
104                tmp = b->data;
105                var = fe_new_str(buk->id,ferite_variable_id_to_str( script, tmp->type ), 0, FE_CHARSET_DEFAULT);
106                ferite_uarray_add(script,VAUA(array),var,buk->id, FE_ARRAY_ADD_AT_END );
107            }
108        }
109        ffree(iter);
110        FE_RETURN_VAR(array);
111    }
112    /**
113     * @function getFunctions
114     * @declaration function getFunctions()
115     * @brief Fetch an array containing names of all the functions within the namespace
116     * @return An array
117     */
118    native function getFunctions()
119    {
120        FeriteVariable *v = reflection_ns_get_list( script, NSObj, FENS_FNC );
121        FE_RETURN_VAR(v);
122    }
123    /**
124     * @function getClasses
125     * @declaration function getClasses()
126     * @brief Fetch an array containing names of all the classes within the namespace
127     * @return An array
128     */
129    native function getClasses()
130    {
131        FeriteVariable *v = reflection_ns_get_list( script, NSObj, FENS_CLS );
132        FE_RETURN_VAR(v);
133    }
134    /**
135     * @function getNamespaces
136     * @declaration function getNamespaces()
137     * @brief Fetch an array containing names of all the namespaces within the namespace
138     * @return An array
139     */
140    native function getNamespaces()
141    {
142        FeriteVariable *v = reflection_ns_get_list( script, NSObj, FENS_NS );
143        FE_RETURN_VAR(v);
144    }
145    /**
146     * @function getNamespace
147     * @declaration function getNamespace()
148     * @brief Fetch a variable containing the namespace that this object wraps.
149     * @return A void variable that has been morphed into a namespace.
150     */
151    native function getNamespace()
152    {
153        FeriteVariable *k = ferite_create_namespace_variable(script,"getNamespace()",NSObj,FE_STATIC);
154        FE_RETURN_VAR(k);
155    }
156    /**
157     * @function getScriptNamespace
158     * @static
159     * @declaration function getScriptNamespace()
160     * @brief Fetch a namespace object wrapping the main script namespace.
161     * @return A namespace object on success, null otherwise.
162     */
163    static native function getScriptNamespace()
164    {
165        FeriteVariable **params = fmalloc(sizeof(FeriteVariable*) * 2);
166        FeriteVariable  *ns = NULL;
167
168        params[0] = ferite_create_namespace_variable(script, "NS", script->mainns, FE_STATIC);
169        MARK_VARIABLE_AS_DISPOSABLE(params[0]);
170        params[1] = NULL;
171
172        ns = ferite_new_object( script, self, params );
173        ferite_delete_parameter_list( script, params );
174
175        if( ns != NULL )
176            FE_RETURN_VAR(ns);
177        FE_RETURN_NULL_OBJECT;
178    }
179    /**
180    * @function fullyQualifiedName
181     * @declaration function fullyQualifiedName()
182     * @brief Find the fully qualified name of the wrapped namespace.
183     * @return A string with the fully qualified name, such as "Stream.StdioStream".
184     */
185    native function fullyQualifiedName()
186    {
187        char *n = ferite_generate_namespace_fqn( script, NSObj );
188        FE_RETURN_CSTR( n, FE_TRUE );
189    }
190    /**
191    * @function getFunction
192     * @declaration function getFunction( string name )
193     * @brief Creates a new Function object from a function in this class
194     * @param string name The name of the method
195     * @return A new Function object, or null on failure
196     * @description This function creates a new Function object which is
197     *              associated with the specified method of the class
198     *              associated with this "Class" object.
199     * @example <nl/><code>
200     <keyword>namespace</keyword> Test {<nl/>
201         <tab/><type>number</type> id;<nl/>
202             <tab/><keyword>static function</span> test( <type>number</type> n )<nl/>
203             <tab/><tab/>.id = n;<nl/>
204     }<nl/>
205     <type>object</type> o = new Namespace(Test);<nl/>
206     <type>object</type> f = o.getFunction('test');</code><nl/>
207     */
208    function getFunction( string name )
209    {
210        return new Function( self.getNamespace(), name );
211    }
212}
213/**
214 * @end
215 */
216
217/**
218 * @class Class
219 * @brief Instances of this class are used to inspect Ferite classes
220 */
221class Class
222{
223   /**
224    * @function constructor
225    * @brief The constructor of the "Class" class
226    * @declaration function constructor( void klass )
227    * @param void klass The class which the object should be able to inspect
228    * @description Objects of the "Class" class are initialised by passing the
229    *              class they should be associated with to the constructor. The
230    *              class name should not be a string (ie. don't quote the class
231    *              name). The instantiation will fail if the argument is not a
232    *              class.
233    * @example <nl/><code>
234    <type>object</type> wrapper = <keyword>new</keyword> Class(Regexp);</code><nl/>
235    */
236   native function constructor( void klass )
237   {
238       if( klass->type != F_VAR_CLASS )
239       {
240           FE_RETURN_NULL_OBJECT;
241       }
242       self->odata = VAC(klass);
243   }
244
245   /**
246    * @function getVariables
247    * @brief Generates an array containing the static variables in this class
248    * @declaration function getVariables( )
249    * @return An array of the static variables in this class
250    * @description This function returns an array of the static (class)
251    *              variables which are contained in the class associated with
252    *              this object. The array keys are the names of the variables,
253    *              and the array values are the names of the types of the
254    *              variables.
255    * @example <nl/><code>
256    <keyword>class</keyword> TestClass {<nl/>
257    <tab/><keyword>static</keyword> <type>number</type> id;<nl/>
258    <tab/><keyword>static</keyword> <type>string</type> name;<nl/>
259    <tab/><keyword>static</keyword> <type>array</type>  keywords;<nl/>
260    }<nl/>
261    <type>object</type> wrapper = <keyword>new</keyword> Class(TestClass);<nl/>
262    <type>array</type> variables = wrapper.getVariables(); &raquo [ 'id' => 'number', 'name' => 'string', 'keywords' => 'array' ]</code><nl/>
263    */
264   native function getVariables()
265   {
266       FeriteVariable *array = NULL, *var = NULL, *tmp = NULL;
267       FeriteHashBucket *buk = NULL;
268       FeriteIterator *iter = NULL;
269
270       ChkSelf;
271       array = ferite_create_uarray_variable(script, "Class::getVars", ClassObj->class_vars->size, FE_STATIC);
272       iter = ferite_create_iterator(script);
273       while((buk = (FeriteHashBucket*)ferite_hash_walk(script, ClassObj->class_vars,iter)) != NULL)
274       {
275           tmp = buk->data;
276           var = fe_new_str(buk->id,ferite_variable_id_to_str( script, tmp->type ), 0, FE_CHARSET_DEFAULT);
277           ferite_uarray_add(script,VAUA(array),var,buk->id, FE_ARRAY_ADD_AT_END );
278       }
279       ffree(iter);
280       FE_RETURN_VAR(array);
281   }
282
283   /**
284    * @function getFunctions
285    * @declaration function getFunctions( )
286    * @brief Generates an array containing the static functions in this class
287    * @return An array of the static functions in this class
288    * @description This function returns an array of the static (class)
289    *              functions which are contained in the class associated with
290    *              this object. The array values are strings containing the
291    *              names of the functions.
292    * @example <nl/><code>
293    <keyword>class</keyword> TestClass {<nl/>
294    <tab/><keyword>static</keyword> <keyword>function</span> f() {<nl/>
295    <tab/>}<nl/>
296    }<nl/>
297    <type>object</type> wrapper = <keyword>new</keyword> Class(TestClass);<nl/>
298    <type>array</type> func = wrapper.getFunctions(); &raquo; [ 'f' ]</code><nl/>
299    */
300   native function getFunctions()
301   {
302       FeriteHashBucket *buk = NULL;
303       FeriteVariable *array = NULL, *var = NULL;
304       FeriteIterator *iter = NULL;
305       FeriteFunction *func = NULL;
306
307       ChkSelf;
308       array = ferite_create_uarray_variable( script, "Class:getFunctions", ClassObj->class_methods->size, FE_STATIC);
309       iter = ferite_create_iterator(script);
310       while((buk = (FeriteHashBucket*)ferite_hash_walk(script,ClassObj->class_methods,iter)) != NULL)
311       {
312           func = buk->data;
313           var = fe_new_str(buk->id,func->name, 0, FE_CHARSET_DEFAULT);
314           ferite_uarray_add(script,VAUA(array),var,NULL,FE_ARRAY_ADD_AT_END);
315       }
316       ffree(iter);
317       FE_RETURN_VAR(array);
318   }
319
320   /**
321    * @function classWithName
322    * @declaration static function classWithName( string name )
323    * @brief Creates a new Class object
324    * @param string name The name of the class the object should be able to inspect
325    * @return A "Class" object or null on failure
326    * @static
327    * @description This function is an alternate way to generate an object of
328    *              the "Class" class. It differs from using "new" and passing
329    *              the class to the constructor in that it takes the name of
330    *              the class to associate with the object as a string instead
331    *              of the class itself.
332    * @example <nl/><code>
333    <keyword>class</keyword> TestClass { }<nl/>
334    <type>object</type> wrapper = Class.classWithName("TestClass");</code><nl/>
335    */
336   static native function classWithName( string name )
337   {
338       FeriteNamespaceBucket *nsb = ferite_find_namespace( script, script->mainns, name->data, FENS_CLS );
339       FeriteNamespaceBucket *classnsb = ferite_find_namespace( script, script->mainns, "Class", FENS_CLS );
340       if( nsb != NULL )
341       {
342           FeriteVariable **plist = ferite_create_parameter_list( 4 );
343           FeriteVariable *rval = NULL;
344
345           plist[0] = ferite_create_void_variable( script, "classWithName", FE_STATIC );
346           plist[0]->type = F_VAR_CLASS;
347           VAC(plist[0]) = nsb->data;
348           MARK_VARIABLE_AS_DISPOSABLE(plist[0]);
349
350           rval = ferite_new_object( script, classnsb->data, plist );
351           ferite_delete_parameter_list( script, plist );
352
353           if( rval != NULL )
354           {
355               FE_RETURN_VAR( rval );
356           }
357       }
358       FE_RETURN_NULL_OBJECT;
359   }
360
361   /**
362    * @function newObject
363    * @declaration static native function newObject( ... )
364    * @brief Creates a new instance of the class associated with this object
365    * @param ... The arguments to pass to the constructor of the class
366    * @return An instance of the class associated with this object or NULL on failure
367    * @description This function creates a new object, much like the "new"
368    *              operator does, which is an instance of the class associated
369    *              with this instance of the "Class" class.
370    * @example <nl/><code>
371    <keyword>class</keyword> TestClass {<nl/>
372    <tab/><type>number</type> id = 0;<nl/>
373    <tab/><keyword>function</keyword> construct<keyword>or</span>( <type>number</type> v )<nl/>
374    <tab/><tab/>.id = v;<nl/>
375    }<nl/>
376    <type>object</type> wrapper = Class.classWithName("TestClass");<nl/>
377    <type>object</type> obj = wrapper.newObject(10);</code><nl/>
378    */
379   native function newObject( ... )
380   {
381       FeriteVariable *var = NULL;
382       FeriteVariable **p = ferite_create_parameter_list( ferite_get_parameter_count( params ) + 1);
383       int i = 0;
384
385       for( i = 0; params[i] != NULL; i++ )
386       {
387           p[i] = ferite_duplicate_variable( script, params[i], NULL );
388           MARK_VARIABLE_AS_DISPOSABLE( p[i] );
389       }
390       var = ferite_new_object( script, ClassObj, p );
391       ferite_delete_parameter_list( script, p );
392       FE_RETURN_VAR( var );
393   }
394
395    /**
396     * @function locate
397     * @declaration static function locate( string name )
398     * @brief Locate a class with a given name.
399     * @description This is a particularily useful function for locating a named class, for example from a configuration
400                    file, so that it can later be instantiated.
401     * @param string name The path to the class.
402     * @return The class. This can be passed to the constructor of Class
403     * @static
404     * @example <nl/><code>
405     <keyword>class</keyword> TestClass {<nl/>
406     <tab/><type>number</type> id = 0;<nl/>
407     <tab/><keyword>function</keyword> construct<keyword>or</span>( <type>number</type> v )<nl/>
408     <tab/><tab/>.id = v;<nl/>
409     }<nl/>
410     <type>void</type> klass = Class.locate("TestClass");<nl/>
411     <type>object</type> obj = <keyword>new</keyword> klass(10);</code><nl/>
412     */
413    static native function locate( string name )
414    {
415        FeriteNamespaceBucket *nsb = ferite_find_namespace( script, script->mainns, name->data, FENS_CLS );
416        if( nsb != NULL )
417        {
418            FeriteVariable *variable = ferite_create_class_variable( script, "classForString", nsb->data, FE_STATIC );
419            FE_RETURN_VAR( variable );
420        }
421        FE_RETURN_NULL_OBJECT;
422    }
423
424    /**
425     * @function name
426     * @static
427     * @declaration static function name( void k )
428     * @brief Get the path for a given class
429     * @param void k The class to obtain the name of.
430     * @return A string containg the path to the class.
431     * @example <nl/><code>
432     <keyword>class</keyword> TestClass {<nl/>
433     }<nl/>
434     <type>void</type> klass = Class.locate("TestClass");<nl/>
435     <type>string</type> name = Class.name(klass);</code><nl/>
436     */
437    static native function name( void k )
438    {
439        char *name = NULL;
440        FeriteString *str = NULL;
441
442        if( k->type != F_VAR_CLASS )
443            str = ferite_str_new( "", 0, FE_CHARSET_DEFAULT );
444        else
445        {
446            name = ferite_generate_class_fqn( script, VAC(k) );
447            str = ferite_str_new( name, 0, FE_CHARSET_DEFAULT );
448            ffree( name );
449        }
450        FE_RETURN_STR( str, FE_TRUE );
451    }
452    /**
453     * @function getClass
454     * @declaration function getClass()
455     * @brief Get the class that the Class object wraps
456     * @return The class.
457     */
458    native function getClass()
459    {
460        FeriteVariable *k = ferite_create_class_variable(script,"getClass()",ClassObj,FE_STATIC);
461        FE_RETURN_VAR(k);
462    }
463    /**
464     * @function fullyQualifiedName
465     * @declaration function fullyQualifiedName()
466     * @brief Find the fully qualified name of the wrapped class.
467     * @return A string with the fully qualified name, such as "Stream.StdioStream".
468     */
469    native function fullyQualifiedName()
470    {
471        char *n = ferite_generate_class_fqn( script, ClassObj );
472        FE_RETURN_CSTR( n, FE_TRUE );
473    }
474
475    /**
476    * @function getFunction
477     * @declaration function getFunction( string name )
478     * @brief Creates a new Function object from a function in this class
479     * @param string name The name of the method
480     * @return A new Function object, or null on failure
481     * @description This function creates a new Function object which is
482     *              associated with the specified method of the class
483     *              associated with this "Class" object.
484     * @example <nl/><code>
485     <keyword>class</keyword> TestClass {<nl/>
486         <tab/><type>number</type> id;<nl/>
487             <tab/><keyword>static function</span> test( <type>number</type> n )<nl/>
488             <tab/><tab/>.id = n;<nl/>
489     }<nl/>
490     <type>object</type> o = Class.classWithName("TestClass");<nl/>
491     <type>object</type> f = o.getFunction('test');</code><nl/>
492     */
493    function getFunction( string name )
494    {
495        return new Function(self.getClass(),name);
496    }
497}
498/**
499 * @end
500 */
501
502/**
503 * @class Object
504 * @brief Instances of this class are used to inspect Ferite objects
505 */
506class Object
507{
508
509   /**
510    * @function constructor
511    * @declaration function constructor( object obj )
512    * @brief The constructor of the "Object" class
513    * @param object obj The object which the new object should be able to inspect
514    * @description Objects of the "Object" class are initialised by passing the
515    *              object which should be associated with it to the constructor.
516    *              The instantiation will fail if the argument is not an object,
517    *              or is the null object.
518    * @example <nl/><code>
519    <type>object</type> f = Sys.openfile( "test.txt", Sys.O_RDONLY );<nl/>
520    <type>object</type> o = <keyword>new</keyword> Object(f);</code><nl/>
521    */
522   native function constructor(object obj)
523   {
524       if(obj != NULL)
525       {
526           self->odata = obj;
527           obj->refcount++;
528       }
529       else
530       {
531           ferite_error(script,0,"Invalid object (a null object?)");
532       }
533   }
534
535   native function destructor()
536   {
537       ObjectObj->refcount--;
538   }
539
540   /**
541    * @function className
542    * @declaration function className( )
543    * @brief Finds the name of the class of the object associated with this object
544    * @return The name of the class as a string
545    * @example <nl/><code>
546    <type>object</type> f = Sys.openfile( "test.txt", Sys.O_RDONLY );<nl/>
547    <type>object</type> o = <keyword>new</keyword> Object(f);<nl/>
548    <type>string</type> n = o.<keyword>class</keyword>Name(); &raquo; "Sys.FileStream"</code><nl/>
549    */
550   native function className()
551   {
552       FeriteVariable *v;
553       v = fe_new_str_static("className",ObjectObj->name, 0, FE_CHARSET_DEFAULT);
554       FE_RETURN_VAR(v);
555   }
556
557   /**
558    * @function fromData
559    * @declaration static native function fromData( string klass, array data )
560    * @brief Creates an object
561    * @param string class The name of the class of the object to create
562    * @param array data The values to set the variables in the object to
563    * @description This function provides another way to create a new object.
564    *              The array is used to set the values of the variables in the
565    *              object. The key strings in the array give the names of the
566    *              variables to set the values of. Note that this function does
567    *              NOT call the object constructor after creating it, so you
568    *              will usually need to do it yourself after calling
569    *              Object.fromData().
570    * @static
571    * @example <nl/><code>
572    <keyword>class</keyword> TestClass {<nl/>
573    <tab/><type>number</type> id;<nl/>
574    <tab/><keyword>function</keyword> construct<keyword>or</span>( <type>number</type> n )<nl/>
575    <tab/><tab/>.id = n;<nl/>
576    }<nl/>
577    <type>object</type> o = Object.fromData("TestClass",[ 10 ]);</code><nl/>
578    */
579   static native function fromData( string klass, array data )
580   {
581       FeriteVariable *obj = NULL;
582       FeriteHashBucket *buk = NULL;
583       FeriteIterator *iter = NULL;
584       FeriteVariable *foo = NULL;
585       FeriteClass *cls = ferite_find_class(script,script->mainns,klass->data);
586
587       obj = ferite_build_object(script,cls);
588       iter = ferite_create_iterator(script);
589       while((buk = (FeriteHashBucket*)ferite_hash_walk(script,data->hash,iter)) != NULL)
590       {
591           if(ferite_object_has_var(script,VAO(obj),buk->id))
592           {
593               foo = fe_new_void_static( "no-var" );
594               ferite_variable_destroy( script, ferite_op_assign( script, foo, (FeriteVariable*)buk->data ) );
595               ferite_object_set_var(script, VAO(obj), buk->id, foo);
596           }
597       }
598       ffree(iter);
599       FE_RETURN_VAR( obj );
600   }
601
602   /**
603    * @function getVariable
604    * @declaration function getVariable( string name )
605    * @brief Retrieves a variable from the object associated with this object
606    * @param string name The name of the variable to get
607    * @return The variable
608    * @description This function retrieves a variable from the object from the
609    *              object associated with this "Object" object. If no variable
610    *              exists in the object with the specified name, an exception
611    *              is thrown.
612    * @example <nl/><code>
613    <keyword>class</keyword> TestClass {<nl/>
614    <tab/><type>number</type> id;<nl/>
615    <tab/><keyword>function</keyword> construct<keyword>or</span>( <type>number</type> n )<nl/>
616    <tab/><tab/>.id = n;<nl/>
617    }<nl/>
618    <type>object</type> o = Object.fromData(Test<keyword>class</keyword>,[ 10 ]);<nl/>
619    <type>number</type> value = o.getVariable('id'); &raquo; value = 10</code><nl/>
620    */
621   native function getVariable( string name )
622   {
623       FeriteVariable *var = ferite_object_get_var( script, ObjectObj, name->data );
624
625       if( var == NULL )
626       {
627           ferite_error( script, 0, "Object.getVariable(\"%s\") - No such variable in object\n", name->data );
628           FE_RETURN_VOID;
629       }
630
631       /* We dont do FE_RETURN_VAR because we dont want the variable to be disposed */
632       return var;
633   }
634
635   /**
636    * @function setVariable
637    * @declaration function setVariable( string name, void value )
638    * @brief Sets a variable in the object associated with this object
639    * @param string name The name of the variable to set the value of
640    * @param void value The value to set the variable to
641    * @return A copy of the variable which was just assigned
642    * @description This function can be used to set the value of a variable in
643    *              an object. If no variable of the specified name exists or if
644    *              it is of a different type to the specified value, an
645    *              exception is thrown.
646    * @example <nl/><code>
647    <keyword>class</keyword> TestClass {<nl/>
648    <tab/><type>number</type> id;<nl/>
649    <tab/><keyword>function</keyword> construct<keyword>or</span>( <type>number</type> n )<nl/>
650    <tab/><tab/>.id = n;<nl/>
651    }<nl/>
652    <type>object</type> o = Object.fromData(Test<keyword>class</keyword>,[ 10 ]);<nl/>
653    o.setVariable('id',100);</code><nl/>
654    */
655   native function setVariable( string name, void value )
656   {
657       FeriteVariable *var = ferite_object_get_var( script, ObjectObj, name->data );
658       FeriteVariable *rval = NULL;
659
660       if( var == NULL )
661       {
662           ferite_error( script, 0, "Object.setVariable(\"%s\") - No such variable in object\n", name->data );
663           FE_RETURN_VOID;
664       }
665
666       if( !ferite_types_are_equal( script, var->type, value->type ) )
667       {
668           ferite_error( script, 0, "Object.setVariable(\"%s\") - can't assign variable of type %s to type %s\n",
669                         name->data,
670                         ferite_variable_id_to_str( script, value->type ),
671                         ferite_variable_id_to_str( script, var->type ) );
672           FE_RETURN_VOID;
673       }
674
675       rval = ferite_op_assign( script, var, value );
676       FE_RETURN_VAR( rval );
677   }
678
679   /**
680    * @function getObject
681    * @declaration function getObject( )
682    * @brief Retrieves a reference to the object that is associated with this object
683    * @return A reference to the object
684    * @example <nl/><code>
685    <keyword>class</keyword> TestClass {<nl/>
686    <tab/><type>number</type> id;<nl/>
687    <tab/><keyword>function</keyword> construct<keyword>or</span>( <type>number</type> n )<nl/>
688    <tab/><tab/>.id = n;<nl/>
689    }<nl/>
690    <type>object</type> o = Object.fromData(Test<keyword>class</keyword>,[ 10 ]);<nl/>
691    <type>object</type> p = o.getObject();<nl/>
692    p.id = 100;</code><nl/>
693    */
694   native function getObject()
695   {
696       FE_RETURN_OBJECT( ObjectObj );
697   }
698
699   /**
700    * @function getFunction
701    * @declaration function getFunction( string name )
702    * @brief Creates a new Function object from a method in this object
703    * @param string name The name of the method
704    * @return A new Function object, or null on failure
705    * @description This function creates a new Function object which is
706    *              associated with the specified method of the object
707    *              associated with this "Object" object.
708    * @example <nl/><code>
709    <keyword>class</keyword> TestClass {<nl/>
710    <tab/><type>number</type> id;<nl/>
711    <tab/><keyword>function</keyword> test( <type>number</type> n )<nl/>
712    <tab/><tab/>.id = n;<nl/>
713    }<nl/>
714    <type>object</type> o = Object.fromData(Test<keyword>class</keyword>,[ 10 ]);<nl/>
715    <type>object</type> f = o.getFunction('test');</code><nl/>
716    */
717   function getFunction( string name )
718   {
719       return new Function( self.getObject(), name );
720   }
721
722   /**
723    * @function getVariables
724    * @brief Generates an array of the variables in the object associated with this object
725    * @declaration function getVariables( )
726    * @return An array of the variables in this object
727    * @description This function creates an array of the instance (non-static)
728    *              variables which are contained in the object associated with
729    *              this "Object" object. The key strings of the array items
730    *              are the names of the variables. Note that the items in the
731    *              returned array are copies of the object variables, not
732    *              references to them (unless they are objects).
733    * @example <nl/><code>
734    <keyword>class</keyword> TestClass {<nl/>
735    <tab/><type>number</type> id;<nl/>
736    }<nl/>
737    <type>object</type> o = Object.fromData(Test<keyword>class</keyword>,[ 10 ]);<nl/>
738    <type>array</type> vars = o.getVariables(); &raquo; [ 'id' => 10 ]</code><nl/>
739    */
740   native function getVariables()
741   {
742       FeriteHashBucket *buk;
743       FeriteVariable *array, *var;
744       FeriteIterator *iter;
745       FeriteObjectVariable *variables;
746       char *buf;
747
748       buf = FE_CLEAN_STRING(1024);
749       array = ferite_create_uarray_variable(script, "Object::getVars", 32, FE_STATIC);
750       iter = ferite_create_iterator(script);
751
752       for( variables = ObjectObj->variables; variables != NULL; variables = variables->parent )
753       {
754           memset( iter, 0, sizeof(FeriteIterator) );
755           while((buk = (FeriteHashBucket*)ferite_hash_walk(script,variables->variables,iter)) != NULL)
756           {
757               var = buk->data;
758
759               if( !FE_VAR_IS_STATIC(var) && var->state == FE_ITEM_IS_PUBLIC && ferite_uarray_get_from_string(script,VAUA(array),var->name) == NULL )
760               {
761                   ferite_uarray_add(script,VAUA(array),
762                                     ferite_duplicate_variable(script,var, NULL),
763                                     var->name,FE_ARRAY_ADD_AT_END);
764               }
765           }
766       }
767       ffree( buf );
768       ffree( iter );
769       FE_RETURN_VAR(array);
770   }
771
772   /**
773    * @function setVariables
774    * @brief Set the variables in the object associated with this object
775    * @declaration function setVars( array vars )
776    * @param array vars The array of variables to set within the object
777    * @description This function sets the variables within the object
778    *              with this "Object" object to the values in the specified
779    *              array. The key strings of the items in the array are used
780    *              the match the array items to the object variables. Note that
781    *              the type of the object variable and the array item must
782    *              match.
783    * @example <nl/><code>
784    <keyword>class</keyword> TestClass {<nl/>
785    <tab/><type>number</type> id;<nl/>
786    }<nl/>
787    <type>object</type> o = Object.fromData(Test<keyword>class</keyword>,[ 10 ]);<nl/>
788    o.setVariables([ 'id' => 100 ]);</code><nl/>
789    */
790   native function setVariables(array vars)
791   {
792       FeriteHashBucket *buk;
793       FeriteIterator *iter;
794       FeriteVariable *var;
795
796       iter = ferite_create_iterator(script);
797       while((buk = (FeriteHashBucket*)ferite_hash_walk(script,vars->hash,iter)) != NULL)
798       {
799           if(ferite_object_has_var(script,ObjectObj,buk->id))
800           {
801               var = ferite_duplicate_variable( script, buk->data, NULL );
802               ferite_object_set_var(script,ObjectObj,buk->id,var);
803           }
804       }
805       ffree(iter);
806   }
807
808   /**
809    * @function hasMember
810    * @declaration static native function hasMember( object o, string member )
811    * @brief Determines if an object has a particular member
812    * @param object o The object
813    * @param string member The name of the member to look for
814    * @return True if a member exists with that name, otherwise false
815    * @description This function checks whether there is a variable or function
816    *              with the specified name within the specified object. Note
817    *              that it does not provide any way to tell whether the member
818    *              is a function or a variable.
819    * @static
820    * @example <nl/><code>
821    <keyword>class</keyword> TestClass {<nl/>
822    <tab/><type>number</type> id;<nl/>
823    }<nl/>
824    <type>object</type> o = <keyword>new</keyword> TestClass();<nl/>
825    Object.hasMember(o, 'id'); &raquo; <type>true</type></code><nl/>
826    */
827   static native function hasMember( object o, string member )
828   {
829       if( o != NULL )
830       {
831           if( ferite_object_get_var( script, o, member->data ) != NULL )
832           {
833               FE_RETURN_TRUE;
834           }
835           if( ferite_object_get_function( script, o, member->data ) != NULL )
836           {
837               FE_RETURN_TRUE;
838           }
839       }
840       FE_RETURN_FALSE;
841   }
842}
843/**
844 * @end
845 */
846
847/**
848 * @class Function
849 * @brief Instances of this class are used to inspect Ferite functions
850 */
851class Function
852{
853   /**
854    * @function constructor
855    * @brief The constructor of the "Function" class
856    * @declaration function constructor( void o, string f )
857    * @param void o The container the function is a member of (optional)
858    * @param string f The name of the function
859    * @description The constructor of the "Function" class can either be called
860    *              with the absolute name of a function (eg. "Console.println")
861    *              or with an object and the name of a method within the object
862    *              (eg. Console.stdout, "printf"). The specified function will
863    *              be associated with the newly created "Function" object.
864    * @example <nl/><code>
865    <keyword>class</keyword> TestClass {<nl/>
866    <tab/><keyword>function</keyword> g( <type>string</type> name ) {<nl/>
867    <tab/>}<nl/>
868    }<nl/>
869    <nl/>
870    <keyword>function</keyword> f( <type>string</type> name ) {<nl/>
871    }<nl/>
872    <nl/>
873    <type>object</type> t = <keyword>new</keyword> TestClass();<nl/>
874    <type>object</type> o = <keyword>new</keyword> Function('f');<nl/>
875    <type>object</type> p = <keyword>new</keyword> Function(t, 'g');</code><nl/>
876    */
877   native function constructor( string f )
878   {
879       FeriteNamespaceBucket *nsb = NULL;
880
881       self->odata = fmalloc( sizeof( FunctionHolder ) );
882       FunctionObj->container = script->mainns;
883
884       nsb = ferite_find_namespace(script,script->mainns,f->data,FENS_PARENT_NS);
885       if( nsb != NULL )
886           FunctionObj->container = nsb->data;
887
888       nsb = ferite_find_namespace(script,script->mainns,f->data,FENS_FNC);
889       if( nsb != NULL )
890           FunctionObj->func = nsb->data;
891       else
892       {
893           ffree( self->odata );
894           FE_RETURN_NULL_OBJECT;
895       }
896   }
897   native function constructor( void o, string f )
898   {
899       self->odata = fmalloc( sizeof( FunctionHolder ) );
900       FunctionObj->func = NULL;
901       switch( o->type )
902       {
903           case F_VAR_OBJ:
904               FunctionObj->func = ferite_object_get_function(script,VAO(o),f->data);
905               break;
906           case F_VAR_NS:
907           {
908               FeriteNamespaceBucket *nsb = ferite_find_namespace(script,VAN(o),f->data,FENS_FNC);
909               if( nsb != NULL )
910                   FunctionObj->func = nsb->data;
911               break;
912           }
913           case F_VAR_CLASS:
914               FunctionObj->func = ferite_class_get_function(script,VAC(o),f->data);
915               break;
916       }
917       FunctionObj->container = VAP(o);
918
919       if( FunctionObj->func == NULL )
920       {
921           ffree( self->odata );
922           FE_RETURN_NULL_OBJECT;
923       }
924   }
925
926   native function destructor()
927   {
928       if( FunctionObj != NULL )
929         ffree( self->odata );
930   }
931
932   /**
933    * @function exec
934    * @declaration function exec( ... )
935    * @brief Calls the function associated with this object
936    * @return The value which the called function returned
937    * @description This function calls the function associated with this
938    *              "Function" object using the specified arguments. The value
939    *              which the function returned is returned unchanged. If you
940    *              want to pass the arguments as an array instead of as a
941    *              variable argument list, see Function.execWithArray().
942    * @example <nl/><code>
943    <keyword>function</keyword> f( <type>string</type> name ) {<nl/>
944    }<nl/>
945    <type>object</type> o = <keyword>new</keyword> Function('f');<nl/>
946    o.exec( "Hi There" );</code><nl/>
947    */
948   native function exec(...)
949   {
950       FeriteVariable *var, *dup;
951       FeriteVariable **np;
952       int i = 0;
953       int cp = ferite_get_parameter_count(params);
954       np = ferite_create_parameter_list(cp+3);
955
956       for(i = 0; i < cp ; i++)
957       {
958           FUD(("number of real params: '%d'\n",cp));
959           var = params[i];
960           FUD(("param %d: '%s' type '%s'\n",i,var->name, ferite_variable_id_to_str(script,var->type)));
961           if(var->type == F_VAR_STR)
962           {
963               FUD(("\tvalue='%s'\n",VAS(var)));
964           }
965           np[i] = ferite_duplicate_variable( script, var, NULL);
966           MARK_VARIABLE_AS_DISPOSABLE(np[i]);
967       }
968
969       FUD(("arg count: '%d'\n",FunctionObj->func->arg_count));
970       FUD(("calling '%s'...\n",FunctionObj->func->name));
971
972       dup = ferite_call_function(script, FunctionObj->container, current_yield_block, FunctionObj->func, np);
973       ferite_delete_parameter_list(script,np);
974       FUD(("finished\n"));
975
976       if( dup != NULL )
977       {
978           FE_RETURN_VAR(dup);
979       }
980   }
981
982   /**
983    * @function execWithArray
984    * @declaration function execWithArray( array params )
985    * @brief Calls the function associated with this object
986    * @param array params The arguments to pass to the function
987    * @return The value which the called function returned
988    * @description This function calls the function associated with this
989    *              "Function" object using the values in the specified array
990    *              as the function arguments. The value which the function
991    *              returned is returned unchanged. If you want to pass the
992    *              arguments directly instead of as an array, see
993    *              Function.exec().
994    * @example <nl/><code>
995    <keyword>function</keyword> f( <type>string</type> name ) {<nl/>
996    }<nl/>
997    <type>object</type> o = <keyword>new</keyword> Function('f');<nl/>
998    o.execWithArray( [ "Hi There" ] );</code><nl/>
999    */
1000   native function execWithArray( array args )
1001   {
1002       FeriteVariable **plist = ferite_create_parameter_list( args->size + 3 );
1003       FeriteVariable *rval = NULL;
1004       int i = 0;
1005
1006       for( i = 0; i < args->size; i++ ) {
1007           plist[i] = ferite_duplicate_variable( script, args->array[i], NULL );
1008           MARK_VARIABLE_AS_DISPOSABLE(plist[i]);
1009       }
1010       rval = ferite_call_function( script, FunctionObj->container, current_yield_block, FunctionObj->func, plist );
1011       ferite_delete_parameter_list( script, plist );
1012       if( rval != NULL )
1013       {
1014           FE_RETURN_VAR( rval );
1015       }
1016   }
1017
1018   /**
1019    * @function getParameterDetails
1020    * @declaration function getParameterDetails( )
1021    * @brief Generates an array of the parameters the function expects
1022    * @return An array of the parameters required by the function
1023    * @description This function generates an array of the parameters which the
1024    *              function associated with this Function object requires. The
1025    *              key strings are the names of the arguments and the values
1026    *              are the names of the arguments types as strings. Note that
1027    *              this function does not work well in conjunction with
1028    *              argument overloading. The returned argument array will
1029    *              describe the arguments of the first function the compiler
1030    *              encountered with a particular name, but there could be other
1031    *              functions with the same name but different arguments.
1032    * @example <nl/><code>
1033    <keyword>function</keyword> f( <type>string</type> name ) {<nl/>
1034    }<nl/>
1035    <type>object</type> o = <keyword>new</keyword> Function('f');<nl/>
1036    <type>array</type> params = o.getParameterDetails*); &raquo; params = [ 'name' => '<type>string</type>' ]</code><nl/>
1037    */
1038   native function getParameterDetails()
1039   {
1040       int i = 0, argcount = FunctionObj->func->arg_count;
1041       FeriteVariable *retval = NULL, *newvar = NULL;
1042
1043       retval = ferite_create_uarray_variable( script, "Function.getParameterDetails", FunctionObj->func->arg_count, FE_STATIC );
1044       for( i = 0; i < argcount; i++ )
1045       {
1046           if( strcmp( FunctionObj->func->signature[i]->variable->name, "..." ) != 0 )
1047           {
1048               newvar = ferite_create_string_variable_from_ptr( script, "",
1049                                                                ferite_variable_id_to_str( script,
1050                                                                                           FunctionObj->func->signature[i]->variable->type ),
1051                                                                0, FE_CHARSET_DEFAULT, FE_STATIC );
1052           }
1053           else
1054             newvar = ferite_create_string_variable_from_ptr( script, "", "...", 0, FE_CHARSET_DEFAULT, FE_STATIC );
1055           ferite_uarray_add( script, VAUA(retval), newvar, FunctionObj->func->signature[i]->variable->name, FE_ARRAY_ADD_AT_END );
1056       }
1057       FE_RETURN_VAR( retval );
1058   }
1059}
1060/**
1061 * @end
1062 */
1063
1064/**
1065 * @class Variable
1066 * @brief This class allows you to wrap a variable and access the accessor mechanism provided by ferite.
1067 * @example <code>
1068 <keyword>uses</keyword> "console", "reflection";<nl/>
1069 <nl/>
1070 <keyword>class</keyword> VariableWatcher <keyword>extends</span> Variable {<nl/>
1071     <tab/><keyword>function</keyword> get() { <nl/>
1072         <tab/><tab/>Console.println( "get called" ); <nl/>
1073             <tab/><tab/><keyword>return</keyword> "har";<nl/>
1074                 <tab/>}<nl/>
1075     <tab/><keyword>function</keyword> set( <type>void</type> value ) { <nl/>
1076         <tab/><tab/>Console.println( "set called: $value" ); <nl/>
1077             <tab/>}<nl/>
1078     <tab/><keyword>function</keyword> cleanup() { <nl/>
1079         <tab/><tab/><keyword>return</keyword> "cleanup called"; <nl/>
1080             <tab/>}<nl/>
1081 }<nl/>
1082 <nl/>
1083 <type>string</type> v = "";<nl/>
1084 <type>object</type> o = <keyword>new</keyword> VariableWatcher(v);<nl/>
1085 v = "hi";<nl/>
1086 Console.println( v );</code><nl/>
1087 */
1088abstract class Variable
1089{
1090    /**
1091     * @function constructor
1092     * @brief The constructor for a variable class.
1093     * @declaration function constructor( void var )
1094     * @param void var The variable to wrap.
1095     */
1096   native function constructor( void var )
1097   {
1098       ferite_create_variable_accessors( script,
1099                                         var,
1100                                         reflection_variable_get,
1101                                         reflection_variable_set,
1102                                         reflection_variable_cleanup,
1103                                         self );
1104       self->refcount++;
1105   }
1106
1107   function get()
1108   {
1109   }
1110
1111   function set( void value )
1112   {
1113   }
1114
1115   function cleanup()
1116   {
1117
1118   }
1119}
1120/*
1121 * @end
1122 */
1123
1124/**
1125 * @namespace Reflection
1126 * @brief Provides a function for runtime inspection of variables
1127 */
1128namespace Reflection
1129{
1130    /**
1131     * @function type
1132     * @declaration function type( void var )
1133     * @brief Generates a string describing the type of a variable
1134     * @param void var The variable
1135     * @return The name of the type of the variable
1136     */
1137    native function type(void var)
1138    {
1139        FeriteVariable *v = NULL;
1140        char *value = ferite_variable_id_to_str( script, var->type );
1141
1142        if( value != NULL )
1143          v = fe_new_str_static( "Reflection.type.return", value, 0, FE_CHARSET_DEFAULT );
1144        else
1145          v = fe_new_str_static( "Reflection.type.return", "", 0, FE_CHARSET_DEFAULT );
1146
1147        MARK_VARIABLE_AS_DISPOSABLE( v );
1148        FE_RETURN_VAR( v );
1149    }
1150}
1151/**
1152 * @end
1153 */
1154