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

org.jparsec.examples.java.parser.TerminalParser Maven / Gradle / Ivy

/*****************************************************************************
 * Copyright (C) jparsec.org                                                *
 * ------------------------------------------------------------------------- *
 * 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.jparsec.examples.java.parser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jparsec.Parser;
import org.jparsec.Parsers;
import org.jparsec.Scanners;
import org.jparsec.Terminals;
import org.jparsec.Token;

/**
 * Parser for terminals.
 * 
 * @author Ben Yu
 */
public final class TerminalParser {
  
  private static final Terminals TERMS = Terminals      
       // <<, >> and >>> are handled by {@link #adjacent(String)},
       // to avoid ambiguity with generics syntax.
      .operators("+", "-", "*", "/", "%", "&", "|", "~", "^",
          ">", "<", "==", ">=", "<=", "!=", "&&", "||", "!",
          ".", ",",  "?", ":", ";", "...", "@",
          "=", "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", "<<=", ">>=", ">>>=", "++", "--",
          "(", ")", "[", "]", "{", "}", "::", "->")
      .words(JavaLexer.IDENTIFIER)
      .keywords("private", "protected", "public", "final", "abstract", "native", "static",
          "transient", "volatile", "throws", "class", "interface", "enum", "package", "import",
          "if", "else", "for", "while", "do", "continue", "break", "return",
          "switch", "case", "default", "throw", "try", "catch", "finally",
          "new", "this", "super", "synchronized", "instanceof", "extends", "implements", "assert",
          "byte", "short", "int", "long", "char", "float", "double", "boolean", "char", "void",
          "true", "false", "null",
          "goto", "const", "strictfp")
      .build();
  
  // hex, oct, int, decimal, scientific, string literal, char literal and the other terms.
  // Let's not worry about unicode escape in char and string literals for now.
  // They are no fun to write and this is just a demo.
  static final Parser TOKENIZER = Parsers.or(
      JavaLexer.SCIENTIFIC_NUMBER_LITERAL,
      Terminals.StringLiteral.DOUBLE_QUOTE_TOKENIZER,
      Terminals.CharLiteral.SINGLE_QUOTE_TOKENIZER,
      TERMS.tokenizer(), JavaLexer.DECIMAL_POINT_NUMBER, JavaLexer.INTEGER);
  
  /**
   * A {@link Parser} that succeeds only if the {@link Token} objects in the {@link List} are
   * adjacent.
   */
  public static Parser adjacent(Parser> parser, final Parser otherwise) {
    return parser.next(tokens -> {
        if (tokens.isEmpty()) return Parsers.always();
        int offset = tokens.get(0).index();
        for (Token token : tokens) {
          if (token.index() != offset) {
            return otherwise;
          }
          offset += token.length();
        }
        return Parsers.always();
      }).atomic().source().token();
  }
  
  /**
   * A {@link Parser} that parses all adjacent characters in {@code operator} as individual
   * {@link Token} and only succeeds if these tokens are adjacent. A {@code Token} representing
   * the entire {@code operator} is returned.
   */
  public static Parser adjacent(String operator) {
    List> parsers = new ArrayList>(operator.length());
    for (int i = 0; i < operator.length(); i++) {
      parsers.add(TERMS.token(Character.toString(operator.charAt(i))));
    }
    return adjacent(Parsers.list(parsers), Parsers.expect(operator));
  }
  
  public static Parser term(String name) {
    if (name.equals(">>")) {
      // manually do the exclusion so that ">>>" never gets interpreted partially as ">>",
      // even if it can be interpreted as ">" followed by ">>" or three ">"s.
      return adjacent(">>>").not().next(adjacent(">>"));
    }
    if (name.equals("<<") || name.equals(">>>")) {
      return adjacent(name);
    }
    return TERMS.token(name);
  }
  
  static Parser oneOf(String... names) {
    return TERMS.token(names);
  }
  
  static  T parse(Parser parser, String source) {
    return parser.from(TOKENIZER, Scanners.JAVA_DELIMITER).parse(source);
  }
  
  static  T parse(Parser parser, Readable readable, String module) throws IOException {
    return parser.from(TOKENIZER, Scanners.JAVA_DELIMITER).parse(readable, module);
  }
  
  public static Parser phrase(String phrase) {
    return TERMS.phrase(phrase.split("\\s+"));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy