Skip to content

Instantly share code, notes, and snippets.

@niner
Created April 1, 2022 17:08
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 niner/0422e5ca8a00c70582e88273717f787b to your computer and use it in GitHub Desktop.
Save niner/0422e5ca8a00c70582e88273717f787b to your computer and use it in GitHub Desktop.
diff --git a/src/Raku/Grammar.nqp b/src/Raku/Grammar.nqp
index cfafe42d9..596f961d3 100644
--- a/src/Raku/Grammar.nqp
+++ b/src/Raku/Grammar.nqp
@@ -1625,6 +1625,7 @@ grammar Raku::Grammar is HLL::Grammar does Raku::Common {
token scope_declarator:sym<HAS> { <sym> <scoped('HAS')> }
token scope_declarator:sym<anon> { <sym> <scoped('anon')> }
token scope_declarator:sym<state> { <sym> <scoped('state')> }
+ token scope_declarator:sym<unit> { <sym> <scoped('unit')> }
token scoped($*SCOPE) {
<.end_keyword>
diff --git a/src/Raku/ast/scoping.rakumod b/src/Raku/ast/scoping.rakumod
index 34760b2a0..9603dea07 100644
--- a/src/Raku/ast/scoping.rakumod
+++ b/src/Raku/ast/scoping.rakumod
@@ -469,7 +469,7 @@ class RakuAST::Lookup is RakuAST::Node {
method resolution() {
nqp::isconcrete($!resolution)
?? $!resolution
- !! nqp::die('This element has not been resolved. Type: ' ~ self.HOW.name(self))
+ !! nqp::die('This element ' ~ self ~ ' has not been resolved. Type: ' ~ self.HOW.name(self))
}
method set-resolution(RakuAST::Declaration $resolution) {
diff --git a/src/Raku/ast/signature.rakumod b/src/Raku/ast/signature.rakumod
index 849fffa7c..fc8838ae4 100644
--- a/src/Raku/ast/signature.rakumod
+++ b/src/Raku/ast/signature.rakumod
@@ -149,12 +149,13 @@ class RakuAST::Parameter is RakuAST::Meta is RakuAST::Attaching
has Mu $!names;
has Bool $.invocant;
has Bool $!optional;
+ has Bool $!hllize;
has RakuAST::Parameter::Slurpy $.slurpy;
has RakuAST::Expression $.default;
has RakuAST::Node $!owner;
method new(RakuAST::Type :$type, RakuAST::ParameterTarget :$target,
- List :$names, Bool :$invocant, Bool :$optional,
+ List :$names, Bool :$invocant, Bool :$optional, Bool :$hllize,
RakuAST::Parameter::Slurpy :$slurpy, List :$traits,
RakuAST::Expression :$default) {
my $obj := nqp::create(self);
@@ -165,6 +166,7 @@ class RakuAST::Parameter is RakuAST::Meta is RakuAST::Attaching
nqp::bindattr($obj, RakuAST::Parameter, '$!optional', nqp::defined($optional)
?? ($optional ?? True !! False)
!! Bool);
+ nqp::bindattr($obj, RakuAST::Parameter, '$!hllize', nqp::defined($hllize) ?? ($hllize ?? True !! False) !! True);
nqp::bindattr($obj, RakuAST::Parameter, '$!slurpy',
nqp::istype($slurpy, RakuAST::Parameter::Slurpy)
?? $slurpy
@@ -278,9 +280,10 @@ class RakuAST::Parameter is RakuAST::Meta is RakuAST::Attaching
elsif $sigil eq '%' { $sigil-type := 'Associative' }
elsif $sigil eq '&' { $sigil-type := 'Callable' }
else { $sigil-type := '' }
- self.IMPL-WRAP-LIST($sigil-type
+ my @lookups := $sigil-type
?? [RakuAST::Type::Setting.new(RakuAST::Name.from-identifier($sigil-type))]
- !! [])
+ !! [];
+ self.IMPL-WRAP-LIST(@lookups)
}
method PRODUCE-META-OBJECT() {
@@ -331,7 +334,7 @@ class RakuAST::Parameter is RakuAST::Meta is RakuAST::Attaching
method IMPL-NOMINAL-TYPE() {
my str $sigil := $!target.sigil;
- if $sigil eq '@' || $sigil eq '%' || $sigil eq '&' {
+ if $!hllize && ($sigil eq '@' || $sigil eq '%' || $sigil eq '&') {
my @lookups := self.IMPL-UNWRAP-LIST(self.get-implicit-lookups());
my $sigil-type := @lookups[0].resolution.compile-time-value;
$!type
@@ -398,15 +401,15 @@ class RakuAST::Parameter is RakuAST::Meta is RakuAST::Attaching
if $!names {
$param-qast.named(nqp::elems($!names) == 1 ?? $!names[0] !! $!names);
}
- elsif !($!slurpy =:= RakuAST::Parameter::Slurpy) {
+ if !($!slurpy =:= RakuAST::Parameter::Slurpy) {
$!slurpy.IMPL-TRANSFORM-PARAM-QAST($context, $param-qast, $temp-qast-var,
- $!target.sigil, @prepend);
+ $!target.sigil, @prepend, $!hllize);
$was-slurpy := 1;
}
# HLLize before type checking unless it was a slurpy (in which
# case we know full well what we produced).
- unless $was-slurpy {
+ if !$was-slurpy && $!hllize {
$param-qast.push(QAST::Op.new(
:op('bind'),
$temp-qast-var,
@@ -606,7 +609,7 @@ class RakuAST::Parameter::Slurpy {
}
method IMPL-TRANSFORM-PARAM-QAST(RakuAST::IMPL::QASTContext $context,
- Mu $param-qast, Mu $temp-qast, str $sigil, @prepend) {
+ Mu $param-qast, Mu $temp-qast, str $sigil, @prepend, $hllize) {
# Not slurply, so nothing to do
$param-qast
}
@@ -636,7 +639,7 @@ class RakuAST::Parameter::Slurpy::Flattened is RakuAST::Parameter::Slurpy {
}
method IMPL-TRANSFORM-PARAM-QAST(RakuAST::IMPL::QASTContext $context,
- Mu $param-qast, Mu $temp-qast, str $sigil, @prepend) {
+ Mu $param-qast, Mu $temp-qast, str $sigil, @prepend, $hllize) {
if $sigil eq '@' {
self.IMPL-QAST-LISTY-SLURP($param-qast, $temp-qast, Array, 'from-slurpy-flat');
}
@@ -656,7 +659,7 @@ class RakuAST::Parameter::Slurpy::Flattened is RakuAST::Parameter::Slurpy {
QAST::SVal.new( :value('$!storage') ),
$temp-qast
)
- ));
+ )) if $hllize;
}
else {
nqp::die("Parameter * quantifier not applicable to sigil '$sigil'");
@@ -672,7 +675,7 @@ class RakuAST::Parameter::Slurpy::Unflattened is RakuAST::Parameter::Slurpy {
}
method IMPL-TRANSFORM-PARAM-QAST(RakuAST::IMPL::QASTContext $context,
- Mu $param-qast, Mu $temp-qast, str $sigil, @prepend) {
+ Mu $param-qast, Mu $temp-qast, str $sigil, @prepend, $hllize) {
if $sigil eq '@' {
self.IMPL-QAST-LISTY-SLURP($param-qast, $temp-qast, Array, 'from-slurpy');
}
@@ -690,7 +693,7 @@ class RakuAST::Parameter::Slurpy::SingleArgument is RakuAST::Parameter::Slurpy {
}
method IMPL-TRANSFORM-PARAM-QAST(RakuAST::IMPL::QASTContext $context,
- Mu $param-qast, Mu $temp-qast, str $sigil, @prepend) {
+ Mu $param-qast, Mu $temp-qast, str $sigil, @prepend, $hllize) {
if $sigil eq '@' || $sigil eq '' {
self.IMPL-QAST-LISTY-SLURP($param-qast, $temp-qast, Array, 'from-slurpy-onearg');
}
@@ -708,7 +711,7 @@ class RakuAST::Parameter::Slurpy::Capture is RakuAST::Parameter::Slurpy {
}
method IMPL-TRANSFORM-PARAM-QAST(RakuAST::IMPL::QASTContext $context,
- Mu $param-qast, Mu $temp-qast, str $sigil, @prepend) {
+ Mu $param-qast, Mu $temp-qast, str $sigil, @prepend, $hllize) {
# Sneak in a slurpy hash parameter too.
$param-qast.slurpy(1);
my $hash-param-name := $temp-qast.name ~ '_hash';
diff --git a/src/Raku/ast/statements.rakumod b/src/Raku/ast/statements.rakumod
index 7440ff597..0d72d2205 100644
--- a/src/Raku/ast/statements.rakumod
+++ b/src/Raku/ast/statements.rakumod
@@ -1123,6 +1123,15 @@ class RakuAST::Statement::Use is RakuAST::Statement is RakuAST::BeginTime
}
True
}
+ elsif $name eq 'MONKEY-SEE-NO-EVAL' {
+ True
+ }
+ elsif $name eq 'MONKEY-GUTS' {
+ True
+ }
+ elsif $name eq 'nqp' {
+ True
+ }
else {
False
}
diff --git a/src/core.c/Compiler.pm6 b/src/core.c/Compiler.pm6
index 77fd3c1bf..8a1b67160 100644
--- a/src/core.c/Compiler.pm6
+++ b/src/core.c/Compiler.pm6
@@ -31,6 +31,14 @@ class Compiler does Systemic {
multi method id(Compiler:U:) { nqp::ifnull(nqp::atkey($compiler,'id'),$id) }
multi method id(Compiler:D:) { $!id }
+ method compile(|a) {
+ nqp::getcomp("Raku").compile(|a)
+ }
+
+ method qast(|a) {
+ nqp::getcomp("Raku").qast(|a)
+ }
+
method verbose-config(:$say) {
my $compiler := nqp::getcomp("Raku");
my $backend := $compiler.backend;
diff --git a/src/vm/moar/dispatchers.nqp b/src/vm/moar/dispatchers.nqp
index e0037af5f..abf8b66c4 100644
--- a/src/vm/moar/dispatchers.nqp
+++ b/src/vm/moar/dispatchers.nqp
@@ -1561,6 +1561,24 @@ sub simple-args-proto($callee, $capture) {
return nqp::capturehasnameds($capture) ?? $accepts-any-named !! 1;
}
+class DispatchASTNode {
+ has @!args;
+ method push($arg) {
+ nqp::push(@!args, $arg);
+ }
+ method IMPL-TO-QAST(RakuAST::IMPL::QASTContext $context) {
+ QAST::Op.new:
+ :op('dispatch'),
+ QAST::SVal.new( :value('boot-resume') ),
+ QAST::IVal.new( :value(nqp::const::DISP_DECONT) ),
+ |@!args;
+ }
+ method IMPL-CHECK($resolver, $resolve-only) {
+ }
+ method visit-children($visitor) {
+ }
+}
+
# We we invoke a multi with an argument that is a Proxy (or some other non-Scalar
# container), we need to read the value(s) from the Proxy argument(s) and then go
# on with the dispatch. The ProxyReaderFactory produces code objects that do
@@ -1596,27 +1614,12 @@ class ProxyReaderFactory {
}
method !produce-reader($num-args, $has-nameds, $indices) {
- # Create a block taking each positional arg required, adding an
- # slurpy named if needed.
- my $block := QAST::Block.new(:is_thunk);
+# # Produce a dispatch op with the required arguments decontainerized.
+ my $dispatch := DispatchASTNode.new;
my int $i := 0;
- while $i < $num-args {
- $block.push(QAST::Var.new( :name("a$i"), :decl<param>, :scope<local> ));
- $i++;
- }
- if $has-nameds {
- $block.push(QAST::Var.new( :name<n>, :decl<param>, :scope<local>, :named, :slurpy ));
- }
-
- # Produce a dispatch op with the required arguments decontainerized.
- my $dispatch := QAST::Op.new:
- :op('dispatch'),
- QAST::SVal.new( :value('boot-resume') ),
- QAST::IVal.new( :value(nqp::const::DISP_DECONT) );
- $i := 0;
my $decont-index := 0;
while $i < $num-args {
- my $var := QAST::Var.new( :name("a$i"), :scope<local> );
+ my $var := QAST::Var.new( :name("a$i"), :scope<lexical> );
if nqp::atpos_i($indices, $decont-index) == $i {
$dispatch.push(QAST::Op.new( :op<decont>, $var ));
$decont-index++;
@@ -1627,19 +1630,78 @@ class ProxyReaderFactory {
$i++;
}
if $has-nameds {
- $dispatch.push(QAST::Var.new( :name<n>, :scope<local>, :named, :flat ));
+ $dispatch.push(QAST::Var.new( :name<%n>, :scope<lexical>, :named, :flat ));
}
- $block.push($dispatch);
+
+ # Create a block taking each positional arg required, adding an
+ # slurpy named if needed.
+ my @parameters;
+ $i := 0;
+ while $i < $num-args {
+ nqp::push(@parameters,
+ RakuAST::Parameter.new(
+ target => RakuAST::ParameterTarget::Var.new("a$i"),
+ hllize => 0,
+ ),
+ );
+ $i++;
+ }
+ if $has-nameds {
+ nqp::push(@parameters,
+ RakuAST::Parameter.new(
+ target => RakuAST::ParameterTarget::Var.new('%n'),
+ names => ['%n'],
+ optional => 0,
+ hllize => 0,
+ slurpy => RakuAST::Parameter::Slurpy::Flattened,
+ ),
+ );
+ }
+
+ my $block := RakuAST::PointyBlock.new(
+ signature => RakuAST::Signature.new(
+ parameters => @parameters,
+ ),
+ body => RakuAST::Blockoid.new(
+ RakuAST::StatementList.new(
+ RakuAST::Statement::Expression.new(
+ expression => $dispatch,
+ ),
+ ),
+ ),
+ );
+ my $compunit := RakuAST::CompUnit.new(
+ :!eval,
+ :comp-unit-name('proxy-reader'),
+ :statement-list(RakuAST::StatementList.new(
+ RakuAST::Statement::Expression.new(
+ expression => $block,
+ ),
+ ))
+ );
+
+ my $ctx := nqp::ctxcaller(nqp::ctx());
+ my $core-rev-sym := 'CORE-SETTING-REV';
+ while nqp::isnull(nqp::getlexrel($ctx, $core-rev-sym)) {
+ $ctx := nqp::ctxcaller($ctx);
+ }
+ my $resolver := RakuAST::Resolver::EVAL.new(
+ :context($ctx),
+ :global(GLOBAL),
+ );
+ nqp::gethllsym('nqp', 'note')('checking...');
+ $compunit.check($resolver);
# Compile and return it.
- nqp::getcomp('Raku').compile($block, :from<optimize>)
+ my $res := nqp::getcomp('Raku').compile($compunit, :from<ast>)();
+ nqp::getattr($res, Code, '$!do')
}
}
my $PROXY-READERS := ProxyReaderFactory.new;
nqp::bindhllsym('Raku', 'PROXY-READERS', $PROXY-READERS);
# The core of multi dispatch. Once we are here, either there was a simple
-# proto that we don't need to inovke, or we already did invoke the proto.
+# proto that we don't need to invoke, or we already did invoke the proto.
#
# Multiple dispatch is relatively complex in the most general case. However,
# the most common case by far consists of:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment