Skip to content

Commit

Permalink
#2178 Enhance the BNF abstraction with the Alternation type
Browse files Browse the repository at this point in the history
  • Loading branch information
homedirectory committed Feb 27, 2024
1 parent a0ff944 commit 51fa045
Show file tree
Hide file tree
Showing 17 changed files with 223 additions and 96 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package fielden.platform.bnf;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

import static java.util.stream.Collectors.joining;

public record Alternation(List<Sequence> options, TermMetadata metadata) implements Notation {

public Alternation(final List<Sequence> options, final TermMetadata metadata) {
this.options = List.copyOf(options);
this.metadata = metadata;
}

public Alternation(List<Sequence> options) {
this(options, TermMetadata.EMPTY_METADATA);
}

@Override
public <V> Alternation annotate(TermMetadata.Key<V> key, V value) {
return new Alternation(options, TermMetadata.merge(metadata(), key, value));
}

@Override
public Alternation normalize() {
return metadata == TermMetadata.EMPTY_METADATA ? this : new Alternation(options);
}

@Override
public Alternation recMap(final Function<? super Term, ? extends Term> mapper) {
return new Alternation(options.stream().map(seq -> seq.recMap(mapper)).toList(), metadata);
}

@Override
public Stream<Term> flatten() {
return options.stream().flatMap(Sequence::flatten);
}

@Override
public String toString() {
return options().stream().map(Term::toString).collect(joining(" | "));
}

}
Original file line number Diff line number Diff line change
@@ -1,55 +1,17 @@
package fielden.platform.bnf;

import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;

