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) { public var opOpAssign(string op, T)(T t) {
if(payloadType() == Type.Object) { 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); var* operator = this._payload._object._peekMember("opOpAssign", true);
if(operator !is null && operator._type == Type.Function) if(operator !is null && operator._type == Type.Function)
return operator.call(this, op, t); return operator.call(this, op, t);
@ -1375,7 +1382,7 @@ struct var {
else else
return *(new var); 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__) { 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 // 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); var* mem = _peekMember(name, recurse);
if(mem !is null) { if(mem !is null) {
// If it is a property, we need to call the getter on it // 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((*mem).payloadType == var.Type.Object && cast(PropertyPrototype) (*mem)._payload._object) {
if(returnRawProperty)
return *mem;
auto prop = cast(PropertyPrototype) (*mem)._payload._object; auto prop = cast(PropertyPrototype) (*mem)._payload._object;
return prop.get; 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__) { /*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); 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) { if(mem !is null) {
// Property check - the setter should be proxied over to it // Property check - the setter should be proxied over to it
if((*mem).payloadType == var.Type.Object && cast(PropertyPrototype) (*mem)._payload._object) { if((*mem).payloadType == var.Type.Object && cast(PropertyPrototype) (*mem)._payload._object) {
auto prop = cast(PropertyPrototype) (*mem)._payload._object; auto prop = cast(PropertyPrototype) (*mem)._payload._object;
return prop.set(t); return prop.set(t);
} }
*mem = t; if(!onParent) {
return *mem; *mem = t;
return *mem;
} else {
mem = null;
}
} }
if(!suppressOverloading) { 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 // just a base class we can reference when looking for native objects
class WrappedNativeObject : PrototypeObject { class WrappedNativeObject : PrototypeObject {
TypeInfo wrappedType; TypeInfo wrappedType;

View File

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