Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implement attribute initializers

  • Loading branch information...
commit d4638e157a76690ef751e7b359b2a7c7d4df809d 1 parent 0e836f6
@sorear authored
View
52 lib/CLRBackend.cs
@@ -13,7 +13,7 @@
using Niecza;
namespace Niecza.CLRBackend {
- // The portable format is a subset of JSON, and is current read
+ // The portable format is a subset of JSON, and is currently read
// into a matching internal form.
sealed class JScalar {
string text;
@@ -387,9 +387,15 @@ class Method {
class Attribute {
public readonly string name;
+ public readonly bool publ;
+ public readonly string ivar;
+ public readonly Xref ibody;
public Attribute(object[] x) {
- name = JScalar.S(x[0]);
+ name = JScalar.S(x[0]);
+ publ = JScalar.B(x[1]);
+ ivar = JScalar.S(x[2]);
+ ibody = Xref.from(x[3]);
}
public static Attribute[] fromArray(object x) {
@@ -912,6 +918,8 @@ sealed class Tokens {
n["sub"] = DynMetaObject.GetMethod("AddSubMethod");
return n;
}
+ public static readonly MethodInfo DMO_AddAttribute =
+ typeof(DynMetaObject).GetMethod("AddAttribute");
public static readonly MethodInfo DMO_Invalidate =
typeof(DynMetaObject).GetMethod("Invalidate");
public static readonly MethodInfo DMO_FillParametricRole =
@@ -3204,13 +3212,8 @@ class NamProcessor {
CpsOp[] supers = new CpsOp[pr.superclasses.Length];
for (int i = 0; i < supers.Length; i++)
supers[i] = CpsOp.GetSField(pr.superclasses[i].Resolve<Class>().metaObject);
- string[] anames = new string[pr.attributes.Length];
- for (int i = 0; i < anames.Length; i++)
- anames[i] = pr.attributes[i].name;
-
build.Add( CpsOp.MethodCall(null, Tokens.DMO_FillRole, new CpsOp[] {
- mo, CpsOp.StringArray(false, anames),
- CpsOp.NewArray(Tokens.DynMetaObject, supers),
+ mo, CpsOp.NewArray(Tokens.DynMetaObject, supers),
CpsOp.NewArray(Tokens.DynMetaObject, new CpsOp[0]) }) );
foreach (Method m in pr.methods) {
@@ -3223,6 +3226,15 @@ class NamProcessor {
CpsOp.MethodCall(null, Tokens.Variable_Fetch, new CpsOp[] { var }) }));
}
+ foreach (Attribute a in pr.attributes) {
+ CpsOp name = CpsOp.StringLiteral(a.name);
+ CpsOp publ = CpsOp.BoolLiteral(a.publ);
+ CpsOp init = a.ivar == null ? CpsOp.Null(Tokens.IP6) :
+ RawAccessLex("scopedlex", a.ivar, null);
+ build.Add(CpsOp.MethodCall(null, Tokens.DMO_AddAttribute,
+ new CpsOp[] { mo, name, publ, init }));
+ }
+
build.Add(CpsOp.MethodCall(null, Tokens.DMO_Invalidate, new CpsOp[] { mo }));
if (sub.sig != null) {
object[] rsig = (object[]) sub.sig;
@@ -3449,26 +3461,19 @@ public class CLRBackend {
if (m is Role) {
Role r = (Role) m;
- string[] anames = new string[r.attributes.Length];
- for (int i = 0; i < anames.Length; i++)
- anames[i] = r.attributes[i].name;
CpsOp[] super = new CpsOp[ r.superclasses.Length ];
for (int i = 0; i < super.Length; i++)
super[i] = CpsOp.GetSField(r.superclasses[i].Resolve<Class>().metaObject);
thaw.Add(CpsOp.MethodCall(null, Tokens.DMO_FillRole, new CpsOp[] {
CpsOp.GetSField(r.metaObject),
- CpsOp.StringArray(false, anames),
CpsOp.NewArray(Tokens.DynMetaObject, super),
CpsOp.NewArray(Tokens.DynMetaObject, new CpsOp[0]) }));
} else if (m is ParametricRole) {
// The heavy lifting is done in WrapBody
} else if (m is Class) {
Class r = (Class) m;
- List<string> all_attr = new List<string>();
- string[] anames = new string[r.attributes.Length];
- for (int i = 0; i < anames.Length; i++)
- anames[i] = r.attributes[i].name;
+ List<string> all_slot = new List<string>();
CpsOp[] super = new CpsOp[ r.superclasses.Length ];
CpsOp[] mro = new CpsOp[ r.linearized_mro.Length ];
for (int i = 0; i < super.Length; i++)
@@ -3477,13 +3482,12 @@ public class CLRBackend {
Class p = r.linearized_mro[i].Resolve<Class>();
mro[i] = CpsOp.GetSField(p.metaObject);
foreach (Attribute a in p.attributes)
- all_attr.Add(a.name);
+ all_slot.Add(a.name);
}
thaw.Add(CpsOp.MethodCall(null, Tokens.DMO_FillClass, new CpsOp[] {
CpsOp.GetSField(r.metaObject),
- CpsOp.StringArray(false, anames),
- CpsOp.StringArray(false, all_attr.ToArray()),
+ CpsOp.StringArray(false, all_slot.ToArray()),
CpsOp.NewArray(Tokens.DynMetaObject, super),
CpsOp.NewArray(Tokens.DynMetaObject, mro) }));
}
@@ -3556,6 +3560,8 @@ public class CLRBackend {
if (m is ParametricRole) return;
Method[] methods = (m is Class) ? ((Class)m).methods :
((Role)m).methods;
+ Attribute[] attrs = (m is Class) ? ((Class)m).attributes :
+ ((Role)m).attributes;
foreach (Method me in methods) {
MethodInfo mi = Tokens.DMO_AddFooMethod[me.kind];
thaw.Add(CpsOp.MethodCall(null, mi, new CpsOp[] {
@@ -3564,6 +3570,14 @@ public class CLRBackend {
CpsOp.GetSField(me.body.Resolve<StaticSub>().protosub)
}));
}
+ foreach (Attribute a in attrs) {
+ CpsOp init = a.ibody == null ? CpsOp.Null(Tokens.IP6) :
+ CpsOp.GetSField(a.ibody.Resolve<StaticSub>().protosub);
+ thaw.Add(CpsOp.MethodCall(null, Tokens.DMO_AddAttribute,
+ new CpsOp[] { CpsOp.GetSField(m.metaObject),
+ CpsOp.StringLiteral(a.name),
+ CpsOp.BoolLiteral(a.publ), init }));
+ }
thaw.Add(CpsOp.MethodCall(null, Tokens.DMO_Invalidate,
new CpsOp [] { CpsOp.GetSField(m.metaObject) }));
thaw.Add(CpsOp.SetField(Tokens.DMO_how, CpsOp.GetSField(m.metaObject),
View
4 lib/JSYNC.cs
@@ -107,7 +107,7 @@ public class JsyncWriter {
for (int i = 0; i < mo.nslots; i++) {
o.Append(',');
- WriteStr(true, mo.all_attr[i]);
+ WriteStr(true, mo.all_slot[i]);
o.Append(':');
WriteObj(((Variable)dyo.slots[i]).Fetch());
}
@@ -588,7 +588,7 @@ public class JsyncReader {
} else {
DynObject dyo = new DynObject(p_cursor.mo);
for (int i = 0; i < dyo.mo.nslots; i++) {
- string sn = dyo.mo.all_attr[i];
+ string sn = dyo.mo.all_slot[i];
if (!zyg.ContainsKey(sn))
Err("No value for attribute " + sn + " in thawed value of class " + dyo.mo.name);
dyo.slots[i] = zyg[sn];
View
48 lib/Kernel.cs
@@ -1036,6 +1036,12 @@ class IxListAtPos : IndexHandler {
// NOT IP6; these things should only be exposed through a ClassHOW-like
// façade
public class DynMetaObject {
+ public struct AttrInfo {
+ public string name;
+ public IP6 init;
+ public bool publ;
+ }
+
public static readonly ContextHandler<Variable> CallStr
= new CtxCallMethod("Str");
public static readonly ContextHandler<Variable> CallBool
@@ -1116,11 +1122,11 @@ public List<DynMetaObject> superclasses
= new Dictionary<string, IP6>();
public Dictionary<string, IP6> submethods
= new Dictionary<string, IP6>();
- public List<string> local_attr = new List<string>();
+ public List<AttrInfo> local_attr = new List<AttrInfo>();
public Dictionary<string, int> slotMap = new Dictionary<string, int>();
public int nslots = 0;
- public string[] all_attr;
+ public string[] all_slot;
private WeakReference wr_this;
// protected by static lock
@@ -1294,6 +1300,14 @@ public List<DynMetaObject> superclasses
submethods[name] = code;
}
+ public void AddAttribute(string name, bool publ, IP6 init) {
+ AttrInfo ai;
+ ai.name = name;
+ ai.publ = publ;
+ ai.init = init;
+ local_attr.Add(ai);
+ }
+
public IP6 GetPrivateMethod(string name) {
IP6 code = priv[name];
if (code == null) { throw new NieczaException("private method lookup failed for " + name + " in class " + this.name); }
@@ -1301,32 +1315,30 @@ public List<DynMetaObject> superclasses
}
- public void FillProtoClass(string[] attr) {
- FillClass(attr, attr, new DynMetaObject[] {},
+ public void FillProtoClass(string[] slots) {
+ FillClass(slots, new DynMetaObject[] {},
new DynMetaObject[] { this });
}
- public void FillClass(string[] local_attr, string[] all_attr,
- DynMetaObject[] superclasses, DynMetaObject[] mro) {
+ public void FillClass(string[] all_slot, DynMetaObject[] superclasses,
+ DynMetaObject[] mro) {
this.superclasses = new List<DynMetaObject>(superclasses);
SetMRO(mro);
- this.local_attr = new List<string>(local_attr);
this.butCache = new Dictionary<DynMetaObject, DynMetaObject>();
- this.all_attr = all_attr;
+ this.all_slot = all_slot;
this.local_does = new DynMetaObject[0];
nslots = 0;
- foreach (string an in all_attr) {
+ foreach (string an in all_slot) {
slotMap[an] = nslots++;
}
Invalidate();
}
- public void FillRole(string[] attr, DynMetaObject[] superclasses,
+ public void FillRole(DynMetaObject[] superclasses,
DynMetaObject[] cronies) {
this.superclasses = new List<DynMetaObject>(superclasses);
- this.local_attr = new List<string>(attr);
this.local_does = cronies;
this.isRole = true;
Revalidate(); // need to call directly as we aren't in any mro list
@@ -1690,13 +1702,16 @@ public class Kernel {
return NewROScalar(AnyP);
}
- public static Variable DefaultNew(IP6 proto) {
+ public static Variable DefaultNew(IP6 proto, VarHash args) {
DynObject n = new DynObject(((DynObject)proto).mo);
DynMetaObject[] mro = n.mo.mro;
for (int i = mro.Length - 1; i >= 0; i--) {
- foreach (string s in mro[i].local_attr) {
- n.SetSlot(s, NewRWScalar(AnyMO, AnyP));
+ foreach (DynMetaObject.AttrInfo a in mro[i].local_attr) {
+ IP6 val = a.init == null ? AnyP :
+ RunInferior(a.init.Invoke(GetInferiorRoot(),
+ Variable.None, null)).Fetch();
+ n.SetSlot(a.name, NewRWScalar(AnyMO, val));
}
}
@@ -1937,10 +1952,11 @@ public class Kernel {
DynMetaObject[] nmro = new DynMetaObject[b.mro.Length + 1];
Array.Copy(b.mro, 0, nmro, 1, b.mro.Length);
nmro[0] = n;
- n.FillClass(b.local_attr.ToArray(), b.all_attr,
- new DynMetaObject[] { b }, nmro);
+ n.FillClass(b.all_slot, new DynMetaObject[] { b }, nmro);
foreach (KeyValuePair<string, IP6> kv in role.priv)
n.AddPrivateMethod(kv.Key, kv.Value);
+ foreach (DynMetaObject.AttrInfo ai in role.local_attr)
+ n.AddAttribute(ai.name, ai.publ, ai.init);
foreach (KeyValuePair<string, IP6> kv in role.ord_methods)
n.AddMethod(kv.Key, kv.Value);
n.Invalidate();
View
3  lib/NieczaCLR.cs
@@ -69,8 +69,7 @@ public class NieczaCLR {
DynMetaObject[] mro = new DynMetaObject[pm.mro.Length + 1];
Array.Copy(pm.mro, 0, mro, 1, pm.mro.Length);
mro[0] = m;
- m.FillClass(new string[] { }, new string[] { },
- new DynMetaObject[] { pm }, mro);
+ m.FillClass(new string[] { }, new DynMetaObject[] { pm }, mro);
m.loc_to_clr = CLRToCLR.Instance;
if (NieczaCLROpts.Debug)
Console.WriteLine("Setting up wrapper for {0}", t.FullName);
View
4 lib/SAFE.setting
@@ -38,8 +38,8 @@ my class Mu {
[l i (+ (l i) (int 2))])]
[ns (l obj)])
} }
- method CREATE() { Q:CgOp { (default_new (@ (l self))) } }
- method new() { Q:CgOp { (default_new (@ {self})) } }
+ method CREATE(*%_) { Q:CgOp { (default_new (@ {self}) (unbox varhash (@ {%_}))) } }
+ method new(*%_) { Q:CgOp { (default_new (@ {self}) (unbox varhash (@ {%_}))) } }
}
my class Any is Mu {
View
31 src/Metamodel.pm
@@ -236,7 +236,7 @@ our %units;
has exports => (is => 'rw', isa => 'ArrayRef[ArrayRef[Str]]');
sub add_attribute {
- my ($self, $name) = @_;
+ my ($self, $name, $public, $ivar, $ibody) = @_;
die "attribute $name defined in a lowly package";
}
@@ -281,8 +281,9 @@ our %units;
has _closing => (isa => 'Bool', is => 'rw');
sub add_attribute {
- my ($self, $name) = @_;
- push @{ $self->attributes }, Metamodel::Attribute->new(name => $name);
+ my ($self, $name, $public, $ivar, $ibody) = @_;
+ push @{ $self->attributes }, Metamodel::Attribute->new(name => $name,
+ public => $public, ivar => $ivar, ibody => $ibody);
}
sub add_method {
@@ -368,8 +369,9 @@ our %units;
default => sub { [] });
sub add_attribute {
- my ($self, $name) = @_;
- push @{ $self->attributes }, Metamodel::Attribute->new(name => $name);
+ my ($self, $name, $public, $ivar, $ibody) = @_;
+ push @{ $self->attributes }, Metamodel::Attribute->new(name => $name,
+ public => $public, ivar => $ivar, ibody => $ibody);
}
sub add_method {
@@ -404,8 +406,9 @@ our %units;
default => sub { [] });
sub add_attribute {
- my ($self, $name) = @_;
- push @{ $self->attributes }, Metamodel::Attribute->new(name => $name);
+ my ($self, $name, $public, $ivar, $ibody) = @_;
+ push @{ $self->attributes }, Metamodel::Attribute->new(name => $name,
+ public => $public, ivar => $ivar, ibody => $ibody);
}
sub add_method {
@@ -455,7 +458,10 @@ our %units;
package Metamodel::Attribute;
use Moose;
- has name => (isa => 'Str', is => 'ro', required => 1);
+ has name => (isa => 'Str', is => 'ro', required => 1);
+ has public => (isa => 'Bool', is => 'ro');
+ has ivar => (isa => 'Maybe[Str]', is => 'ro');
+ has ibody => (isa => 'Maybe[ArrayRef]', is => 'ro');
no Moose;
__PACKAGE__->meta->make_immutable;
@@ -1004,8 +1010,15 @@ sub Op::Attribute::begin {
" declared outside of any class");
die "attribute $self->name declared in an augment"
if $opensubs[-1]->augmenting;
+ my ($ibref, $ibvar);
+ if ($self->initializer) {
+ my $ibody = $self->initializer->begin;
+ $ibvar = Niecza::Actions->gensym;
+ $opensubs[-1]->add_my_sub($ibvar, $ibody);
+ $ibref = $ibody->xref;
+ }
$ns = $unit->deref($ns);
- $ns->add_attribute($self->name);
+ $ns->add_attribute($self->name, ($self->accessor ? 1 : 0), $ibvar, $ibref);
my $nb = Metamodel::StaticSub->new(
unit => $unit,
outer => $opensubs[-1]->xref,
View
2  src/NAMBackend.pm
@@ -124,7 +124,7 @@ sub Metamodel::Method::to_nam {
}
sub Metamodel::Attribute::to_nam {
- [ $_[0]->name ]
+ [ $_[0]->name, $_[0]->public, $_[0]->ivar, $_[0]->ibody ]
}
sub Sig::Parameter::to_nam {
View
8 src/Niecza/Actions.pm
@@ -1245,7 +1245,7 @@ sub INFIX { my ($cl, $M) = @_;
$M->{_ast} = Op::CallSub->new(node($M), invocant => $fn,
positionals => [ $l, $r ]);
- if ($s eq '&infix:<=>' || $s eq '&assignop') {
+ if ($s eq '&infix:<=>') {
# Assignments to has and state declarators are rewritten into
# an appropriate phaser
if ($l->isa('Op::Lexical') && $l->state_decl) {
@@ -1254,6 +1254,12 @@ sub INFIX { my ($cl, $M) = @_;
Op::Start->new(condvar => $cv, body => $M->{_ast}),
Op::Lexical->new(name => $l->name)]);
}
+ elsif ($l->isa('Op::Attribute') && !$l->initializer) {
+ $l->initializer(
+ $cl->sl_to_block('bare', $r, subname => $l->name . " init")
+ );
+ $M->{_ast} = $l;
+ }
elsif ($l->isa('Op::ConstantDecl') && !$l->init) {
$l->init($r);
$M->{_ast} = $l;
View
1  src/Op.pm
@@ -846,6 +846,7 @@ use CgOp;
has name => (isa => 'Str', is => 'ro');
has accessor => (isa => 'Bool', is => 'ro');
+ has initializer => (isa => 'Maybe[Body]', is => 'rw');
sub code {
my ($self, $body) = @_;
View
13 test2.pl
@@ -27,6 +27,19 @@
}
{
+ my class X1 {
+ has $.a = 123;
+ has $.b;
+ }
+
+ my $x = X1.new;
+ ok !defined($x.b), "without initializer, attr is undefined";
+ is $x.a, 123, "initializers work";
+ $x.a = 456;
+ is $x.a, 456, "initialized attrs can still be reset";
+}
+
+{
my $str = '';
$str ~= 1;
INIT $str ~= 2;
Please sign in to comment.
Something went wrong with that request. Please try again.