Skip to content

Commit

Permalink
#2178 Implement normalisation of grammar terms to support term compar…
Browse files Browse the repository at this point in the history
…ison irrespective of metadata
  • Loading branch information
homedirectory committed Feb 23, 2024
1 parent def3f3d commit 76ad92a
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ public <V> OneOrMore annotate(TermMetadata.Key<V> key, V value) {
return new OneOrMore(term, TermMetadata.merge(metadata(), key, value));
}

@Override
public OneOrMore normalize() {
return new OneOrMore(term);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ public <V> Optional annotate(TermMetadata.Key<V> key, V value) {
return new Optional(term, TermMetadata.merge(metadata(), key, value));
}

@Override
public Optional normalize() {
return new Optional(term);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public Sequence(Term... terms) {
this(Arrays.asList(terms), TermMetadata.EMPTY_METADATA);
}

@Override
public Term normalize() {
return new Sequence(terms);
}

@Override
public <V> Sequence annotate(final TermMetadata.Key<V> key, final V value) {
return new Sequence(terms, TermMetadata.merge(metadata, key, value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
*/
public sealed interface Term permits Notation, Sequence, Symbol {

/**
* Returns this term in its normal form.
* The normal form doesn't include any metadata, making it possible to correctly compare terms irrespective of their
* metadata.
*/
default Term normalize() {
return this;
}

default TermMetadata metadata() {
return TermMetadata.EMPTY_METADATA;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,28 @@ default Token rest(Class<?> varArityParameter) {
return with(List.of(new VarArityParameter(varArityParameter)));
}

@Override
default Terminal normalize() {
return this;
}

@Override
default <V> Terminal annotate(TermMetadata.Key<V> key, V value) {
final var newMetadata = TermMetadata.merge(metadata(), key, value);
final String name = name();
final Terminal normal = normalize();

return new Terminal() {
@Override
public String name() {
return name;
}

@Override
public Terminal normalize() {
return normal;
}

@Override
public TermMetadata metadata() {
return newMetadata;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@ public boolean hasParameters() {
return !parameters.isEmpty();
}

@Override
public Token normalize() {
return new Token(name, TermMetadata.EMPTY_METADATA, parameters);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,28 @@
*/
public non-sealed interface Variable extends Symbol {

@Override
default Variable normalize() {
return this;
}

@Override
default <V> Variable annotate(TermMetadata.Key<V> key, V value) {
final var newMetadata = TermMetadata.merge(metadata(), key, value);
final String name = name();
final Variable normal = normalize();

return new Variable() {
@Override
public String name() {
return name;
}

@Override
public Variable normalize() {
return normal;
}

@Override
public TermMetadata metadata() {
return newMetadata;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ public <V> ZeroOrMore annotate(TermMetadata.Key<V> key, V value) {
return new ZeroOrMore(term, TermMetadata.merge(metadata(), key, value));
}

@Override
public ZeroOrMore normalize() {
return new ZeroOrMore(term);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import fielden.platform.bnf.BNF;
import fielden.platform.bnf.Rule;
import fielden.platform.bnf.Term;
import fielden.platform.bnf.Variable;
import org.apache.commons.collections4.CollectionUtils;

Expand All @@ -14,8 +15,8 @@
public final class BnfVerifier {

public static void verifyBnf(BNF bnf) {
var rhsVars = bnf.rules().stream().flatMap(BnfVerifier::ruleRhsVariables).collect(toSet());
var lhsVars = bnf.rules().stream().map(Rule::lhs).collect(toSet());
var rhsVars = bnf.rules().stream().flatMap(BnfVerifier::ruleRhsVariables).map(Variable::normalize).collect(toSet());
var lhsVars = bnf.rules().stream().map(Rule::lhs).map(Variable::normalize).collect(toSet());
final Collection<Variable> diff = CollectionUtils.subtract(rhsVars, lhsVars);
if (!diff.isEmpty()) {
throw new RuntimeException("BNF uses non-terminals with no productions: { %s }".formatted(
Expand Down

0 comments on commit 76ad92a

Please sign in to comment.