Skip to content
Browse files

Add support for attributive parameters, & role constraint

  • Loading branch information...
1 parent f9b2ede commit 4fbf38826c01c94a1fab171d7ebf6e39584e2e27 @sorear committed Jan 15, 2012
Showing with 180 additions and 139 deletions.
  1. +5 −2 lib/CodeGen.cs
  2. +38 −4 lib/Kernel.cs
  3. +1 −1 lib/Serialize.cs
  4. +2 −1 src/NieczaBackendDotnet.pm6
  5. +1 −1 src/STD.pm6
  6. +4 −0 src/Sig.pm6
  7. +129 −130 src/niecza
View
7 lib/CodeGen.cs
@@ -4475,17 +4475,20 @@ public class DowncallReceiver : CallReceiver {
STable type = (STable)Handle.Unbox(args[ix++]);
if (deflt != null) flags |= Parameter.HASDEFAULT;
if (type != null) flags |= Parameter.HASTYPE;
+ string attr = (string)args[ix++];
+ STable atype = (STable)Handle.Unbox(args[ix++]);
return Handle.Wrap(new Parameter(flags,
(slot == null ? -1 : tgt.dylex[slot].SigIndex()),
name, (names.Count == 0 ? null : names.ToArray()),
- deflt, type ?? Kernel.AnyMO));
+ deflt, type ?? Kernel.AnyMO, attr, atype));
}
public static object param_constraints(object[] args) {
Parameter tgt = (Parameter)Handle.Unbox(args[1]);
tgt.post_constraints = new object[args.Length - 2];
for (int ix = 2; ix != args.Length; ix++)
- tgt.post_constraints[ix-2] = Handle.Unbox(args[ix]);
+ tgt.post_constraints[ix-2] = (args[ix] is Handle) ?
+ Handle.Unbox(args[ix]) : args[ix];
return null;
}
public static object param_subsig(object[] args) {
View
42 lib/Kernel.cs
@@ -1390,30 +1390,37 @@ public class Parameter : P6any, IFixup {
public SubInfo def;
public STable type;
+ // XXX I don't really like dangling two extra fields on every param...
+ public string attribute;
+ public STable attribute_type;
+
public object[] post_constraints; // Signature | SubInfo
public override string ReprName() { return "P6parameter"; }
private Parameter() { }
public Parameter(int flags, int slot, string name,
- string[] names, SubInfo def, STable type) {
+ string[] names, SubInfo def, STable type, string attr,
+ STable atype) {
this.mo = Kernel.ParameterMO;
this.flags = flags;
this.name = name;
this.slot = slot;
this.names = names;
this.def = def;
this.type = type;
+ this.attribute = attr;
+ this.attribute_type = atype;
}
public static Parameter TPos(string name, int slot) {
return new Parameter(RWTRANS | POSITIONAL, slot, name,
- null, null, Kernel.AnyMO);
+ null, null, Kernel.AnyMO, null, null);
}
public static Parameter TNamedOpt(string name, int slot) {
return new Parameter(RWTRANS | OPTIONAL, slot, name,
- new string[] { name }, null, Kernel.AnyMO);
+ new string[] { name }, null, Kernel.AnyMO, null, null);
}
// Value processing
@@ -1434,6 +1441,7 @@ public class Parameter : P6any, IFixup {
public const int IS_COPY = 32768;
public const int IS_LIST = 65536;
public const int IS_HASH = 131072;
+ public const int CALLABLE = 0x200000;
// Value source
public const int HASDEFAULT = 32;
@@ -1455,6 +1463,9 @@ public class Parameter : P6any, IFixup {
fb.ObjRef(def);
fb.ObjRef(type);
fb.Refs(post_constraints);
+ fb.String(attribute);
+ if (attribute != null)
+ fb.ObjRef(attribute_type);
}
internal static Parameter Thaw(ThawBuffer tb) {
@@ -1469,6 +1480,9 @@ public class Parameter : P6any, IFixup {
n.def = (SubInfo)tb.ObjRef();
n.type = (STable)tb.ObjRef();
n.post_constraints = tb.RefsA<object>();
+ n.attribute = tb.String();
+ if (n.attribute != null)
+ n.attribute_type = (STable)tb.ObjRef();
return n;
}
@@ -2617,6 +2631,8 @@ public class Frame: P6any, IFixup {
type = Kernel.PositionalMO;
if ((flags & Parameter.IS_HASH) != 0)
type = Kernel.AssociativeMO;
+ if ((flags & Parameter.CALLABLE) != 0)
+ type = Kernel.CallableMO;
if (!srco.Does(type)) {
if (quiet) return false;
if (srco.mo.HasType(Kernel.JunctionMO) && obj_src != -1 && (mode & NO_JUNCTION) == 0) {
@@ -2649,6 +2665,23 @@ public class Frame: P6any, IFixup {
}
bound: ;
}
+ if (param.attribute != null) {
+ object self;
+ if (!th.TryGetDynamic("self", 0, out self))
+ throw new NieczaException("No 'self' available for attributive?");
+ Variable selfv = (Variable)self;
+ if (param.attribute[1] == '!') {
+ Kernel.Assign(((Variable)(selfv.Fetch().
+ GetSlot(param.attribute_type, param.attribute))),
+ src);
+ } else {
+ Variable dest = Kernel.RunInferior(selfv.Fetch().
+ InvokeMethod(Kernel.GetInferiorRoot(),
+ param.attribute.Substring(2),
+ new Variable[] { selfv }, null));
+ Kernel.Assign(dest, src);
+ }
+ }
if ((flags & Parameter.INVOCANT) != 0 && th.info.self_key >= 0)
th.SetDynamic(th.info.self_key, src);
switch (slot + 1) {
@@ -4611,6 +4644,7 @@ public class Kernel {
[CORESaved] public static STable GrammarMO;
[CORESaved] public static STable PositionalMO;
[CORESaved] public static STable AssociativeMO;
+ [CORESaved] public static STable CallableMO;
[CORESaved] public static STable CodeMO;
[CORESaved] public static STable WhateverCodeMO;
[CORESaved] public static STable RoutineMO;
@@ -5400,7 +5434,7 @@ internal class MMDCandidate : MultiCandidate {
SubInfo si = new SubInfo("KERNEL " + kl.name + "." + name,
WrapPushycb);
si.sig = new Signature(Parameter.TPos("self", 0),
- new Parameter(Parameter.RWTRANS | Parameter.SLURPY_PCL, 1, "$args", null, null, null)
+ new Parameter(Parameter.RWTRANS | Parameter.SLURPY_PCL, 1, "$args", null, null, null, null, null)
);
si.param = new object[] { null, cv };
kl.AddMethod(0, name, MakeSub(si, null));
View
2 lib/Serialize.cs
@@ -64,7 +64,7 @@ struct ObjRef {
internal static HashAlgorithm NewHash() { return new SHA256Managed(); }
static readonly string signature = "Niecza-Serialized-Module";
- static readonly int version = 21;
+ static readonly int version = 22;
// Routines for use by serialization code
public bool CheckWriteObject(SerUnit into, object o,
View
3 src/NieczaBackendDotnet.pm6
@@ -123,7 +123,8 @@ class StaticSub {
my @args;
for @( $sig.params ) {
push @args, downcall("param_new", self, .flags, .name, .slot,
- @( .names ), Str, .mdefault, .tclass);
+ @( .names ), Str, .mdefault, .tclass, .attribute,
+ .attribute_type);
@args[*-1].subsig(self!signature(.subsig)) if .subsig;
@args[*-1].constraints(@(.where)) if .where;
}
View
2 src/STD.pm6
@@ -2871,7 +2871,7 @@ grammar P6 is STD {
| <named_param> { $quant = ''; $kind = '*'; }
]
[
- | '?' { $quant = '?'; $kind = '?' }
+ | '?' { $quant = '?'; $kind = '?' if $kind eq '!' }
| '!' { $quant = '!'; $kind //= '!' }
| <?>
]
View
4 src/Sig.pm6
@@ -17,6 +17,7 @@ our constant $INVOCANT = 8192; #OK not used
our constant $IS_COPY = 32768; #OK not used
our constant $IS_LIST = 65536; #OK not used
our constant $IS_HASH = 131072; #OK not used
+our constant $CALLABLE = 0x20_0000; #OK
# Value source
our constant $HASDEFAULT = 32; #OK not used
@@ -40,6 +41,9 @@ class Parameter {
has Sig $.subsig is rw;
has $.typecap is rw; # List of Str; lazily created
+ has Str $.attribute;
+ has $.attribute_type;
+
method simple($n) { self.new(name => $n, slot => $n, flags => $RWTRANS + $POSITIONAL) }
}
View
259 src/niecza
@@ -23,135 +23,6 @@ augment class Any {
submethod new(|$) { die "Attempted to instantiate undefined class." }
}
-our $Sig = Sig;
-our $SigParameter = Sig::Parameter;
-our $Actions = NieczaActions;
-our $PassSimplifier = NieczaPassSimplifier;
-our $CgOp = CgOp;
-our $CClass = CClass;
-our $OptBeta = OptBeta;
-our $OptRxSimple = OptRxSimple;
-
-our $Op = Op;
-our $OpCgOp = Op::CgOp;
-our $OpStatementList = Op::StatementList;
-our $OpCallLike = Op::CallLike;
-our $OpCallSub = Op::CallSub;
-our $OpCallMethod = Op::CallMethod;
-our $OpGetSlot = Op::GetSlot;
-our $OpSetSlot = Op::SetSlot;
-our $OpParen = Op::Paren;
-our $OpSimplePair = Op::SimplePair;
-our $OpSimpleParcel = Op::SimpleParcel;
-our $OpInterrogative = Op::Interrogative;
-our $OpHereStub = Op::HereStub;
-our $OpYada = Op::Yada;
-our $OpShortCircuit = Op::ShortCircuit;
-our $OpShortCircuitAssign = Op::ShortCircuitAssign;
-our $OpStringLiteral = Op::StringLiteral;
-our $OpConditional = Op::Conditional;
-our $OpWhileLoop = Op::WhileLoop;
-our $OpGeneralLoop = Op::GeneralLoop;
-our $OpForLoop = Op::ForLoop;
-our $OpImmedForLoop = Op::ImmedForLoop;
-our $OpLabelled = Op::Labelled;
-our $OpWhen = Op::When;
-our $OpStart = Op::Start;
-our $OpTry = Op::Try;
-our $OpControl = Op::Control;
-our $OpMakeJunction = Op::MakeJunction;
-our $OpNum = Op::Num;
-our $OpAttribute = Op::Attribute;
-our $OpWhatever = Op::Whatever;
-our $OpWhateverCode = Op::WhateverCode;
-our $OpBareBlock = Op::BareBlock;
-our $OpSubDef = Op::SubDef;
-our $OpLexical = Op::Lexical;
-our $OpConstantDecl = Op::ConstantDecl;
-our $OpContextVar = Op::ContextVar;
-our $OpRequire = Op::Require;
-our $OpTake = Op::Take;
-our $OpGather = Op::Gather;
-our $OpMakeCursor = Op::MakeCursor;
-our $OpLetVar = Op::LetVar;
-our $OpRegexBody = Op::RegexBody;
-our $OpYouAreHere = Op::YouAreHere;
-our $OpGetBlock = Op::GetBlock;
-our $OpAssign = Op::Assign;
-our $OpBuiltin = Op::Builtin;
-our $OpLet = Op::Let;
-our $OpLetScope = Op::LetScope;
-our $OpTopicalHook = Op::TopicalHook;
-our $OpLeaveHook = Op::LeaveHook;
-our $OpLabelHook = Op::LabelHook;
-our $OpLexicalBind = Op::LexicalBind;
-our $OpROify = Op::ROify;
-our $OpStateDecl = Op::StateDecl;
-our $OpDoOnceLoop = Op::DoOnceLoop;
-our $OpFlipFlop = Op::FlipFlop;
-our $OpTemporize = Op::Temporize;
-our $OpIndirectVar = Op::IndirectVar;
-our $OpCatchyWrapper = Op::CatchyWrapper;
-our $OpGeneralConst = Op::GeneralConst;
-
-our $RxOp = RxOp;
-our $RxOpCapturing = RxOp::Capturing;
-our $RxOpSym = RxOp::Sym;
-our $RxOpString = RxOp::String;
-our $RxOpVarString = RxOp::VarString;
-our $RxOpQuantifier = RxOp::Quantifier;
-our $RxOpSequence = RxOp::Sequence;
-our $RxOpConj = RxOp::Conj;
-our $RxOpAltBase = RxOp::AltBase;
-our $RxOpSeqAlt = RxOp::SeqAlt;
-our $RxOpConfineLang = RxOp::ConfineLang;
-our $RxOpCut = RxOp::Cut;
-our $RxOpBeforeString = RxOp::BeforeString;
-our $RxOpZeroWidthCCs = RxOp::ZeroWidthCCs;
-our $RxOpNotBeforeString = RxOp::NotBeforeString;
-our $RxOpZeroWidth = RxOp::ZeroWidth;
-our $RxOpNotBefore = RxOp::NotBefore;
-our $RxOpBefore = RxOp::Before;
-our $RxOpTilde = RxOp::Tilde;
-our $RxOpSubrule = RxOp::Subrule;
-our $RxOpSigspace = RxOp::Sigspace;
-our $RxOpCutLTM = RxOp::CutLTM;
-our $RxOpCutRule = RxOp::CutRule;
-our $RxOpCutBrack = RxOp::CutBrack;
-our $RxOpSetLang = RxOp::SetLang;
-our $RxOpAlt = RxOp::Alt;
-our $RxOpCheckBlock = RxOp::CheckBlock;
-our $RxOpSaveValue = RxOp::SaveValue;
-our $RxOpVoidBlock = RxOp::VoidBlock;
-our $RxOpStatement = RxOp::Statement;
-our $RxOpProtoRedis = RxOp::ProtoRedis;
-our $RxOpAny = RxOp::Any;
-our $RxOpQuantCClass = RxOp::QuantCClass;
-our $RxOpCClassElem = RxOp::CClassElem;
-our $RxOpNone = RxOp::None;
-our $RxOpNewline = RxOp::Newline;
-our $RxOpStringCap = RxOp::StringCap;
-our $RxOpListPrim = RxOp::ListPrim;
-our $RxOpEndpoint = RxOp::Endpoint;
-
-our $Operator = Operator;
-our $Operator_Function = Operator::Function;
-our $Operator_PostCall = Operator::PostCall;
-our $Operator_Method = Operator::Method;
-our $Operator_FlipFlop = Operator::FlipFlop;
-our $Operator_ShortCircuit = Operator::ShortCircuit;
-our $Operator_CompoundAssign = Operator::CompoundAssign;
-our $Operator_MetaNot = Operator::MetaNot;
-our $Operator_Binding = Operator::Binding;
-our $Operator_Comma = Operator::Comma;
-our $Operator_Ternary = Operator::Ternary;
-our $Operator_Temp = Operator::Temp;
-our $Operator_Let = Operator::Let;
-our $Operator_SmartMatch = Operator::SmartMatch;
-our $Operator_DotEq = Operator::DotEq;
-our $Operator_Replicate = Operator::Replicate;
-our $Operator_Mixin = Operator::Mixin;
-
# augment class RxOp {
# method oplift() {
# say "oplift: {self.typename}";
@@ -160,7 +31,135 @@ our $Operator_Mixin = Operator::Mixin;
# }
# }
-augment class NieczaActions {
+our ($Sig, $SigParameter, $OpGeneralConst);
+
+our $Actions; $Actions = $Actions but role {
+method parameter($/) {
+ my $sorry;
+ my $p = $<param_var> // $<named_param>;
+ my $p_ast = $p ?? $p.ast !! { names => [], flags => $Sig::POSITIONAL };
+ my $flags = $p_ast<flags>;
+
+ $flags +|= $Sig::READWRITE if $*SIGNUM && $*CURLEX<!rw_lambda>;
+
+ for @( $<trait> ) -> $trait {
+ if $trait.ast<rw> { $flags +|= $Sig::READWRITE }
+ elsif $trait.ast<copy> { $flags +|= $Sig::IS_COPY }
+ elsif $trait.ast<parcel> { $flags +|= $Sig::RWTRANS }
+ elsif $trait.ast<readonly> { $flags +&= +^$Sig::READWRITE }
+ else {
+ $trait.CURSOR.sorry('Unhandled trait ' ~ $trait.ast.keys.[0]);
+ }
+ }
+
+ my $default = $<default_value> ?? $<default_value>.ast !! Any;
+ $default.set_name("$/ init") if $default;
+
+ my $tag = $<quant> ~ ':' ~ $<kind>;
+ if $tag eq '**:*' { $sorry = "Slice parameters NYI" }
+ elsif $tag eq '*:*' { $flags +|= ($flags +& $Sig::IS_HASH) ?? $Sig::SLURPY_NAM !! $Sig::SLURPY_POS }
+ elsif $tag eq '|:*' { $flags +|= $Sig::SLURPY_CAP }
+ elsif $tag eq '\\:!' { $flags +|= $Sig::RWTRANS }
+ elsif $tag eq '\\:?' { $flags +|= ($Sig::RWTRANS + $Sig::OPTIONAL) }
+ elsif $tag eq ':!' { }
+ elsif $tag eq ':*' { $flags +|= $Sig::OPTIONAL }
+ elsif $tag eq '?:*' { $flags +|= $Sig::OPTIONAL }
+ elsif $tag eq ':?' { $flags +|= $Sig::OPTIONAL }
+ elsif $tag eq '?:?' { $flags +|= $Sig::OPTIONAL }
+ elsif $tag eq '!:!' { }
+ elsif $tag eq '!:?' { $flags +|= $Sig::OPTIONAL }
+ elsif $tag eq '!:*' { }
+ else { $sorry = "Confusing parameters ($tag)" }
+ if $sorry { $/.CURSOR.sorry($sorry); }
+
+ if defined $p_ast<slot> {
+ # TODO: type constraint here
+ }
+
+ make $SigParameter.new(name => ~$/, mdefault => $default,
+ |$p_ast, :$flags);
+
+ for @<type_constraint> -> $tc {
+ if $tc.ast<where> {
+ push ($/.ast.where //= []), self.thunk_sub($tc.ast<where>.ast);
+ } elsif $tc.ast<value> {
+ $/.ast.tclass = $tc.ast<value>.get_type;
+ push ($/.ast.where //= []), self.thunk_sub(
+ $OpGeneralConst.new(value => $tc.ast<value>));
+ } else {
+ $/.CURSOR.sorry("Parameter coercion NYI") if $tc.ast<as>;
+ my $type = $tc.ast<type>;
+ if $type.kind eq 'subset' {
+ push ($/.ast.where //= []), self.thunk_sub(
+ $OpGeneralConst.new(value => $type.get_type_var));
+ $type = $type.get_basetype while $type.kind eq 'subset';
+ }
+ $/.ast.tclass = $type;
+ $/.ast.flags +|= $tc.ast<tmode>;
+ }
+ }
+
+ for @<post_constraint> -> $pc {
+ # XXX this doesn't seem to be specced anywhere, but it's
+ # Rakudo-compatible and shouldn't hurt
+ if $pc<bracket> {
+ $/.ast.flags +&= +^$Sig::IS_HASH;
+ $/.ast.flags +|= $Sig::IS_LIST;
+ }
+
+ if $pc<signature> -> $ssig {
+ $ssig.CURSOR.sorry('Cannot have more than one sub-signature for a pparameter') if $/.ast.subsig;
+ $/.ast.subsig = $pc<signature>.ast;
+ } else {
+ push ($/.ast.where //= []), self.thunk_sub($pc<EXPR>.ast);
+ }
+ }
+}
+method param_var($/) {
+ if $<signature> {
+ make { slot => Any, names => [], subsig => $<signature>.ast,
+ flags => $Sig::POSITIONAL +
+ (substr($/,0,1) eq '[' ?? $Sig::IS_LIST !! 0) };
+ return;
+ }
+ my $twigil = $<twigil> ?? ~$<twigil> !! '';
+ my $sigil = ~$<sigil>;
+ my $list = $sigil eq '@';
+ my $hash = $sigil eq '%';
+ my $name = $<name> ?? ~$<name> !! Any;
+ my $where;
+
+ my $flags = ($list ?? $Sig::IS_LIST !! 0) + ($hash ?? $Sig::IS_HASH !! 0) +
+ ($sigil eq '&' ?? $Sig::CALLABLE !! 0) + $Sig::POSITIONAL;
+ my $slot;
+ if $twigil eq '' {
+ $slot = defined($name) ?? ($sigil ~ $name) !! Any;
+ } elsif $twigil eq '*' {
+ $slot = "$sigil*" ~ "$name";
+ } elsif $twigil eq ('!' | '.') {
+ make { :$flags, :$slot, attribute => "$sigil$twigil$name",
+ names => [ $name ], attribute_type => $*CURLEX<!sub>.cur_pkg };
+ return;
+ } else {
+ $/.CURSOR.sorry("Unhandled parameter twigil $twigil");
+ make { };
+ return Nil;
+ }
+
+ if ($sigil ne '$' && $sigil ne '@' && $sigil ne '%' && $sigil ne '&') {
+ $/.CURSOR.sorry('Non bare scalar targets NYI');
+ make { }
+ return Nil;
+ }
+
+ $/.CURSOR.trymop({
+ $/.CURSOR.check_categorical($slot);
+ $*CURLEX<!sub>.add_my_name($slot, :$list, :$hash, |mnode($/),
+ noinit => ?($*SIGNUM)) if defined($slot);
+ });
+
+ make { :$slot, names => defined($name) ?? [ $name ] !! [], :$flags };
+}
}
# remove run_dispatch

0 comments on commit 4fbf388

Please sign in to comment.
Something went wrong with that request. Please try again.