Улучшена работа с областью видимости

This commit is contained in:
Victor 2016-04-03 12:26:54 +03:00
parent 48f3ce1a5f
commit 3c6571c7ae
2 changed files with 88 additions and 17 deletions

View File

@ -1,7 +1,6 @@
package com.annimon.ownlang.lib; package com.annimon.ownlang.lib;
import java.util.Map; import java.util.Map;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
@ -10,44 +9,105 @@ import java.util.concurrent.ConcurrentHashMap;
*/ */
public final class Variables { public final class Variables {
private static final Stack<Map<String, Value>> stack; private static final Object lock = new Object();
private static Map<String, Value> variables;
static { private static class Scope {
stack = new Stack<>(); public final Scope parent;
public final Map<String, Value> variables;
public Scope() {
this(null);
}
public Scope(Scope parent) {
this.parent = parent;
variables = new ConcurrentHashMap<>(); variables = new ConcurrentHashMap<>();
}
}
private static class ScopeFindData {
public boolean isFound;
public Scope scope;
}
private static volatile Scope scope;
static {
scope = new Scope();
Variables.clear(); Variables.clear();
} }
public static void clear() { public static void clear() {
stack.clear(); scope.variables.clear();
variables.clear(); scope.variables.put("true", NumberValue.ONE);
variables.put("true", NumberValue.ONE); scope.variables.put("false", NumberValue.ZERO);
variables.put("false", NumberValue.ZERO);
} }
public static void push() { public static void push() {
stack.push(new ConcurrentHashMap<>(variables)); synchronized (lock) {
final Scope newScope = new Scope(scope);
scope = newScope;
}
} }
public static void pop() { public static void pop() {
variables = stack.pop(); synchronized (lock) {
if (scope.parent != null) {
scope = scope.parent;
}
}
} }
public static boolean isExists(String key) { public static boolean isExists(String key) {
return variables.containsKey(key); synchronized (lock) {
return findScope(key).isFound;
}
} }
public static Value get(String key) { public static Value get(String key) {
if (!isExists(key)) return NumberValue.ZERO; synchronized (lock) {
return variables.get(key); final ScopeFindData scopeData = findScope(key);
if (scopeData.isFound) {
return scopeData.scope.variables.get(key);
}
}
return NumberValue.ZERO;
} }
public static void set(String key, Value value) { public static void set(String key, Value value) {
variables.put(key, value); synchronized (lock) {
findScope(key).scope.variables.put(key, value);
}
}
public static void define(String key, Value value) {
synchronized (lock) {
scope.variables.put(key, value);
}
} }
public static void remove(String key) { public static void remove(String key) {
variables.remove(key); synchronized (lock) {
findScope(key).scope.variables.remove(key);
}
}
/*
* Find scope where variable exists.
*/
private static ScopeFindData findScope(String variable) {
final ScopeFindData result = new ScopeFindData();
Scope current = scope;
do {
if (current.variables.containsKey(variable)) {
result.isFound = true;
result.scope = current;
return result;
}
} while ((current = current.parent) != null);
result.isFound = false;
result.scope = scope;
return result;
} }
} }

View File

@ -36,4 +36,15 @@ def testFail() {
assertTrue(false) assertTrue(false)
} }
def testScope() {
x = 5
def func() {
assertEquals(5, x)
x += 10
assertEquals(15, x)
}
func();
assertEquals(15, x)
}
println runTests() println runTests()