mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Fix this in non-static class methods
This commit is contained in:
parent
34490813a6
commit
3eddbbcdef
@ -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
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
# История изменений
|
# История изменений
|
||||||
|
|
||||||
|
## Next
|
||||||
|
|
||||||
|
### Исправления
|
||||||
|
- Исправлена передача аргументов командной строки скриптам
|
||||||
|
- Исправлен `this` в нестатических методах классов
|
||||||
|
|
||||||
|
|
||||||
## 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
### Критические изменения
|
### Критические изменения
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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()) {
|
||||||
|
if (classInstance != null) {
|
||||||
|
// non-static method
|
||||||
ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap());
|
ScopeHandler.defineVariableInCurrentScope("this", classInstance.getThisMap());
|
||||||
|
}
|
||||||
try {
|
|
||||||
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 + ']';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
44
ownlang-parser/src/test/resources/other/classScope.own
Normal file
44
ownlang-parser/src/test/resources/other/classScope.own
Normal 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 + "}"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user