import static java.util.stream.Collectors.joining;
public record Derivation(Variable lhs, Alternation rhs) implements Rule {

public final class Derivation implements Rule {

private final Variable lhs;
private final List<Sequence> rhs;

public Derivation(Variable lhs, List<Sequence> rhs) {
this.lhs = lhs;
this.rhs = rhs;
}

@Override
public Stream<Sequence> rhs() {
return rhs.stream();
}

@Override
public Variable lhs() {
return lhs;
}

public Rule map(final Function<? super Term, ? extends Term> mapper) {
return new Derivation(lhs, rhs.stream().map(seq -> seq.map(mapper)).toList());
}

@Override
public boolean equals(Object obj) {
return obj == this ||
(obj instanceof Derivation that &&
Objects.equals(this.lhs, that.lhs) &&
Objects.equals(this.rhs, that.rhs));
}

@Override
public int hashCode() {
return Objects.hash(lhs, rhs);
public Rule recMap(final Function<? super Term, ? extends Term> mapper) {
return new Derivation(lhs, rhs.recMap(mapper));
}

@Override
public String toString() {
return "%s -> %s".formatted(
lhs.name(),
rhs.stream().map(terms -> terms.stream().map(Term::toString).collect(joining(" ")))
.collect(joining(" | ")));
return "%s -> %s".formatted(lhs.name(), rhs);
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,13 @@ public IDerivationTail or(final Term... terms) {

@Override
protected Rule finishRule() {
return new Derivation(lhs, bodies);
return new Derivation(lhs, new Alternation(bodies));
}

@Override
protected boolean buildsRule() {
return true;
}

}

private static final class SpecializationImpl extends BnfBodyImpl implements FluentBNF.ISpecialization {
Expand Down Expand Up @@ -142,12 +141,15 @@ private static final class Builder {

void add(final Rule rule) {
add(rule.lhs());
rule.rhs().forEach(this::add);
rule.rhs().options().forEach(this::add);
rules.add(rule);
}

void add(final Notation notation) {
add(notation.term());
switch (notation) {
case Alternation alternation -> alternation.options().forEach(this::add);
case Quantifier quantifier -> add(quantifier.term());
}
}

void add(final Sequence sequence) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package fielden.platform.bnf;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public sealed interface Notation extends Term permits OneOrMore, Optional, ZeroOrMore {

Term term();
public sealed interface Notation extends Term permits Alternation, Quantifier {

static OneOrMore repeat1(Term term) {
return new OneOrMore(term);
Expand Down Expand Up @@ -40,4 +39,11 @@ static Optional opt(Term term, Term... terms) {
return new Optional(new Sequence(list));
}

static Alternation oneOf(Term term, Term... terms) {
var list = new ArrayList<Sequence>(1 + terms.length);
list.add(Sequence.of(term));
Arrays.stream(terms).map(Sequence::of).forEach(list::add);
return new Alternation(list);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package fielden.platform.bnf;

public record OneOrMore(Term term, TermMetadata metadata) implements Notation {
import java.util.function.Function;

public record OneOrMore(Term term, TermMetadata metadata) implements Quantifier {

public OneOrMore(Term term) {
this(term, TermMetadata.EMPTY_METADATA);
Expand All @@ -16,6 +18,11 @@ public OneOrMore normalize() {
return new OneOrMore(term);
}

@Override
public OneOrMore recMap(final Function<? super Term, ? extends Term> mapper) {
return new OneOrMore(term.recMap(mapper), metadata);
}

@Override
public String toString() {
return "{%s}+".formatted(term);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package fielden.platform.bnf;

public record Optional(Term term, TermMetadata metadata) implements Notation {
import java.util.function.Function;

public record Optional(Term term, TermMetadata metadata) implements Quantifier {

public Optional(Term term) {
this(term, TermMetadata.EMPTY_METADATA);
Expand All @@ -16,6 +18,11 @@ public Optional normalize() {
return new Optional(term);
}

@Override
public Optional recMap(final Function<? super Term, ? extends Term> mapper) {
return new Optional(term.recMap(mapper), metadata);
}

@Override
public String toString() {
return "{%s}?".formatted(term);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fielden.platform.bnf;

import java.util.stream.Stream;

public sealed interface Quantifier extends Notation permits OneOrMore, Optional, ZeroOrMore {

Term term();

@Override
default Stream<Term> flatten() {
return term().flatten();
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
package fielden.platform.bnf;

import java.util.Collection;
import java.util.stream.Stream;

public sealed interface Rule permits Derivation, Specialization {

Variable lhs();

Stream<Sequence> rhs();

default Stream<Term> rhsTerms() {
return rhs().flatMap(Collection::stream);
}
Alternation rhs();

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

public final class Sequence implements List<Term>, Term {

private static final Sequence EMPTY_SEQUENCE = new Sequence();

private final List<Term> terms;
private final TermMetadata metadata;

Expand All @@ -22,6 +24,16 @@ public Sequence(Term... terms) {
this(Arrays.asList(terms), TermMetadata.EMPTY_METADATA);
}

public static Sequence of(Term... terms) {
if (terms.length == 0) {
return EMPTY_SEQUENCE;
}
else if (terms.length == 1 && terms[0] instanceof Sequence seq) {
return seq;
}
return new Sequence(terms);
}

@Override
public Term normalize() {
return new Sequence(terms);
Expand All @@ -32,8 +44,18 @@ public <V> Sequence annotate(final TermMetadata.Key<V> key, final V value) {
return new Sequence(terms, TermMetadata.merge(metadata, key, value));
}

@Override
public Sequence recMap(final Function<? super Term, ? extends Term> mapper) {
return new Sequence(terms.stream().map(t -> t.recMap(mapper)).toList(), metadata);
}

public Sequence map(final Function<? super Term, ? extends Term> mapper) {
return new Sequence(terms.stream().map(mapper).toList());
return new Sequence(terms.stream().map(mapper).toList(), metadata);
}

@Override
public Stream<Term> flatten() {
return terms.stream().flatMap(Term::flatten);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package fielden.platform.bnf;

import java.util.List;
import java.util.stream.Stream;

import static java.util.stream.Collectors.joining;

public record Specialization(Variable lhs, List<Variable> specializers) implements Rule {

@Override
public Stream<Sequence> rhs() {
return specializers.stream().map(Sequence::new);
public Alternation rhs() {
return new Alternation(specializers.stream().map(Sequence::new).toList());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
package fielden.platform.bnf;

import java.util.function.Function;
import java.util.stream.Stream;

public sealed interface Symbol extends Term permits Variable, Terminal {

String name();

@Override
default Stream<Term> flatten() {
return Stream.of(this);
}

@Override
default Term recMap(Function<? super Term, ? extends Term> mapper) {
return mapper.apply(this);
}

}
10 changes: 10 additions & 0 deletions platform-eql-grammar/src/main/java/fielden/platform/bnf/Term.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package fielden.platform.bnf;

import java.util.function.Function;
import java.util.stream.Stream;

/**
* The most general grammar term.
*/
Expand All @@ -20,4 +23,11 @@ default TermMetadata metadata() {

<V> Term annotate(TermMetadata.Key<V> key, V value);

Stream<Term> flatten();

/**
* Recursive map.
*/
Term recMap(Function<? super Term, ? extends Term> mapper);

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package fielden.platform.bnf;

public record ZeroOrMore(Term term, TermMetadata metadata) implements Notation {
import java.util.function.Function;

public record ZeroOrMore(Term term, TermMetadata metadata) implements Quantifier {

public ZeroOrMore(Term term) {
this(term, TermMetadata.EMPTY_METADATA);
Expand All @@ -16,6 +18,11 @@ public ZeroOrMore normalize() {
return new ZeroOrMore(term);
}

@Override
public ZeroOrMore recMap(final Function<? super Term, ? extends Term> mapper) {
return new ZeroOrMore(term.recMap(mapper), metadata);
}

@Override
public String toString() {
return "{%s}*".formatted(term);
Expand Down

0 comments on commit 51fa045

Please sign in to comment.