Skip to content

Commit b939813

Browse files
committed
Implemented casts and prototypes
1 parent c531930 commit b939813

File tree

5 files changed

+119
-79
lines changed

5 files changed

+119
-79
lines changed

src/AngleSharp.Scripting.JavaScript/DomConstructorInstance.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,46 @@
44
using Jint.Native.Function;
55
using Jint.Native.Object;
66
using Jint.Runtime;
7+
using Jint.Runtime.Interop;
8+
using System;
79
using System.Reflection;
810

911
sealed class DomConstructorInstance : FunctionInstance, IConstructor
1012
{
11-
readonly ConstructorInfo _constructor;
12-
readonly EngineInstance _engine;
13+
private readonly ConstructorInfo _constructor;
14+
private readonly EngineInstance _engine;
15+
private readonly ObjectInstance _prototype;
1316

14-
public DomConstructorInstance(EngineInstance engine, ConstructorInfo constructor)
17+
public DomConstructorInstance(EngineInstance engine, Type type)
1518
: base(engine.Jint, null, null, false)
1619
{
20+
var toString = new ClrFunctionInstance(Engine, ToString);
21+
_prototype = engine.GetDomPrototype(type);
1722
_engine = engine;
23+
FastAddProperty("toString", toString, true, false, true);
24+
FastAddProperty("prototype", _prototype, false, false, false);
25+
_prototype.FastAddProperty("constructor", this, true, false, true);
26+
}
27+
28+
public DomConstructorInstance(EngineInstance engine, ConstructorInfo constructor)
29+
: this(engine, constructor.DeclaringType)
30+
{
1831
_constructor = constructor;
1932
}
2033

2134
public override JsValue Call(JsValue thisObject, JsValue[] arguments)
2235
{
23-
throw new JavaScriptException("Only call the constructor with the new keyword.");
36+
if (_constructor != null)
37+
throw new JavaScriptException("Only call the constructor with the new keyword.");
38+
39+
return ((IConstructor)this).Construct(arguments);
2440
}
2541

26-
public ObjectInstance Construct(JsValue[] arguments)
42+
ObjectInstance IConstructor.Construct(JsValue[] arguments)
2743
{
44+
if (_constructor == null)
45+
throw new JavaScriptException("Illegal constructor.");
46+
2847
try
2948
{
3049
var parameters = _engine.BuildArgs(_constructor, arguments);
@@ -35,7 +54,11 @@ public ObjectInstance Construct(JsValue[] arguments)
3554
{
3655
throw new JavaScriptException(_engine.Jint.Error);
3756
}
57+
}
3858

59+
private JsValue ToString(JsValue thisObj, JsValue[] arguments)
60+
{
61+
return $"function {_prototype.Class}() {{ [native code] }}";
3962
}
4063
}
4164
}

src/AngleSharp.Scripting.JavaScript/DomFunctionInstance.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88

99
sealed class DomFunctionInstance : FunctionInstance
1010
{
11-
private readonly MethodInfo _method;
1211
private readonly EngineInstance _engine;
12+
private readonly MethodInfo _method;
1313

1414
public DomFunctionInstance(EngineInstance engine, MethodInfo method)
1515
: base(engine.Jint, method.GetParameterNames(), null, false)
1616
{
17+
var toString = new ClrFunctionInstance(Engine, ToString);
1718
_engine = engine;
1819
_method = method;
19-
20-
FastAddProperty("toString", new ClrFunctionInstance(Engine, ToString), true, false, true);
20+
FastAddProperty("toString", toString, true, false, true);
2121
}
2222

2323
public override JsValue Call(JsValue thisObject, JsValue[] arguments)
@@ -53,7 +53,7 @@ private JsValue ToString(JsValue thisObj, JsValue[] arguments)
5353
}
5454

5555
var officialName = _method.GetOfficialName();
56-
return string.Format("function {0} () {{ [native code] }}", officialName);
56+
return $"function {officialName}() {{ [native code] }}";
5757
}
5858
}
5959
}

