mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-21 07:59:19 +00:00
重命名成人类可读的变量名
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -26,46 +26,44 @@ public class SnbtOperations {
|
|||||||
public static final Map<BuiltinKey, BuiltinOperation> BUILTIN_OPERATIONS = Map.of(
|
public static final Map<BuiltinKey, BuiltinOperation> BUILTIN_OPERATIONS = Map.of(
|
||||||
new BuiltinKey("bool", 1), new BuiltinOperation() {
|
new BuiltinKey("bool", 1), new BuiltinOperation() {
|
||||||
@Override
|
@Override
|
||||||
public <T> T run(DynamicOps<T> ops, List<T> args, ParseState<StringReader> parseState) {
|
public <T> T run(DynamicOps<T> ops, List<T> arguments, ParseState<StringReader> state) {
|
||||||
Boolean bool = convert(ops, args.getFirst());
|
Boolean result = convert(ops, arguments.getFirst());
|
||||||
if (bool == null) {
|
if (result == null) {
|
||||||
parseState.errorCollector().store(parseState.mark(), SnbtOperations.ERROR_EXPECTED_NUMBER_OR_BOOLEAN);
|
state.errorCollector().store(state.mark(), SnbtOperations.ERROR_EXPECTED_NUMBER_OR_BOOLEAN);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
|
||||||
return ops.createBoolean(bool);
|
|
||||||
}
|
}
|
||||||
|
return ops.createBoolean(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static <T> Boolean convert(DynamicOps<T> ops, T value) {
|
private static <T> Boolean convert(DynamicOps<T> ops, T arg) {
|
||||||
Optional<Boolean> optional = ops.getBooleanValue(value).result();
|
Optional<Boolean> asBoolean = ops.getBooleanValue(arg).result();
|
||||||
if (optional.isPresent()) {
|
if (asBoolean.isPresent()) {
|
||||||
return optional.get();
|
return asBoolean.get();
|
||||||
} else {
|
} else {
|
||||||
Optional<Number> optional1 = ops.getNumberValue(value).result();
|
Optional<Number> asNumber = ops.getNumberValue(arg).result();
|
||||||
return optional1.isPresent() ? optional1.get().doubleValue() != 0.0 : null;
|
return asNumber.isPresent() ? asNumber.get().doubleValue() != 0.0 : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, new BuiltinKey("uuid", 1), new BuiltinOperation() {
|
}, new BuiltinKey("uuid", 1), new BuiltinOperation() {
|
||||||
@Override
|
@Override
|
||||||
public <T> T run(DynamicOps<T> ops, List<T> args, ParseState<StringReader> parseState) {
|
public <T> T run(DynamicOps<T> ops, List<T> arguments, ParseState<StringReader> state) {
|
||||||
Optional<String> optional = ops.getStringValue(args.getFirst()).result();
|
Optional<String> arg = ops.getStringValue(arguments.getFirst()).result();
|
||||||
if (optional.isEmpty()) {
|
if (arg.isEmpty()) {
|
||||||
parseState.errorCollector().store(parseState.mark(), SnbtOperations.ERROR_EXPECTED_STRING_UUID);
|
state.errorCollector().store(state.mark(), SnbtOperations.ERROR_EXPECTED_STRING_UUID);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
}
|
||||||
UUID uuid;
|
UUID uuid;
|
||||||
try {
|
try {
|
||||||
uuid = UUID.fromString(optional.get());
|
uuid = UUID.fromString(arg.get());
|
||||||
} catch (IllegalArgumentException var7) {
|
} catch (IllegalArgumentException var7) {
|
||||||
parseState.errorCollector().store(parseState.mark(), SnbtOperations.ERROR_EXPECTED_STRING_UUID);
|
state.errorCollector().store(state.mark(), SnbtOperations.ERROR_EXPECTED_STRING_UUID);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ops.createIntList(IntStream.of(UUIDUtil.uuidToIntArray(uuid)));
|
return ops.createIntList(IntStream.of(UUIDUtil.uuidToIntArray(uuid)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
);
|
);
|
||||||
public static final SuggestionSupplier<StringReader> BUILTIN_IDS = new SuggestionSupplier<>() {
|
public static final SuggestionSupplier<StringReader> BUILTIN_IDS = new SuggestionSupplier<>() {
|
||||||
private final Set<String> keys = Stream.concat(
|
private final Set<String> keys = Stream.concat(
|
||||||
@@ -74,7 +72,7 @@ public class SnbtOperations {
|
|||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> possibleValues(ParseState<StringReader> parseState) {
|
public Stream<String> possibleValues(ParseState<StringReader> state) {
|
||||||
return this.keys.stream();
|
return this.keys.stream();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -88,6 +86,6 @@ public class SnbtOperations {
|
|||||||
|
|
||||||
public interface BuiltinOperation {
|
public interface BuiltinOperation {
|
||||||
@Nullable
|
@Nullable
|
||||||
<T> T run(DynamicOps<T> ops, List<T> args, ParseState<StringReader> parseState);
|
<T> T run(DynamicOps<T> ops, List<T> arguments, ParseState<StringReader> state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,34 +42,34 @@ public class TagParser<T> {
|
|||||||
return new TagParser<>(ops, SnbtGrammar.createParser(ops));
|
return new TagParser<>(ops, SnbtGrammar.createParser(ops));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CompoundTag castToCompoundOrThrow(StringReader reader, Tag tag) throws CommandSyntaxException {
|
private static CompoundTag castToCompoundOrThrow(StringReader reader, Tag result) throws CommandSyntaxException {
|
||||||
if (tag instanceof CompoundTag compoundTag) {
|
if (result instanceof CompoundTag compoundTag) {
|
||||||
return compoundTag;
|
return compoundTag;
|
||||||
}
|
}
|
||||||
throw ERROR_EXPECTED_COMPOUND.createWithContext(reader);
|
throw ERROR_EXPECTED_COMPOUND.createWithContext(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompoundTag parseCompoundFully(String data) throws CommandSyntaxException {
|
public static CompoundTag parseCompoundFully(String input) throws CommandSyntaxException {
|
||||||
StringReader stringReader = new StringReader(data);
|
StringReader reader = new StringReader(input);
|
||||||
return parseCompoundAsArgument(stringReader);
|
return parseCompoundAsArgument(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object parseObjectFully(String data) throws CommandSyntaxException {
|
public static Object parseObjectFully(String input) throws CommandSyntaxException {
|
||||||
StringReader stringReader = new StringReader(data);
|
StringReader reader = new StringReader(input);
|
||||||
return parseObjectAsArgument(stringReader);
|
return parseObjectAsArgument(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T parseFully(String text) throws CommandSyntaxException {
|
public T parseFully(String input) throws CommandSyntaxException {
|
||||||
return this.parseFully(new StringReader(text));
|
return this.parseFully(new StringReader(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T parseFully(StringReader reader) throws CommandSyntaxException {
|
public T parseFully(StringReader reader) throws CommandSyntaxException {
|
||||||
T object = this.grammar.parse(reader);
|
T result = this.grammar.parse(reader);
|
||||||
reader.skipWhitespace();
|
reader.skipWhitespace();
|
||||||
if (reader.canRead()) {
|
if (reader.canRead()) {
|
||||||
throw ERROR_TRAILING_DATA.createWithContext(reader);
|
throw ERROR_TRAILING_DATA.createWithContext(reader);
|
||||||
}
|
}
|
||||||
return object;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T parseAsArgument(StringReader reader) throws CommandSyntaxException {
|
public T parseAsArgument(StringReader reader) throws CommandSyntaxException {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package net.momirealms.craftengine.core.util.snbt.parse;
|
package net.momirealms.craftengine.core.util.snbt.parse;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
|
||||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -14,7 +12,6 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
private SimpleControl[] controlCache = new SimpleControl[16];
|
private SimpleControl[] controlCache = new SimpleControl[16];
|
||||||
private int nextControlToReturn;
|
private int nextControlToReturn;
|
||||||
private final Silent silent = new Silent();
|
private final Silent silent = new Silent();
|
||||||
private final IntList markedNull = new IntArrayList();
|
|
||||||
public static final Object JAVA_NULL_VALUE_MARKER = new Object() {
|
public static final Object JAVA_NULL_VALUE_MARKER = new Object() {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@@ -39,11 +36,11 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <T> T parse(NamedRule<S, T> rule) {
|
public <T> T parse(NamedRule<S, T> rule) {
|
||||||
int i = this.mark();
|
int markBeforeParse = this.mark();
|
||||||
PositionCache cacheForPosition = this.getCacheForPosition(i);
|
PositionCache positionCache = this.getCacheForPosition(markBeforeParse);
|
||||||
int i1 = cacheForPosition.findKeyIndex(rule.name());
|
int entryIndex = positionCache.findKeyIndex(rule.name());
|
||||||
if (i1 != -1) {
|
if (entryIndex != -1) {
|
||||||
CacheEntry<T> value = cacheForPosition.getValue(i1);
|
CacheEntry<T> value = positionCache.getValue(entryIndex);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (value == CachedParseState.CacheEntry.NEGATIVE) {
|
if (value == CachedParseState.CacheEntry.NEGATIVE) {
|
||||||
return null;
|
return null;
|
||||||
@@ -52,59 +49,60 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
return value.value;
|
return value.value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i1 = cacheForPosition.allocateNewEntry(rule.name());
|
entryIndex = positionCache.allocateNewEntry(rule.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
T object = rule.value().parse(this);
|
T result = rule.value().parse(this);
|
||||||
CacheEntry<T> cacheEntry;
|
CacheEntry<T> entry;
|
||||||
if (object == null) {
|
if (result == null) {
|
||||||
cacheEntry = (CacheEntry<T>) CacheEntry.NEGATIVE;
|
entry = CacheEntry.negativeEntry();
|
||||||
} else {
|
} else {
|
||||||
cacheEntry = new CacheEntry<>(object, this.mark());
|
int markAfterParse = this.mark();
|
||||||
|
entry = new CacheEntry<>(result, markAfterParse);
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheForPosition.setValue(i1, cacheEntry);
|
positionCache.setValue(entryIndex, entry);
|
||||||
return object;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PositionCache getCacheForPosition(int position) {
|
private PositionCache getCacheForPosition(int index) {
|
||||||
int i = this.positionCache.length;
|
int currentSize = this.positionCache.length;
|
||||||
if (position >= i) {
|
if (index >= currentSize) {
|
||||||
int i1 = MiscUtils.growByHalf(i, position + 1);
|
int newSize = MiscUtils.growByHalf(currentSize, index + 1);
|
||||||
PositionCache[] positionCaches = new PositionCache[i1];
|
PositionCache[] newCache = new PositionCache[newSize];
|
||||||
System.arraycopy(this.positionCache, 0, positionCaches, 0, i);
|
System.arraycopy(this.positionCache, 0, newCache, 0, currentSize);
|
||||||
this.positionCache = positionCaches;
|
this.positionCache = newCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionCache positionCache = this.positionCache[position];
|
PositionCache result = this.positionCache[index];
|
||||||
if (positionCache == null) {
|
if (result == null) {
|
||||||
positionCache = new PositionCache();
|
result = new PositionCache();
|
||||||
this.positionCache[position] = positionCache;
|
this.positionCache[index] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return positionCache;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Control acquireControl() {
|
public Control acquireControl() {
|
||||||
int i = this.controlCache.length;
|
int currentSize = this.controlCache.length;
|
||||||
if (this.nextControlToReturn >= i) {
|
if (this.nextControlToReturn >= currentSize) {
|
||||||
int i1 = MiscUtils.growByHalf(i, this.nextControlToReturn + 1);
|
int newSize = MiscUtils.growByHalf(currentSize, this.nextControlToReturn + 1);
|
||||||
SimpleControl[] simpleControls = new SimpleControl[i1];
|
SimpleControl[] newControlCache = new SimpleControl[newSize];
|
||||||
System.arraycopy(this.controlCache, 0, simpleControls, 0, i);
|
System.arraycopy(this.controlCache, 0, newControlCache, 0, currentSize);
|
||||||
this.controlCache = simpleControls;
|
this.controlCache = newControlCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i1 = this.nextControlToReturn++;
|
int controlIndex = this.nextControlToReturn++;
|
||||||
SimpleControl simpleControl = this.controlCache[i1];
|
SimpleControl entry = this.controlCache[controlIndex];
|
||||||
if (simpleControl == null) {
|
if (entry == null) {
|
||||||
simpleControl = new SimpleControl();
|
entry = new SimpleControl();
|
||||||
this.controlCache[i1] = simpleControl;
|
this.controlCache[controlIndex] = entry;
|
||||||
} else {
|
} else {
|
||||||
simpleControl.reset();
|
entry.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
return simpleControl;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -117,18 +115,12 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
return this.silent;
|
return this.silent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void markNull(int mark) {
|
|
||||||
this.markedNull.add(mark);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNull(int mark) {
|
|
||||||
return this.markedNull.contains(mark);
|
|
||||||
}
|
|
||||||
|
|
||||||
record CacheEntry<T>(@Nullable T value, int markAfterParse) {
|
record CacheEntry<T>(@Nullable T value, int markAfterParse) {
|
||||||
public static final CacheEntry<?> NEGATIVE = new CacheEntry<>(null, -1);
|
public static final CacheEntry<?> NEGATIVE = new CacheEntry<>(null, -1);
|
||||||
|
|
||||||
|
public static <T> CacheEntry<T> negativeEntry() {
|
||||||
|
return (CacheEntry<T>) NEGATIVE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PositionCache {
|
static class PositionCache {
|
||||||
@@ -137,9 +129,9 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
private Object[] atomCache = new Object[16];
|
private Object[] atomCache = new Object[16];
|
||||||
private int nextKey;
|
private int nextKey;
|
||||||
|
|
||||||
public int findKeyIndex(Atom<?> atom) {
|
public int findKeyIndex(Atom<?> key) {
|
||||||
for (int i = 0; i < this.nextKey; i += ENTRY_STRIDE) {
|
for (int i = 0; i < this.nextKey; i += ENTRY_STRIDE) {
|
||||||
if (this.atomCache[i] == atom) {
|
if (this.atomCache[i] == key) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,29 +139,29 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int allocateNewEntry(Atom<?> entry) {
|
public int allocateNewEntry(Atom<?> key) {
|
||||||
int i = this.nextKey;
|
int newKeyIndex = this.nextKey;
|
||||||
this.nextKey += 2;
|
this.nextKey += ENTRY_STRIDE;
|
||||||
int i1 = i + 1;
|
int newValueIndex = newKeyIndex + 1;
|
||||||
int i2 = this.atomCache.length;
|
int currentSize = this.atomCache.length;
|
||||||
if (i1 >= i2) {
|
if (newValueIndex >= currentSize) {
|
||||||
int i3 = MiscUtils.growByHalf(i2, i1 + 1);
|
int newSize = MiscUtils.growByHalf(currentSize, newValueIndex + 1);
|
||||||
Object[] objects = new Object[i3];
|
Object[] newCache = new Object[newSize];
|
||||||
System.arraycopy(this.atomCache, 0, objects, 0, i2);
|
System.arraycopy(this.atomCache, 0, newCache, 0, currentSize);
|
||||||
this.atomCache = objects;
|
this.atomCache = newCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.atomCache[i] = entry;
|
this.atomCache[newKeyIndex] = key;
|
||||||
return i;
|
return newKeyIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public <T> CacheEntry<T> getValue(int index) {
|
public <T> CacheEntry<T> getValue(int keyIndex) {
|
||||||
return (CacheEntry<T>)this.atomCache[index + 1];
|
return (CacheEntry<T>) this.atomCache[keyIndex + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(int index, CacheEntry<?> value) {
|
public void setValue(int keyIndex, CacheEntry<?> entry) {
|
||||||
this.atomCache[index + 1] = value;
|
this.atomCache[keyIndex + 1] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,8 +195,8 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restore(int cursor) {
|
public void restore(int mark) {
|
||||||
CachedParseState.this.restore(cursor);
|
CachedParseState.this.restore(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -221,16 +213,6 @@ public abstract class CachedParseState<S> implements ParseState<S> {
|
|||||||
public ParseState<S> silent() {
|
public ParseState<S> silent() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void markNull(int mark) {
|
|
||||||
CachedParseState.this.markNull(mark);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNull(int mark) {
|
|
||||||
return CachedParseState.this.isNull(mark);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class SimpleControl implements Control {
|
static class SimpleControl implements Control {
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import net.momirealms.craftengine.core.util.snbt.parse.grammar.StringReaderTerms
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface DelayedException<T extends Exception> {
|
public interface DelayedException<T extends Exception> {
|
||||||
T create(String message, int cursor);
|
T create(String contents, int position);
|
||||||
|
|
||||||
static DelayedException<CommandSyntaxException> create(SimpleCommandExceptionType exception) {
|
static DelayedException<CommandSyntaxException> create(SimpleCommandExceptionType type) {
|
||||||
return (message, cursor) -> exception.createWithContext(StringReaderTerms.createReader(message, cursor));
|
return (contents, position) -> type.createWithContext(StringReaderTerms.createReader(contents, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
static DelayedException<CommandSyntaxException> create(DynamicCommandExceptionType exception, String argument) {
|
static DelayedException<CommandSyntaxException> create(DynamicCommandExceptionType type, String argument) {
|
||||||
return (message, cursor) -> exception.createWithContext(StringReaderTerms.createReader(message, cursor), argument);
|
return (contents, position) -> type.createWithContext(StringReaderTerms.createReader(contents, position), argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,28 +11,30 @@ import java.util.function.Supplier;
|
|||||||
public class Dictionary<S> {
|
public class Dictionary<S> {
|
||||||
private final Map<Atom<?>, Entry<S, ?>> terms = new IdentityHashMap<>();
|
private final Map<Atom<?>, Entry<S, ?>> terms = new IdentityHashMap<>();
|
||||||
|
|
||||||
public <T> NamedRule<S, T> put(Atom<T> name, Rule<S, T> rule) {
|
public <T> NamedRule<S, T> put(Atom<T> name, Rule<S, T> entry) {
|
||||||
Entry<S, T> entry = (Entry<S, T>)this.terms.computeIfAbsent(name, Entry::new);
|
Entry<S, T> holder = (Entry<S, T>)this.terms.computeIfAbsent(name, Entry::new);
|
||||||
if (entry.value != null) {
|
if (holder.value != null) {
|
||||||
throw new IllegalArgumentException("Trying to override rule: " + name);
|
throw new IllegalArgumentException("Trying to override rule: " + name);
|
||||||
} else {
|
|
||||||
entry.value = rule;
|
|
||||||
return entry;
|
|
||||||
}
|
}
|
||||||
|
holder.value = entry;
|
||||||
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> NamedRule<S, T> putComplex(Atom<T> name, Term<S> term, Rule.RuleAction<S, T> ruleAction) {
|
public <T> NamedRule<S, T> putComplex(Atom<T> name, Term<S> term, Rule.RuleAction<S, T> action) {
|
||||||
return this.put(name, Rule.fromTerm(term, ruleAction));
|
return this.put(name, Rule.fromTerm(term, action));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> NamedRule<S, T> put(Atom<T> name, Term<S> term, Rule.SimpleRuleAction<S, T> ruleAction) {
|
public <T> NamedRule<S, T> put(Atom<T> name, Term<S> term, Rule.SimpleRuleAction<S, T> action) {
|
||||||
return this.put(name, Rule.fromTerm(term, ruleAction));
|
return this.put(name, Rule.fromTerm(term, action));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkAllBound() {
|
public void checkAllBound() {
|
||||||
List<? extends Atom<?>> list = this.terms.entrySet().stream().filter(entry -> entry.getValue() == null).map(Map.Entry::getKey).toList();
|
List<? extends Atom<?>> unboundNames = this.terms.entrySet().stream()
|
||||||
if (!list.isEmpty()) {
|
.filter(entry -> entry.getValue() == null)
|
||||||
throw new IllegalStateException("Unbound names: " + list);
|
.map(Map.Entry::getKey)
|
||||||
|
.toList();
|
||||||
|
if (!unboundNames.isEmpty()) {
|
||||||
|
throw new IllegalStateException("Unbound names: " + unboundNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,8 +50,8 @@ public class Dictionary<S> {
|
|||||||
return new Reference<>(this.getOrCreateEntry(name), name);
|
return new Reference<>(this.getOrCreateEntry(name), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> Term<S> namedWithAlias(Atom<T> name, Atom<T> alias) {
|
public <T> Term<S> namedWithAlias(Atom<T> nameToParse, Atom<T> nameToStore) {
|
||||||
return new Reference<>(this.getOrCreateEntry(name), alias);
|
return new Reference<>(this.getOrCreateEntry(nameToParse), nameToStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Entry<S, T> implements NamedRule<S, T>, Supplier<String> {
|
static class Entry<S, T> implements NamedRule<S, T>, Supplier<String> {
|
||||||
@@ -79,14 +81,13 @@ public class Dictionary<S> {
|
|||||||
|
|
||||||
record Reference<S, T>(Entry<S, T> ruleToParse, Atom<T> nameToStore) implements Term<S> {
|
record Reference<S, T>(Entry<S, T> ruleToParse, Atom<T> nameToStore) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
T object = parseState.parse(this.ruleToParse);
|
T result = state.parse(this.ruleToParse);
|
||||||
if (object == null) {
|
if (result == null) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
scope.put(this.nameToStore, object);
|
scope.put(this.nameToStore, result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public interface ErrorCollector<S> {
|
|||||||
this.store(cursor, SuggestionSupplier.empty(), reason);
|
this.store(cursor, SuggestionSupplier.empty(), reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish(int cursor);
|
void finish(int finalCursor);
|
||||||
|
|
||||||
class LongestOnly<S> implements ErrorCollector<S> {
|
class LongestOnly<S> implements ErrorCollector<S> {
|
||||||
private MutableErrorEntry<S>[] entries = new MutableErrorEntry[16];
|
private MutableErrorEntry<S>[] entries = new MutableErrorEntry[16];
|
||||||
@@ -28,8 +28,8 @@ public interface ErrorCollector<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finish(int cursor) {
|
public void finish(int finalCursor) {
|
||||||
this.discardErrorsFromShorterParse(cursor);
|
this.discardErrorsFromShorterParse(finalCursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -41,39 +41,38 @@ public interface ErrorCollector<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addErrorEntry(SuggestionSupplier<S> suggestions, Object reason) {
|
private void addErrorEntry(SuggestionSupplier<S> suggestions, Object reason) {
|
||||||
int i = this.entries.length;
|
int currentSize = this.entries.length;
|
||||||
if (this.nextErrorEntry >= i) {
|
if (this.nextErrorEntry >= currentSize) {
|
||||||
int i1 = MiscUtils.growByHalf(i, this.nextErrorEntry + 1);
|
int newSize = MiscUtils.growByHalf(currentSize, this.nextErrorEntry + 1);
|
||||||
MutableErrorEntry<S>[] mutableErrorEntrys = new MutableErrorEntry[i1];
|
MutableErrorEntry<S>[] newEntries = new MutableErrorEntry[newSize];
|
||||||
System.arraycopy(this.entries, 0, mutableErrorEntrys, 0, i);
|
System.arraycopy(this.entries, 0, newEntries, 0, currentSize);
|
||||||
this.entries = mutableErrorEntrys;
|
this.entries = newEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i1 = this.nextErrorEntry++;
|
int entryIndex = this.nextErrorEntry++;
|
||||||
MutableErrorEntry<S> mutableErrorEntry = this.entries[i1];
|
MutableErrorEntry<S> entry = this.entries[entryIndex];
|
||||||
if (mutableErrorEntry == null) {
|
if (entry == null) {
|
||||||
mutableErrorEntry = new MutableErrorEntry<>();
|
entry = new MutableErrorEntry<>();
|
||||||
this.entries[i1] = mutableErrorEntry;
|
this.entries[entryIndex] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutableErrorEntry.suggestions = suggestions;
|
entry.suggestions = suggestions;
|
||||||
mutableErrorEntry.reason = reason;
|
entry.reason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ErrorEntry<S>> entries() {
|
public List<ErrorEntry<S>> entries() {
|
||||||
int i = this.nextErrorEntry;
|
int errorCount = this.nextErrorEntry;
|
||||||
if (i == 0) {
|
if (errorCount == 0) {
|
||||||
return List.of();
|
return List.of();
|
||||||
} else {
|
}
|
||||||
List<ErrorEntry<S>> list = new ArrayList<>(i);
|
List<ErrorEntry<S>> result = new ArrayList<>(errorCount);
|
||||||
|
|
||||||
for (int i1 = 0; i1 < i; i1++) {
|
for (int i = 0; i < errorCount; i++) {
|
||||||
MutableErrorEntry<S> mutableErrorEntry = this.entries[i1];
|
MutableErrorEntry<S> mutableErrorEntry = this.entries[i];
|
||||||
list.add(new ErrorEntry<>(this.lastCursor, mutableErrorEntry.suggestions, mutableErrorEntry.reason));
|
result.add(new ErrorEntry<>(this.lastCursor, mutableErrorEntry.suggestions, mutableErrorEntry.reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return result;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int cursor() {
|
public int cursor() {
|
||||||
@@ -92,7 +91,7 @@ public interface ErrorCollector<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finish(int cursor) {
|
public void finish(int finalCursor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,16 +9,15 @@ public interface ParseState<S> {
|
|||||||
ErrorCollector<S> errorCollector();
|
ErrorCollector<S> errorCollector();
|
||||||
|
|
||||||
default <T> Optional<T> parseTopRule(NamedRule<S, T> rule) {
|
default <T> Optional<T> parseTopRule(NamedRule<S, T> rule) {
|
||||||
T object = this.parse(rule);
|
T result = this.parse(rule);
|
||||||
if (object != null) {
|
if (result != null) {
|
||||||
this.errorCollector().finish(this.mark());
|
this.errorCollector().finish(this.mark());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.scope().hasOnlySingleFrame()) {
|
if (!this.scope().hasOnlySingleFrame()) {
|
||||||
throw new IllegalStateException("Malformed scope: " + this.scope());
|
throw new IllegalStateException("Malformed scope: " + this.scope());
|
||||||
} else {
|
|
||||||
return Optional.ofNullable(object);
|
|
||||||
}
|
}
|
||||||
|
return Optional.ofNullable(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -28,15 +27,11 @@ public interface ParseState<S> {
|
|||||||
|
|
||||||
int mark();
|
int mark();
|
||||||
|
|
||||||
void restore(int cursor);
|
void restore(int mark);
|
||||||
|
|
||||||
Control acquireControl();
|
Control acquireControl();
|
||||||
|
|
||||||
void releaseControl();
|
void releaseControl();
|
||||||
|
|
||||||
ParseState<S> silent();
|
ParseState<S> silent();
|
||||||
|
|
||||||
void markNull(int mark);
|
|
||||||
|
|
||||||
boolean isNull(int mark);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
public interface Rule<S, T> {
|
public interface Rule<S, T> {
|
||||||
@Nullable
|
@Nullable
|
||||||
T parse(ParseState<S> parseState);
|
T parse(ParseState<S> state);
|
||||||
|
|
||||||
static <S, T> Rule<S, T> fromTerm(Term<S> child, RuleAction<S, T> action) {
|
static <S, T> Rule<S, T> fromTerm(Term<S> child, RuleAction<S, T> action) {
|
||||||
return new WrappedTerm<>(action, child);
|
return new WrappedTerm<>(action, child);
|
||||||
@@ -17,38 +17,35 @@ public interface Rule<S, T> {
|
|||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
interface RuleAction<S, T> {
|
interface RuleAction<S, T> {
|
||||||
@Nullable
|
@Nullable
|
||||||
T run(ParseState<S> parseState);
|
T run(ParseState<S> state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
interface SimpleRuleAction<S, T> extends RuleAction<S, T> {
|
interface SimpleRuleAction<S, T> extends RuleAction<S, T> {
|
||||||
T run(Scope scope);
|
T run(Scope ruleScope);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default T run(ParseState<S> parseState) {
|
default T run(ParseState<S> state) {
|
||||||
return this.run(parseState.scope());
|
return this.run(state.scope());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record WrappedTerm<S, T>(RuleAction<S, T> action, Term<S> child) implements Rule<S, T> {
|
record WrappedTerm<S, T>(RuleAction<S, T> action, Term<S> child) implements Rule<S, T> {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public T parse(ParseState<S> parseState) {
|
public T parse(ParseState<S> state) {
|
||||||
Scope scope = parseState.scope();
|
Scope scope = state.scope();
|
||||||
scope.pushFrame();
|
scope.pushFrame();
|
||||||
|
|
||||||
T var3;
|
|
||||||
try {
|
try {
|
||||||
if (!this.child.parse(parseState, scope, Control.UNBOUND)) {
|
if (!this.child.parse(state, scope, Control.UNBOUND)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var3 = this.action.run(parseState);
|
return this.action.run(state);
|
||||||
} finally {
|
} finally {
|
||||||
scope.popFrame();
|
scope.popFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
return var3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ public final class Scope {
|
|||||||
this.stack[1] = null;
|
this.stack[1] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int valueIndex(Atom<?> name) {
|
private int valueIndex(Atom<?> atom) {
|
||||||
for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) {
|
for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) {
|
||||||
Object object = this.stack[i];
|
Object key = this.stack[i];
|
||||||
|
|
||||||
assert object instanceof Atom;
|
assert key instanceof Atom;
|
||||||
|
|
||||||
if (object == name) {
|
if (key == atom) {
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,14 +42,14 @@ public final class Scope {
|
|||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int valueIndexForAny(Atom<?>... names) {
|
public int valueIndexForAny(Atom<?>... atoms) {
|
||||||
for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) {
|
for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) {
|
||||||
Object object = this.stack[i];
|
Object key = this.stack[i];
|
||||||
|
|
||||||
assert object instanceof Atom;
|
assert key instanceof Atom;
|
||||||
|
|
||||||
for (Atom<?> atom : names) {
|
for (Atom<?> atom : atoms) {
|
||||||
if (atom == object) {
|
if (atom == key) {
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,15 +58,15 @@ public final class Scope {
|
|||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureCapacity(int requiredCapacitty) {
|
private void ensureCapacity(int additionalEntryCount) {
|
||||||
int i = this.stack.length;
|
int currentSize = this.stack.length;
|
||||||
int i1 = this.topEntryKeyIndex + 1;
|
int currentLastValueIndex = this.topEntryKeyIndex + 1;
|
||||||
int i2 = i1 + requiredCapacitty * 2;
|
int newLastValueIndex = currentLastValueIndex + additionalEntryCount * 2;
|
||||||
if (i2 >= i) {
|
if (newLastValueIndex >= currentSize) {
|
||||||
int i3 = MiscUtils.growByHalf(i, i2 + 1);
|
int newSize = MiscUtils.growByHalf(currentSize, newLastValueIndex + 1);
|
||||||
Object[] objects = new Object[i3];
|
Object[] newStack = new Object[newSize];
|
||||||
System.arraycopy(this.stack, 0, objects, 0, i);
|
System.arraycopy(this.stack, 0, newStack, 0, currentSize);
|
||||||
this.stack = objects;
|
this.stack = newStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert this.validateStructure();
|
assert this.validateStructure();
|
||||||
@@ -86,8 +86,8 @@ public final class Scope {
|
|||||||
assert this.validateStructure();
|
assert this.validateStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPreviousMarkerIndex(int markerIndex) {
|
private int getPreviousMarkerIndex(int markerKeyIndex) {
|
||||||
return (Integer)this.stack[markerIndex + 1];
|
return (Integer) this.stack[markerKeyIndex + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void popFrame() {
|
public void popFrame() {
|
||||||
@@ -100,25 +100,25 @@ public final class Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void splitFrame() {
|
public void splitFrame() {
|
||||||
int i = this.topMarkerKeyIndex;
|
int currentFrameMarkerIndex = this.topMarkerKeyIndex;
|
||||||
int i1 = (this.topEntryKeyIndex - this.topMarkerKeyIndex) / ENTRY_STRIDE;
|
int nonMarkerEntriesInFrame = (this.topEntryKeyIndex - this.topMarkerKeyIndex) / ENTRY_STRIDE;
|
||||||
this.ensureCapacity(i1 + 1);
|
this.ensureCapacity(nonMarkerEntriesInFrame + 1);
|
||||||
this.setupNewFrame();
|
this.setupNewFrame();
|
||||||
int i2 = i + ENTRY_STRIDE;
|
int sourceCursor = currentFrameMarkerIndex + ENTRY_STRIDE;
|
||||||
int i3 = this.topEntryKeyIndex;
|
int targetCursor = this.topEntryKeyIndex;
|
||||||
|
|
||||||
for (int i4 = 0; i4 < i1; i4++) {
|
for (int i = 0; i < nonMarkerEntriesInFrame; i++) {
|
||||||
i3 += ENTRY_STRIDE;
|
targetCursor += ENTRY_STRIDE;
|
||||||
Object object = this.stack[i2];
|
Object key = this.stack[sourceCursor];
|
||||||
|
|
||||||
assert object != null;
|
assert key != null;
|
||||||
|
|
||||||
this.stack[i3] = object;
|
this.stack[targetCursor] = key;
|
||||||
this.stack[i3 + 1] = null;
|
this.stack[targetCursor + 1] = null;
|
||||||
i2 += ENTRY_STRIDE;
|
sourceCursor += ENTRY_STRIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.topEntryKeyIndex = i3;
|
this.topEntryKeyIndex = targetCursor;
|
||||||
|
|
||||||
assert this.validateStructure();
|
assert this.validateStructure();
|
||||||
}
|
}
|
||||||
@@ -135,40 +135,40 @@ public final class Scope {
|
|||||||
|
|
||||||
public void mergeFrame() {
|
public void mergeFrame() {
|
||||||
int previousMarkerIndex = this.getPreviousMarkerIndex(this.topMarkerKeyIndex);
|
int previousMarkerIndex = this.getPreviousMarkerIndex(this.topMarkerKeyIndex);
|
||||||
int i = previousMarkerIndex;
|
int previousFrameCursor = previousMarkerIndex;
|
||||||
int i1 = this.topMarkerKeyIndex;
|
int currentFrameCursor = this.topMarkerKeyIndex;
|
||||||
|
|
||||||
while (i1 < this.topEntryKeyIndex) {
|
while (currentFrameCursor < this.topEntryKeyIndex) {
|
||||||
i += ENTRY_STRIDE;
|
previousFrameCursor += ENTRY_STRIDE;
|
||||||
i1 += ENTRY_STRIDE;
|
currentFrameCursor += ENTRY_STRIDE;
|
||||||
Object object = this.stack[i1];
|
Object newKey = this.stack[currentFrameCursor];
|
||||||
|
|
||||||
assert object instanceof Atom;
|
assert newKey instanceof Atom;
|
||||||
|
|
||||||
Object object1 = this.stack[i1 + 1];
|
Object newValue = this.stack[currentFrameCursor + 1];
|
||||||
Object object2 = this.stack[i];
|
Object oldKey = this.stack[previousFrameCursor];
|
||||||
if (object2 != object) {
|
if (oldKey != newKey) {
|
||||||
this.stack[i] = object;
|
this.stack[previousFrameCursor] = newKey;
|
||||||
this.stack[i + 1] = object1;
|
this.stack[previousFrameCursor + 1] = newValue;
|
||||||
} else if (object1 != null) {
|
} else if (newValue != null) {
|
||||||
this.stack[i + 1] = object1;
|
this.stack[previousFrameCursor + 1] = newValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.topEntryKeyIndex = i;
|
this.topEntryKeyIndex = previousFrameCursor;
|
||||||
this.topMarkerKeyIndex = previousMarkerIndex;
|
this.topMarkerKeyIndex = previousMarkerIndex;
|
||||||
|
|
||||||
assert this.validateStructure();
|
assert this.validateStructure();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void put(Atom<T> atom, @Nullable T value) {
|
public <T> void put(Atom<T> name, @Nullable T value) {
|
||||||
int i = this.valueIndex(atom);
|
int valueIndex = this.valueIndex(name);
|
||||||
if (i != NOT_FOUND) {
|
if (valueIndex != NOT_FOUND) {
|
||||||
this.stack[i] = value;
|
this.stack[valueIndex] = value;
|
||||||
} else {
|
} else {
|
||||||
this.ensureCapacity(1);
|
this.ensureCapacity(1);
|
||||||
this.topEntryKeyIndex += ENTRY_STRIDE;
|
this.topEntryKeyIndex += ENTRY_STRIDE;
|
||||||
this.stack[this.topEntryKeyIndex] = atom;
|
this.stack[this.topEntryKeyIndex] = name;
|
||||||
this.stack[this.topEntryKeyIndex + 1] = value;
|
this.stack[this.topEntryKeyIndex + 1] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,77 +176,75 @@ public final class Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public <T> T get(Atom<T> atom) {
|
public <T> T get(Atom<T> name) {
|
||||||
int i = this.valueIndex(atom);
|
int valueIndex = this.valueIndex(name);
|
||||||
return (T)(i != NOT_FOUND ? this.stack[i] : null);
|
return (T) (valueIndex != NOT_FOUND ? this.stack[valueIndex] : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T getOrThrow(Atom<T> atom) {
|
public <T> T getOrThrow(Atom<T> name) {
|
||||||
int i = this.valueIndex(atom);
|
int valueIndex = this.valueIndex(name);
|
||||||
if (i == NOT_FOUND) {
|
if (valueIndex == NOT_FOUND) {
|
||||||
throw new IllegalArgumentException("No value for atom " + atom);
|
throw new IllegalArgumentException("No value for atom " + name);
|
||||||
} else {
|
|
||||||
return (T)this.stack[i];
|
|
||||||
}
|
}
|
||||||
|
return (T) this.stack[valueIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T getOrDefault(Atom<T> atom, T defaultValue) {
|
public <T> T getOrDefault(Atom<T> name, T fallback) {
|
||||||
int i = this.valueIndex(atom);
|
int valueIndex = this.valueIndex(name);
|
||||||
return (T)(i != NOT_FOUND ? this.stack[i] : defaultValue);
|
return (T) (valueIndex != NOT_FOUND ? this.stack[valueIndex] : fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
public final <T> T getAny(Atom<? extends T>... atoms) {
|
public final <T> T getAny(Atom<? extends T>... names) {
|
||||||
int i = this.valueIndexForAny(atoms);
|
int valueIndex = this.valueIndexForAny(names);
|
||||||
return (T)(i != NOT_FOUND ? this.stack[i] : null);
|
return (T) (valueIndex != NOT_FOUND ? this.stack[valueIndex] : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
public final <T> T getAnyOrThrow(Atom<? extends T>... atoms) {
|
public final <T> T getAnyOrThrow(Atom<? extends T>... names) {
|
||||||
int i = this.valueIndexForAny(atoms);
|
int valueIndex = this.valueIndexForAny(names);
|
||||||
if (i == NOT_FOUND) {
|
if (valueIndex == NOT_FOUND) {
|
||||||
throw new IllegalArgumentException("No value for atoms " + Arrays.toString(atoms));
|
throw new IllegalArgumentException("No value for atoms " + Arrays.toString(names));
|
||||||
} else {
|
|
||||||
return (T)this.stack[i];
|
|
||||||
}
|
}
|
||||||
|
return (T) this.stack[valueIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
boolean flag = true;
|
boolean afterFrame = true;
|
||||||
|
|
||||||
for (int i = 0; i <= this.topEntryKeyIndex; i += ENTRY_STRIDE) {
|
for (int i = 0; i <= this.topEntryKeyIndex; i += ENTRY_STRIDE) {
|
||||||
Object object = this.stack[i];
|
Object key = this.stack[i];
|
||||||
Object object1 = this.stack[i + 1];
|
Object value = this.stack[i + 1];
|
||||||
if (object == FRAME_START_MARKER) {
|
if (key == FRAME_START_MARKER) {
|
||||||
stringBuilder.append('|');
|
result.append('|');
|
||||||
flag = true;
|
afterFrame = true;
|
||||||
} else {
|
} else {
|
||||||
if (!flag) {
|
if (!afterFrame) {
|
||||||
stringBuilder.append(',');
|
result.append(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
flag = false;
|
afterFrame = false;
|
||||||
stringBuilder.append(object).append(':').append(object1);
|
result.append(key).append(':').append(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringBuilder.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public Map<Atom<?>, ?> lastFrame() {
|
public Map<Atom<?>, ?> lastFrame() {
|
||||||
HashMap<Atom<?>, Object> map = new HashMap<>();
|
HashMap<Atom<?>, Object> result = new HashMap<>();
|
||||||
|
|
||||||
for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) {
|
for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) {
|
||||||
Object object = this.stack[i];
|
Object key = this.stack[i];
|
||||||
Object object1 = this.stack[i + 1];
|
Object value = this.stack[i + 1];
|
||||||
map.put((Atom<?>)object, object1);
|
result.put((Atom<?>) key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasOnlySingleFrame() {
|
public boolean hasOnlySingleFrame() {
|
||||||
@@ -258,9 +256,8 @@ public final class Scope {
|
|||||||
|
|
||||||
if (this.stack[0] != FRAME_START_MARKER) {
|
if (this.stack[0] != FRAME_START_MARKER) {
|
||||||
throw new IllegalStateException("Corrupted stack");
|
throw new IllegalStateException("Corrupted stack");
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateStructure() {
|
private boolean validateStructure() {
|
||||||
@@ -289,10 +286,11 @@ public final class Scope {
|
|||||||
public static <S> Term<S> increaseDepth() {
|
public static <S> Term<S> increaseDepth() {
|
||||||
class IncreasingDepthTerm<W> implements Term<W> {
|
class IncreasingDepthTerm<W> implements Term<W> {
|
||||||
public static final IncreasingDepthTerm INSTANCE = new IncreasingDepthTerm();
|
public static final IncreasingDepthTerm INSTANCE = new IncreasingDepthTerm();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(final ParseState<W> parseState, final Scope scope, final Control control) {
|
public boolean parse(final ParseState<W> state, final Scope scope, final Control control) {
|
||||||
if (++scope.depth > 512) {
|
if (++scope.depth > 512) {
|
||||||
parseState.errorCollector().store(parseState.mark(), new IllegalStateException("Too deep"));
|
state.errorCollector().store(state.mark(), new IllegalStateException("Too deep"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -305,8 +303,9 @@ public final class Scope {
|
|||||||
public static <S> Term<S> decreaseDepth() {
|
public static <S> Term<S> decreaseDepth() {
|
||||||
class DecreasingDepthTerm<W> implements Term<W> {
|
class DecreasingDepthTerm<W> implements Term<W> {
|
||||||
public static final DecreasingDepthTerm INSTANCE = new DecreasingDepthTerm();
|
public static final DecreasingDepthTerm INSTANCE = new DecreasingDepthTerm();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(final ParseState<W> parseState, final Scope scope, final Control control) {
|
public boolean parse(final ParseState<W> state, final Scope scope, final Control control) {
|
||||||
scope.depth--;
|
scope.depth--;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package net.momirealms.craftengine.core.util.snbt.parse;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public interface SuggestionSupplier<S> {
|
public interface SuggestionSupplier<S> {
|
||||||
Stream<String> possibleValues(ParseState<S> parseState);
|
Stream<String> possibleValues(ParseState<S> state);
|
||||||
|
|
||||||
static <S> SuggestionSupplier<S> empty() {
|
static <S> SuggestionSupplier<S> empty() {
|
||||||
return parseState -> Stream.empty();
|
return state -> Stream.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,20 +4,20 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface Term<S> {
|
public interface Term<S> {
|
||||||
boolean parse(ParseState<S> parseState, Scope scope, Control control);
|
boolean parse(ParseState<S> state, Scope scope, Control control);
|
||||||
|
|
||||||
static <S, T> Term<S> marker(Atom<T> name, T value) {
|
static <S, T> Term<S> marker(Atom<T> name, T value) {
|
||||||
return new Marker<>(name, value);
|
return new Marker<>(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
static <S> Term<S> sequence(Term<S>... elements) {
|
static <S> Term<S> sequence(Term<S>... terms) {
|
||||||
return new Sequence<>(elements);
|
return new Sequence<>(terms);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
static <S> Term<S> alternative(Term<S>... elements) {
|
static <S> Term<S> alternative(Term<S>... terms) {
|
||||||
return new Alternative<>(elements);
|
return new Alternative<>(terms);
|
||||||
}
|
}
|
||||||
|
|
||||||
static <S> Term<S> optional(Term<S> term) {
|
static <S> Term<S> optional(Term<S> term) {
|
||||||
@@ -32,8 +32,8 @@ public interface Term<S> {
|
|||||||
return new Repeated<>(element, listName, minRepetitions);
|
return new Repeated<>(element, listName, minRepetitions);
|
||||||
}
|
}
|
||||||
|
|
||||||
static <S, T> Term<S> repeatedWithTrailingSeparator(NamedRule<S, T> element, Atom<List<T>> listName, Term<S> seperator) {
|
static <S, T> Term<S> repeatedWithTrailingSeparator(NamedRule<S, T> element, Atom<List<T>> listName, Term<S> separator) {
|
||||||
return repeatedWithTrailingSeparator(element, listName, seperator, 0);
|
return repeatedWithTrailingSeparator(element, listName, separator, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static <S, T> Term<S> repeatedWithTrailingSeparator(NamedRule<S, T> element, Atom<List<T>> listName, Term<S> seperator, int minRepetitions) {
|
static <S, T> Term<S> repeatedWithTrailingSeparator(NamedRule<S, T> element, Atom<List<T>> listName, Term<S> seperator, int minRepetitions) {
|
||||||
@@ -47,7 +47,7 @@ public interface Term<S> {
|
|||||||
static <S> Term<S> cut() {
|
static <S> Term<S> cut() {
|
||||||
return new Term<>() {
|
return new Term<>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
control.cut();
|
control.cut();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ public interface Term<S> {
|
|||||||
static <S> Term<S> empty() {
|
static <S> Term<S> empty() {
|
||||||
return new Term<>() {
|
return new Term<>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,11 +73,11 @@ public interface Term<S> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static <S> Term<S> fail(final Object reason) {
|
static <S> Term<S> fail(final Object message) {
|
||||||
return new Term<>() {
|
return new Term<>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
parseState.errorCollector().store(parseState.mark(), reason);
|
state.errorCollector().store(state.mark(), message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,22 +90,22 @@ public interface Term<S> {
|
|||||||
|
|
||||||
record Alternative<S>(Term<S>[] elements) implements Term<S> {
|
record Alternative<S>(Term<S>[] elements) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
Control control1 = parseState.acquireControl();
|
Control controlForThis = state.acquireControl();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int i = parseState.mark();
|
int mark = state.mark();
|
||||||
scope.splitFrame();
|
scope.splitFrame();
|
||||||
|
|
||||||
for (Term<S> term : this.elements) {
|
for (Term<S> element : this.elements) {
|
||||||
if (term.parse(parseState, scope, control1)) {
|
if (element.parse(state, scope, controlForThis)) {
|
||||||
scope.mergeFrame();
|
scope.mergeFrame();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.clearFrameValues();
|
scope.clearFrameValues();
|
||||||
parseState.restore(i);
|
state.restore(mark);
|
||||||
if (control1.hasCut()) {
|
if (controlForThis.hasCut()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,24 +113,24 @@ public interface Term<S> {
|
|||||||
scope.popFrame();
|
scope.popFrame();
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
parseState.releaseControl();
|
state.releaseControl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record LookAhead<S>(Term<S> term, boolean positive) implements Term<S> {
|
record LookAhead<S>(Term<S> term, boolean positive) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
int i = parseState.mark();
|
int mark = state.mark();
|
||||||
boolean flag = this.term.parse(parseState.silent(), scope, control);
|
boolean result = this.term.parse(state.silent(), scope, control);
|
||||||
parseState.restore(i);
|
state.restore(mark);
|
||||||
return this.positive == flag;
|
return this.positive == result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record Marker<S, T>(Atom<T> name, T value) implements Term<S> {
|
record Marker<S, T>(Atom<T> name, T value) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
scope.put(this.name, this.value);
|
scope.put(this.name, this.value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -138,10 +138,10 @@ public interface Term<S> {
|
|||||||
|
|
||||||
record Maybe<S>(Term<S> term) implements Term<S> {
|
record Maybe<S>(Term<S> term) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
int i = parseState.mark();
|
int mark = state.mark();
|
||||||
if (!this.term.parse(parseState, scope, control)) {
|
if (!this.term.parse(state, scope, control)) {
|
||||||
parseState.restore(i);
|
state.restore(mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -150,25 +150,24 @@ public interface Term<S> {
|
|||||||
|
|
||||||
record Repeated<S, T>(NamedRule<S, T> element, Atom<List<T>> listName, int minRepetitions) implements Term<S> {
|
record Repeated<S, T>(NamedRule<S, T> element, Atom<List<T>> listName, int minRepetitions) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
int i = parseState.mark();
|
int mark = state.mark();
|
||||||
List<T> list = new ArrayList<>(this.minRepetitions);
|
List<T> elements = new ArrayList<>(this.minRepetitions);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int i1 = parseState.mark();
|
int entryMark = state.mark();
|
||||||
T object = parseState.parse(this.element);
|
T parsedElement = state.parse(this.element);
|
||||||
if (object == null) {
|
if (parsedElement == null) {
|
||||||
parseState.restore(i1);
|
state.restore(entryMark);
|
||||||
if (list.size() < this.minRepetitions) {
|
if (elements.size() < this.minRepetitions) {
|
||||||
parseState.restore(i);
|
state.restore(mark);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
}
|
||||||
scope.put(this.listName, list);
|
scope.put(this.listName, elements);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
list.add(object);
|
elements.add(parsedElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,56 +176,55 @@ public interface Term<S> {
|
|||||||
NamedRule<S, T> element, Atom<List<T>> listName, Term<S> separator, int minRepetitions, boolean allowTrailingSeparator
|
NamedRule<S, T> element, Atom<List<T>> listName, Term<S> separator, int minRepetitions, boolean allowTrailingSeparator
|
||||||
) implements Term<S> {
|
) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
int i = parseState.mark();
|
int listMark = state.mark();
|
||||||
List<T> list = new ArrayList<>(this.minRepetitions);
|
List<T> elements = new ArrayList<>(this.minRepetitions);
|
||||||
boolean flag = true;
|
boolean first = true;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int i1 = parseState.mark();
|
int markBeforeSeparator = state.mark();
|
||||||
if (!flag && !this.separator.parse(parseState, scope, control)) {
|
if (!first && !this.separator.parse(state, scope, control)) {
|
||||||
parseState.restore(i1);
|
state.restore(markBeforeSeparator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2 = parseState.mark();
|
int markAfterSeparator = state.mark();
|
||||||
T object = parseState.parse(this.element);
|
T parsedElement = state.parse(this.element);
|
||||||
if (object == null) {
|
if (parsedElement == null) {
|
||||||
if (flag) {
|
if (first) {
|
||||||
parseState.restore(i2);
|
state.restore(markAfterSeparator);
|
||||||
} else {
|
} else {
|
||||||
if (!this.allowTrailingSeparator) {
|
if (!this.allowTrailingSeparator) {
|
||||||
parseState.restore(i);
|
state.restore(listMark);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseState.restore(i2);
|
state.restore(markAfterSeparator);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
list.add(object);
|
elements.add(parsedElement);
|
||||||
flag = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list.size() < this.minRepetitions) {
|
if (elements.size() < this.minRepetitions) {
|
||||||
parseState.restore(i);
|
state.restore(listMark);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
scope.put(this.listName, list);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
scope.put(this.listName, elements);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
record Sequence<S>(Term<S>[] elements) implements Term<S> {
|
record Sequence<S>(Term<S>[] elements) implements Term<S> {
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<S> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<S> state, Scope scope, Control control) {
|
||||||
int i = parseState.mark();
|
int mark = state.mark();
|
||||||
|
|
||||||
for (Term<S> term : this.elements) {
|
for (Term<S> element : this.elements) {
|
||||||
if (!term.parse(parseState, scope, control)) {
|
if (!element.parse(state, scope, control)) {
|
||||||
parseState.restore(i);
|
state.restore(mark);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,41 +13,39 @@ public record Grammar<T>(Dictionary<StringReader> rules, NamedRule<StringReader,
|
|||||||
rules.checkAllBound();
|
rules.checkAllBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<T> parse(ParseState<StringReader> parseState) {
|
public Optional<T> parse(ParseState<StringReader> state) {
|
||||||
return parseState.parseTopRule(this.top);
|
return state.parseTopRule(this.top);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T parse(StringReader reader) throws CommandSyntaxException {
|
public T parse(StringReader reader) throws CommandSyntaxException {
|
||||||
ErrorCollector.LongestOnly<StringReader> longestOnly = new ErrorCollector.LongestOnly<>();
|
ErrorCollector.LongestOnly<StringReader> errorCollector = new ErrorCollector.LongestOnly<>();
|
||||||
StringReaderParserState stringReaderParserState = new StringReaderParserState(longestOnly, reader);
|
StringReaderParserState stringReaderParserState = new StringReaderParserState(errorCollector, reader);
|
||||||
Optional<T> optional = this.parse(stringReaderParserState);
|
Optional<T> optionalResult = this.parse(stringReaderParserState);
|
||||||
if (optional.isPresent()) {
|
if (optionalResult.isPresent()) {
|
||||||
T result = optional.get();
|
T result = optionalResult.get();
|
||||||
if (CachedParseState.JAVA_NULL_VALUE_MARKER.equals(result)) {
|
if (CachedParseState.JAVA_NULL_VALUE_MARKER.equals(result)) {
|
||||||
result = null;
|
result = null;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
}
|
||||||
List<ErrorEntry<StringReader>> list = longestOnly.entries();
|
List<ErrorEntry<StringReader>> errorEntries = errorCollector.entries();
|
||||||
List<Exception> list1 = list.stream().<Exception>mapMulti((errorEntry, consumer) -> {
|
List<Exception> exceptions = errorEntries.stream().<Exception>mapMulti((entry, output) -> {
|
||||||
if (errorEntry.reason() instanceof DelayedException<?> delayedException) {
|
if (entry.reason() instanceof DelayedException<?> delayedException) {
|
||||||
consumer.accept(delayedException.create(reader.getString(), errorEntry.cursor()));
|
output.accept(delayedException.create(reader.getString(), entry.cursor()));
|
||||||
} else if (errorEntry.reason() instanceof Exception exception1) {
|
} else if (entry.reason() instanceof Exception exception1) {
|
||||||
consumer.accept(exception1);
|
output.accept(exception1);
|
||||||
}
|
}
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
for (Exception exception : list1) {
|
for (Exception exception : exceptions) {
|
||||||
if (exception instanceof CommandSyntaxException commandSyntaxException) {
|
if (exception instanceof CommandSyntaxException cse) {
|
||||||
throw commandSyntaxException;
|
throw cse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list1.size() == 1 && list1.getFirst() instanceof RuntimeException runtimeException) {
|
if (exceptions.size() == 1 && exceptions.getFirst() instanceof RuntimeException re) {
|
||||||
throw runtimeException;
|
throw re;
|
||||||
} else {
|
}
|
||||||
throw new IllegalStateException("Failed to parse: " + list.stream().map(ErrorEntry::toString).collect(Collectors.joining(", ")));
|
throw new IllegalStateException("Failed to parse: " + errorEntries.stream().map(ErrorEntry::toString).collect(Collectors.joining(", ")));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,15 @@ public final class GreedyPatternParseRule implements Rule<StringReader, String>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String parse(ParseState<StringReader> parseState) {
|
public String parse(ParseState<StringReader> state) {
|
||||||
StringReader stringReader = parseState.input();
|
StringReader input = state.input();
|
||||||
String string = stringReader.getString();
|
String fullString = input.getString();
|
||||||
Matcher matcher = this.pattern.matcher(string).region(stringReader.getCursor(), string.length());
|
Matcher matcher = this.pattern.matcher(fullString).region(input.getCursor(), fullString.length());
|
||||||
if (!matcher.lookingAt()) {
|
if (!matcher.lookingAt()) {
|
||||||
parseState.errorCollector().store(parseState.mark(), this.error);
|
state.errorCollector().store(state.mark(), this.error);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
}
|
||||||
stringReader.setCursor(matcher.end());
|
input.setCursor(matcher.end());
|
||||||
return matcher.group(0);
|
return matcher.group(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -25,24 +25,23 @@ public abstract class GreedyPredicateParseRule implements Rule<StringReader, Str
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public String parse(ParseState<StringReader> parseState) {
|
public String parse(ParseState<StringReader> state) {
|
||||||
StringReader stringReader = parseState.input();
|
StringReader input = state.input();
|
||||||
String string = stringReader.getString();
|
String fullString = input.getString();
|
||||||
int cursor = stringReader.getCursor();
|
int start = input.getCursor();
|
||||||
int i = cursor;
|
int pos = start;
|
||||||
|
|
||||||
while (i < string.length() && this.isAccepted(string.charAt(i)) && i - cursor < this.maxSize) {
|
while (pos < fullString.length() && this.isAccepted(fullString.charAt(pos)) && pos - start < this.maxSize) {
|
||||||
i++;
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i1 = i - cursor;
|
int length = pos - start;
|
||||||
if (i1 < this.minSize) {
|
if (length < this.minSize) {
|
||||||
parseState.errorCollector().store(parseState.mark(), this.error);
|
state.errorCollector().store(state.mark(), this.error);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
|
||||||
stringReader.setCursor(i);
|
|
||||||
return string.substring(cursor, i);
|
|
||||||
}
|
}
|
||||||
|
input.setCursor(pos);
|
||||||
|
return fullString.substring(start, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean isAccepted(char c);
|
protected abstract boolean isAccepted(char c);
|
||||||
|
|||||||
@@ -19,28 +19,27 @@ public abstract class NumberRunParseRule implements Rule<StringReader, String> {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public String parse(ParseState<StringReader> parseState) {
|
public String parse(ParseState<StringReader> state) {
|
||||||
StringReader stringReader = parseState.input();
|
StringReader input = state.input();
|
||||||
stringReader.skipWhitespace();
|
input.skipWhitespace();
|
||||||
String string = stringReader.getString();
|
String fullString = input.getString();
|
||||||
int cursor = stringReader.getCursor();
|
int start = input.getCursor();
|
||||||
int i = cursor;
|
int pos = start;
|
||||||
|
|
||||||
while (i < string.length() && this.isAccepted(string.charAt(i))) {
|
while (pos < fullString.length() && this.isAccepted(fullString.charAt(pos))) {
|
||||||
i++;
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i1 = i - cursor;
|
int length = pos - start;
|
||||||
if (i1 == 0) {
|
if (length == 0) {
|
||||||
parseState.errorCollector().store(parseState.mark(), this.noValueError);
|
state.errorCollector().store(state.mark(), this.noValueError);
|
||||||
return null;
|
|
||||||
} else if (string.charAt(cursor) != '_' && string.charAt(i - 1) != '_') {
|
|
||||||
stringReader.setCursor(i);
|
|
||||||
return string.substring(cursor, i);
|
|
||||||
} else {
|
|
||||||
parseState.errorCollector().store(parseState.mark(), this.underscoreNotAllowedError);
|
|
||||||
return null;
|
return null;
|
||||||
|
} else if (fullString.charAt(start) != '_' && fullString.charAt(pos - 1) != '_') {
|
||||||
|
input.setCursor(pos);
|
||||||
|
return fullString.substring(start, pos);
|
||||||
}
|
}
|
||||||
|
state.errorCollector().store(state.mark(), this.underscoreNotAllowedError);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean isAccepted(char c);
|
protected abstract boolean isAccepted(char c);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class StringReaderParserState extends CachedParseState<StringReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restore(int cursor) {
|
public void restore(int mark) {
|
||||||
this.input.setCursor(cursor);
|
this.input.setCursor(mark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,50 +16,49 @@ public interface StringReaderTerms {
|
|||||||
static Term<StringReader> character(final char value) {
|
static Term<StringReader> character(final char value) {
|
||||||
return new TerminalCharacters(CharList.of(value)) {
|
return new TerminalCharacters(CharList.of(value)) {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isAccepted(char c) {
|
protected boolean isAccepted(char v) {
|
||||||
return value == c;
|
return value == v;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Term<StringReader> characters(final char value1, final char value2) {
|
static Term<StringReader> characters(final char v1, final char v2) {
|
||||||
return new TerminalCharacters(CharList.of(value1, value2)) {
|
return new TerminalCharacters(CharList.of(v1, v2)) {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isAccepted(char c) {
|
protected boolean isAccepted(char v) {
|
||||||
return c == value1 || c == value2;
|
return v == v1 || v == v2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static StringReader createReader(String input, int cursor) {
|
static StringReader createReader(String contents, int cursor) {
|
||||||
StringReader stringReader = new StringReader(input);
|
StringReader reader = new StringReader(contents);
|
||||||
stringReader.setCursor(cursor);
|
reader.setCursor(cursor);
|
||||||
return stringReader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TerminalCharacters implements Term<StringReader> {
|
abstract class TerminalCharacters implements Term<StringReader> {
|
||||||
private final DelayedException<CommandSyntaxException> error;
|
private final DelayedException<CommandSyntaxException> error;
|
||||||
private final SuggestionSupplier<StringReader> suggestions;
|
private final SuggestionSupplier<StringReader> suggestions;
|
||||||
|
|
||||||
public TerminalCharacters(CharList characters) {
|
public TerminalCharacters(CharList values) {
|
||||||
String string = characters.intStream().mapToObj(Character::toString).collect(Collectors.joining("|"));
|
String joinedValues = values.intStream().mapToObj(Character::toString).collect(Collectors.joining("|"));
|
||||||
this.error = DelayedException.create(LITERAL_INCORRECT, string);
|
this.error = DelayedException.create(LITERAL_INCORRECT, joinedValues);
|
||||||
this.suggestions = parseState -> characters.intStream().mapToObj(Character::toString);
|
this.suggestions = s -> values.intStream().mapToObj(Character::toString);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean parse(ParseState<StringReader> parseState, Scope scope, Control control) {
|
public boolean parse(ParseState<StringReader> state, Scope scope, Control control) {
|
||||||
parseState.input().skipWhitespace();
|
state.input().skipWhitespace();
|
||||||
int i = parseState.mark();
|
int cursor = state.mark();
|
||||||
if (parseState.input().canRead() && this.isAccepted(parseState.input().read())) {
|
if (state.input().canRead() && this.isAccepted(state.input().read())) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
parseState.errorCollector().store(i, this.suggestions, this.error);
|
state.errorCollector().store(cursor, this.suggestions, this.error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract boolean isAccepted(char c);
|
protected abstract boolean isAccepted(char value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,15 +19,14 @@ public class UnquotedStringParseRule implements Rule<StringReader, String> {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public String parse(ParseState<StringReader> parseState) {
|
public String parse(ParseState<StringReader> state) {
|
||||||
parseState.input().skipWhitespace();
|
state.input().skipWhitespace();
|
||||||
int i = parseState.mark();
|
int cursor = state.mark();
|
||||||
String unquotedString = parseState.input().readUnquotedString();
|
String value = state.input().readUnquotedString();
|
||||||
if (unquotedString.length() < this.minSize) {
|
if (value.length() < this.minSize) {
|
||||||
parseState.errorCollector().store(i, this.error);
|
state.errorCollector().store(cursor, this.error);
|
||||||
return null;
|
return null;
|
||||||
} else {
|
}
|
||||||
return unquotedString;
|
return value;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user