Skip to content

Commit 3c6571c

Browse files
committed
Улучшена работа с областью видимости
1 parent 48f3ce1 commit 3c6571c

File tree

2 files changed

+88
-17
lines changed

2 files changed

+88
-17
lines changed
Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.annimon.ownlang.lib;
22

33
import java.util.Map;
4-
import java.util.Stack;
54
import java.util.concurrent.ConcurrentHashMap;
65

76
/**
@@ -10,44 +9,105 @@
109
*/
1110
public final class Variables {
1211

13-
private static final Stack<Map<String, Value>> stack;
14-
private static Map<String, Value> variables;
15-
12+
private static final Object lock = new Object();
13+
14+
private static class Scope {
15+
public final Scope parent;
16+
public final Map<String, Value> variables;
17+
18+
public Scope() {
19+
this(null);
20+
}
21+
22+
public Scope(Scope parent) {
23+
this.parent = parent;
24+
variables = new ConcurrentHashMap<>();
25+
}
26+
}
27+
28+
private static class ScopeFindData {
29+
public boolean isFound;
30+
public Scope scope;
31+
}
32+
33+
private static volatile Scope scope;
1634
static {
17-
stack = new Stack<>();
18-
variables = new ConcurrentHashMap<>();
35+
scope = new Scope();
1936
Variables.clear();
2037
}
2138

2239
public static void clear() {
23-
stack.clear();
24-
variables.clear();
25-
variables.put("true", NumberValue.ONE);
26-
variables.put("false", NumberValue.ZERO);
40+
scope.variables.clear();
41+
scope.variables.put("true", NumberValue.ONE);
42+
scope.variables.put("false", NumberValue.ZERO);
2743
}
2844

2945
public static void push() {
30-
stack.push(new ConcurrentHashMap<>(variables));
46+
synchronized (lock) {
47+
final Scope newScope = new Scope(scope);
48+
scope = newScope;
49+
}
3150
}
3251

3352
public static void pop() {
34-
variables = stack.pop();
53+
synchronized (lock) {
54+
if (scope.parent != null) {
55+
scope = scope.parent;
56+
}
57+
}
3558
}
3659

3760
public static boolean isExists(String key) {
38-
return variables.containsKey(key);
61+
synchronized (lock) {
62+
return findScope(key).isFound;
63+
}
3964
}
4065

4166
public static Value get(String key) {
42-
if (!isExists(key)) return NumberValue.ZERO;
43-
return variables.get(key);
67+
synchronized (lock) {
68+
final ScopeFindData scopeData = findScope(key);
69+
if (scopeData.isFound) {
70+
return scopeData.scope.variables.get(key);
71+
}
72+
}
73+
return NumberValue.ZERO;
4474
}
4575

4676
public static void set(String key, Value value) {
47-
variables.put(key, value);
77+
synchronized (lock) {
78+
findScope(key).scope.variables.put(key, value);
79+
}
4880
}
4981

82+
public static void define(String key, Value value) {
83+
synchronized (lock) {
84+
scope.variables.put(key, value);
85+
}
86+
}
87+
5088
public static void remove(String key) {
51-
variables.remove(key);
89+
synchronized (lock) {
90+
findScope(key).scope.variables.remove(key);
91+
}
92+
}
93+
94+
/*
95+
* Find scope where variable exists.
96+
*/
97+
private static ScopeFindData findScope(String variable) {
98+
final ScopeFindData result = new ScopeFindData();
99+
100+
Scope current = scope;
101+
do {
102+
if (current.variables.containsKey(variable)) {
103+
result.isFound = true;
104+
result.scope = current;
105+
return result;
106+
}
107+
} while ((current = current.parent) != null);
108+
109+
result.isFound = false;
110+
result.scope = scope;
111+
return result;
52112
}
53113
}

tests.own

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,15 @@ def testFail() {
3636
assertTrue(false)
3737
}
3838

39+
def testScope() {
40+
x = 5
41+
def func() {
42+
assertEquals(5, x)
43+
x += 10
44+
assertEquals(15, x)
45+
}
46+
func();
47+
assertEquals(15, x)
48+
}
49+
3950
println runTests()

0 commit comments

Comments
 (0)