Skip to content

Instantly share code, notes, and snippets.

@lizmat
Created September 25, 2017 11:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lizmat/16e79ba101327c5780dce9db7f767e49 to your computer and use it in GitHub Desktop.
Save lizmat/16e79ba101327c5780dce9db7f767e49 to your computer and use it in GitHub Desktop.
diff for building custom BUILD methods
diff --git a/src/Perl6/World.nqp b/src/Perl6/World.nqp
index 5e56702..ca71c61 100644
--- a/src/Perl6/World.nqp
+++ b/src/Perl6/World.nqp
@@ -3009,7 +3009,120 @@ class Perl6::World is HLL::World {
$code.set_rw() if $rw;
return $code;
}
+
+ # Generate a method for building a new object that takes a hash
+ # with attribute => value pairs to be assigned to the object's
+ # attributes. Basically a flattened version of Mu.BUILDALL, which
+ # iterates over the BUILDALLPLAN at runtime with fewer inlining
+ # and JITting opportunities.
+ method generate_buildplan_executor($in_object, $in_build_plan) {
+
+ # The basic statements for object initialization, to be
+ # filled in later
+ my $execution := QAST::Stmts.new();
+
+ # The block of the method
+ my $block := QAST::Block.new(
+ :name<BUILDALL>, :blocktype<declaration_static>,
+ QAST::Stmts.new(
+ QAST::Var.new( :decl<param>, :scope<local>, :name<self> ),
+ QAST::Var.new( :decl<param>, :scope<local>, :name('%init') ),
+ QAST::Var.new( :decl<var>, :scope<local>, :name<init> )
+ ),
+ $execution
+ );
+
+ # deconted / low level access
+ my $object := nqp::decont($in_object);
+ my $build_plan := nqp::getattr(
+ nqp::decont($in_build_plan),
+ $!w.find_symbol(['List']),
+ '$!reified'
+ );
+
+ # my $init := nqp::getattr(%init,Map,'$!storage')
+ $execution.push(QAST::Op.new(
+ :op('bind'),
+ (my $init := QAST::Var.new(:scope<local>, :name<init>)),
+ QAST::Op.new(
+ :op('getattr'),
+ QAST::Var.new( :scope<local>, :name('%init') ),
+ QAST::WVal.new( :value($!w.find_symbol(['Map'])) ),
+ QAST::SVal.new( :value('$!storage') )
+ )
+ ));
+
+ my int $count := nqp::elems($build_plan);
+ my int $i := -1;
+ while nqp::islt_i($i := nqp::add_i($i, 1), $count) {
+ if nqp::islist(my $task := nqp::atpos($build_plan,$i)) {
+ if nqp::atpos($task,0) -> $code {
+ }
+
+ # 0 = initialize opaque from %init
+ else {
+# Generate:
+# nqp::if(
+# nqp::existskey($init,'a'),
+# nqp::getattr(self,Foo,'$!a') = %init.AT-KEY('a')
+# ),
+ my $objectop :=
+ QAST::WVal.new( :value( nqp::atpos($task,1) ) );
+ $!w.add_object($objectop);
+
+ my $existskeyop := QAST::Op.new(
+ :op("existskey"),
+ $init,
+ QAST::SVal.new( :value(nqp::atpos($task,2)) )
+ );
+ my $getattrop := QAST::Op.new(
+ :op<getattr>,
+ QAST::Var.new( :name<self>, :scope<local> ),
+ $objectop,
+ QAST::SVal.new( :value( nqp::atpos($task,3) ) )
+ );
+
+ $execution.push(
+ QAST::Op.new( :op<if>,
+ $existskeyop,
+ QAST::Op.new( :op<assign>,
+ $getattrop,
+ QAST::Op.new( :op<callmethod>,
+ QAST::Var.new( :scope<local>, :name('%init') ),
+ QAST::SVal.new( :value<AT-KEY> ),
+ QAST::Op.new( :op<p6box_s>,
+ QAST::SVal.new(:value( nqp::atpos($task,2) ))
+ )
+ )
+ )
+ )
+ );
+ }
+ }
+
+ # BUILD/TWEAK
+ else {
+ }
+ }
+
+ # finally, add the return value
+ $execution.push(QAST::Var.new( :name('self'), :scope('local') ));
+
+ # ?? not sure why this is
+ $!w.cur_lexpad()[0].push($block);
+
+ # Set up signature and create completed Method object
+ my %sig_info := nqp::hash('parameters', [
+ nqp::hash('variable_name', '%init')
+ ]);
+ my $sig := $!w.create_signature_and_params(NQPMu, %sig_info,
+ $block, 'Any', :method, invocant_type => $in_object);
+ my $code := $!w.create_code_object($block, 'Method', $sig);
+
+ return $code;
+ }
}
+
method get_compiler_services() {
unless nqp::isconcrete($!compiler_services) {
try {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment