Hi all, Here's an experiment I worked on yesterday to make creating objects a little easier from PIR. The MakeObject library allows you to create an object by passing its name (or, more usefully, a Key PMC) and a set of named arguments to the initializer.
It then calls the class's BUILDALL() method, if it exists, or the BUILD() methods on each class, least-to-most-derived, passing the arguments. This surprisingly removes a lot of complexity in PIR objects. -- c
=== runtime/parrot/library/MakeObject.pir ================================================================== --- runtime/parrot/library/MakeObject.pir (revision 22977) +++ runtime/parrot/library/MakeObject.pir (local) @@ -0,0 +1,87 @@ +.include "iterator.pasm" + +.namespace [ 'MakeObject' ] + +.sub make_object + .param pmc classname + .param pmc args :slurpy :named + + .local int obj_type + find_type obj_type, classname + + .local pmc obj + obj = new obj_type + + build_all( obj, args ) + .return( obj ) +.end + +.sub build_all + .param pmc obj + .param pmc args + + .local int can_ba + can_ba = can obj, 'BUILDALL' + + unless can_ba goto do_it_yourself + obj.'BUILDALL'( args ) + .return() + + do_it_yourself: + .local pmc class_pmc + class_pmc = class obj + + .local pmc mro + mro = get_mro class_pmc + + .local pmc iter + iter = new .Iterator, mro + set iter, .ITERATE_FROM_END + + .local pmc class_pmc + .local pmc class_ns + .local pmc build_meth + .local int has_build + iter_loop: + unless iter goto iter_end + class_pmc = pop iter + class_ns = get_class_namespace( class_pmc ) + build_meth = class_ns.'find_sub'( 'BUILD' ) + + has_build = defined build_meth + unless has_build goto iter_loop + + obj.build_meth( args ) + + goto iter_loop + + iter_end: + .return() +.end + +.sub get_class_namespace + .param pmc class_pmc + + .local pmc ns + ns = get_hll_namespace + + .local string class_name + class_name = typeof class_pmc + + .local pmc name_array + name_array = split ';', class_name + + .local pmc iter + iter = new .Iterator, name_array + iter = 0 + + .local pmc elem + iter_loop: + unless iter goto iter_end + elem = shift iter + ns = ns.find_namespace( elem ) + goto iter_loop + + iter_end: + .return( ns ) +.end === t/library/make_object.pir ================================================================== --- t/library/make_object.pir (revision 22977) +++ t/library/make_object.pir (local) @@ -0,0 +1,83 @@ +.sub main :main + load_bytecode 'MakeObject.pir' + + build_classes() + + .local pmc make_object + make_object = find_global 'MakeObject', 'make_object' + + .local pmc gk_name + gk_name = new .Array + gk_name = 4 + gk_name[0] = 'Grandchild' + gk_name[1] = 'Happy' + gk_name[2] = 'Fun' + gk_name[3] = 'Class' + + .local pmc gk + gk = make_object( gk_name, 'foo' => 'bar', 'baz' => 'quux' ) +.end + +.sub build_classes + .local pmc parent + parent = newclass 'Parent' + + .local pmc kid_name + .local pmc key_item + kid_name = new .Key + kid_name = 'Child' + key_item = new .Key + key_item = 'Class' + push kid_name, key_item + + .local pmc child + child = subclass 'Parent', kid_name + + .local pmc gk_name + gk_name = new .Key + gk_name = 'Grandchild' + key_item = new .Key + key_item = 'Happy' + push gk_name, key_item + key_item = new .Key + key_item = 'Fun' + push gk_name, key_item + key_item = new .Key + key_item = 'Class' + push gk_name, key_item + + .local pmc grandchild + grandchild = subclass child, gk_name +.end + +.namespace [ 'Parent' ] + +.sub BUILD :method + .param pmc args :slurpy :named + .local pmc foo + foo = args['foo'] + args['baz'] = 'fzort' + print "Build in parent\n" + print "Foo: " + print foo + print "\n" +.end + +.namespace [ 'Child'; 'Class' ] + +.sub BUILD :method + .param pmc args :slurpy :named + print "Build in child\n" +.end + +.namespace [ 'Grandchild'; 'Happy'; 'Fun'; 'Class' ] + +.sub BUILD :method + .param pmc args :slurpy :named + .local pmc baz + baz = args['baz'] + print "Build in grandchild\n" + print "Baz: " + print baz + print "\n" +.end