Skip to content

Commit

Permalink
start super support, refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Dec 15, 2020
1 parent 5ea2472 commit ad12d3d
Show file tree
Hide file tree
Showing 19 changed files with 295 additions and 206 deletions.
2 changes: 1 addition & 1 deletion Jint.Tests/Runtime/Domain/UuidConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private JsValue Parse(JsValue @this, JsValue[] arguments)
return Undefined;
}

protected override ObjectInstance GetPrototypeOf() => _prototype;
protected internal override ObjectInstance GetPrototypeOf() => _prototype;

internal ObjectInstance _prototype;

Expand Down
2 changes: 1 addition & 1 deletion Jint.Tests/Runtime/Domain/UuidInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Jint.Tests.Runtime.Domain
{
internal class UuidInstance : ObjectInstance, IObjectWrapper
{
protected override ObjectInstance GetPrototypeOf() => _prototype;
protected internal override ObjectInstance GetPrototypeOf() => _prototype;

internal ObjectInstance _prototype;

Expand Down
12 changes: 6 additions & 6 deletions Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ internal JsValue GetValue(Reference reference, bool returnReferenceToPool)
if (baseValue.IsObject())
{
var o = TypeConverter.ToObject(this, baseValue);
var v = o.Get(property);
var v = o.Get(property, reference.GetThisValue());
return v;
}
else
Expand Down Expand Up @@ -672,7 +672,7 @@ public Node GetLastSyntaxNode()
/// <param name="property">The name of the property to return.</param>
public JsValue GetValue(JsValue scope, JsValue property)
{
var reference = _referencePool.Rent(scope, property, _isStrict);
var reference = _referencePool.Rent(scope, property, _isStrict, thisValue: null);
var jsValue = GetValue(reference, false);
_referencePool.Return(reference);
return jsValue;
Expand All @@ -687,20 +687,20 @@ internal Reference ResolveBinding(string name, LexicalEnvironment env = null)
return GetIdentifierReference(env, name, StrictModeScope.IsStrictModeCode);
}

private Reference GetIdentifierReference(LexicalEnvironment lex, string name, in bool strict)
private Reference GetIdentifierReference(LexicalEnvironment env, string name, in bool strict)
{
if (lex is null)
if (env is null)
{
return new Reference(JsValue.Undefined, name, strict);
}

var envRec = lex._record;
var envRec = env._record;
if (envRec.HasBinding(name))
{
return new Reference(envRec, name, strict);
}

return GetIdentifierReference(lex._outer, name, strict);
return GetIdentifierReference(env._outer, name, strict);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/Error/ErrorConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)

public ErrorPrototype PrototypeObject { get; private set; }

protected override ObjectInstance GetPrototypeOf()
protected internal override ObjectInstance GetPrototypeOf()
{
return _name._value != "Error" ? _engine.Error : _prototype;
}
Expand Down
181 changes: 22 additions & 159 deletions Jint/Native/Function/ClassConstructorInstance.cs
Original file line number Diff line number Diff line change
@@ -1,148 +1,52 @@
#nullable enable

using Esprima;
using Esprima.Ast;
using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Environments;
using Jint.Runtime.Interpreter.Expressions;
using Jint.Runtime.Interpreter;

namespace Jint.Native.Function
{
internal sealed class ClassConstructorInstance : FunctionInstance, IConstructor
{
private readonly Expression? _superClass;
private readonly ClassBody _body;
private readonly JintFunctionDefinition _constructorFunction;

public ClassConstructorInstance(
Engine engine,
Expression? superClass,
ClassBody body,
JintFunctionDefinition constructorFunction,
LexicalEnvironment scope,
string? name = null) : base(engine, name != null ? new JsString(name) : null, FunctionThisMode.Global)
string? name = null) : base(engine, name != null ? new JsString(name) : null, FunctionThisMode.Strict)
{
_superClass = superClass;
_body = body;
_constructorFunction = constructorFunction;
_environment = scope;
}

var env = _engine.ExecutionContext.LexicalEnvironment;
var classScope = LexicalEnvironment.NewDeclarativeEnvironment(_engine, env);

ObjectInstance? protoParent = null;
JsValue? constructorParent = null;
if (_superClass is null)
{
protoParent = _engine.Object.PrototypeObject;
constructorParent = _engine.Function.PrototypeObject;
}
else
{
_engine.ExecutionContext.UpdateLexicalEnvironment(classScope);
var superclassRef = JintExpression.Build(_engine, _superClass).GetValue();
_engine.ExecutionContext.UpdateLexicalEnvironment(env);

var superclass = _engine.GetValue(superclassRef);

if (superclass.IsNull())
{
protoParent = null;
constructorParent = _engine.Function.PrototypeObject;
}
else if (!superclass.IsConstructor)
{
ExceptionHelper.ThrowTypeError(_engine, "super class is not a constructor");
}
else
{
var temp = superclass.Get("prototype");
if (temp is ObjectInstance protoParentObject)
{
protoParent = protoParentObject;
}
else if (temp._type == InternalTypes.Null)
{
// OK
}
else
{
ExceptionHelper.ThrowTypeError(_engine);
return;
}

constructorParent = superclass;
}
}

var proto = _engine.Object.Construct(Arguments.Empty);
proto._prototype = protoParent;

MethodDefinition? constructor = null;
var classBody = _body.Body;
for (var i = 0; i < classBody.Count; ++i)
{
if (classBody[i].Kind == PropertyKind.Constructor)
{
constructor = (MethodDefinition) classBody[i];
break;
}
}
public override JsValue Call(JsValue thisValue, JsValue[] arguments)
{
var localEnv = LexicalEnvironment.NewFunctionEnvironment(_engine, this, Undefined);
_engine.EnterExecutionContext(localEnv, localEnv);
var envRec = (FunctionEnvironmentRecord) localEnv._record;
envRec.BindThisValue(thisValue);

if (constructor is null)
// actual call
using (new StrictModeScope(true, true))
{
string constructorText;
if (_superClass != null)
try
{
constructorText = "class temp { constructor(...args) { super(...args); } }";
_constructorFunction.Execute();
return Undefined;
}
else
finally
{
constructorText = "class temp { constructor() {} }";
_engine.LeaveExecutionContext();
}

var parser = new JavaScriptParser(constructorText, Engine.DefaultParserOptions);
var script = parser.ParseScript();
constructor = (MethodDefinition) script.Body[0].ChildNodes[2].ChildNodes[0];
}

_engine.ExecutionContext.UpdateLexicalEnvironment(classScope);

foreach (var classProperty in _body.Body)
{
if (classProperty is not MethodDefinition m)
{
continue;
}

var target = !m.Static ? proto : this;
var property = TypeConverter.ToPropertyKey(m.GetKey(_engine));
var valueExpression = JintExpression.Build(_engine, m.Value);
PropertyDefinitionEvaluation(
target,
m,
property,
valueExpression,
isStrictModeCode: true);
}

_prototype = proto;
//var temp = constructorParent as ObjectInstance ?? _engine.Function.PrototypeObject;
_prototypeDescriptor = new PropertyDescriptor(proto, PropertyFlag.AllForbidden);

_engine.ExecutionContext.UpdateLexicalEnvironment(env);
}

public override JsValue Call(JsValue thisObject, JsValue[] arguments)
{
return Construct(arguments, thisObject);
}

public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
{
var obj = new ObjectInstance(_engine)
{
_prototype = this
};
var obj = OrdinaryCreateFromConstructor(TypeConverter.ToObject(_engine, newTarget), _prototype);
Call(obj, arguments);
return obj;
}

Expand All @@ -155,49 +59,8 @@ public override string ToString()
{
name = TypeConverter.ToString(nameValue);
}
return "function " + name + "() {{[native code]}}";
}

private void PropertyDefinitionEvaluation(
ObjectInstance obj,
MethodDefinition property,
JsValue propName,
JintExpression valueExpression,
bool isStrictModeCode)
{
PropertyDescriptor? propDesc;
if (property.Kind == PropertyKind.Get || property.Kind == PropertyKind.Set)
{
var function = property.Value as IFunction ?? ExceptionHelper.ThrowSyntaxError<IFunction>(obj.Engine);

var functionInstance = new ScriptFunctionInstance(
obj.Engine,
function,
obj.Engine.ExecutionContext.LexicalEnvironment,
isStrictModeCode
);
functionInstance.SetFunctionName(propName);
functionInstance._prototypeDescriptor = null;

propDesc = new GetSetPropertyDescriptor(
get: property.Kind == PropertyKind.Get ? functionInstance : null,
set: property.Kind == PropertyKind.Set ? functionInstance : null,
PropertyFlag.Enumerable | PropertyFlag.Configurable);
}
else
{
var expr = valueExpression;
var propValue = expr.GetValue().Clone();
if (expr._expression.IsFunctionWithName())
{
var functionInstance = (FunctionInstance) propValue;
functionInstance.SetFunctionName(propName);
}

propDesc = new PropertyDescriptor(propValue, PropertyFlag.ConfigurableEnumerableWritable);
}

obj.DefinePropertyOrThrow(propName, propDesc);
return "function " + name + "() {{[native code]}}";
}
}
}

0 comments on commit ad12d3d

Please sign in to comment.