Skip to content

Commit

Permalink
#2178 Implement translation from Fling BNF to human-readable represen…
Browse files Browse the repository at this point in the history
…tation
  • Loading branch information
homedirectory committed Feb 12, 2024
1 parent e636417 commit a18488e
Showing 1 changed file with 89 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import il.ac.technion.cs.fling.EBNF;
import il.ac.technion.cs.fling.adapters.JavaMediator;
import il.ac.technion.cs.fling.internal.grammar.rules.*;
import il.ac.technion.cs.fling.internal.grammar.types.ClassParameter;
import il.ac.technion.cs.fling.internal.grammar.types.Parameter;
import il.ac.technion.cs.fling.internal.grammar.types.StringTypeParameter;
import il.ac.technion.cs.fling.internal.grammar.types.VarargsClassParameter;
import ua.com.fielden.platform.entity.query.model.ExpressionModel;
import ua.com.fielden.platform.entity.query.model.PrimitiveResultQueryModel;
import ua.com.fielden.platform.processors.metamodel.IConvertableToPath;
Expand All @@ -13,13 +17,18 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static fielden.platform.eql.fling.EqlGrammar.V.*;
import static fielden.platform.eql.fling.EqlGrammar.Σ.*;
import static il.ac.technion.cs.fling.grammars.api.BNFAPI.bnf;
import static il.ac.technion.cs.fling.internal.grammar.rules.Quantifiers.noneOrMore;
import static il.ac.technion.cs.fling.internal.grammar.rules.Quantifiers.optional;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.joining;

public class EqlGrammar {

Expand Down Expand Up @@ -178,16 +187,27 @@ public enum V implements Variable {

private static final String API_CLASS_NAME = "Eql";

// Program arguments: package [dir]
// Program arguments: Command
// Command = Generate | PrintBnf
// Generate = 'generate' package dir?
// PrintBnf = 'print-bnf'
//
// package -- package name for generated sources
// dir -- output directory for generated sources that will contain the package;
// if omitted, then generated sources are printed to stdout
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.println("usage: EqlGrammar.java package [dir]");
System.err.println("usage: EqlGrammar.java command");
System.exit(1);
}

if ("generate".equals(args[0]))
generate(Arrays.copyOfRange(args, 1, args.length));
else if ("print-bnf".equals(args[0]))
printBNF();
}

private static void generate(final String[] args) throws Exception {
String pkgName = args[0];
Path outDirPath = args.length < 2 ? null : Path.of(args[1], pkgName.replace('.', '/'));

Expand All @@ -196,6 +216,7 @@ public static void main(String[] args) throws Exception {
pkgName,
API_CLASS_NAME,
Σ.class // language terminals enum
// new WiseNamer(pkgName, API_CLASS_NAME)
);

Map<String, String> classes = Map.of(
Expand All @@ -213,8 +234,8 @@ public static void main(String[] args) throws Exception {
}

// google-java-formatter will abort without useful messages if generated sources don't compile
Formatter formatter = new Formatter();
// Formatter formatter = null;
// Formatter formatter = new Formatter();
Formatter formatter = null;
for (var entry : classes.entrySet()) {
String name = entry.getKey();
String code = formatSource(entry.getValue(), formatter);
Expand All @@ -233,8 +254,72 @@ public static void main(String[] args) throws Exception {
}
}

public static void printBNF() {
System.out.println(toString(bnf));
}

private static String formatSource(String s, @Nullable Formatter formatter) throws FormatterException {
return formatter != null ? formatter.formatSource(s) : s;
}

private static String toString(EBNF ebnf) {
return ebnf.rules()
.collect(groupingBy(rule -> rule.variable, LinkedHashMap::new, Collectors.toList()))
.entrySet().stream()
.map(entry -> {
var variable = entry.getKey();
var rules = entry.getValue();
return new ERule(variable, rules.stream().flatMap(ERule::bodies).toList());
})
.map(EqlGrammar::toString).collect(joining("\n"));
}

private static String toString(ERule eRule) {
return eRule.bodies()
.map(EqlGrammar::toString)
.collect(joining(" | ", "%s = ".formatted(eRule.variable), ";"));
}

private static String toString(final Body body) {
return body.stream().map(EqlGrammar::toString).collect(joining(" "));
}

private static String toString(Component component) {
return component.isToken() ? toString(component.asToken())
: component.isQuantifier() ? toString(component.asQuantifier())
: (component.isVariable() || component.isTerminal()) ? component.name()
: fail("Unrecognised rule component: %s", component);
}

private static String toString(Token token) {
return !token.isParameterized() ? token.name()
: token.name() + token.parameters().map(EqlGrammar::toString).collect(joining(", ", "(", ")"));
}

private static String toString(Parameter parameter) {
return parameter.isStringTypeParameter() ? toString(parameter.asStringTypeParameter())
: parameter.isVariableTypeParameter() ? parameter.asVariableTypeParameter().variable.name()
: parameter.isVarargsTypeParameter() ? "{ %s }*".formatted(parameter.asVarargsVariableTypeParameter().variable.name())
: fail("Unrecognised token parameter: %s", parameter);
}

private static String toString(StringTypeParameter parameter) {
String s = "<%s>".formatted(parameter instanceof ClassParameter cp ? cp.parameterClass.getSimpleName()
: parameter instanceof VarargsClassParameter vcp ? vcp.parameterClass.getSimpleName()
: fail("Unrecognised token parameter: %s", parameter));
return parameter instanceof VarargsClassParameter ? s + "*" : s;
}

private static String toString(Quantifier quantifier) {
var symbols = quantifier.symbols().map(EqlGrammar::toString);
return quantifier instanceof NoneOrMore ? symbols.collect(joining(" ", "{ ", " }*"))
: quantifier instanceof OneOrMore ? symbols.collect(joining(" ", "{ ", " }+"))
: quantifier instanceof Opt ? symbols.collect(joining(" ", "{ ", " }?"))
: fail("Unrecognised quantifier: %s", quantifier);
}

private static <T> T fail(String formatString, Object... args) {
throw new RuntimeException(String.format(formatString, args));
}

}

0 comments on commit a18488e

Please sign in to comment.