TokenizerRepeater.java

  1. /*
  2.  * Copyright (c) 2015-2020, Stein Eldar Johnsen
  3.  *
  4.  * Licensed to the Apache Software Foundation (ASF) under one
  5.  * or more contributor license agreements. See the NOTICE file
  6.  * distributed with this work for additional information
  7.  * regarding copyright ownership. The ASF licenses this file
  8.  * to you under the Apache License, Version 2.0 (the
  9.  * "License"); you may not use this file except in compliance
  10.  * with the License. You may obtain a copy of the License at
  11.  *
  12.  *   http://www.apache.org/licenses/LICENSE-2.0
  13.  *
  14.  * Unless required by applicable law or agreed to in writing,
  15.  * software distributed under the License is distributed on an
  16.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17.  * KIND, either express or implied. See the License for the
  18.  * specific language governing permissions and limitations
  19.  * under the License.
  20.  */
  21. package net.morimekta.lexer;

  22. import java.io.IOException;
  23. import java.util.ArrayDeque;
  24. import java.util.List;
  25. import java.util.Objects;
  26. import java.util.Queue;
  27. import java.util.stream.Collectors;

  28. import static java.util.Objects.requireNonNull;
  29. import static net.morimekta.strings.EscapeUtil.javaEscape;

  30. /**
  31.  * the tokenizer repeater is meant to repeat a set of tokens in the same
  32.  * sequence.
  33.  *
  34.  * @param <TT> TokenType type.
  35.  * @param <T> Token type.
  36.  */
  37. public class TokenizerRepeater<TT, T extends Token<TT>> implements Tokenizer<TT, T> {
  38.     private final Queue<T> unread;
  39.     private       T        lastToken;

  40.     /**
  41.      * @param tokens List of tokens.
  42.      */
  43.     public TokenizerRepeater(List<T> tokens) {
  44.         if (requireNonNull(tokens, "tokens == null").isEmpty()) {
  45.             throw new IllegalArgumentException("Empty token list cannot be repeated");
  46.         }

  47.         unread = new ArrayDeque<>();
  48.         unread.addAll(tokens);
  49.     }

  50.     @Override
  51.     public T parseNextToken() {
  52.         if (unread.size() > 0) {
  53.             lastToken = unread.poll();
  54.             return lastToken;
  55.         }
  56.         return null;
  57.     }

  58.     @Override
  59.     public T readUntil(CharSequence terminator, TT type, boolean allowEof) throws IOException {
  60.         if (unread.size() > 0) {
  61.             if (!Objects.equals(unread.peek().type(), type)) {
  62.                 throw new LexerException("type mismatch: " + type + " != " + lastToken.type());
  63.             }
  64.             lastToken = requireNonNull(unread.poll());
  65.             return lastToken;
  66.         }
  67.         if (allowEof) return null;
  68.         throw new LexerException(currentLine(), currentLineNo(), currentLinePos(), 1,
  69.                                  "End of stream reading until '" + terminator + "'");
  70.     }

  71.     @Override
  72.     public int currentLineNo() {
  73.         if (lastToken != null) {
  74.             return lastToken.lineNo();
  75.         }
  76.         T next = requireNonNull(unread.peek());
  77.         return next.lineNo();
  78.     }

  79.     @Override
  80.     public int currentLinePos() {
  81.         if (lastToken != null) {
  82.             return lastToken.linePos() + lastToken.length();
  83.         }
  84.         T next = requireNonNull(unread.peek());
  85.         return next.linePos();
  86.     }

  87.     @Override
  88.     public CharSequence currentLine() {
  89.         if (lastToken != null) {
  90.             return lastToken.line();
  91.         }
  92.         T next = requireNonNull(unread.peek());
  93.         return next.line();
  94.     }

  95.     @Override
  96.     public String toString() {
  97.         return getClass().getSimpleName() + "{" +
  98.                unread.stream()
  99.                      .map(TokenizerRepeater::quote)
  100.                      .collect(Collectors.joining(", ")) + "}";
  101.     }

  102.     private static String quote(Token<?> t) {
  103.         return "'" + javaEscape(t) + "'";
  104.     }
  105. }