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

Reply via email to