All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.projectnessie.nessie.cli.syntax.SyntaxTool Maven / Gradle / Ivy

There is a newer version: 0.101.3
Show newest version
/*
 * Copyright (C) 2024 Dremio
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.projectnessie.nessie.cli.syntax;

import static org.jline.utils.AttributedStyle.CYAN;
import static org.jline.utils.AttributedStyle.GREEN;
import static org.jline.utils.AttributedStyle.RED;
import static org.jline.utils.AttributedStyle.YELLOW;

import com.google.common.annotations.VisibleForTesting;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.congocc.core.BNFProduction;
import org.jline.utils.AttributedCharSequence;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.AttributedStyle;
import org.projectnessie.nessie.cli.grammar.Token;

/**
 * Used to generate resource files for Nessie-CLI online help and include files for the
 * projectnessie.org site.
 */
public class SyntaxTool {
  public static void main(String[] args) throws Exception {
    Path outputDir = Paths.get(args[0]);

    Files.createDirectories(outputDir);

    Map preprocessorSymbols = new HashMap<>();
    for (int i = 2; i < args.length; i++) {
      String arg = args[i];
      int eq = arg.indexOf('=');
      String k = arg.substring(0, eq);
      String v = arg.substring(eq + 1);
      preprocessorSymbols.put(k, v);
    }

    Syntax syntax = new Syntax(Paths.get(args[1]), preprocessorSymbols);

    Map styleMap = ansiStyleMap();

    for (Map.Entry productionEntry :
        syntax.getGrammar().getProductionTable().entrySet()) {
      String name = productionEntry.getKey();

      List leadingTokens = leadingTokens(name);

      String ansi = syntaxAsAnsi(leadingTokens, syntax, productionEntry.getValue(), styleMap);
      String markdown = syntaxAsMarkdown(leadingTokens, syntax, productionEntry.getValue());
      String plain = syntaxAsPlain(leadingTokens, syntax, productionEntry.getValue());
      String refs = syntaxReferences(syntax, productionEntry.getValue());

      Files.writeString(outputDir.resolve(name + ".ansi.txt"), ansi);
      Files.writeString(outputDir.resolve(name + ".plain.txt"), plain);
      Files.writeString(outputDir.resolve(name + ".md"), markdown);
      Files.writeString(outputDir.resolve(name + ".refs"), refs);
    }
  }

  @SuppressWarnings("unchecked")
  @VisibleForTesting
  static List leadingTokens(String name)
      throws ClassNotFoundException, IllegalAccessException {
    List leadingTokens = List.of();
    Class statementClass = Class.forName("org.projectnessie.nessie.cli.grammar.ast." + name);
    try {
      leadingTokens =
          (List) statementClass.getDeclaredField("LEADING_TOKENS").get(null);
    } catch (NoSuchFieldException nsf) {
      // ignore
    }
    return leadingTokens;
  }

  static Map ansiStyleMap() {
    Map styleMap = new EnumMap<>(SyntaxPrinter.Type.class);
    AttributedStyle def = AttributedStyle.DEFAULT;
    AttributedStyle bold = def.bold();
    styleMap.put(SyntaxPrinter.Type.PRE, def);
    styleMap.put(SyntaxPrinter.Type.POST, def);
    styleMap.put(SyntaxPrinter.Type.SEP, def);
    styleMap.put(SyntaxPrinter.Type.IDENTIFIER, bold.foreground(YELLOW));
    styleMap.put(SyntaxPrinter.Type.TERMINAL, bold.foreground(CYAN));
    styleMap.put(SyntaxPrinter.Type.NON_TERMINAL, bold.foreground(GREEN));
    styleMap.put(SyntaxPrinter.Type.UNKNOWN, bold.foreground(RED));
    return styleMap;
  }

  static final String MARKDOWN_ESCAPES = "\\`*_{}[]<>#+-.!";

  static String syntaxAsMarkdown(
      List leadingTokens, Syntax syntax, BNFProduction production) {
    StringBuilder sb = new StringBuilder();

    sb.append("> ");

    SyntaxPrinter printer =
        new SyntaxPrinter() {
          @Override
          public void newline(String indent) {
            sb.append("
\n ").append(indent); } @Override public void space() { sb.append(' '); } @Override public void write(Type type, String str) { String pre = ""; String post = ""; switch (type) { case PRE: case POST: case SEP: break; case IDENTIFIER: pre = "**`"; post = "`**"; break; case TERMINAL: pre = post = "`"; break; case NON_TERMINAL: pre = post = "**"; break; case UNKNOWN: break; default: break; } sb.append(pre); for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (MARKDOWN_ESCAPES.indexOf(c) != -1) { sb.append('\\'); } sb.append(c); } sb.append(post); } }; for (Token.TokenType leadingToken : leadingTokens) { printer.write(SyntaxPrinter.Type.TERMINAL, leadingToken.name()); printer.space(); } syntax.print(production, printer); return sb.toString(); } static String syntaxAsAnsi( List leadingTokens, Syntax syntax, BNFProduction production, Map styleMap) { AttributedStringBuilder sb = new AttributedStringBuilder(); SyntaxPrinter printer = new SyntaxPrinter() { @Override public void newline(String indent) { sb.append('\n').append(indent); } @Override public void space() { sb.append(' '); } @Override public void write(Type type, String str) { sb.append(str, styleMap.get(type)); } }; for (Token.TokenType leadingToken : leadingTokens) { printer.write(SyntaxPrinter.Type.TERMINAL, leadingToken.name()); printer.space(); } syntax.print(production, printer); return sb.toAnsi(256, AttributedCharSequence.ForceMode.Force256Colors); } static String syntaxAsPlain( List leadingTokens, Syntax syntax, BNFProduction production) { StringBuilder sb = new StringBuilder(); SyntaxPrinter printer = new SyntaxPrinter() { @Override public void newline(String indent) { sb.append('\n').append(indent); } @Override public void space() { sb.append(' '); } @Override public void write(Type type, String str) { sb.append(str); } }; for (Token.TokenType leadingToken : leadingTokens) { printer.write(SyntaxPrinter.Type.TERMINAL, leadingToken.name()); printer.space(); } syntax.print(production, printer); return sb.toString(); } static String syntaxReferences(Syntax syntax, BNFProduction production) { StringBuilder sb = new StringBuilder(); SyntaxPrinter printer = new SyntaxPrinter() { final Set seen = new HashSet<>(); @Override public void newline(String indent) {} @Override public void space() {} @Override public void write(Type type, String str) { if (type == Type.NON_TERMINAL) { if (seen.add(str)) { sb.append(str).append('\n'); } } } }; syntax.print(production, printer); return sb.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy