Skip to content

Commit 3eddbbc

Browse files
committed
Fix this in non-static class methods
1 parent 3449081 commit 3eddbbc

File tree

7 files changed

+97
-59
lines changed

7 files changed

+97
-59
lines changed

docs/docs/en/changelog.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
## Next
44

55
### Fixes
6-
- Fix passing arguments
6+
- Fix passing command-line arguments to scripts
7+
- Fix `this` in non-static class methods
78

89

910
## 2.0.0

docs/docs/ru/changelog.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# История изменений
22

3+
## Next
4+
5+
### Исправления
6+
- Исправлена передача аргументов командной строки скриптам
7+
- Исправлен `this` в нестатических методах классов
8+
9+
310
## 2.0.0
411

512
### Критические изменения

ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassDeclaration.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
public record ClassDeclaration(
66
String name,
77
List<ClassField> classFields,
8-
List<ClassMethod> classMethods) implements Instantiable {
8+
List<ClassMethod> classMethods
9+
) implements Instantiable {
910

1011
/**
1112
* Create an instance and put evaluated fields with method declarations

ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassInstance.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ public void addField(ClassField f) {
2525
thisMap.set(f.name(), f.evaluableValue().eval());
2626
}
2727

28-
public void addMethod(ClassMethod method) {
29-
method.setClassInstance(this);
30-
final String name = method.getName();
28+
public void addMethod(ClassMethod m) {
29+
final String name = m.name();
30+
final var method = new ClassMethod(m, this);
3131
thisMap.set(name, method);
3232
if (name.equals(className)) {
3333
constructor = method;

ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassMethod.java

+19-27
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,28 @@
22

33
import java.util.Objects;
44

5-
public class ClassMethod implements Function {
6-
private final String name;
7-
private final Function function;
8-
private ClassInstance classInstance;
5+
public record ClassMethod(
6+
String name,
7+
Function function,
8+
ClassInstance classInstance
9+
) implements Function {
910

1011
public ClassMethod(String name, Function function) {
11-
this.name = name;
12-
this.function = function;
12+
this(name, function, null);
1313
}
1414

15-
public String getName() {
16-
return name;
17-
}
18-
19-
public void setClassInstance(ClassInstance classInstance) {
20-
this.classInstance = classInstance;
15+
public ClassMethod(ClassMethod m, ClassInstance instance) {
16+
this(m.name, m.function, instance);
2117
}
2218

2319
@Override
2420
public Value execute(Value... args) {
25-
ScopeHandler.push();
26-
ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap());
27-
28-
try {
21+
try (final var ignored = ScopeHandler.closeableScope()) {
22+
if (classInstance != null) {
23+
// non-static method
24+
ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap());
25+
}
2926
return function.execute(args);
30-
} finally {
31-
ScopeHandler.pop();
3227
}
3328
}
3429

@@ -38,12 +33,11 @@ public int getArgsCount() {
3833
}
3934

4035
@Override
41-
public boolean equals(Object obj) {
42-
if (obj == this) return true;
43-
if (obj == null || obj.getClass() != this.getClass()) return false;
44-
var that = (ClassMethod) obj;
45-
return Objects.equals(this.name, that.name) &&
46-
Objects.equals(this.function, that.function);
36+
public boolean equals(Object o) {
37+
if (this == o) return true;
38+
if (!(o instanceof ClassMethod that)) return false;
39+
return Objects.equals(name, that.name)
40+
&& Objects.equals(function, that.function);
4741
}
4842

4943
@Override
@@ -53,8 +47,6 @@ public int hashCode() {
5347

5448
@Override
5549
public String toString() {
56-
return "ClassMethod[" +
57-
"name=" + name + ", " +
58-
"function=" + function + ']';
50+
return "ClassMethod[" + name + ']';
5951
}
6052
}

ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ConditionalExpression.java

+20-27
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public enum Operator {
2727

2828
private final String name;
2929

30-
private Operator(String name) {
30+
Operator(String name) {
3131
this.name = name;
3232
}
3333

@@ -36,7 +36,8 @@ public String getName() {
3636
}
3737
}
3838

39-
public final Node expr1, expr2;
39+
public final Node expr1;
40+
public final Node expr2;
4041
public final Operator operation;
4142

4243
public ConditionalExpression(Operator operation, Node expr1, Node expr2) {
@@ -47,25 +48,20 @@ public ConditionalExpression(Operator operation, Node expr1, Node expr2) {
4748

4849
@Override
4950
public Value eval() {
50-
switch (operation) {
51-
case AND:
52-
return NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0));
53-
case OR:
54-
return NumberValue.fromBoolean((expr1AsInt() != 0) || (expr2AsInt() != 0));
55-
56-
case NULL_COALESCE:
57-
return nullCoalesce();
58-
59-
default:
60-
return NumberValue.fromBoolean(evalAndCompare());
61-
}
51+
return switch (operation) {
52+
case AND -> NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0));
53+
case OR -> NumberValue.fromBoolean((expr1AsInt() != 0) || (expr2AsInt() != 0));
54+
case NULL_COALESCE -> nullCoalesce();
55+
default -> NumberValue.fromBoolean(evalAndCompare());
56+
};
6257
}
6358

6459
private boolean evalAndCompare() {
6560
final Value value1 = expr1.eval();
6661
final Value value2 = expr2.eval();
6762

68-
double number1, number2;
63+
double number1;
64+
double number2;
6965
if (value1.type() == Types.NUMBER) {
7066
number1 = value1.asNumber();
7167
number2 = value2.asNumber();
@@ -74,18 +70,15 @@ private boolean evalAndCompare() {
7470
number2 = 0;
7571
}
7672

77-
switch (operation) {
78-
case EQUALS: return number1 == number2;
79-
case NOT_EQUALS: return number1 != number2;
80-
81-
case LT: return number1 < number2;
82-
case LTEQ: return number1 <= number2;
83-
case GT: return number1 > number2;
84-
case GTEQ: return number1 >= number2;
85-
86-
default:
87-
throw new OperationIsNotSupportedException(operation);
88-
}
73+
return switch (operation) {
74+
case EQUALS -> number1 == number2;
75+
case NOT_EQUALS -> number1 != number2;
76+
case LT -> number1 < number2;
77+
case LTEQ -> number1 <= number2;
78+
case GT -> number1 > number2;
79+
case GTEQ -> number1 >= number2;
80+
default -> throw new OperationIsNotSupportedException(operation);
81+
};
8982
}
9083

9184
private Value nullCoalesce() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use std, debug
2+
3+
def testThisOnSingleInstance() {
4+
s = new ClassScope({"id": 1})
5+
assertEquals(1, s.getId())
6+
assertEquals(1, s.getDataId())
7+
}
8+
9+
def testThisOnMultipleInstances() {
10+
s1 = new ClassScope({"id": 1})
11+
s2 = new ClassScope({"id": 2})
12+
s3 = new ClassScope({"id": 3})
13+
assertEquals(1, s1.getId())
14+
assertEquals(1, s1.getDataId())
15+
assertEquals(2, s2.getId())
16+
assertEquals(2, s2.getDataId())
17+
assertEquals(3, s3.getId())
18+
assertEquals(3, s3.getDataId())
19+
}
20+
def testToString() {
21+
s1 = new ClassScope({"id": 1})
22+
s2 = new ClassScope({"id": 2})
23+
assertEquals("ClassScope{id=1}", s1.toString())
24+
assertEquals("ClassScope{id=2}", s2.toString())
25+
}
26+
27+
class ClassScope {
28+
def ClassScope(data) {
29+
this.id = data.id
30+
this.data = data
31+
}
32+
33+
def getId() {
34+
return this.id
35+
}
36+
37+
def getDataId() {
38+
return this.data.id
39+
}
40+
41+
def toString() {
42+
return "ClassScope{id=" + this.id + "}"
43+
}
44+
}

0 commit comments

Comments
 (0)