7 $LexicalPrelude{'&True'} := sub {::True}
8 $LexicalPrelude{'&False'} := sub {::False}
11 method ACCEPTS($thing) {
12 PRIMITIVES::ritest((|$thing),PRIMITIVES::SMOP_RI(2));
16 my sub return(|$capture) {
17 my $e = ::ControlExceptionReturn.new();
18 $e.capture = $capture;
19 $e.routine = CALLER::<&?ROUTINE>;
26 ############## Operators ##############
28 # TODO change binds to sub definitions
30 $LexicalPrelude{'&infix:+:(int,int)'} := sub ($a,$b) {
31 PRIMITIVES::int_add($a.FETCH,$b.FETCH);
34 $LexicalPrelude{'&infix:<:(int,int)'} := sub ($a,$b) {
35 PRIMITIVES::int_less($a.FETCH,$b.FETCH);
38 $LexicalPrelude{'&infix:-:(int,int)'} := sub ($a,$b) {
39 PRIMITIVES::int_substract($a.FETCH,$b.FETCH);
42 $LexicalPrelude{'&infix:==:(int,int)'} := sub ($a,$b) {
43 PRIMITIVES::int_equal($a.FETCH,$b.FETCH);
46 $LexicalPrelude{'&infix:~'} := sub (|$capture) {
50 if &infix:<==>:(int,int)($i.FETCH,$capture.elems) {
53 $str = PRIMITIVES::idconst_concat($str.FETCH,$capture.positional($i.FETCH).FETCH.Str);
54 $i = &infix:<+>:(int,int)($i.FETCH,1);
58 $LexicalPrelude{'&infix:eq'} := sub ($a,$b) {
59 PRIMITIVES::idconst_eq($a.Str,$b.Str);
61 $LexicalPrelude{'&infix:ne'} := sub ($a,$b) {
62 if PRIMITIVES::idconst_eq($a.Str,$b.Str) {
68 $LexicalPrelude{'&postfix:++'} := sub ($a) {
69 $a = &infix:<+>:(int,int)($a,1);
71 $LexicalPrelude{'&prefix:++'} := sub ($a) {
73 $a = &infix:<+>:(int,int)($a,1);
77 ############## RoleHOW ##############
79 my sub copy_methods($dst,$src) {
81 $dst.^!methods{$key.FETCH} = $src.^!methods{$key.FETCH};
82 },$src.^!methods.keys);
84 my sub copy_does($dst,$src) {
87 if &infix:<==>:(int,int)($i,$src.^!does.elems) {
90 $dst.^!does[$i.FETCH] = $src.^!does[$i.FETCH];
91 $i = &infix:<+>:(int,int)($i.FETCH,1);
95 my sub compose_role($obj,$role) {
96 $obj.^!does.push((|$role));
98 if $obj.^!methods{$key.FETCH} {
99 ::Exception.new.throw;
101 $obj.^add_method($key.FETCH,$role.^!methods{$key.FETCH}.FETCH);
102 },$role.^!methods.keys);
105 method add_attribute($object, $privname, $attribute) {
106 $object.^!attributes{$privname.FETCH} = $attribute;
108 method compose_role($object, $role) {
109 compose_role($object,$role);
111 method add_method($object, $name, $code) {
112 $object.^!methods{$name.FETCH} = $code
114 method dispatch($object, $identifier, \$capture) {
115 if PRIMITIVES::idconst_eq($identifier.FETCH,'FETCH') {
116 # in item context, returns itself.
119 # Roles are not classes! so we're going to delegate this to a
120 # punned class that does this role. For now, we're going to pun a
121 # new class every time, then we'll think in some sort of caching.
123 if $object.^!instance_storage.exists('CACHED_PUNNED_CLASS') {
124 $punned = $object.^!instance_storage{'CACHED_PUNNED_CLASS'};
126 my $class = ::p6opaque.^!CREATE;
127 $class.^!how = ::PrototypeHOW;
130 $class.^!who = $object.^!who;
132 $class.^!does.push((|$object));
133 # $class.^compose_role(::LowObject);
134 # $class.^compose_role($object);
135 copy_methods($class,::LowObject);
136 copy_methods($class,$object);
138 $object.^!instance_storage{'CACHED_PUNNED_CLASS'} = $class;
140 my $delegated = ::Scalar.new($capture.delegate($punned.FETCH));
141 return $punned.^dispatch($identifier.FETCH, (|$delegated));
147 my $obj = ::p6opaque.^!CREATE;
148 $obj.^!how = self.^!how;
149 $obj.^!who = self.^!who;
150 copy_methods($obj,self);
151 copy_does($obj,self);
152 if $obj.^!methods{'BUILDALL'} {
157 method ACCEPTS($obj) {
158 my $role = self.^!does[0];
161 if PRIMITIVES::pointer_equal((|$role),(|$r)) {
163 } elsif self.ACCEPTS($r) {
171 ############## basic subroutines ##############
173 my sub map($expression,$values) {
175 my $ret = ::Array.new;
177 if &infix:<==>:(int,int)($i,$values.elems) {
180 $ret.push((|$expression($values[$i.FETCH])));
181 $i = &infix:<+>:(int,int)($i.FETCH,1);
186 my sub grep($expression,$values) {
188 my $ret = ::Array.new;
190 if &infix:<==>:(int,int)($i,$values.elems) {
193 if ($expression($values[$i.FETCH])) {
194 $ret.push($values[$i.FETCH].FETCH);
197 $i = &infix:<+>:(int,int)($i.FETCH,1);
202 my sub say(|$capture) {
205 if &infix:<==>:(int,int)($i,$capture.elems) {
209 $OUT.print($capture.positional($i.FETCH).Str);
210 $i = &infix:<+>:(int,int)($i.FETCH,1);
215 my sub print(|$capture) {
218 if &infix:<==>:(int,int)($i,$capture.elems) {
221 $OUT.print($capture.positional($i.FETCH).Str);
222 $i = &infix:<+>:(int,int)($i.FETCH,1);
234 $LexicalPrelude{'&prefix:not'} := ¬
235 $LexicalPrelude{'&prefix:!'} := ¬
237 ############## Signatures ##############
239 my role ReadonlyWrapper {
244 method STORE($value) {
245 ::Exception.new.throw;
251 method ACCEPTS(\$capture) {
257 if $param.ACCEPTS_param($capture,$i,$named) {
259 ::Exception.new.throw;
267 if &infix:<==>:(int,int)($i,$capture.elems) {
268 if &infix:<==>:(int,int)($named,$capture.named_count) {
277 method BIND(\$capture,$scope) {
280 $param.BIND($scope,$capture,$i);
284 self.params = ::Array.new;
286 method compare($other) {
289 my $pos_self = grep(sub ($param) {::Positional.ACCEPTS($param.FETCH)},self.params);
291 my $pos_other = grep(sub ($param) {::Positional.ACCEPTS($param.FETCH)},$other.params);
293 if &infix:<==>:(int,int)($pos_self.elems,$pos_other.elems) {
298 if &infix:<==>:(int,int)($i,$pos_self.elems) {
301 my $cmp = $pos_self[$i.FETCH].compare($pos_other[$i.FETCH]);
302 if &infix:<==>:(int,int)($cmp,0) {
306 $i = &infix:<+>:(int,int)($i,1);
311 ":(" ~ self.params[0].perl ~ "...)";
323 method register($sig) {
324 $sig.params.push((|self));
328 Positional.^compose_role(::Param);
330 method BIND($scope,$capture,$i is ref) {
331 if $capture.named($.name.FETCH) {
333 $scope{self.variable.FETCH} := self.wrap($capture.named($.name.FETCH));
335 } elsif &infix:<<<>>:(int,int)($i,$capture.elems) {
337 $scope{self.variable.FETCH} := self.wrap($capture.positional($i.FETCH));
339 $i = &infix:<+>:(int,int)($i.FETCH,1);
340 } elsif self.default_value {
341 my $default_value = self.default_value;
343 $scope{self.variable.FETCH} := self.wrap($default_value());
350 method ACCEPTS_param($capture,$i is ref,$named is ref) {
351 if $capture.named($.name.FETCH) {
352 $named = &infix:<+>:(int,int)($named.FETCH,1);
353 } elsif &infix:<<<>>:(int,int)($i,$capture.elems) {
354 if $.type.ACCEPTS($capture.positional($i.FETCH)) {
355 $i = &infix:<+>:(int,int)($i,1);
359 } elsif self.default_value {
366 method compare($other) {
367 if $other.type.ACCEPTS(self.type) {
368 if self.type.ACCEPTS($other.type) {
371 return &infix:<->:(int,int)(0,1);
374 if self.type.ACCEPTS($other.type) {
383 RefParam.^compose_role(::Positional);
388 my role ReadonlyParam {
389 ReadonlyParam.^compose_role(::Positional);
391 my $wrapper = ReadonlyWrapper.new;
392 $wrapper.value = $arg;
393 $wrapper.^!is_container = 1;
402 my role NamedReadonlyParam {
403 NamedReadonlyParam.^compose_role(::Param);
405 method BIND($scope,$capture,$i) {
406 my $arg = $capture.named(self.name.FETCH);
407 my $wrapper = ReadonlyWrapper.new;
408 $wrapper.value = $arg;
409 $wrapper.^!is_container = 1;
411 $scope{self.variable.FETCH} := (|$wrapper);
413 method ACCEPTS_param($capture,$i is ref,$named is ref) {
414 if $capture.named($.name.FETCH) {
415 $named = &infix:<+>:(int,int)($named.FETCH,1);
420 my role WholeCaptureParam {
422 WholeCaptureParam.^compose_role(::Param);
423 method ACCEPTS_param($capture,$i is ref,$named is ref) {
425 $named = $capture.named_count;
427 method BIND($scope,$capture,$i) {
428 $scope{self.variable.FETCH} = $capture;
431 ############## Exception ##############
434 my $interpreter = PRIMITIVES::get_interpreter;
435 my $current = $interpreter.continuation;
438 $current = $current.back;
439 if ($current.catch) {
440 $current.catch.postcircumfix:<( )>(::capture.new(self),:cc($current.back));
444 say "uncaught exception";
451 ############## Any ##############
459 ############## Multi ##############
463 has $.sorted_candidates is rw;
465 my sub qsort($array) {
466 if &infix:<==>:(int,int)($array.elems,0) {
469 my $partition = $array[0].signature;
471 my $left = qsort(grep sub ($elem) {&infix:<==>:(int,int)($elem.signature.compare($partition),&infix:<->:(int,int)(0,1))},$array);
472 my $equal = grep(sub ($elem) {&infix:<==>:(int,int)($elem.signature.compare($partition),0)},$array);
473 my $right = qsort(grep sub ($elem) {&infix:<==>:(int,int)($elem.signature.compare($partition),1)},$array);
475 my $result = ::Array.new;
476 map(sub ($x) {$result.push($x.FETCH)},$left);
477 map(sub ($x) {$result.push($x.FETCH)},$equal);
478 map(sub ($x) {$result.push($x.FETCH)},$right);
482 method postcircumfix:<( )>(\$capture, :$cc) {
483 my sub ACCEPTS($candidate) {
484 $candidate.signature.ACCEPTS((|$capture));
486 if self.sorted_candidates {
489 self.sorted_candidates = qsort(self.candidates);
492 my $candidates = grep &ACCEPTS,self.sorted_candidates;
494 if &infix:<==>:(int,int)($candidates.elems,1) {
495 $candidates[0].postcircumfix:<( )>((|$capture), :cc($cc.FETCH));
496 } elsif &infix:<==>:(int,int)($candidates.elems,0) {
497 say "signature mismatch failure";
498 ::Exception.new.throw;
499 #my $e = ::SignatureMismatchFailure.new();
501 #$e.capture = $capture;
504 } elsif &infix:<==>:(int,int)($candidates[0].signature.compare($candidates[1].signature),&infix:<->:(int,int)(0,1)) {
505 $candidates[0].postcircumfix:<( )>((|$capture), :cc($cc.FETCH));
507 say "ambiguous dispatch";
508 say $candidates[0].signature.compare($candidates[1].signature);
509 ::Exception.new.throw;
510 #my $e = ::AmbiguousDispatchFailure.new();
512 #$e.capture = $capture;
513 #$e.candidates = $candidates;
518 self.candidates = ::Array.new;
520 method get_outer_candidates($name,$scope) {
521 my $outer = $scope.outer;
526 if $outer.exists((|$name)) {
528 my $multi = $outer.lookup((|$name));
529 map(sub ($candidate) {self.candidates.push((|$candidate))},$multi.candidates);
533 $outer = $outer.outer;
542 ############## fail ##############
560 # UNKNOWN_METHOD is a spec def
561 method UNKNOWN_METHOD($identifier) {
569 if ($failure.handled) {
577 my $failure = Failure.new;
578 $failure.exception = ::Exception.new;
580 my $e = ::ControlExceptionReturn.new();
581 $e.capture = $failure;
582 $e.routine = CALLER::<&?ROUTINE>;
586 ############## ModuleLoader ##############
588 my role ModuleLoader {
590 my $loader = ::MildewSOLoader.new;
591 method load($module) {
592 my $filename = self.resolve_filename($module);
593 if $.cache{$filename.FETCH} {
595 $.cache{$filename.FETCH} = $loader.load($filename.FETCH,$LexicalPrelude.FETCH);
597 $.cache{$filename.FETCH};
599 method resolve_filename($module) {
600 $module ~ '.mildew.so'
603 $.cache = ::Hash.new;
608 ############## Perl5 interop ##############
609 my knowhow EXTERNAL {
611 sub use_from_perl5($module) {
613 $p5 := ::P5Interpreter.new;
615 $p5.eval(PRIMITIVES::idconst_concat('use ',$module.FETCH));
616 $p5.eval(PRIMITIVES::idconst_concat(PRIMITIVES::idconst_concat("'",$module.FETCH),"'"));
618 sub eval_perl5($code) {
620 $p5 := ::P5Interpreter.new;
622 $p5.eval($code.FETCH.FETCH);
626 ############## int ##############
630 method ACCEPTS($thing) {
631 PRIMITIVES::ritest((|$thing),PRIMITIVES::SMOP_RI(2));
635 my multi infix:<==>(int $a,int $b) {
636 &infix:<==>:(int,int)($a,$b);
639 my multi infix:<!=>(int $a,int $b) {
640 if &infix:<==>:(int,int)($a,$b) {
646 my multi infix:<+>(int $a,int $b) {
647 &infix:<+>:(int,int)($a,$b);
649 my multi infix:<->(int $a,int $b) {
650 &infix:<->:(int,int)($a,$b);
652 my multi prefix:<->(int $a) {
653 &infix:<->:(int,int)(0,$a);
656 #HACK we don't support such fancy multi names so we bind to $LexicalPrelude
658 #TODO fix multi infix:<\<> {...}
659 my multi less(int $a,int $b) {
660 &infix:<<<>>:(int,int)($a,$b);
662 my multi more(int $a,int $b) {
663 if &infix:<<<>>:(int,int)($a,$b) {
665 } elsif &infix:<==>:(int,int)($a,$b) {
671 #TODO fix multi infix:<\<> {...}
672 my multi less_or_equal(int $a,int $b) {
673 &infix:<<<>>:(int,int)($a,$b) || &infix:<==>:(int,int)($a,$b);
675 my multi more_or_equal(int $a,int $b) {
676 not(&infix:<<<>>:(int,int)($a,$b));
679 $LexicalPrelude{'&infix:<='} := &less_or_equal;
680 $LexicalPrelude{'&infix:>='} := &more_or_equal;
681 $LexicalPrelude{'&infix:<'} := &less;
682 $LexicalPrelude{'&infix:>'} := &more;