src/AngleSharp.Scripting.JavaScript/DomPrototypeInstance.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ sealed class DomPrototypeInstance : ObjectInstance
2222
public DomPrototypeInstance(EngineInstance engine, Type type)
2323
: base(engine.Jint)
2424
{
25-
var baseType = type.GetTypeInfo().BaseType;
25+
var baseType = type.GetTypeInfo().BaseType ?? typeof(Object);
2626
_type = type;
2727
_name = type.GetOfficialName(baseType);
2828
_engine = engine;

src/AngleSharp.Scripting.JavaScript/EngineInstance.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public EngineInstance(IWindow window, IDictionary<String, Object> assignments)
5050
_lexicals = LexicalEnvironment.NewObjectEnvironment(_engine, _window, _engine.ExecutionContext.LexicalEnvironment, true);
5151
_variables = LexicalEnvironment.NewObjectEnvironment(_engine, _engine.Global, null, false);
5252

53-
this.AddConstructors(_window, typeof(INode));
54-
this.AddConstructors(_window, this.GetType());
53+
this.AddConstructors(_window, typeof(INode).GetAssembly());
54+
this.AddConstructors(_window, this.GetType().GetAssembly());
5555
this.AddInstances(_window, this.GetType());
5656
}
5757

src/AngleSharp.Scripting.JavaScript/Extensions.cs

Lines changed: 84 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -98,78 +98,41 @@ public static Object FromJsValue(this JsValue val)
9898
return val.ToObject();
9999
}
100100

101-
public static Object As(this Object value, Type targetType, EngineInstance engine)
101+
public static Object As(this JsValue value, Type targetType, EngineInstance engine)
102102
{
103-
if (value != null)
103+
if (value != JsValue.Null)
104104
{
105-
var sourceType = value.GetType();
106-
107-
if (sourceType == targetType || sourceType.GetTypeInfo().IsSubclassOf(targetType) || targetType.GetTypeInfo().IsAssignableFrom(sourceType.GetTypeInfo()))
105+
if (targetType == typeof(Int32))
108106
{
109-
return value;
110-
}
111-
else if (targetType == typeof(Int32))
112-
{
113-
if (sourceType != typeof(Double))
114-
{
115-
var v = value.ToJsValue(engine);
116-
return TypeConverter.ToInt32(v);
117-
}
118-
119-
return (Int32)(Double)value;
107+
return TypeConverter.ToInt32(value);
120108
}
121109
else if (targetType == typeof(Double))
122110
{
123-
var v = value.ToJsValue(engine);
124-
return TypeConverter.ToNumber(v);
111+
return TypeConverter.ToNumber(value);
125112
}
126113
else if (targetType == typeof(String))
127114
{
128-
var v = value.ToJsValue(engine);
129-
130-
if (v.IsPrimitive())
131-
{
132-
return TypeConverter.ToString(v);
133-
}
134-
135-
return v.ToString();
115+
return value.IsPrimitive() ? TypeConverter.ToString(value) : value.ToString();
136116
}
137117
else if (targetType == typeof(Boolean))
138118
{
139-
var v = value.ToJsValue(engine);
140-
return TypeConverter.ToBoolean(v);
119+
return TypeConverter.ToBoolean(value);
141120
}
142-
else if (targetType.GetTypeInfo().IsSubclassOf(typeof(Delegate)))
121+
else if (targetType == typeof(UInt32))
143122
{
144-
var f = value as FunctionInstance;
145-
146-
if (f == null)
147-
{
148-
var b = value as String;
149-
150-
if (b != null)
151-
{
152-
var e = engine.Jint;
153-
var p = new[] { new JsValue(b) };
154-
f = new ClrFunctionInstance(e, (_this, args) => e.Eval.Call(_this, p));
155-
}
156-
}
157-
158-
if (f != null)
159-
{
160-
return targetType.ToDelegate(f, engine);
161-
}
123+
return TypeConverter.ToUint32(value);
124+
}
125+
else if (targetType == typeof(UInt16))
126+
{
127+
return TypeConverter.ToUint16(value);
128+
}
129+
else
130+
{
131+
return value.AsComplex(targetType, engine);
162132
}
163-
164-
var method = sourceType.PrepareConvert(targetType);
165-
166-
if (method == null)
167-
throw new JavaScriptException("[Internal] Could not find corresponding cast target.");
168-
169-
return method.Invoke(value, null);
170133
}
171134

172-
return value;
135+
return null;
173136
}
174137

175138
public static Object GetDefaultValue(this Type type)
@@ -218,7 +181,7 @@ public static Object[] BuildArgs(this EngineInstance context, MethodBase method,
218181
}
219182
else
220183
{
221-
args[i + offset] = arguments[i].FromJsValue().As(parameters[i].ParameterType, context);
184+
args[i + offset] = arguments[i].As(parameters[i].ParameterType, context);
222185
}
223186
}
224187

