fix more property wrapping stuff

This commit is contained in:
Adam D. Ruppe 2022-01-15 13:22:34 -05:00
parent db857a4470
commit 1debdf7cc7
2 changed files with 72 additions and 17 deletions

60
jsvar.d
View File

@ -808,7 +808,14 @@ struct var {
public var opOpAssign(string op, T)(T t) {
if(payloadType() == Type.Object) {
if(this._payload._object !is null) {
if(auto pt = cast(PropertyPrototype) this._payload._object) {
auto propValue = pt.get;
auto result = propValue.opOpAssign!(op)(t);
pt.set(result);
return result;
} else if(this._payload._object !is null) {
var* operator = this._payload._object._peekMember("opOpAssign", true);
if(operator !is null && operator._type == Type.Function)
return operator.call(this, op, t);
@ -1375,7 +1382,7 @@ struct var {
else
return *(new var);
}
return from._getMember(name, true, false, file, line);
return from._getMember(name, true, false, false, file, line);
}
public ref var opIndexAssign(T)(T t, string name, string file = __FILE__, size_t line = __LINE__) {
@ -1823,12 +1830,14 @@ class PrototypeObject {
}
// FIXME: maybe throw something else
/*package*/ ref var _getMember(string name, bool recurse, bool throwOnFailure, string file = __FILE__, size_t line = __LINE__) {
/*package*/ ref var _getMember(string name, bool recurse, bool throwOnFailure, bool returnRawProperty = false, string file = __FILE__, size_t line = __LINE__) {
var* mem = _peekMember(name, recurse);
if(mem !is null) {
// If it is a property, we need to call the getter on it
if((*mem).payloadType == var.Type.Object && cast(PropertyPrototype) (*mem)._payload._object) {
if(returnRawProperty)
return *mem;
auto prop = cast(PropertyPrototype) (*mem)._payload._object;
return prop.get;
}
@ -1854,14 +1863,25 @@ class PrototypeObject {
/*package*/ ref var _setMember(string name, var t, bool recurse, bool throwOnFailure, bool suppressOverloading, string file = __FILE__, size_t line = __LINE__) {
var* mem = _peekMember(name, recurse);
bool onParent = false;
if(mem is null && !recurse) {
mem = _peekMember(name, true); // properties need the check anyway as a setter might be on a prototype
onParent = true;
}
if(mem !is null) {
// Property check - the setter should be proxied over to it
if((*mem).payloadType == var.Type.Object && cast(PropertyPrototype) (*mem)._payload._object) {
auto prop = cast(PropertyPrototype) (*mem)._payload._object;
return prop.set(t);
}
*mem = t;
return *mem;
if(!onParent) {
*mem = t;
return *mem;
} else {
mem = null;
}
}
if(!suppressOverloading) {
@ -2369,6 +2389,36 @@ unittest {
);
}
version(with_arsd_script)
unittest {
import arsd.script;
static class Test {
@scriptable int a;
}
Test test = new Test;
test.a = 15;
var globals = var.emptyObject;
globals.test = test;
globals.Test = subclassable!Test;
interpret(q{
test.a = 4;
var wtf = test.a += 5;
assert(wtf == 9);
assert(test.a == 9);
var test2 = new Test;
test2.a = 2;
test2.a += 5;
assert(test2.a == 7);
}, globals);
assert(test.a == 9);
assert(globals.test2.get!Test.a == 7);
}
// just a base class we can reference when looking for native objects
class WrappedNativeObject : PrototypeObject {
TypeInfo wrappedType;

View File

@ -1503,7 +1503,7 @@ class OpAssignExpression : Expression {
var n;
foreach(ctOp; CtList!("+=", "-=", "*=", "/=", "~=", "&=", "|=", "^=", "%="))
if(ctOp[0..1] == op)
n = mixin("v.getVar(sc) "~ctOp~" right");
n = mixin("v.getVar(sc, true, true) "~ctOp~" right");
// FIXME: ensure the variable is updated in scope too
@ -1579,9 +1579,9 @@ class VariableExpression : Expression {
return getVar(sc).get!string;
}
ref var getVar(PrototypeObject sc, bool recurse = true) {
ref var getVar(PrototypeObject sc, bool recurse = true, bool returnRawProperty = false) {
try {
return sc._getMember(identifier, true /* FIXME: recurse?? */, true);
return sc._getMember(identifier, true /* FIXME: recurse?? */, true, returnRawProperty);
} catch(DynamicTypeException dte) {
dte.callStack ~= loc;
throw dte;
@ -1592,7 +1592,12 @@ class VariableExpression : Expression {
return sc._setMember(identifier, t, true /* FIXME: recurse?? */, true, suppressOverloading);
}
ref var getVarFrom(PrototypeObject sc, ref var v) {
ref var getVarFrom(PrototypeObject sc, ref var v, bool returnRawProperty) {
if(returnRawProperty) {
if(v.payloadType == var.Type.Object)
return v._payload._object._getMember(identifier, true, false, returnRawProperty);
}
return v[identifier];
}
@ -1658,7 +1663,7 @@ class DotVarExpression : VariableExpression {
return e1.toString() ~ "." ~ e2.toString();
}
override ref var getVar(PrototypeObject sc, bool recurse = true) {
override ref var getVar(PrototypeObject sc, bool recurse = true, bool returnRawProperty = false) {
if(!this.recurse) {
// this is a special hack...
if(auto ve = cast(VariableExpression) e1) {
@ -1676,7 +1681,7 @@ class DotVarExpression : VariableExpression {
}
if(auto ve = cast(VariableExpression) e1) {
return this.getVarFrom(sc, ve.getVar(sc, recurse));
return this.getVarFrom(sc, ve.getVar(sc, recurse), returnRawProperty);
} else if(cast(StringLiteralExpression) e1 && e2.identifier == "interpolate") {
auto se = cast(StringLiteralExpression) e1;
var* functor = new var;
@ -1690,7 +1695,7 @@ class DotVarExpression : VariableExpression {
// make a temporary for the lhs
auto v = new var();
*v = e1.interpret(sc).value;
return this.getVarFrom(sc, *v);
return this.getVarFrom(sc, *v, returnRawProperty);
}
}
@ -1702,8 +1707,8 @@ class DotVarExpression : VariableExpression {
}
override ref var getVarFrom(PrototypeObject sc, ref var v) {
return e2.getVarFrom(sc, v);
override ref var getVarFrom(PrototypeObject sc, ref var v, bool returnRawProperty) {
return e2.getVarFrom(sc, v, returnRawProperty);
}
override string toInterpretedString(PrototypeObject sc) {
@ -1725,13 +1730,13 @@ class IndexExpression : VariableExpression {
return e1.toString() ~ "[" ~ e2.toString() ~ "]";
}
override ref var getVar(PrototypeObject sc, bool recurse = true) {
override ref var getVar(PrototypeObject sc, bool recurse = true, bool returnRawProperty = false) {
if(auto ve = cast(VariableExpression) e1)
return ve.getVar(sc, recurse)[e2.interpret(sc).value];
return ve.getVar(sc, recurse, returnRawProperty)[e2.interpret(sc).value];
else {
auto v = new var();
*v = e1.interpret(sc).value;
return this.getVarFrom(sc, *v);
return this.getVarFrom(sc, *v, returnRawProperty);
}
}