Skip to content

Commit 83ef0f8

Browse files
committed
Fix Class members processing and scope level resolve
1 parent 389b47e commit 83ef0f8

2 files changed

Lines changed: 86 additions & 43 deletions

File tree

NiL.JS/Expressions/ClassDefinition.cs

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public MemberDescriptor(Expression name, Expression value, bool @static)
3232
public override string ToString()
3333
{
3434
if (_static)
35-
return "static " + _value;
36-
return _value.ToString();
35+
return "static " + _name + " = " + _value;
36+
return _name + " = " + _value;
3737
}
3838
}
3939

@@ -44,31 +44,32 @@ public sealed class ClassDefinition : EntityDefinition
4444
{
4545
private sealed class ClassConstructor : Function
4646
{
47-
private readonly ClassDefinition classDefinition;
47+
private readonly ClassDefinition _classDefinition;
4848
public override string name
4949
{
5050
get
5151
{
52-
return classDefinition.Name;
52+
return _classDefinition.Name;
5353
}
5454
}
5555

5656
public ClassConstructor(Context context, FunctionDefinition creator, ClassDefinition classDefinition)
5757
: base(context, creator)
5858
{
59-
this.classDefinition = classDefinition;
59+
_classDefinition = classDefinition;
6060
}
6161

6262
protected internal override JSValue ConstructObject()
6363
{
6464
var result = CreateObject();
6565
result.__proto__ = prototype._oValue as JSObject;
66+
_classDefinition.setProperties(Context, result, false);
6667
return result;
6768
}
6869

6970
public override string ToString(bool headerOnly)
7071
{
71-
return classDefinition.ToString();
72+
return _classDefinition.ToString();
7273
}
7374
}
7475

@@ -316,9 +317,7 @@ internal static CodeNode Parse(ParseInfo state, ref int index)
316317
string fieldName = null;
317318
if (state.Code[i] == '*')
318319
{
319-
do
320-
i++;
321-
while (Tools.IsWhiteSpace(state.Code[i]));
320+
do i++; while (Tools.IsWhiteSpace(state.Code[i]));
322321
}
323322

324323
if (Parser.ValidateName(state.Code, ref i, false, true, state.Strict))
@@ -352,7 +351,6 @@ internal static CodeNode Parse(ParseInfo state, ref int index)
352351
}
353352
else if (@static)
354353
{
355-
fieldName = "static " + fieldName;
356354
state.CodeContext |= CodeContext.InStaticMember;
357355
}
358356

@@ -365,18 +363,34 @@ internal static CodeNode Parse(ParseInfo state, ref int index)
365363
if (async)
366364
state.CodeContext |= CodeContext.InAsync;
367365

368-
i = s;
369-
var method = FunctionDefinition.Parse(state, ref i, async ? FunctionKind.AsyncMethod : FunctionKind.Method) as FunctionDefinition;
370-
if (method == null)
371-
ExceptionHelper.ThrowSyntaxError("Unable to parse method", state.Code, i);
366+
while (Tools.IsWhiteSpace(state.Code[i])) i++;
367+
368+
Expression expression = null;
369+
370+
if (async || asterisk || fieldName == "constructor")
371+
{
372+
i = s;
373+
expression = FunctionDefinition.Parse(state, ref i, async ? FunctionKind.AsyncMethod : FunctionKind.Method) as FunctionDefinition;
374+
if (expression == null)
375+
ExceptionHelper.ThrowSyntaxError("Unable to parse method", state.Code, i);
376+
}
377+
else if (state.Code[i] == '=')
378+
{
379+
do i++; while (Tools.IsWhiteSpace(state.Code[i]));
380+
expression = ExpressionTree.Parse(state, ref i) as Expression;
381+
}
382+
else if (state.Code[i] == ';')
383+
{
384+
i++;
385+
}
372386

373387
if (fieldName == "constructor")
374388
{
375-
ctor = method;
389+
ctor = expression as FunctionDefinition;
376390
}
377391
else
378392
{
379-
flds[fieldName] = new MemberDescriptor(new Constant(method._name), method, @static);
393+
flds[fieldName] = new MemberDescriptor(new Constant(fieldName), expression, @static);
380394
}
381395
}
382396
}
@@ -398,6 +412,7 @@ internal static CodeNode Parse(ParseInfo state, ref int index)
398412

399413
var classDefinition = new ClassDefinition(name, baseType, new List<MemberDescriptor>(flds.Values).ToArray(), ctor, computedProperties.ToArray());
400414
classDefinition.reference.ScopeLevel = state.LexicalScopeLevel;
415+
classDefinition.reference._descriptor.definitionScopeLevel = state.LexicalScopeLevel;
401416

