Skip to content

Instantly share code, notes, and snippets.

@FROGGS
Last active October 18, 2016 12:47
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save FROGGS/b49225ac2e445f8d595579a12f2600b9 to your computer and use it in GitHub Desktop.
$ TEST=1 perl6 -e 'my &abc:(Num --> Str)'
variable '&abc:(Num --> Str)'
- sigil: &
- sublongname: abc:(Num --> Str)
- sigterm: :(Num --> Str)
- fakesignature: Num --> Str
- signature: Num --> Str
- parameter: 1 matches
- type_constraint: 1 matches
- typename: Num
- longname: Num
- name: Num
- identifier: Num
- typename: Str
- longname: Str
- name: Str
- identifier: Str
- subshortname: abc
- desigilname: abc
- identifier: abc
----------------
$ TEST=1 perl6 -e 'class Foo { has &.def:(Num --> Str) }'
variable '&.def:(Num --> Str)'
- twigil: .
- sym: .
- sigil: &
- sublongname: def:(Num --> Str)
- sigterm: :(Num --> Str)
- fakesignature: Num --> Str
- signature: Num --> Str
- parameter: 1 matches
- type_constraint: 1 matches
- typename: Num
- longname: Num
- name: Num
- identifier: Num
- typename: Str
- longname: Str
- name: Str
- identifier: Str
- subshortname: def
- desigilname: def
- identifier: def
----------------
diff --git a/src/Perl6/Actions.nqp b/src/Perl6/Actions.nqp
index 9995441..44c5ab0 100644
--- a/src/Perl6/Actions.nqp
+++ b/src/Perl6/Actions.nqp
@@ -542,6 +542,7 @@ role STDActions {
class Perl6::Actions is HLL::Actions does STDActions {
our @MAX_PERL_VERSION;
+ my $TEST := +nqp::ifnull(nqp::atkey(nqp::getenvhash(), 'TEST'), 0);
# Could add to this based on signatures.
our %commatrap := nqp::hash(
@@ -2320,6 +2321,7 @@ class Perl6::Actions is HLL::Actions does STDActions {
}
method variable($/) {
+ nqp::say("variable '$/'\n" ~ $/.dump ~ "\n----------------\n") if $TEST;
my $past;
if $<index> {
$past := QAST::Op.new(
@@ -2361,6 +2363,9 @@ class Perl6::Actions is HLL::Actions does STDActions {
'item');
}
else {
+ if $<sublongname> {
+ $<desigilname> := $<sublongname><subshortname><desigilname>;
+ }
my $indirect;
if $<desigilname> && $<desigilname><longname> {
my $longname := $*W.dissect_longname($<desigilname><longname>);
@@ -2377,7 +2382,7 @@ class Perl6::Actions is HLL::Actions does STDActions {
}
}
else {
- my $name := ~$/;
+ my $name := $<sublongname> ?? ~$<sublongname><subshortname> !! ~$/;
if !$*IN_DECL && nqp::chars($name) == 1 && $name eq ~$<sigil> {
my $*IN_DECL := 'variable';
my $*SCOPE := 'state';
@@ -3036,7 +3041,9 @@ class Perl6::Actions is HLL::Actions does STDActions {
my $past := $<variable>.ast;
my $sigil := $<variable><sigil>;
my $twigil := $<variable><twigil>;
- my $desigilname := ~$<variable><desigilname>;
+ my $desigilname := $<variable><sublongname>
+ ?? ~$<variable><sublongname><subshortname><desigilname>
+ !! ~$<variable><desigilname>;
my $name := $sigil ~ $twigil ~ $desigilname;
# Don't know why this doesn't work all the time.
@@ -3049,7 +3056,18 @@ class Perl6::Actions is HLL::Actions does STDActions {
for $<post_constraint> {
@post.push($_.ast);
}
- if $<variable><desigilname> {
+ if $<variable><sublongname><sigterm> -> $st {
+ my $get_signature_past := QAST::Op.new(
+ :op('callmethod'),
+ :name('signature'),
+ WANTED(QAST::Var.new( :name('$_'), :scope('lexical') ),'param_var'),
+ );
+ my $fakesig := $st<fakesignature>;
+ my $closure_signature := $fakesig.ast;
+ my $where := make_where_block($fakesig, $closure_signature, $get_signature_past);
+ @post.push($where);
+ }
+ if $desigilname {
my $lex := $*W.cur_lexpad();
if $lex.symbol($name) {
$/.CURSOR.typed_worry('X::Redeclaration', symbol => $name);
@@ -4254,8 +4272,11 @@ class Perl6::Actions is HLL::Actions does STDActions {
method type_declarator:sym<enum>($/) {
# Get, or find, enumeration base type and create type object with
# correct base type.
+ my $desigilname := $<variable><sublongname>
+ ?? $<variable><sublongname><subshortname><desigilname>
+ !! $<variable><desigilname>;
my $longname := $<longname> ?? $*W.dissect_longname($<longname>) !! 0;
- my $name := $<longname> ?? $longname.name() !! $<variable><desigilname> || '';
+ my $name := $<longname> ?? $longname.name() !! $desigilname || '';
my @name_parts := $<longname> ?? $longname.type_name_parts('enum name', :decl(1)) !! [];
my $type_obj;
diff --git a/src/Perl6/Grammar.nqp b/src/Perl6/Grammar.nqp
index 778fa62..8a676b0 100644
--- a/src/Perl6/Grammar.nqp
+++ b/src/Perl6/Grammar.nqp
@@ -2033,7 +2033,7 @@ grammar Perl6::Grammar is HLL::Grammar does STD {
:my $*IN_META := '';
[
| :dba('infix noun') '&[' ~ ']' <infixish('[]')>
- | <sigil> <twigil>? <desigilname>
+ | <sigil> <twigil>? <desigilname> <!before ':('>
[ <?{ !$*IN_DECL && $*VARIABLE && $*VARIABLE eq $<sigil> ~ $<twigil> ~ $<desigilname> }>
{ self.typed_panic: 'X::Syntax::Variable::Initializer', name => $*VARIABLE } ]?
| <special_variable>
@@ -2041,6 +2041,7 @@ grammar Perl6::Grammar is HLL::Grammar does STD {
| <sigil> <?[<]> <postcircumfix> [<?{ $*IN_DECL }> <.typed_panic('X::Syntax::Variable::Match')>]?
| <?before <sigil> <?[ ( [ { ]>> <!RESTRICTED> <?{ !$*IN_DECL }> <contextualizer>
| $<sigil>=['$'] $<desigilname>=[<[/_!¢]>]
+ | <sigil> <twigil>? <sublongname>
| {} <sigil> <!{ $*QSIGIL }> <?MARKER('baresigil')> # try last, to allow sublanguages to redefine sigils (like & in regex)
]
[ <?{ $<twigil> && $<twigil> eq '.' }>
use Test;
plan 4;
{
my $abc:(Int --> Str);
$abc = -> Int $a --> Str { "ha" x $a };
is $abc(2), 'haha', 'my $abc:(Int --> Str); $abc = -> Int $a --> Str { "ha" x $a }';
}
{
my $abc:(Int --> Str);
$abc = sub (Int $a --> Str) { "ha" x $a };
is $abc(2), 'haha', 'my $abc:(Int --> Str); $abc = sub (Int $a --> Str) { "ha" x $a }';
}
{
my $abc:(Int --> Str);
throws-like { $abc = -> Int $a, Num --> Str { "ha" x $a } },
X::TypeCheck::Assignment,
symbol => '$abc',
}
{
# XXX No such method 'signature' for invocant of type 'Str'
# in any accepts_type at gen/moar/m-Metamodel.nqp line 3472
my &abc:(Int --> Str);
&abc = sub (Int $a --> Str) { "ha" x $a };
is &abc(2), 'haha', 'my &abc:(Int --> Str); &abc = sub (Int $a --> Str) { "ha" x $a }';
CATCH {
default {
skip ~$_, 1
}
}
}
--
1..5
ok 1 - my $abc:(Int --> Str); $abc = -> Int $a --> Str { "ha" x $a }
ok 2 - my $abc:(Int --> Str); $abc = sub (Int $a --> Str) { "ha" x $a }
1..3
ok 1 - code dies
ok 2 - right exception type (X::TypeCheck::Assignment)
ok 3 - .symbol matches $abc
ok 3 - did we throws-like X::TypeCheck::Assignment?
ok 4 - my $abc:(Int --> Str); $abc = sub (Int $a --> Str) { "ha" x $a }
ok 5 - \# SKIP No such method 'signature' for invocant of type 'Str'
@FROGGS
Copy link
Author

FROGGS commented Oct 17, 2016

FROGGS jnthn: and now I'm asking... what should it do in the end?
FROGGS I think it should:
FROGGS a) attach the signature as a trait
FROGGS b) which means we can use it for nativecall
FROGGS c) which will mean that if you assign a codeblock/subroutine reference to it, then its signature gets checked
FROGGS right?
jnthn FROGGS: Well, c alone would be achievable by having it added as if it were a where clause
jnthn FROGGS: But that doesn't answer the introspection question
FROGGS jnthn: maybe I should look at what params do?
jnthn Yeah, but I think they "cheat" in some way
jnthn If we want this to generalize nicely, then it's probably best to handle it in metaspace
FROGGS m: sub foo(&a:(Int --> Str)) { say &a }; foo(-> Num { })
camelia rakudo-moar 2dd0dd: OUTPUT«Constraint type check failed for parameter '&a'␤ in sub foo at line 1␤ in block at line 1␤␤»
FROGGS m: sub foo(&a:(Int --> Str)) { say &a }; foo(-> Int --> Str { })
camelia rakudo-moar 2dd0dd: OUTPUT«-> Int $ --> Str { #(Block|80443168) ... }␤» **jnthn** m: my &a:(Int --> Str) = sub (Int $x --> Str) {} **camelia** rakudo-moar 2dd0dd: OUTPUT«===SORRY!=== Error while compiling <tmp>␤You can't adverb &a␤at <tmp>:1␤------> my &a:(Int --> Str)⏏ = sub (Int $x --> Str) {}␤» **jnthn** Oops :) **FROGGS** :o) **FROGGS** it does not bail out using my patch, but it does not do anything with &a yet **jnthn** m: subset Callable of :(Int --> Str) **camelia** rakudo-moar 2dd0dd: OUTPUT«===SORRY!=== Error while compiling <tmp>␤Malformed trait␤at <tmp>:1␤------> subset Callable of⏏ :(Int --> Str)␤» **jnthn** gah, not enough coffee **FROGGS** heh **jnthn** m: subset Thingy of Callable where :(Int --> Str) **camelia** rakudo-moar 2dd0dd: ( no output ) **jnthn** m: subset Thingy of Callable where :(Int --> Str); say Thingy.^refineee **camelia** rakudo-moar 2dd0dd: OUTPUT«No such method 'refineee' for invocant of type 'Perl6::Metamodel::SubsetHOW'␤ in block <unit> at <tmp> line 1␤␤» **jnthn** m: subset Thingy of Callable where :(Int --> Str); say Thingy.^refinee **camelia** rakudo-moar 2dd0dd: OUTPUT«(Callable)␤» **jnthn** m: subset Thingy of Callable where :(Int --> Str); say Thingy.^refinement **camelia** rakudo-moar 2dd0dd: OUTPUT«-> ;; $_ { #(Block|51432080) ... }␤»
FROGGS ahh
jnthn Yeah, it compiles it into a Block
jnthn that presumably smart-matches
jnthn m: subset Thingy of Callable where 42; say Thingy.^refinement
camelia rakudo-moar 2dd0dd: OUTPUT«-> ;; $_ { #`(Block|80755656) ... }␤»
jnthn Always, it seems
FROGGS m: subset Thingy of Callable where :(Int --> Str); say :(Int --> Str) ~~ Thingy
camelia rakudo-moar 2dd0dd: OUTPUT«False␤»
jnthn A Signature isn't Callable
jnthn m: subset Thingy of Callable where :(Int --> Str); say sub (Int --> Str {} ~~ Thingy
camelia rakudo-moar 2dd0dd: OUTPUT«===SORRY!=== Error while compiling ␤Missing block␤at :1␤------> re :(Int --> Str); say sub (Int --> Str ⏏{} ~~ Thingy␤»
jnthn m: subset Thingy of Callable where :(Int --> Str); say sub (Int --> Str) {} ~~ Thingy
camelia rakudo-moar 2dd0dd: OUTPUT«False␤»
FROGGS m: subset Thingy of Callable where :(Int --> Str); sub foo(Thingy $a) { say $a }; foo(-> Int --> Str { })
camelia rakudo-moar 2dd0dd: OUTPUT«Constraint type check failed for parameter '$a'␤ in sub foo at line 1␤ in block at line 1␤␤»
jnthn hmm, what's up with that...
jnthn m: say -> Int --> Str { } ~~ :(Int --> Str)
camelia rakudo-moar 2dd0dd: OUTPUT«False␤»
jnthn m: say (-> Int --> Str { }).signature ~~ :(Int --> Str)
camelia rakudo-moar 2dd0dd: OUTPUT«True␤»
FROGGS ahh
jnthn Hm, maybe I'm misremembering the smartmatch table. Or maybe Rakudo is ;)
jnthn One way to go, though, might be to have a subclass of SubsetHOW like SignatureCheckHOW or something
jnthn And it has a .signature property
jnthn And then we can distinguish things that were actually written using the &.a:(...) style forms
jnthn .HOW ~~ Metamodel::SignatureHOW or so
jnthn (on the type)
FROGGS yeah
jnthn That would generalize nicely over vars/attrs/params

@FROGGS
Copy link
Author

FROGGS commented Oct 18, 2016

FROGGS jnthn: (needs lots of cleanup though)
FROGGS and the proper implementation like you said :o)
FROGGS jnthn: I've hit a problem... for nativecall subs we build info hashes in NC.pm for params and return types so that moar knows what todo...
FROGGS jnthn: now, we dont touch attributes, so we dont have these hashes for attributes which have a signature
FROGGS I mean, I can do the same hack like what I did with HAS, but I'd like to not do that...
jnthn FROGGS: At what point is the signature needed?
FROGGS after instanciating the class I guess... not before
FROGGS jnthn: or when accessing the attribute, but I dunno how we could intercept that
jnthn What should the attribute contain?
jnthn I guess some kind of Code that when invoked will make the call?
jnthn If so...maybe we can give NativeCall an "example" object when configuring the CStruct
jnthn Plus an attribute pointing to a native callsite
jnthn And it can clone + set that attr
jnthn (clone the object that is)
jnthn So it happens as part of the marshalling of the struct back from C-land
jnthn Would that help?
FROGGS I guess... but how would we configure the CStruct in NativeCall.pm?
jnthn Hmmm
jnthn Yeah, I guess there's a slight timing issue there
jnthn Or something like.
FROGGS aye
jnthn In that the CStruct REPR is decoupled from nativecall itself
FROGGS m: multi sub trait_mod:(Mu $a, :$repr = 'CStruct') { say 42 }; class Foo is repr { has int8 $.a } # :o(
camelia rakudo-moar 20d37a: ( no output )
FROGGS m: multi sub trait_mod:(Mu $a, :$repr!) { say 42 }; class Foo is repr { has int8 $.a }
camelia rakudo-moar 20d37a: ( no output )
FROGGS uhh
FROGGS method trait_mod:sym($/) {
FROGGS # Handle is repr specially.
FROGGS if ~$ eq 'repr' {
FROGGS (it sets $*REPR in the actions fwiw)
jnthn Right
jnthn That has to be a special form
FROGGS but cant the trait just set $*REPR?
jnthn ...don't do that :P
FROGGS damn
FROGGS g
jnthn It'll be fragile in ways we'll regret later
jnthn But
jnthn In the attribute composition
jnthn You can detect the target package has repr CStruct
jnthn And do something differently there
jnthn (nqp::reprname)
FROGGS yes, but all of what I'd liked to do is in NativeCall.pm
FROGGS and I dont think we want to move that stuff
FROGGS or do think of something else?
jnthn Well, we could have NativeCall install a hook on load, for example using nqp::bindhllsym or so, and look for that if we see we have repr CStruct
FROGGS ahhh
FROGGS sure, the user would have loaded NativeCall at that time...
jnthn In combination with a Callable type
jnthn Right
FROGGS THUMBS UP
jnthn And if they didn't we can complain "Can only use Callable attributes inside of a CStruct after loading a native calling module"
FROGGS yes... I love it!
jnthn Then we don't couple it too tightly to the present NativeCall :)
FROGGS aye

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment