Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implement fancy proto regexes with stuff around {*}

  • Loading branch information...
commit 5b610267031e171cb73cb29682adf49b37e57fbf 1 parent 2f1fbaa
@sorear authored
View
1  docs/TODO.S05
@@ -22,7 +22,6 @@ All line numbers are relative to c4882a67. Also, deliberate discrepencies.)
(1178) No bindings to existing variables
(1186) No || @array temporal-alternation syntax DISCUSS
(1253) No handling of formal parameters in LTM
-(1258) No {*} and funky proto handling in general
(1276) Declarativeness of constants is insufficiently general
(1461) DISCUSS: STD parses EXPR in assertion:variable, why?
(1507) No support for indirect <::($name)> calls
View
1  lib/CodeGen.cs
@@ -3003,7 +3003,6 @@ class NamProcessor {
thandlers["rxsetcapsfrom"] = RxCall(null, "SetCapturesFrom");
thandlers["rxgetpos"] = RxCall(null, "GetPos");
thandlers["rxcommitgroup"] = RxCall(null, "CommitGroup");
- thandlers["run_dispatch"] = Methody(null, typeof(Lexer).GetMethod("RunDispatch"));
handlers["rawcall"] = delegate(NamProcessor th, object[] z) {
string name = JScalar.S(z[1]);
CpsOp[] rst = JScalar.A<CpsOp>(2, z, th.Scan);
View
51 lib/Cursor.cs
@@ -588,6 +588,12 @@ public sealed class RxFrame: IFreeze {
return nth;
}
+ public Frame proto_dispatch(Frame th, Variable unused) {
+ Frame nth = th.MakeChild(null, Lexer.StandardProtoSI, Kernel.AnyP);
+ nth.pos = new Variable[] { MakeCursorV() };
+ return nth;
+ }
+
private static SubInfo ArrayHelperSI = new SubInfo("KERNEL ArrayHelper", ArrayHelperC);
private static Frame ArrayHelperC(Frame th) {
int[] cases = (int[]) th.lex2;
@@ -1829,13 +1835,13 @@ public class Lexer {
return ret;
}
- public static Lexer GetDispatchLexer(Frame fromf, STable kl, SubInfo disp) {
+ public static Lexer GetDispatchLexer(STable kl, SubInfo disp) {
LexerCache lc = kl.GetLexerCache();
Lexer ret;
if (lc.dispatch_nfas.TryGetValue(disp, out ret))
return ret;
if (lc.parent != null && lc.parent.mo.name != "Cursor" && lc.parent.mo.name != "Any") {
- ret = GetDispatchLexer(fromf, lc.parent.mo, disp);
+ ret = GetDispatchLexer(lc.parent.mo, disp);
foreach (string u in ret.pad.used_methods) {
if (lc.repl_methods.Contains(u))
goto anew;
@@ -1984,12 +1990,17 @@ public class Lexer {
return uniqfates;
}
- public static P6any[] RunDispatch(Frame fromf, P6any cursor) {
+ internal static P6any[] RunDispatch(Frame fromf, Cursor cursor) {
+ if (fromf.info.param == null) {
+ fromf = fromf.caller;
+ while (fromf.info.param == null ||
+ !(fromf.info.param[0] is P6any[]))
+ fromf = fromf.outer;
+ }
+
STable kl = cursor.mo;
- while (fromf.info.param == null ||
- fromf.info.param[0] == null) fromf = fromf.outer;
- Lexer l = GetDispatchLexer(fromf, kl, fromf.info);
+ Lexer l = GetDispatchLexer(kl, fromf.info);
P6any[] candidates = (P6any[]) fromf.info.param[0];
Cursor c = (Cursor)cursor;
@@ -2002,7 +2013,8 @@ public class Lexer {
return ret;
}
- // XXX duplicates logic from RxOp::ProtoRedis and Op::RegexBody
+ internal static SubInfo StandardProtoSI =
+ new SubInfo("KERNEL protoregex", StandardProtoC);
internal static Frame StandardProtoC(Frame th) {
switch (th.ip) {
default:
@@ -2010,12 +2022,10 @@ public class Lexer {
case 1:
return th.rx.Backtrack(th);
case 0:
- if (th.pos.Length == 0)
- return Kernel.Die(th, "No value for self argument to LTM dispatcher");
- th.lex0 = th.pos[0];
- th.rx = new RxFrame(th.info.name, (Cursor) ((Variable)th.lex0).Fetch(), false);
+ th.lex0 = (Cursor)th.pos[0].Fetch();
+ th.rx = new RxFrame(th.info.name, (Cursor)th.lex0, false);
th.rx.PushCutGroup("LTM");
- th.lex1 = RunDispatch(th, ((Variable)th.lex0).Fetch());
+ th.lex1 = RunDispatch(th, (Cursor)th.lex0);
th.lexi0 = 0;
goto case 2;
case 2:
@@ -2037,12 +2047,15 @@ public class Lexer {
}
public static P6any MakeDispatcher(string name, P6any proto, P6any[] cands) {
- SubInfo si = (proto != null) ?
- new SubInfo((SubInfo)proto.GetSlot("info")) :
- new SubInfo(name, StandardProtoC);
-
- si.param = new object[] { cands, null };
- si.ltm = new LADDispatcher();
- return Kernel.MakeSub(si, null);
+ if (proto != null) {
+ SubInfo si = new SubInfo((SubInfo)proto.GetSlot("info"));
+ si.param = new object[] { cands, null };
+ return Kernel.MakeSub(si, (Frame)proto.GetSlot("outer"));
+ } else {
+ SubInfo si = new SubInfo(name, StandardProtoC);
+ si.param = new object[] { cands, null };
+ si.ltm = new LADDispatcher();
+ return Kernel.MakeSub(si, null);
+ }
}
}
View
24 lib/Kernel.cs
@@ -1447,6 +1447,9 @@ public class SubInfo : IFreeze, IFixup {
// not saved, rarely used
internal Dictionary<string,SubInfo> rx_compile_cache;
+ public int[] edata;
+ public string[] label_names;
+
// No instance fields past this point
public class UsedInScopeInfo {
public string file;
@@ -1515,8 +1518,6 @@ public class UsedInScopeInfo {
public const int ON_WARNING = 11;
// ON_VARLOOKUP is kinda special, it's not used for exceptions
// but rather for $*FOO and the like; goto = the variable index
- public int[] edata;
- public string[] label_names;
[Immutable]
private static string[] controls = new string[] { "unknown", "next",
@@ -1556,6 +1557,8 @@ public class UsedInScopeInfo {
}
public int FindControlEnt(int ip, int ty, string name) {
+ if (edata == null)
+ return -1;
for (int i = 0; i < edata.Length; i+=5) {
if (ip < edata[i] || ip >= edata[i+1])
continue;
@@ -2008,6 +2011,8 @@ public class UsedInScopeInfo {
children = null;
extend = o.extend;
rx_compile_cache = null;
+ edata = o.edata;
+ label_names = o.label_names;
prototype = o.prototype ?? o;
}
@@ -2240,11 +2245,13 @@ public class UsedInScopeInfo {
self_key = -1;
}
- foreach (SubInfo z in children) {
- if (z.phaser == Kernel.PHASER_CATCH)
- catch_ = z;
- if (z.phaser == Kernel.PHASER_CONTROL)
- control = z;
+ if (children != null) {
+ foreach (SubInfo z in children) {
+ if (z.phaser == Kernel.PHASER_CATCH)
+ catch_ = z;
+ if (z.phaser == Kernel.PHASER_CONTROL)
+ control = z;
+ }
}
}
}
@@ -4706,7 +4713,8 @@ public class MMDCandidateLongname {
new SubInfo((SubInfo)proto.GetSlot("info")) :
new SubInfo(name, StandardTypeProtoC);
si.param = new object[] { cands, null };
- return Kernel.MakeSub(si, null);
+ return Kernel.MakeSub(si, proto == null ? null :
+ (Frame)proto.GetSlot("outer"));
ltm:
List<P6any> lp = new List<P6any>();
foreach (P6any p in cands)
View
195 src/niecza
@@ -25,16 +25,25 @@ use STD;
# }
# }
+augment class RxOp::ProtoRedis {
+ # name, cutltm not used
+ method code($) {
+ my $bt = self.label;
+
+ my @code;
+ push @code, CgOp.rxcall("InitCursorList",
+ CgOp.rxlprim('proto_dispatch', CgOp.scopedlex('Any')));
+ push @code, CgOp.label($bt);
+ push @code, CgOp.rxincorpshift(['dispatch'], $bt);
+ @code;
+ }
+}
+
augment class NieczaActions {
method regex_def($/) {
my $ast = $<regex_block>.ast;
- if $*CURLEX<!multi> eq 'proto' {
- if ($<signature> && $<signature>[0].ast.params != 1) ||
- !$<regex_block><onlystar> {
- $/.CURSOR.sorry('Only {*} protoregexes with no parameters are supported');
- }
-
+ if $<regex_block><onlystar> {
$ast = ::RxOp::ProtoRedis.new(name => $*CURLEX<!name>);
}
@@ -42,7 +51,7 @@ method regex_def($/) {
my $ltm = ::GLOBAL::OptRxSimple.run_lad($ast.lad);
$*CURLEX<!sub>.set_ltm($ltm);
($ast, my $mb) = ::GLOBAL::OptRxSimple.run($ast);
- if $*CURLEX<!multi> eq 'proto' {
+ if $<regex_block><onlystar> {
$*CURLEX<!sub>.finish_dispatcher('regex');
} else {
$*CURLEX<!sub>.finish(::Op::RegexBody.new(|node($/), pre => @lift,
@@ -50,6 +59,16 @@ method regex_def($/) {
}
make ::Op::Lexical.new(|node($/), name => $*CURLEX<!sub>.outervar);
}
+method metachar:sym<{*}> ($/) {
+ make ::RxOp::ProtoRedis.new(name => '', :!cutltm);
+ return;
+}
+method metachar:sym<[*]> ($/) {
+ $/.CURSOR.sorry("This syntax is not specced.");
+ make ::RxOp::None.new;
+ return;
+}
+
method is_dispatcher($blockoid) {
$blockoid.Str ~~ m/ '{' \s* '*' \s* '}' /;
}
@@ -63,6 +82,168 @@ method finish_method_routine ($/) {
}
method routine_def ($/) { self.finish_method_routine($/) }
method method_def ($/) { self.finish_method_routine($/) }
+method install_sub($/, $sub, :$multiness is copy, :$scope is copy, :$class,
+ :$longname, :$method_type is copy, :$contextual is copy) {
+
+ $multiness ||= 'only';
+ my ($pkg, $name) = self.process_name($longname, :declaring);
+
+ if !$scope {
+ if !defined($name) {
+ $scope = 'anon';
+ } elsif defined($pkg) {
+ $scope = 'our';
+ } elsif defined($method_type) {
+ $scope = 'has';
+ } else {
+ $scope = 'my';
+ }
+ }
+
+ if $class eq 'Regex' {
+ my $/;
+ $*CURLEX<!name> = $name;
+ $*CURLEX<!cleanname !sym> =
+ !defined($name) ?? (Str, Str) !!
+ ($name ~~ /\:sym\<(.*)\>/) ?? ($name.substr(0, $/.from), ~$0) !!
+ ($name ~~ /\:(\w+)/) ?? ($name.substr(0, $/.from), ~$0) !!
+ ($name, Str);
+ %*RX<sym> = $*CURLEX<!sym>;
+ $multiness = 'multi' if defined $*CURLEX<!sym>;
+ $*CURLEX<!multi> = $multiness;
+ }
+
+ if $scope ne 'my' && $scope ne 'our' && $scope ne 'anon' && $scope ne 'has' {
+ $/.CURSOR.sorry("Illegal scope $scope for subroutine");
+ $scope = 'anon';
+ }
+
+ if $scope eq 'has' && !defined($method_type) {
+ $/.CURSOR.sorry('has scope-type is only valid for methods');
+ $scope = 'anon';
+ }
+
+ if $scope ne 'anon' && !defined($name) {
+ $/.CURSOR.sorry("Scope $scope requires a name");
+ $scope = 'anon';
+ }
+
+ if $scope ne 'our' && defined($pkg) {
+ $/.CURSOR.sorry("Double-colon-qualified subs must be our");
+ $scope = 'our';
+ }
+
+ if $scope eq 'anon' && $multiness ne 'only' {
+ $/.CURSOR.sorry("Multi routines must have a name");
+ $multiness = 'only';
+ }
+
+ if $contextual && (defined($method_type) || $scope ne 'my') {
+ $/.CURSOR.sorry("Context-named routines must by purely my-scoped");
+ $contextual = False;
+ }
+
+ $method_type = Str if $scope eq 'anon';
+
+ my $method_targ = $method_type && $sub.outer.body_of;
+ if !$method_targ && defined($method_type) {
+ $/.CURSOR.sorry("Methods must be used in some kind of package");
+ $method_type = Str;
+ }
+
+ if $method_targ && !$method_targ.CAN('add_method') {
+ $/.CURSOR.sorry("A {$method_targ.kind} cannot have methods added");
+ $method_type = Str;
+ $method_targ = Any;
+ }
+
+ if $name ~~ Op && (!defined($method_type) || $scope ne 'has' ||
+ $method_targ.kind ne 'prole') {
+ $/.CURSOR.sorry("Computed names are only implemented for parametric roles");
+ $name = "placeholder";
+ }
+
+ my $bindlex = $scope eq 'my' || ($scope eq 'our' && !$pkg);
+
+ $sub.set_name(defined($method_type) ?? $method_targ.name ~ "." ~ $name !!
+ ($name // 'ANON'));
+ $sub.set_class($class);
+
+ my $std = $/.CURSOR;
+ {
+ my $/;
+ if $sub.name ~~ /^(\w+)\:\<(.*)\>$/ {
+ my %new = %( $std.default_O(~$0, ~$1) );
+ $sub.set_extend('prec', %new.kv);
+ }
+ }
+
+ my Str $symbol;
+ $/.CURSOR.trymop({
+ if $bindlex && $class eq 'Regex' {
+ $symbol = '&' ~ $name;
+ my $proto = $symbol;
+ { my $/; $proto ~~ s/\:.*//; }
+ $sub.outer.add_dispatcher($proto, |mnode($/))
+ if $multiness ne 'only' && !$sub.outer.has_lexical($proto);
+ $symbol ~= ":(!proto)" if $multiness eq 'proto';
+ } elsif $bindlex {
+ $symbol = '&' ~ $name;
+ $/.CURSOR.check_categorical($symbol);
+ if $multiness ne 'only' && !$sub.outer.has_lexical($symbol) {
+ $sub.outer.add_dispatcher($symbol, |mnode($/))
+ }
+
+ given $multiness {
+ when 'multi' { $symbol ~= ":({ self.gensym })"; }
+ when 'proto' { $symbol ~= ":(!proto)"; }
+ default {
+ $/.CURSOR.check_categorical($symbol);
+ }
+ }
+ } else {
+ $symbol = self.gensym;
+ }
+
+ $sub.set_outervar($symbol);
+ $sub.set_methodof(defined($method_type) ?? $method_targ !! Any);
+ $sub.outer.add_my_sub($symbol, $sub, |mnode($/));
+
+ if $multiness ne 'only' || $scope eq 'our' || $method_type {
+ $/.CURSOR.mark_used($symbol);
+ }
+
+ if defined($method_type) || $scope eq 'our' {
+ $sub.outer.create_static_pad;
+ }
+
+ if defined($method_type) {
+ my $mode = 0;
+ given $method_type {
+ when 'sub' { $mode += 2 }
+ when 'normal' { $mode += 0 }
+ when 'private' { $mode += 1 }
+ default { die "Unimplemented method type $_" }
+ }
+ given $multiness {
+ when 'only' { $mode += 0 }
+ when 'proto' { $mode += 4 }
+ when 'multi' { $mode += 8 }
+ default { die "Unimplemented multiness $_" }
+ }
+ if defined $*AUGMENT_BUFFER {
+ push $*AUGMENT_BUFFER, $mode, $name, $symbol;
+ } else {
+ $method_targ.add_method($mode, $name, $sub, |mnode($/));
+ }
+ }
+
+ if $scope eq 'our' {
+ $*unit.bind(($pkg // $sub.outer.cur_pkg).who,
+ "&$name", $sub);
+ }
+ });
+}
}
CgOp._register_ops: < who sc_root sc_indir temporize _addmethod _invalidate
View
17 test2.pl
@@ -60,6 +60,23 @@
}
{
+ my proto regex foo { x {*} y }
+ my regex foo:sym<+> { <sym> }
+ my regex foo:sym<-> { <sym> }
+
+ is ("x+y" ~~ /<&foo>/), "x+y", "proto regexes can add stuff before and after";
+ #is ~$<foo><dispatch>, "+", "<dispatch> works"; #NIECZA
+
+ my grammar G {
+ proto token bar { c {*} d }
+ token bar:xyz { eee }
+
+ token TOP { ([<bar> | ceee]) .* }
+ }
+ is G.parse("ceeed")[0], 'ceeed', 'LTM works into dispatch nodes';
+}
+
+{
my class Bt {
has $!pie;
method get_pie() { $!pie }
Please sign in to comment.
Something went wrong with that request. Please try again.