package net.minecraft.util.parsing.packrat; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Supplier; import org.jspecify.annotations.Nullable; public class Dictionary { private final Map, Dictionary.Entry> terms = new IdentityHashMap<>(); public NamedRule put(final Atom name, final Rule entry) { Dictionary.Entry holder = (Dictionary.Entry)this.terms.computeIfAbsent(name, Dictionary.Entry::new); if (holder.value != null) { throw new IllegalArgumentException("Trying to override rule: " + name); } holder.value = entry; return holder; } public NamedRule putComplex(final Atom name, final Term term, final Rule.RuleAction action) { return this.put(name, Rule.fromTerm(term, action)); } public NamedRule put(final Atom name, final Term term, final Rule.SimpleRuleAction action) { return this.put(name, Rule.fromTerm(term, action)); } public void checkAllBound() { List> unboundNames = this.terms.entrySet().stream().filter(e -> e.getValue().value == null).map(Map.Entry::getKey).toList(); if (!unboundNames.isEmpty()) { throw new IllegalStateException("Unbound names: " + unboundNames); } } public NamedRule getOrThrow(final Atom name) { return (NamedRule)Objects.requireNonNull(this.terms.get(name), () -> "No rule called " + name); } public NamedRule forward(final Atom name) { return this.getOrCreateEntry(name); } private Dictionary.Entry getOrCreateEntry(final Atom name) { return (Dictionary.Entry)this.terms.computeIfAbsent(name, Dictionary.Entry::new); } public Term named(final Atom name) { return new Dictionary.Reference<>(this.getOrCreateEntry(name), name); } public Term namedWithAlias(final Atom nameToParse, final Atom nameToStore) { return new Dictionary.Reference<>(this.getOrCreateEntry(nameToParse), nameToStore); } private static class Entry implements NamedRule, Supplier { private final Atom name; private @Nullable Rule value; private Entry(final Atom name) { this.name = name; } @Override public Atom name() { return this.name; } @Override public Rule value() { return Objects.requireNonNull(this.value, this); } public String get() { return "Unbound rule " + this.name; } } private record Reference(Dictionary.Entry ruleToParse, Atom nameToStore) implements Term { @Override public boolean parse(final ParseState state, final Scope scope, final Control control) { T result = state.parse(this.ruleToParse); if (result == null) { return false; } scope.put(this.nameToStore, result); return true; } } }