diff --git a/docs/docs/en/changelog.md b/docs/docs/en/changelog.md index a2d6262..cfdc37b 100644 --- a/docs/docs/en/changelog.md +++ b/docs/docs/en/changelog.md @@ -3,7 +3,8 @@ ## Next ### Fixes -- Fix passing arguments +- Fix passing command-line arguments to scripts +- Fix `this` in non-static class methods ## 2.0.0 diff --git a/docs/docs/ru/changelog.md b/docs/docs/ru/changelog.md index 7553642..7e914a2 100644 --- a/docs/docs/ru/changelog.md +++ b/docs/docs/ru/changelog.md @@ -1,5 +1,12 @@ # История изменений +## Next + +### Исправления +- Исправлена передача аргументов командной строки скриптам +- Исправлен `this` в нестатических методах классов + + ## 2.0.0 ### Критические изменения diff --git a/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassDeclaration.java b/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassDeclaration.java index 6f0e50e..4a60f15 100644 --- a/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassDeclaration.java +++ b/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassDeclaration.java @@ -5,7 +5,8 @@ import java.util.List; public record ClassDeclaration( String name, List classFields, - List classMethods) implements Instantiable { + List classMethods +) implements Instantiable { /** * Create an instance and put evaluated fields with method declarations diff --git a/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassInstance.java b/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassInstance.java index a5a0fe2..b7ff173 100644 --- a/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassInstance.java +++ b/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassInstance.java @@ -25,9 +25,9 @@ public class ClassInstance implements Value { thisMap.set(f.name(), f.evaluableValue().eval()); } - public void addMethod(ClassMethod method) { - method.setClassInstance(this); - final String name = method.getName(); + public void addMethod(ClassMethod m) { + final String name = m.name(); + final var method = new ClassMethod(m, this); thisMap.set(name, method); if (name.equals(className)) { constructor = method; diff --git a/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassMethod.java b/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassMethod.java index 643b700..b34e321 100644 --- a/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassMethod.java +++ b/ownlang-core/src/main/java/com/annimon/ownlang/lib/ClassMethod.java @@ -2,33 +2,28 @@ package com.annimon.ownlang.lib; import java.util.Objects; -public class ClassMethod implements Function { - private final String name; - private final Function function; - private ClassInstance classInstance; +public record ClassMethod( + String name, + Function function, + ClassInstance classInstance +) implements Function { public ClassMethod(String name, Function function) { - this.name = name; - this.function = function; + this(name, function, null); } - public String getName() { - return name; - } - - public void setClassInstance(ClassInstance classInstance) { - this.classInstance = classInstance; + public ClassMethod(ClassMethod m, ClassInstance instance) { + this(m.name, m.function, instance); } @Override public Value execute(Value... args) { - ScopeHandler.push(); - ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap()); - - try { + try (final var ignored = ScopeHandler.closeableScope()) { + if (classInstance != null) { + // non-static method + ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap()); + } return function.execute(args); - } finally { - ScopeHandler.pop(); } } @@ -38,12 +33,11 @@ public class ClassMethod implements Function { } @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (ClassMethod) obj; - return Objects.equals(this.name, that.name) && - Objects.equals(this.function, that.function); + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ClassMethod that)) return false; + return Objects.equals(name, that.name) + && Objects.equals(function, that.function); } @Override @@ -53,8 +47,6 @@ public class ClassMethod implements Function { @Override public String toString() { - return "ClassMethod[" + - "name=" + name + ", " + - "function=" + function + ']'; + return "ClassMethod[" + name + ']'; } } diff --git a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ConditionalExpression.java b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ConditionalExpression.java index e6f14e7..21fac47 100644 --- a/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ConditionalExpression.java +++ b/ownlang-parser/src/main/java/com/annimon/ownlang/parser/ast/ConditionalExpression.java @@ -27,7 +27,7 @@ public final class ConditionalExpression implements Node { private final String name; - private Operator(String name) { + Operator(String 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 ConditionalExpression(Operator operation, Node expr1, Node expr2) { @@ -47,25 +48,20 @@ public final class ConditionalExpression implements Node { @Override public Value eval() { - switch (operation) { - case AND: - return NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0)); - case OR: - return NumberValue.fromBoolean((expr1AsInt() != 0) || (expr2AsInt() != 0)); - - case NULL_COALESCE: - return nullCoalesce(); - - default: - return NumberValue.fromBoolean(evalAndCompare()); - } + return switch (operation) { + case AND -> NumberValue.fromBoolean((expr1AsInt() != 0) && (expr2AsInt() != 0)); + case OR -> NumberValue.fromBoolean((expr1AsInt() != 0) || (expr2AsInt() != 0)); + case NULL_COALESCE -> nullCoalesce(); + default -> NumberValue.fromBoolean(evalAndCompare()); + }; } private boolean evalAndCompare() { final Value value1 = expr1.eval(); final Value value2 = expr2.eval(); - double number1, number2; + double number1; + double number2; if (value1.type() == Types.NUMBER) { number1 = value1.asNumber(); number2 = value2.asNumber(); @@ -74,18 +70,15 @@ public final class ConditionalExpression implements Node { number2 = 0; } - switch (operation) { - case EQUALS: return number1 == number2; - case NOT_EQUALS: return number1 != number2; - - case LT: return number1 < number2; - case LTEQ: return number1 <= number2; - case GT: return number1 > number2; - case GTEQ: return number1 >= number2; - - default: - throw new OperationIsNotSupportedException(operation); - } + return switch (operation) { + case EQUALS -> number1 == number2; + case NOT_EQUALS -> number1 != number2; + case LT -> number1 < number2; + case LTEQ -> number1 <= number2; + case GT -> number1 > number2; + case GTEQ -> number1 >= number2; + default -> throw new OperationIsNotSupportedException(operation); + }; } private Value nullCoalesce() { diff --git a/ownlang-parser/src/test/resources/other/classScope.own b/ownlang-parser/src/test/resources/other/classScope.own new file mode 100644 index 0000000..3d33aa1 --- /dev/null +++ b/ownlang-parser/src/test/resources/other/classScope.own @@ -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 + "}" + } +} \ No newline at end of file