Skip to content

Commit

Permalink
Implement attribute initializers
Browse files Browse the repository at this point in the history
  • Loading branch information
sorear committed Dec 28, 2010
1 parent 0e836f6 commit d4638e1
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 52 deletions.
52 changes: 33 additions & 19 deletions lib/CLRBackend.cs
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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++)
Expand All @@ -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) }));
}
Expand Down Expand Up @@ -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[] {
Expand All @@ -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),
Expand Down
4 changes: 2 additions & 2 deletions lib/JSYNC.cs
Expand Up @@ -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());
}
Expand Down Expand Up @@ -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];
Expand Down
48 changes: 32 additions & 16 deletions lib/Kernel.cs
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1294,39 +1300,45 @@ 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); }
return code;
}


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
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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();
Expand Down
3 changes: 1 addition & 2 deletions lib/NieczaCLR.cs
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions lib/SAFE.setting
Expand Up @@ -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 {
Expand Down
31 changes: 22 additions & 9 deletions src/Metamodel.pm
Expand Up @@ -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";
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/NAMBackend.pm
Expand Up @@ -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 {
Expand Down
8 changes: 7 additions & 1 deletion src/Niecza/Actions.pm
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down

0 comments on commit d4638e1

Please sign in to comment.