Fix this in non-static class methods

This commit is contained in:
aNNiMON 2024-08-10 23:51:19 +03:00
parent 34490813a6
commit 3eddbbcdef
7 changed files with 97 additions and 59 deletions

View File

@ -3,7 +3,8 @@
## Next ## Next
### Fixes ### Fixes
- Fix passing arguments - Fix passing command-line arguments to scripts
- Fix `this` in non-static class methods
## 2.0.0 ## 2.0.0

View File

@ -1,5 +1,12 @@
# История изменений # История изменений
## Next
### Исправления
- Исправлена передача аргументов командной строки скриптам
- Исправлен `this` в нестатических методах классов
## 2.0.0 ## 2.0.0
### Критические изменения ### Критические изменения

View File

@ -5,7 +5,8 @@ import java.util.List;
public record ClassDeclaration( public record ClassDeclaration(
String name, String name,
List<ClassField> classFields, List<ClassField> classFields,
List<ClassMethod> classMethods) implements Instantiable { List<ClassMethod> classMethods
) implements Instantiable {
/** /**
* Create an instance and put evaluated fields with method declarations * Create an instance and put evaluated fields with method declarations

View File

@ -25,9 +25,9 @@ public class ClassInstance implements Value {
thisMap.set(f.name(), f.evaluableValue().eval()); thisMap.set(f.name(), f.evaluableValue().eval());
} }
public void addMethod(ClassMethod method) { public void addMethod(ClassMethod m) {
method.setClassInstance(this); final String name = m.name();
final String name = method.getName(); final var method = new ClassMethod(m, this);
thisMap.set(name, method); thisMap.set(name, method);
if (name.equals(className)) { if (name.equals(className)) {
constructor = method; constructor = method;

View File

@ -2,33 +2,28 @@ package com.annimon.ownlang.lib;
import java.util.Objects; import java.util.Objects;
public class ClassMethod implements Function { public record ClassMethod(
private final String name; String name,
private final Function function; Function function,
private ClassInstance classInstance; ClassInstance classInstance
) implements Function {
public ClassMethod(String name, Function function) { public ClassMethod(String name, Function function) {
this.name = name; this(name, function, null);
this.function = function;
} }
public String getName() { public ClassMethod(ClassMethod m, ClassInstance instance) {
return name; this(m.name, m.function, instance);
}
public void setClassInstance(ClassInstance classInstance) {
this.classInstance = classInstance;
} }
@Override @Override
public Value execute(Value... args) { public Value execute(Value... args) {
ScopeHandler.push(); try (final var ignored = ScopeHandler.closeableScope()) {
ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap()); if (classInstance != null) {
// non-static method
try { ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap());
}
return function.execute(args); return function.execute(args);
} finally {
ScopeHandler.pop();
} }
} }
@ -38,12 +33,11 @@ public class ClassMethod implements Function {
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object o) {
if (obj == this) return true; if (this == o) return true;
if (obj == null || obj.getClass() != this.getClass()) return false; if (!(o instanceof ClassMethod that)) return false;
var that = (ClassMethod) obj; return Objects.equals(name, that.name)
return Objects.equals(this.name, that.name) && && Objects.equals(function, that.function);
Objects.equals(this.function, that.function);
} }
@Override @Override
@ -53,8 +47,6 @@ public class ClassMethod implements Function {
@Override @Override
public String toString() { public String toString() {
return "ClassMethod[" + return "ClassMethod[" + name + ']';
"name=" + name + ", " +
"function=" + function + ']';
} }
} }

View File

@ -27,7 +27,7 @@ public final class ConditionalExpression implements Node {
private final String name; private final String name;
private Operator(String name) { Operator(String name) {
this.name = name; this.name = name;
} }
@ -36,7 +36,8 @@ public final class ConditionalExpression implements Node {
} }
} }
public final Node expr1, expr2; public final Node expr1;
public final Node expr2;
public final Operator operation; public final Operator operation;
public ConditionalExpression(Operator operation, Node expr1, Node expr2) { public ConditionalExpression(Operator operation, Node expr1, Node expr2) {
@ -47,25 +48,20 @@ public final class ConditionalExpression implements Node {
@Override @Override
public Value eval() { public Value eval() {
switch (operation) { return switch (operation) {
case AND: case AND -> NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0));
return NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0)); case OR -> NumberValue.fromBoolean((expr1AsInt() != 0) || (expr2AsInt() != 0));
case OR: case NULL_COALESCE -> nullCoalesce();
return NumberValue.fromBoolean((expr1AsInt() != 0) || (expr2AsInt() != 0)); default -> NumberValue.fromBoolean(evalAndCompare());
};
case NULL_COALESCE:
return nullCoalesce();
default:
return NumberValue.fromBoolean(evalAndCompare());
}
} }
private boolean evalAndCompare() { private boolean evalAndCompare() {
final Value value1 = expr1.eval(); final Value value1 = expr1.eval();
final Value value2 = expr2.eval(); final Value value2 = expr2.eval();
double number1, number2; double number1;
double number2;
if (value1.type() == Types.NUMBER) { if (value1.type() == Types.NUMBER) {
number1 = value1.asNumber(); number1 = value1.asNumber();
number2 = value2.asNumber(); number2 = value2.asNumber();
@ -74,18 +70,15 @@ public final class ConditionalExpression implements Node {
number2 = 0; number2 = 0;
} }
switch (operation) { return switch (operation) {
case EQUALS: return number1 == number2; case EQUALS -> number1 == number2;
case NOT_EQUALS: return number1 != number2; case NOT_EQUALS -> number1 != number2;
case LT -> number1 < number2;
case LT: return number1 < number2; case LTEQ -> number1 <= number2;
case LTEQ: return number1 <= number2; case GT -> number1 > number2;
case GT: return number1 > number2; case GTEQ -> number1 >= number2;
case GTEQ: return number1 >= number2; default -> throw new OperationIsNotSupportedException(operation);
};
default:
throw new OperationIsNotSupportedException(operation);
}
} }
private Value nullCoalesce() { private Value nullCoalesce() {

View File

@ -0,0 +1,44 @@
use std, debug
def testThisOnSingleInstance() {
s = new ClassScope({"id": 1})
assertEquals(1, s.getId())
assertEquals(1, s.getDataId())
}
def testThisOnMultipleInstances() {
s1 = new ClassScope({"id": 1})
s2 = new ClassScope({"id": 2})
s3 = new ClassScope({"id": 3})
assertEquals(1, s1.getId())
assertEquals(1, s1.getDataId())
assertEquals(2, s2.getId())
assertEquals(2, s2.getDataId())
assertEquals(3, s3.getId())
assertEquals(3, s3.getDataId())
}
def testToString() {
s1 = new ClassScope({"id": 1})
s2 = new ClassScope({"id": 2})
assertEquals("ClassScope{id=1}", s1.toString())
assertEquals("ClassScope{id=2}", s2.toString())
}
class ClassScope {
def ClassScope(data) {
this.id = data.id
this.data = data
}
def getId() {
return this.id
}
def getDataId() {
return this.data.id
}
def toString() {
return "ClassScope{id=" + this.id + "}"
}
}