-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMapValue.java
152 lines (135 loc) · 4.28 KB
/
MapValue.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package org.example.interpreter.model.value;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.Builder;
import org.example.ast.ValueType;
import org.example.ast.type.TypeDeclaration;
import org.example.interpreter.error.ArgumentListDoesNotMatch;
import org.example.interpreter.error.TypesDoNotMatchException;
import org.example.interpreter.model.Value;
@AllArgsConstructor
@Builder(toBuilder = true)
@lombok.Value
public class MapValue implements Value {
TypeDeclaration type;
Map<Value, Value> map;
Map<String, Function<List<Value>, Optional<Value>>> mapMethods = Map.of(
"operator[]", this::get,
"retrieveValue", this::retrieveValue,
"put", this::put,
"contains", this::contains,
"remove", this::remove,
"iterable", this::iterable,
"sortedIterable", this::sortedIterable
);
@Override
public Optional<Function<List<Value>, Optional<Value>>> findMethod(String method) {
return Optional.ofNullable(mapMethods.get(method));
}
private Optional<Value> get(List<Value> arguments) {
validateArguments(arguments, List.of(getKeyType()));
var key = arguments.get(0);
return Optional.ofNullable(map.get(key));
}
private Optional<Value> retrieveValue(List<Value> arguments) {
validateArguments(arguments, List.of(getKeyType()));
var key = arguments.get(0);
return Optional.ofNullable(map.get(key).copy());
}
private Optional<Value> put(List<Value> arguments) {
validateArguments(arguments, List.of(getKeyType(), getValueType()));
var key = arguments.get(0);
var value = arguments.get(1);
map.put(key, value);
return Optional.empty();
}
private Optional<Value> contains(List<Value> arguments) {
validateArguments(arguments, List.of(getKeyType()));
var key = arguments.get(0);
var result = map.containsKey(key);
return Optional.of(new BooleanValue(result));
}
private Optional<Value> remove(List<Value> arguments) {
validateArguments(arguments, List.of(getKeyType()));
var key = arguments.get(0);
map.remove(key);
return Optional.empty();
}
public Optional<Value> iterable(List<Value> arguments) {
validateArguments(arguments, List.of());
return Optional.of(iterable());
}
public IterableValue iterable() {
var tupleType = new TypeDeclaration(ValueType.TUPLE, List.of(getKeyType(), getValueType()));
var result = map.entrySet()
.stream()
.map(it -> new TupleValue(
tupleType,
Map.of("key", it.getKey(), "value", it.getValue()))
)
.map(Value.class::cast)
.toList();
return new IterableValue(
new TypeDeclaration(ValueType.ITERABLE, List.of(tupleType)),
result
);
}
private Optional<Value> sortedIterable(List<Value> arguments) {
validateArguments(
arguments,
List.of(new TypeDeclaration(ValueType.COMPARATOR,
List.of(
new TypeDeclaration(ValueType.TUPLE, List.of(getKeyType(), getValueType())
)
)
)
)
);
var comparator = arguments.get(0);
var tupleType = new TypeDeclaration(ValueType.TUPLE, List.of(getKeyType(), getValueType()));
var result = map.entrySet()
.stream()
.map(it -> new TupleValue(
tupleType,
Map.of("key", it.getKey(), "value", it.getValue()))
)
.map(Value.class::cast)
.sorted(comparator.getComparator())
.toList();
return Optional.of(
new IterableValue(
new TypeDeclaration(ValueType.ITERABLE, List.of(tupleType)),
result
)
);
}
private TypeDeclaration getKeyType() {
return type.getTypes().get(0);
}
private TypeDeclaration getValueType() {
return type.getTypes().get(1);
}
private void validateArguments(List<Value> arguments, List<TypeDeclaration> expected) {
if (arguments.size() != expected.size()) {
throw new ArgumentListDoesNotMatch();
}
for (var i = 0; i < arguments.size(); i++) {
if (!Objects.equals(arguments.get(i).getType(), expected.get(i))) {
throw new TypesDoNotMatchException(arguments.get(i).getType(), expected.get(i));
}
}
}
@Override
public Value copy() {
var result = map.entrySet()
.stream()
.map(it -> Map.entry(it.getKey().copy(), it.getValue().copy()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return new MapValue(type, result);
}
}