@@ -255,11 +218,16 @@ public static String[] GetParameterNames(this MethodInfo method)
255218
return method != null ? method.GetParameters().Select(m => m.Name).ToArray() : null;
256219
}
257220

258-
public static void AddConstructors(this EngineInstance engine, ObjectInstance obj, Type type)
221+
public static Assembly GetAssembly(this Type type)
259222
{
260-
foreach (var exportedType in type.GetTypeInfo().Assembly.ExportedTypes)
223+
return type.GetTypeInfo().Assembly;
224+
}
225+
226+
public static void AddConstructors(this EngineInstance engine, ObjectInstance ctx, Assembly assembly)
227+
{
228+
foreach (var exportedType in assembly.ExportedTypes)
261229
{
262-
engine.AddConstructor(obj, exportedType);
230+
engine.AddConstructor(ctx, exportedType);
263231
}
264232
}
265233

@@ -273,14 +241,15 @@ public static void AddInstances(this EngineInstance engine, ObjectInstance obj,
273241

274242
public static void AddConstructor(this EngineInstance engine, ObjectInstance obj, Type type)
275243
{
276-
var info = type.GetTypeInfo().DeclaredConstructors.FirstOrDefault(m =>
277-
m.GetCustomAttributes<DomConstructorAttribute>().Any());
244+
var ti = type.GetTypeInfo();
245+
var names = ti.GetCustomAttributes<DomNameAttribute>();
246+
var name = names.FirstOrDefault();
278247

279-
if (info != null)
248+
if (name != null)
280249
{
281-
var name = type.GetTypeInfo().GetOfficialName();
282-
var constructor = new DomConstructorInstance(engine, info);
283-
obj.FastSetProperty(name, new PropertyDescriptor(constructor, false, true, false));
250+
var info = ti.DeclaredConstructors.FirstOrDefault(m => m.GetCustomAttributes<DomConstructorAttribute>().Any());
251+
var constructor = info != null ? new DomConstructorInstance(engine, info) : new DomConstructorInstance(engine, type);
252+
obj.FastSetProperty(name.OfficialName, new PropertyDescriptor(constructor, false, true, false));
284253
}
285254
}
286255

@@ -328,7 +297,16 @@ public static String GetOfficialName(this Type currentType, Type baseType)
328297

329298
if (name == null)
330299
{
331-
foreach (var impl in ti.ImplementedInterfaces.Except(baseType.GetTypeInfo().ImplementedInterfaces))
300+
var interfaces = ti.ImplementedInterfaces;
301+
302+
if (baseType != null)
303+
{
304+
var bi = baseType.GetTypeInfo();
305+
var exclude = bi.ImplementedInterfaces;
306+
interfaces = interfaces.Except(exclude);
307+
}
308+
309+
foreach (var impl in interfaces)
332310
{
333311
name = impl.GetTypeInfo().GetCustomAttribute<DomNameAttribute>(false)?.OfficialName;
334312

@@ -337,7 +315,46 @@ public static String GetOfficialName(this Type currentType, Type baseType)
337315
}
338316
}
339317

340-
return name ?? currentType.Name;
318+
return name;
319+
}
320+
321+
private static Object AsComplex(this JsValue value, Type targetType, EngineInstance engine)
322+
{
323+
var obj = value.FromJsValue();
324+
var sourceType = obj.GetType();
325+
326+
if (sourceType == targetType || sourceType.GetTypeInfo().IsSubclassOf(targetType) || targetType.GetTypeInfo().IsAssignableFrom(sourceType.GetTypeInfo()))
327+
{
328+
return obj;
329+
}
330+
else if (targetType.GetTypeInfo().IsSubclassOf(typeof(Delegate)))
331+
{
332+
var f = obj as FunctionInstance;
333+
334+
if (f == null)
335+
{
336+
var b = obj as String;
337+
338+
if (b != null)
339+
{
340+
var e = engine.Jint;
341+
var p = new[] { new JsValue(b) };
342+
f = new ClrFunctionInstance(e, (_this, args) => e.Eval.Call(_this, p));
343+
}
344+
}
345+
346+
if (f != null)
347+
{
348+
return targetType.ToDelegate(f, engine);
349+
}
350+
}
351+
352+
var method = sourceType.PrepareConvert(targetType);
353+
354+
if (method == null)
355+
throw new JavaScriptException("[Internal] Could not find corresponding cast target.");
356+
357+
return method.Invoke(obj, null);
341358
}
342359
}
343360
}

0 commit comments

Comments
 (0)