402417
if ((state.CodeContext & CodeContext.InExpression) == 0)
403418
{
@@ -497,39 +512,36 @@ public override JSValue Evaluate(Context context)
497512
ctor.prototype.__proto__ = Tools.GetPropertyOrValue(baseProto.GetProperty("prototype"), baseProto)._oValue as JSObject;
498513
}
499514

500-
ctor.__proto__ = baseProto as JSObject;
515+
ctor.__proto__ = baseProto;
501516
}
502517

518+
setProperties(context, ctor, true);
519+
520+
variable?.Assign(ctor);
521+
522+
return ctor;
523+
}
524+
525+
private void setProperties(Context context, JSObject target, bool @static)
526+
{
503527
for (var i = 0; i < _members.Length; i++)
504528
{
505529
var member = _members[i];
506-
var value = member.Value.Evaluate(context);
507-
JSValue target = null;
508-
if (member.Static)
509-
{
510-
target = ctor;
511-
}
512-
else
513-
{
514-
target = ctor.prototype;
515-
}
530+
if (member.Static != @static)
531+
continue;
532+
533+
var value = member.Value?.Evaluate(context);
534+
if (value is null)
535+
continue;
516536

517537
target.SetProperty(member.Name.Evaluate(null), value, true);
518538
}
519539

520540
for (var i = 0; i < _computedProperties.Length; i++)
521541
{
522542
var member = _computedProperties[i];
523-
524-
JSObject target = null;
525-
if (member.Static)
526-
{
527-
target = ctor;
528-
}
529-
else
530-
{
531-
target = ctor.prototype._oValue as JSObject;
532-
}
543+
if (member.Static != @static)
544+
continue;
533545

534546
var key = member._name.Evaluate(context).CloneImpl(false);
535547
var value = member._value.Evaluate(context).CloneImpl(false);
@@ -575,10 +587,6 @@ public override JSValue Evaluate(Context context)
575587
}
576588
}
577589
}
578-
579-
variable?.Assign(ctor);
580-
581-
return ctor;
582590
}
583591

584592
public override T Visit<T>(Visitor<T> visitor)
@@ -657,7 +665,8 @@ public override void Optimize(ref CodeNode _this, FunctionDefinition owner, Inte
657665

658666
for (var i = _members.Length; i-- > 0;)
659667
{
660-
_members[i]._value.Optimize(ref _members[i]._value, owner, message, opts, stats);
668+
if (_members[i]._value is not null)
669+
_members[i]._value.Optimize(ref _members[i]._value, owner, message, opts, stats);
661670
}
662671

663672
for (var i = 0; i < _computedProperties.Length; i++)
@@ -681,7 +690,7 @@ public override void RebuildScope(FunctionInfo functionInfo, Dictionary<string,
681690
for (var i = 0; i < _members.Length; i++)
682691
{
683692
_members[i].Name.RebuildScope(functionInfo, null, scopeBias);
684-
_members[i].Value.RebuildScope(functionInfo, null, scopeBias);
693+
_members[i].Value?.RebuildScope(functionInfo, null, scopeBias);
685694
}
686695
}
687696
}

Tests/Fuzz/ClassMembers.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
(function () {
2+
3+
function f() { };
4+
var c = 1;
5+
class Test {
6+
d = 1;
7+
m = 1;
8+
static s = 2;
9+
constructor() {
10+
this.m = c++;
11+
}
12+
}
13+
14+
var t0 = new Test();
15+
var t1 = new Test();
16+
17+
console.assert(Test.s == 2, "Error #" + 1);
18+
console.assert(t0.s === undefined, "Error #" + 2);
19+
console.assert(t1.s === undefined, "Error #" + 3);
20+
console.assert(t0.s === undefined, "Error #" + 4);
21+
console.assert(t0.__proto__.s === undefined, "Error #" + 5)
22+
23+
console.assert(Test.d === undefined, "Error #" + 6);
24+
console.assert(t0.d === 1, "Error #" + 7);
25+
console.assert(t1.d === 1, "Error #" + 8);
26+
console.assert(t0.d === 1, "Error #" + 9);
27+
console.assert(t0.__proto__.d === undefined, "Error #" + 10);
28+
29+
console.assert(Test.m === undefined, "Error #" + 11);
30+
console.assert(t0.m === 1, "Error #" + 12);
31+
console.assert(t1.m === 2, "Error #" + 13);
32+
console.assert(t0.m === 1, "Error #" + 14);
33+
console.assert(t0.__proto__.m === undefined, "Error #" + 15);
34+
})();

0 commit comments

Comments
 (0)