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(); » [ '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(); » [ '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(); » "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'); » 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(); » [ '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'); » <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*); » 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