001/*
002 * Units of Measurement Reference Implementation
003 * Copyright (c) 2005-2025, Jean-Marie Dautelle, Werner Keil, Otavio Santana.
004 *
005 * All rights reserved.
006 *
007 * Redistribution and use in source and binary forms, with or without modification,
008 * are permitted provided that the following conditions are met:
009 *
010 * 1. Redistributions of source code must retain the above copyright notice,
011 *    this list of conditions and the following disclaimer.
012 *
013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
014 *    and the following disclaimer in the documentation and/or other materials provided with the distribution.
015 *
016 * 3. Neither the name of JSR-385, Indriya nor the names of their contributors may be used to endorse or promote products
017 *    derived from this software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package tech.units.indriya.format;
031
032import javax.measure.format.MeasurementParseException;
033
034/**
035 * This exception is thrown when token errors are encountered. You can explicitly create objects of this exception type by calling the method
036 * raiseTokenException in the generated parser.
037 *
038 * You can modify this class to customize your error reporting mechanisms so long as you retain the public fields.
039 * 
040 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
041 * @author <a href="mailto:werner@units.tech">Werner Keil</a>
042 * @version 1.1, Sep 29, 2020
043 */
044public class TokenException extends MeasurementParseException {
045  /**
046   * The Serialization identifier for this class. Increment only if the <i>serialized</i> form of the class changes.
047   */
048  private static final long serialVersionUID = 2932151235799168061L;
049
050  /**
051   * This is the last token that has been consumed successfully. If this object has been created due to a parse error, the token following this token
052   * will (therefore) be the first error token.
053   */
054  public Token currentToken;
055
056  /**
057   * Each entry in this array is an array of integers. Each array of integers represents a sequence of tokens (by their ordinal values) that is
058   * expected at this point of the parse.
059   */
060  @SuppressWarnings("unused")
061  private int[][] expectedTokenSequences;
062
063  /**
064   * This is a reference to the "tokenImage" array of the generated parser within which the parse error occurred. This array is defined in the
065   * generated ...Constants interface.
066   */
067  @SuppressWarnings("unused")
068  private String[] tokenImage;
069  
070  /**
071   * This constructor is used by the method "raiseTokenException" in the generated parser. Calling this constructor generates a new object of this
072   * type with the fields "currentToken", "expectedTokenSequences", and "tokenImage" set.
073   */
074  public TokenException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal) {
075    super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
076    currentToken = currentTokenVal;
077    expectedTokenSequences = expectedTokenSequencesVal;
078    tokenImage = tokenImageVal;
079  }
080
081  /**
082   * The following constructors are for use by you for whatever purpose you can think of. Constructing the exception in this manner makes the
083   * exception behave in the normal way - i.e., as documented in the class "Throwable". The fields "errorToken", "expectedTokenSequences", and
084   * "tokenImage" do not contain relevant information. The JavaCC generated code does not use these constructors.
085   */
086
087  public TokenException() {
088    super("");
089  }
090
091  /** Constructor with message. */
092  public TokenException(String message) {
093    super(message);
094  }
095
096  public Token getToken() {
097        return currentToken;
098  }
099  
100  /**
101   * It uses "currentToken" and "expectedTokenSequences" to generate a parse error message and returns it. If this object has been created due to a
102   * parse error, and you do not catch it (it gets thrown from the parser) the correct error message gets displayed.
103   */
104  private static String initialise(Token currentToken, int[][] expectedTokenSequences, String[] tokenImage) {
105    String eol = System.getProperty("line.separator", "\n");
106    StringBuilder expected = new StringBuilder();
107    int maxSize = 0;
108    for (int[] expectedTokenSequence : expectedTokenSequences) {
109      if (maxSize < expectedTokenSequence.length) {
110        maxSize = expectedTokenSequence.length;
111      }
112      for (int anExpectedTokenSequence : expectedTokenSequence) {
113        expected.append(tokenImage[anExpectedTokenSequence]).append(' ');
114      }
115      if (expectedTokenSequence[expectedTokenSequence.length - 1] != 0) {
116        expected.append("...");
117      }
118      expected.append(eol).append("    ");
119    }
120    String retval = "Encountered \"";
121    Token tok = currentToken.next;
122    for (int i = 0; i < maxSize; i++) {
123      if (i != 0)
124        retval += " ";
125      if (tok.kind == 0) {
126        retval += tokenImage[0];
127        break;
128      }
129      retval += " " + tokenImage[tok.kind];
130      retval += " \"";
131      retval += add_escapes(tok.image);
132      retval += " \"";
133      tok = tok.next;
134    }
135    retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
136    retval += "." + eol;
137    if (expectedTokenSequences.length == 1) {
138      retval += "Was expecting:" + eol + "    ";
139    } else {
140      retval += "Was expecting one of:" + eol + "    ";
141    }
142    retval += expected.toString();
143    return retval;
144  }
145
146  /**
147   * The end of line string for this machine.
148   */
149  protected String eol = System.getProperty("line.separator", "\n");
150
151  /**
152   * Used to convert raw characters to their escaped version when these raw version cannot be used as part of an ASCII string literal.
153   */
154  private static String add_escapes(String str) {
155    StringBuilder retval = new StringBuilder();
156    char ch;
157    for (int i = 0; i < str.length(); i++) {
158      switch (str.charAt(i)) {
159        case 0:
160          continue;
161        case '\b':
162          retval.append("\\b");
163          continue;
164        case '\t':
165          retval.append("\\t");
166          continue;
167        case '\n':
168          retval.append("\\n");
169          continue;
170        case '\f':
171          retval.append("\\f");
172          continue;
173        case '\r':
174          retval.append("\\r");
175          continue;
176        case '\"':
177          retval.append("\\\"");
178          continue;
179        case '\'':
180          retval.append("\\\'");
181          continue;
182        case '\\':
183          retval.append("\\\\");
184          continue;
185        default:
186          if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
187            String s = "0000" + Integer.toString(ch, 16);
188            retval.append("\\u").append(s.substring(s.length() - 4, s.length()));
189          } else {
190            retval.append(ch);
191          }
192      }
193    }
194    return retval.toString();
195  }
196
197}
198/*
199 * JavaCC - OriginalChecksum=c67b0f8ee6c642900399352b33f90efd (do not edit this
200 * line)
201 */