#!/usr/bin/perl use strict; use warnings; use Perl6::Runtime; use Perl6::Core::Nil; use Perl6::Core::Str; use Perl6::Core::Num; use Perl6::Core::Ref; use Perl6::Core::Hash; use Perl6::Core::List; use Perl6::Core::Block; use Perl6::MM::Opaque; use Perl6::MM::Method; use Perl6::MM::Attribute; use Perl6::MM::C3; use Carp 'confess'; use Scalar::Util 'blessed'; # create our basic variables/functions for # the metamodel that the runtime needs to # have available ... $::Class = undef; $::Object = undef; $::Module = undef; $::Package = undef; # for sending messages to an opaque object # (very primitive at the moment) sub opaque::send { my ($inv, $label, @args) = @_; #warn "calling send for $label"; $label = str->new($label) unless (blessed($label) && $label->isa('str')); my $args = list->new($inv, @args); my $class = $inv->class; # gather all the classes to look through my @classes = ($class); #warn "inv: " . $inv->id->to_native . " => class: " . $inv->class->id->to_native; # we take the MRO first, however at some early # stages of the bootstrap, this is not yet # populated with anything, so .... my $supers = $class->get_attr(symbol->new('@:MRO')); # if nothing is in MRO, we take the superclasses # because we know that is there ... $supers = $class->get_attr(symbol->new('@:superclasses')) if $supers->is_empty == $bit::TRUE; push @classes => $supers->to_native; foreach my $class (@classes) { my $methods = $class->get_attr(symbol->new('%:methods')); #warn "looking for method (" . $label->to_native . ")"; if ($methods->exists($label) == $bit::TRUE) { #warn "calling method (" . $label->to_native . ")"; return $methods->fetch($label)->do($args); } } confess "Method (" . $label->to_native . ") not found in \$::Class " . $class->id->to_native; } $::ENV = Perl6::Runtime::get_top_level_env(); ## ---------------------------------------------------------------------------- ## some metamodel tools =pod sub *WALKMETH (block &dispatcher, symbol $label, hash %opts) returns method { while (my $current = &dispatcher.()) { return $current.get_method($label, %opts) if $current.has_method($label, %opts); } } # alternate p6 version sub *WALKMETH (block &dispatcher, symbol $label, hash %opts) returns method { { (&dispatcher.() // return).get_method($label, %opts) || redo } } (closure *WALKMETH ((block &dispatcher) (symbol $label) (hash ?%opts)) returns method ((= $method NIL) (= $current (&dispatcher do)) (while (($current is_not_nil) and ($method is_nil)) (($current send (has_method $label)) and (= $method ($current send (get_method $label))) (= $current (&dispatcher do)))) ($method)) =cut $::ENV->create('WALKMETH' => closure->new( $::ENV, closure::signature->new( params => closure::params->new( symbol->new('&dispatcher' => 'block'), symbol->new('$label' => 'symbol'), symbol->new('?%opts' => 'hash'), ), returns => 'method' ), sub { my $e = shift; $e->create('$method' => $nil::NIL); $e->create('$current' => $e->get('&dispatcher')->do()); block->new($e, sub { my $e = shift; $e->get('$current') ->send('has_method' => $e->get('$label')) ->and( block->new($e, sub { my $e = shift; $e->set('$method' => $e->get('$current')->send('get_method' => $e->get('$label'))); }) ); $e->set('$current' => $e->get('&dispatcher')->do()); })->do_while( block->new($e, sub { my $e = shift; $e->get('$current') ->is_not_nil ->and( block->new($e, sub { my $e = shift; $e->get('$method')->is_nil }) ); }) ); return $e->get('$method'); } ) ); =pod sub *WALKCLASS (block &dispatcher) returns opaque { &dispatcher.() } (closure *WALKCLASS ((block &dispatcher)) returns opaque (&dispatcher do) =cut $::ENV->create('WALKCLASS' => closure->new( $::ENV, closure::signature->new( params => closure::params->new(symbol->new('&dispatcher' => 'block')), returns => 'opaque' ), sub { my $e = shift; return $e->get('&dispatcher')->do(); } ) ); ## ---------------------------------------------------------------------------- ## now begin creating the metamodel, starting with Class =pod class Class { has @:MRO; has @:subclasses; has @:superclasses; has %:private_methods; has %:attributes; has %:methods; } (class (Class) ((attribute new (@:MRO)) (list) (attribute new (@:subclasses)) (list) (attribute new (@:superclasses)) (list) (attribute new (%:private_methods)) (hash) (attribute new (%:attributes)) (hash) (attribute new (%:methods)) (hash))) =cut # create the basic Class $::Class = opaque->new( reference->new($opaque::NULL_OBJECT), hash->new( attribute->new('@:MRO') => list->new(), attribute->new('@:subclasses') => list->new(), attribute->new('@:superclasses') => list->new(), attribute->new('%:private_methods') => hash->new(), attribute->new('%:attributes') => hash->new(), attribute->new('%:methods') => hash->new(), ) ); # link Class back to Class $::Class->change_class($::Class); =pod method add_method (opaque $self: symbol $label, method $method) returns nil { %:methods{$label} = $method; } (method add_method ((opaque $self:) (symbol $label) (method $method)) returns nil ((($self: get_attr (symbol new (%:methods))) store ($label $method)))) =cut { # add the first method my $_add_method = method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol'), symbol->new('$method' => 'method') ), returns => 'nil' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:methods')) ->store( $e->get('$label'), $e->get('$method') ); } ); # and use it to add itself to the $::Class $_add_method->do(list->new($::Class, symbol->new('add_method'), $_add_method)); } =pod method has_method (opaque $self: symbol $label) returns bit { %:methods.exists($label); } (method has_method ((opaque $self:) (symbol $label)) returns bit ((($self: get_attr (symbol new (%:methods))) exists ($label)))) =cut $::Class->send('add_method' => ( # method label symbol->new('has_method'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol') ), returns => 'bit' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:methods')) ->exists($e->get('$label')); } ) ) ); =pod method get_method (opaque $self: symbol $label) returns method { %:methods{$label}; } (method get_method ((opaque $self:) (symbol $label)) returns method ((($self: get_attr (symbol new (%:methods))) fetch ($label)))) =cut $::Class->send('add_method' => ( # method label symbol->new('get_method'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol') ), returns => 'method' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:methods')) ->fetch($e->get('$label')); } ) ) ); =pod method remove_method (opaque $self: symbol $label) returns nil { %:methods.delete($label); } (method remove_method ((opaque $self:) (symbol $label)) returns nil ((($self: get_attr (symbol new (%:methods))) delete ($label)))) =cut $::Class->send('add_method' => ( # method label symbol->new('remove_method'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol') ), returns => 'nil' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:methods')) ->remove($e->get('$label')); } ) ) ); =pod method get_method_list (opaque $self:) returns list { %:methods.keys; } (method get_method_list ((opaque $self:)) returns list ((($self: get_attr (symbol new (%:methods))) keys))) =cut $::Class->send('add_method' => ( # method label symbol->new('get_method_list'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'list' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:methods')) ->keys(); } ) ) ); =pod method new (opaque $class: hash %params) returns opaque { $class.bless(undef, %params // hash()); } (method new ((opaque $class:) (hash ?%params)) returns opaque (((?%params is_nil) and (= ?%params (hash new))) ($class: send (bless (NIL ?%params))))) =cut $::Class->send('add_method' => ( # method label symbol->new('new'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$class:' => 'opaque'), symbol->new('?%params' => 'hash') ), returns => 'opaque' ), sub { my $e = shift; $e->get('?%params') ->is_nil ->and(block->new($e, sub { my $e = shift; $e->set('?%params' => hash->new()); })); $e->get('$class:')->send('bless' => (str->new(), $e->get('?%params'))); } ) ) ); =pod method bless (opaque $class: str $canidate, hash %params) returns opaque { $canidate //= 'P6opaque'; my $self = $class.CREATE(repr => $canidate, %params); $self.BUILDALL($params); return $self; } (method bless ((opaque $class:) (str $canidate) (hash %params)) returns opaque ((($canidate to_bit) or (= $canidate (str new ('P6opaque')))) (= ($self ($class: send (CREATE ($canidate %params))))) ($self send (BUILDALL %params)) ($self))) =cut $::Class->send('add_method' => ( # method label symbol->new('bless'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$class:' => 'opaque'), symbol->new('$canidate' => 'str'), symbol->new('%params' => 'hash') ), returns => 'opaque' ), sub { my $e = shift; # p6opaque is our default $e->get('$canidate') ->to_bit ->or(block->new($e, sub { my $e = shift; $e->set('$canidate' => str->new('P6opaque')) })); # create and init the object $e->create('$self' => $e->get('$class:')->send('CREATE' => ($e->get('$canidate'), $e->get('%params')))); $e->get('$self')->send('BUILDALL' => ($e->get('%params'))); return $e->get('$self'); } ) ) ); =pod method CREATE (opaque $class: str $repr, hash %params) returns opaque { my %attrs; my $dispatcher = $class.dispatcher(:descendant); for WALKCLASS($dispatcher) -> $c { for $c->get_attribute_list() -> $attr { %attrs{$attr->name} = $attr.instantiate_container(); } } my $self = opaque.new(\$class, %attrs); return $self; } method CREATE (opaque $class: str $repr, hash %params) returns opaque { my %attrs = hash(); my &dispatcher = $class.dispatcher(:descendent); my $c = WALKCLASS(&dispatcher); while (!$c.defined) { $c.get_attributes().map:{ %attrs{$_.meta.name()} = $_.meta.instantite_container(); }; $c = WALKCLASS(&dispatcher); } return opaque.new(\$class, %attrs) } (method CREATE ((opaque $class:) (str $repr) (hash %params)) returns opaque ((= %attrs (hash new)) (= &dispatcher ($class: send (dispatcher :descendent))) (= $c (WALKCLASS (&dispatcher))) (while ($c is_not_nil) ((($c send (get_attributes)) apply ((= %attrs store (($_ name) ($_ instantite_container))) (= $c (WALKCLASS (&dispatcher))))))) (opaque new (\$class: %attrs))) =cut $::Class->send('add_method' => ( # method label symbol->new('CREATE'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$class:' => 'opaque'), symbol->new('$repr' => 'str'), symbol->new('%params' => 'hash') ), returns => 'opaque' ), sub { my $e = shift; $e->create('$attrs' => hash->new()); $e->create('&dispatcher' => $e->get('$class:')->send('dispatcher' => (symbol->new(':descendant')))); $e->create('$c' => $e->get('WALKCLASS')->do(list->new($e->get('&dispatcher')))); block->new($e, sub { my $e = shift; $e->get('$c') ->send('get_attributes') ->apply( block->new($e, sub { my $e = shift; $e->get('$attrs') ->store( $e->get('$_')->name => $e->get('$_')->instantiate_container ); }) ); $e->set('$c' => $e->get('WALKCLASS')->do(list->new($e->get('&dispatcher')))); })->do_while( block->new($e, sub { my $e = shift; $e->get('$c')->is_not_nil; }) ); return opaque->new(reference->new($e->get('$class:')), $e->get('$attrs')); } ) ) ); =pod method BUILDALL (opaque $self: hash %params) returns nil { my $dispatcher = $self.dispatcher(:descendant); for WALKMETH($dispatcher, 'BUILD') -> $method { $method.($self, %params); } } (method BUILDALL ((opaque $self:) (hash %params)) returns nil ((= &dispatcher (($self: class) send (dispatcher :descendant))) (= $method (WALKMETH (&dispatcher (symbol new BUILD)))) (while ($method is_not_nil) ($method do ($self %params)) (= $method (WALKMETH (&dispatcher (symbol new BUILD))))))) =cut $::Class->send('add_method' => ( # method label symbol->new('BUILDALL'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('%params' => 'hash') ), returns => 'nil' ), sub { my $e = shift; $e->create('&dispatcher' => $e->get('$self:')->class->send('dispatcher' => symbol->new(':descendant'))); $e->create('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('BUILD')))); block->new($e, sub { my $e = shift; $e->get('$method')->do(list->new($e->get('$self:'), $e->get('%params'))); $e->set('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('BUILD')))); })->do_while( block->new($e, sub { my $e = shift; $e->get('$method')->is_not_nil; }) ); return $nil::NIL; } ) ) ); =pod method BUILD (opaque $self: hash %params) returns nil { for %params.kv -> $key, $value { # not sure if this is the # correct syntax for fetching # an attribute symbolically $.($key) = $value if $.($key); } } (method BUILD ((opaque $self:) (hash %params)) returns nil ((%params keys) apply ($self: set_attrs ((symbol new ($_)) (%params fetch ($_))))) (nil)) =cut $::Class->send('add_method' => ( # method label symbol->new('BUILD'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('%params' => 'hash') ), returns => 'nil' ), sub { my $e = shift; $e->get('%params') ->keys ->apply( block->new($e, sub { my $e = shift; $e->get('$self:') ->set_attr( symbol->new($e->get('$_')->to_native), $e->get('%params')->fetch($e->get('$_')) ); }) ); return $nil::NIL; } ) ) ); =pod method DESTROYALL (opaque $self:) returns nil { my $dispatcher = $self.dispatcher(:descendant); for WALKMETH($dispatcher, 'DESTROYALL') -> $method { $method.($self); } } (method DESTROYALL ((opaque $self:) (hash %params)) returns nil ((= &dispatcher (($self: class) send (dispatcher :ascendant))) (= $method (WALKMETH (&dispatcher (symbol new DESTROY)))) (while ($method is_not_nil) ($method do ($self %params)) (= $method (WALKMETH (&dispatcher (symbol new DESTROY))))))) =cut $::Class->send('add_method' => ( # method label symbol->new('DESTROYALL'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'nil' ), sub { my $e = shift; $e->create('&dispatcher' => $e->get('$self:')->class->send('dispatcher' => symbol->new(':ascendant'))); $e->create('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('DESTROY')))); block->new($e, sub { my $e = shift; $e->get('$method')->do(list->new($e->get('$self:'), $e->get('%params'))); $e->set('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('DESTROY')))); })->do_until( block->new($e, sub { my $e = shift; $e->get('$method')->is_nil; }) ); return $nil::NIL; } ) ) ); =pod method id (opaque $self:) returns num { # speculative syntax here :) unbox($self).id } (method id ((opaque $self:)) returns num ($self: id)) =cut $::Class->send('add_method' => ( # method label symbol->new('id'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'num' ), sub { my $e = shift; $e->get('$self:')->id; } ) ) ); =pod method class (opaque $self:) returns opaque { # speculative syntax here :) unbox($self).class } (method class ((opaque $self:)) returns opaque ($self: class)) =cut $::Class->send('add_method' => ( # method label symbol->new('class'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'opaque' ), sub { my $e = shift; return $e->get('$self:')->class; } ) ) ); =pod method superclasses (opaque $self: list ?@superclasses) returns list { if (@superclasses.defined) { for @superclasses -> $super { $super.add_subclass($self); } @:superclasses = @superclasses; @:MRO = (); $self.MRO(); } return @:superclasses; } (method superclasses ((opaque $self) (list ?@superclasses)) returns list ((?@superclasses is_nil) or (?@superclasses apply ($_ send (add_subclass $self:)) ($self: set_attr ((symbol new @:superclasses) (?@superclasses))) ($self: set_attr ((symbol new @:MRO) (list new))) ($self: send (MRO)))) ($self: get_attr (symbol new @:superclasses))) =cut $::Class->send('add_method' => ( # method label symbol->new('superclasses'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('?@superclasses' => 'list'), ), returns => 'list' ), sub { my $e = shift; $e->get('?@superclasses') ->is_nil ->or( block->new($e, sub { $e->get('?@superclasses') ->apply( block->new($e, sub { my $e = shift; $e->get('$_')->send('add_subclass' => $e->get('$self:')); }) ); $e->get('$self:')->set_attr(symbol->new('@:superclasses') => $e->get('?@superclasses')); # clear the MRO now $e->get('$self:')->set_attr(symbol->new('@:MRO') => list->new()); # and recalculate it .. $e->get('$self:')->send('MRO'); }) ); $e->get('$self:')->get_attr(symbol->new('@:superclasses')); } ) ) ); =pod method subclasses (opaque $self:) returns list { @:subclasses; } (method subclasses ((opaque $self:)) returns list ($self: get_attr (symbol new @:subclasses))) =cut $::Class->send('add_method' => ( # method label symbol->new('subclasses'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'list' ), sub { my $e = shift; $e->get('$self:')->get_attr(symbol->new('@:subclasses')); } ) ) ); =pod method add_subclass (opaque $self: opaque $subclass) returns nil { @:subclasses.push($subclass); } (method add_subclass ((opaque $self:) (opaque $subclass)) returns nil (($self: get_attr (symbol new @:subclasses)) push ($subclass))) =cut $::Class->send('add_method' => ( # method label symbol->new('add_subclass'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$subclass' => 'opaque'), ), returns => 'nil' ), sub { my $e = shift; $e->get('$self:')->get_attr(symbol->new('@:subclasses'))->push($e->get('$subclass')); } ) ) ); =pod method _merge (opaque $self:) returns list { ... } =cut $::Class->send('add_method' => ( # method label symbol->new('_merge'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'list' ), sub { my $e = shift; C3->new($e->get('$self:'))->linearize; } ) ) ); =pod method MRO (opaque $self:) returns list { unless (@:MRO) { @:MRO = $self._merge(); } @:MRO; } (method MRO ((opaque $self:)) returns list (($self: get_attr (symbol new @:MRO)) is_empty) and ($self: set_attr ((symbol new @:MRO) ($self: send (_merge)))) ($self: get_attr (symbol new @:MRO))) =cut $::Class->send('add_method' => ( # method label symbol->new('MRO'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'list' ), sub { my $e = shift; # if it is empty ... $e->get('$self:') ->get_attr(symbol->new('@:MRO')) ->is_empty ->and( block->new($e, sub { my $e = shift; $e->get('$self:') ->set_attr( symbol->new('@:MRO'), $e->get('$self:')->send('_merge') ); }) ); return $e->get('$self:')->get_attr(symbol->new('@:MRO')); } ) ) ); =pod method dispatcher (opaque $self: symbol $order) returns block { $order = ':ascendant' if !~$order || $order == ':canonical'; ... } =cut $::Class->send('add_method' => ( # method label symbol->new('dispatcher'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('?$order' => 'symbol') ), returns => 'block' ), sub { my $e = shift; my $self = $e->get('$self:'); my $order = $e->get('?$order'); $order = str->new(':ascendant') # C3 is the canonical order if $order == $nil::NIL || $order->equal_to(str->new(':canonical')); my $dispatcher; if ($order->equal_to(str->new(':descendant')) == $bit::TRUE) { $dispatcher = $self->send('_make_descendant_dispatcher'); } elsif ($order->equal_to(str->new(':ascendant')) == $bit::TRUE) { $dispatcher = $self->send('_make_ascendant_dispatcher'); } else { confess 'Unsupported dispatch order ($order)' } return $dispatcher; } ) ) ); =pod method _make_dispatcher_iterator (opaque $self: list @values) returns block { my $counter = 0; return sub { return @values[$counter++]; }; } =cut $::Class->send('add_method' => ( # method label symbol->new('_make_dispatcher_iterator'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('@values' => 'list') ), returns => 'block' ), sub { my $e = shift; $e->create('$counter' => num->new(0)); return block->new($e, sub { my $e = shift; $e->create('$temp' => $e->get('$counter')); $e->set('$counter' => $e->get('$counter')->increment); return $e->get('@values')->fetch($e->get('$temp')); }); } ) ) ); =pod method _make_descendant_dispatcher (opaque $self:) returns block { $self._make_dispatcher_iterator(@:MRO.reverse); } =cut $::Class->send('add_method' => ( # method label symbol->new('_make_descendant_dispatcher'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'block' ), sub { my $e = shift; $e->get('$self:')->send('_make_dispatcher_iterator' => $e->get('$self:')->send('MRO')->reverse); } ) ) ); =pod method _make_ascendant_dispatcher (opaque $self:) returns block { $self._make_dispatcher_iterator(@:MRO); } =cut $::Class->send('add_method' => ( # method label symbol->new('_make_ascendant_dispatcher'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'block' ), sub { my $e = shift; $e->get('$self:')->send('_make_dispatcher_iterator' => $e->get('$self:')->send('MRO')); } ) ) ); =pod =cut $::Class->send('add_method' => ( # method label symbol->new('is_a'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$class' => 'opaque'), ), returns => 'bit' ), sub { my $e = shift; $e->create('$return' => bit->new(0)); $e->get('$self:') ->id ->equal_to( $e->get('$class')->id )->and( block->new($e, sub { my $e = shift; $e->set('$return' => bit->new(1)) }) ); $e->create('$dispatcher' => $e->get('$self:')->send('dispatcher', symbol->new(':canonical'))); $e->create('$next' => $e->get('$dispatcher')->do()); block->new($e, sub { $e->get('$next') ->id ->equal_to( $e->get('$class')->id )->and( block->new($e, sub { my $e = shift; $e->set('$return' => bit->new(1)) }) ); $e->set('$next' => $e->get('$dispatcher')->do()); })->do_while( block->new($e, sub { my $e = shift; ($e->get('$return') == $bit::FALSE && $e->get('$next') != $nil::NIL) ? $bit::TRUE : $bit::FALSE }) ); return $e->get('$return'); } ) ) ); =pod =cut $::Class->send('add_method' => ( # method label symbol->new('add_attribute'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol'), symbol->new('$attribute' => 'attribute'), ), returns => 'nil' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:attributes')) ->store( $e->get('$label'), $e->get('$attribute') ); } ) ) ); =pod =cut $::Class->send('add_method' => ( # method label symbol->new('get_attribute'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol'), ), returns => 'attribute' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:attributes')) ->fetch($e->get('$label')); } ) ) ); =pod =cut $::Class->send('add_attribute', (symbol->new('@:MRO') => attribute->new('@:MRO' => 'list'))); $::Class->send('add_attribute', (symbol->new('@:superclasses') => attribute->new('@:superclasses' => 'list'))); $::Class->send('add_attribute', (symbol->new('@:subclasses') => attribute->new('@:subclasses' => 'list'))); $::Class->send('add_attribute', (symbol->new('%:private_methods') => attribute->new('%:private_methods' => 'hash'))); $::Class->send('add_attribute', (symbol->new('%:attributes') => attribute->new('%:attributes' => 'hash'))); $::Class->send('add_attribute', (symbol->new('%:methods') => attribute->new('%:methods' => 'hash'))); =pod =cut $::Class->send('add_method' => ( # method label symbol->new('has_attribute'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol'), ), returns => 'bit' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:attributes')) ->exists($e->get('$label')); } ) ) ); =pod =cut $::Class->send('add_method' => ( # method label symbol->new('get_attribute_list'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'list' ), sub { my $e = shift; $e->get('$self:')->get_attr(symbol->new('%:attributes'))->keys(); } ) ) ); =pod =cut $::Class->send('add_method' => ( # method label symbol->new('get_attributes'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'list' ), sub { my $e = shift; $e->get('$self:')->get_attr(symbol->new('%:attributes'))->values(); } ) ) ); ## ---------------------------------------------------------------------------- ## now build Object, so we can create something here $::Object = $::Class->send('new'); $::Object->send('add_method' => ( # method label symbol->new('BUILD'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('%params' => 'hash') ), returns => 'nil' ), sub { my $e = shift; $e->get('%params') ->keys ->apply( block->new($e, sub { my $e = shift; $e->get('$self:') ->set_attr( symbol->new($e->get('$_')->to_native), $e->get('%params')->fetch($e->get('$_')) ); }) ); return $nil::NIL; } ) ) ); $::Object->send('add_method' => ( # method label symbol->new('BUILDALL'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('%params' => 'hash') ), returns => 'nil' ), sub { my $e = shift; $e->create('&dispatcher' => $e->get('$self:')->class->send('dispatcher' => symbol->new(':descendant'))); $e->create('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('BUILD')))); block->new($e, sub { my $e = shift; $e->get('$method')->do(list->new($e->get('$self:'), $e->get('%params'))); $e->set('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('BUILD')))); })->do_until( block->new($e, sub { my $e = shift; $e->get('$method')->is_nil; }) ); return $nil::NIL; } ) ) ); $::Object->send('add_method' => ( # method label symbol->new('id'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'num' ), sub { my $e = shift; $e->get('$self:')->id; } ) ) ); $::Object->send('add_method' => ( # method label symbol->new('class'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'opaque' ), sub { my $e = shift; return $e->get('$self:')->class; } ) ) ); $::Object->send('add_method' => ( # method label symbol->new('can'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol'), ), returns => 'method' ), sub { my $e = shift; $e->get('WALKMETH') ->do(list->new( $e->get('$self:')->class->send('dispatcher' => symbol->new(':canonical')), $e->get('$label') )); } ) ) ); $::Object->send('add_method' => ( # method label symbol->new('DESTROYALL'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'nil' ), sub { my $e = shift; $e->create('&dispatcher' => $e->get('$self:')->class->send('dispatcher' => symbol->new(':ascendant'))); $e->create('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('DESTROY')))); block->new($e, sub { my $e = shift; $e->get('$method')->do(list->new($e->get('$self:'), $e->get('%params'))); $e->set('$method' => $e->get('WALKMETH')->do(list->new($e->get('&dispatcher'), symbol->new('DESTROY')))); })->do_until( block->new($e, sub { my $e = shift; $e->get('$method')->is_nil; }) ); return $nil::NIL; } ) ) ); ## ---------------------------------------------------------------------------- ## now build Package & Module, so we can create something here $::Package = $::Class->send('new'); $::Package->send('superclasses' => list->new($::Object)); $::Package->send('add_attribute', (symbol->new('$:name') => attribute->new('$:name' => 'str'))); $::Package->send('add_attribute', (symbol->new('%:namespace') => attribute->new('%:namespace' => 'hash'))); $::Package->send('add_method' => ( # method label symbol->new('name'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('?$name' => 'str'), ), returns => 'str' ), sub { my $e = shift; $e->get('?$name') ->is_not_nil ->and(block->new($e, sub { my $e = shift; $e->get('$self:')->set_attr(symbol->new('$:name'), $e->get('?$name')); })); $e->get('$self:')->get_attr(symbol->new('$:name')); } ) ) ); $::Package->send('add_method' => ( # method label symbol->new('FETCH'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol'), ), returns => 'type' ), sub { my $e = shift; $e->create('$return' => $nil::NIL); $e->get('$label') ->to_str ->is_equal(str->new('{}')) ->and(block->new($e, sub { $e->set('$return' => $e->get('$self:')->get_attr(symbol->new('%:namespace'))); })) ->or(block->new($e, sub { $e->set('$return' => $e->get('$self:')->get_attr(symbol->new('%:namespace'))->fetch($e->get('$label'))); })); $e->get('$return'); } ) ) ); $::Package->send('add_method' => ( # method label symbol->new('STORE'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('$label' => 'symbol'), symbol->new('$value' => 'type'), ), returns => 'nil' ), sub { my $e = shift; $e->get('$self:') ->get_attr(symbol->new('%:namespace')) ->store( $e->get('$label'), $e->get('$value') ); } ) ) ); ## ---------------------------------------------------------------------------- ## add Module $::Module = $::Class->send('new'); $::Module->send('superclasses' => list->new($::Package)); $::Module->send('add_attribute', (symbol->new('$:version') => attribute->new('$:version' => 'str'))); $::Module->send('add_attribute', (symbol->new('$:authority') => attribute->new('$:authority' => 'str'))); $::Module->send('add_method' => ( # method label symbol->new('version'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('?$version' => 'str'), ), returns => 'str' ), sub { my $e = shift; $e->get('?$version') ->is_not_nil ->and(block->new($e, sub { my $e = shift; $e->get('$self:')->set_attr(symbol->new('$:version'), $e->get('?$version')); })); $e->get('$self:')->get_attr(symbol->new('$:version')); } ) ) ); $::Module->send('add_method' => ( # method label symbol->new('authority'), # method body method->new( $::ENV, method::signature->new( params => method::params->new( symbol->new('$self:' => 'opaque'), symbol->new('?$authority' => 'str'), ), returns => 'str' ), sub { my $e = shift; $e->get('?$authority') ->is_not_nil ->and(block->new($e, sub { my $e = shift; $e->get('$self:')->set_attr(symbol->new('$:authority'), $e->get('?$authority')); })); $e->get('$self:')->get_attr(symbol->new('$:authority')); } ) ) ); $::Module->send('add_method' => ( # method label symbol->new('identifier'), # method body method->new( $::ENV, method::signature->new( params => method::params->new(symbol->new('$self:' => 'opaque')), returns => 'str' ), sub { my $e = shift; $e->create('$identifier' => $e->get('$self:')->get_attr(symbol->new('$:name'))); $e->get('$self:') ->get_attr(symbol->new('$:version')) ->to_bit() ->and(block->new($e, sub { my $e = shift; $e->set('$identifier' => $e->get('$identifier') ->concat( str->new('-') ) ->concat( $e->get('$self:')->get_attr(symbol->new('$:version')) ) ); })); $e->get('$self:') ->get_attr(symbol->new('$:authority')) ->to_bit() ->and(block->new($e, sub { my $e = shift; $e->set('$identifier' => $e->get('$identifier') ->concat( str->new('-') ) ->concat( $e->get('$self:')->get_attr(symbol->new('$:authority')) ) ); })); $e->get('$identifier'); } ) ) ); ## ---------------------------------------------------------------------------- ## finishing up the boostrapping # < Class is subclass of Object > $::Class->set_attr(symbol->new('@:superclasses') => list->new($::Module)); $::Module->set_attr(symbol->new('@:subclasses') => list->new($::Class)); # NOTE: # this is to avoid recursion $::Class->set_attr(symbol->new('@:MRO') => list->new($::Class, $::Module, $::Package, $::Object)); $::Object->set_attr(symbol->new('@:MRO') => list->new($::Object)); foreach my $meta ($::Class, $::Object, $::Package, $::Module) { $meta->add_attr(symbol->new('$:name' => 'str')); $meta->add_attr(symbol->new('%:namespace' => 'hash')); $meta->add_attr(symbol->new('$:version' => 'str')); $meta->add_attr(symbol->new('$:authority' => 'str')); } # add their names in $::Class->send('name' => str->new('Class')); $::Object->send('name' => str->new('Object')); $::Package->send('name' => str->new('Package')); $::Module->send('name' => str->new('Module')); 1; __END__