diff a/test/lib/org/openjdk/asmtools/jasm/Environment.java b/test/lib/org/openjdk/asmtools/jasm/Environment.java --- /dev/null +++ b/test/lib/org/openjdk/asmtools/jasm/Environment.java @@ -0,0 +1,454 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.asmtools.jasm; + +import static org.openjdk.asmtools.jasm.Constants.EOF; +import static org.openjdk.asmtools.jasm.Constants.OFFSETBITS; +import org.openjdk.asmtools.util.I18NResourceBundle; + +import java.io.*; +import java.nio.file.Paths; +import java.text.MessageFormat; + +/** + * An input stream for java programs. The stream treats either "\n", "\r" or "\r\n" as the + * end of a line, it always returns \n. It also parses UNICODE characters expressed as + * \uffff. However, if it sees "\\", the second slash cannot begin a unicode sequence. It + * keeps track of the current position in the input stream. + * + * An position consists of: ((linenr << OFFSETBITS) | offset) this means that both + * the line number and the exact offset into the file are encoded in each position + * value.
+ */ +public class Environment { + + /*-------------------------------------------------------- */ + /* Environment Inner Classes */ + /** + * A sorted list of error messages + */ + final class ErrorMessage { + + int where; + String message; + ErrorMessage next; + + /** + * Constructor + */ + ErrorMessage(int where, String message) { + this.where = where; + this.message = message; + } + } + + /*-------------------------------------------------------- */ + /* Environment Fields */ + static boolean traceFlag = false; + boolean debugInfoFlag = false; + + private String inputFileName; + private String simpleInputFileName; + public PrintWriter out; + private boolean nowarn; + private byte[] data; + private int bytepos; + private int linepos; + public int pos; + /*-------------------------------------------------------- */ + + public Environment(DataInputStream dis, String inputFileName, PrintWriter out, boolean nowarn) throws IOException { + this.out = out; + this.inputFileName = inputFileName; + this.nowarn = nowarn; + // Read the file + data = new byte[dis.available()]; + dis.read(data); + dis.close(); + bytepos = 0; + linepos = 1; + } + + public String getInputFileName() { + return inputFileName; + } + + public String getSimpleInputFileName() { + if( simpleInputFileName == null ) { + simpleInputFileName = Paths.get(inputFileName).getFileName().toString(); + } + return simpleInputFileName; + } + + int lookForward() { + try { + return data[bytepos]; + } catch (ArrayIndexOutOfBoundsException e) { + return EOF; + } + } + + int convertUnicode() { + int c; + try { + while ((c = data[bytepos]) == 'u') { + bytepos++; + } + int d = 0; + for (int i = 0; i < 4; i++) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + d = (d << 4) + c - '0'; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + d = (d << 4) + 10 + c - 'a'; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + d = (d << 4) + 10 + c - 'A'; + break; + default: + error(pos, "invalid.escape.char"); + return d; + } + ++bytepos; + c = data[bytepos]; + } + return d; + } catch (ArrayIndexOutOfBoundsException e) { + error(pos, "invalid.escape.char"); + return EOF; + } + } + + public int read() { + int c; + pos = (linepos << OFFSETBITS) | bytepos; + try { + c = data[bytepos]; + } catch (ArrayIndexOutOfBoundsException e) { + return EOF; + } + bytepos++; + + // parse special characters + switch (c) { + /* case '\\': + if (lookForward() != 'u') { + return '\\'; + } + // we have a unicode sequence + return convertUnicode();*/ + case '\n': + linepos++; + return '\n'; + + case '\r': + if (lookForward() == '\n') { + bytepos++; + } + linepos++; + return '\n'; + + default: + return c; + } + } + + int lineNumber(int lcpos) { + return lcpos >>> OFFSETBITS; + } + + int lineNumber() { + return lineNumber(pos); + } + + int lineOffset(int lcpos) { + return lcpos & ((1 << OFFSETBITS) - 1); + } + + int lineOffset() { + return lineOffset(pos); + } + + /*============================================================== Environment */ + /** + * The number of errors and warnings + */ + public int nerrors; + public int nwarnings; + public static final I18NResourceBundle i18n + = I18NResourceBundle.getBundleForClass(Main.class); + + /** + * Error String + */ + String errorString(String err, Object arg1, Object arg2, Object arg3) { + String str = null; + + //str = getProperty(err); + str = i18n.getString(err); + if (str == null) { + return "error message '" + err + "' not found"; + } + + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if ((c == '%') && (i + 1 < str.length())) { + switch (str.charAt(++i)) { + case 's': + String arg = arg1.toString(); + for (int j = 0; j < arg.length(); j++) { + switch (c = arg.charAt(j)) { + case ' ': + case '\t': + case '\n': + case '\r': + buf.append((char) c); + break; + + default: + if ((c > ' ') && (c <= 255)) { + buf.append((char) c); + } else { + buf.append('\\'); + buf.append('u'); + buf.append(Integer.toString(c, 16)); + } + } + } + arg1 = arg2; + arg2 = arg3; + break; + + case '%': + buf.append('%'); + break; + + default: + buf.append('?'); + break; + } + } else { + buf.append((char) c); + } + } + // KTL + // Need to do message format to substitute args + String msg = buf.toString(); + MessageFormat form = new MessageFormat(msg); + Object args[] = {arg1, arg2, arg3}; + msg = form.format(args); + + return msg; + + } + + /** + * List of outstanding error messages + */ + ErrorMessage errors; + + /** + * Insert an error message in the list of outstanding error messages. The list is + * sorted on input position. + */ + void insertError(int where, String message) { + //output("ERR = " + message); + ErrorMessage msg = new ErrorMessage(where, message); + if (errors == null) { + errors = msg; + } else if (errors.where > where) { + msg.next = errors; + errors = msg; + } else { + ErrorMessage m = errors; + for (; (m.next != null) && (m.next.where <= where); m = m.next); + msg.next = m.next; + m.next = msg; + } + } + + /** + * Flush outstanding errors + */ + public void flushErrors() { + if (errors == null) { + traceln("flushErrors: errors == null"); + return; + } + + // Report the errors + for (ErrorMessage msg = errors; msg != null; msg = msg.next) { + int off = lineOffset(msg.where); + + int i, j; + for (i = off; (i > 0) && (data[i - 1] != '\n') && (data[i - 1] != '\r'); i--); + for (j = off; (j < data.length) && (data[j] != '\n') && (data[j] != '\r'); j++); + + outputln( String.format( "%s (%d:%d) %s", getSimpleInputFileName(), lineNumber(msg.where), off - i, msg.message)); + outputln(new String(data, i, j - i)); + + char strdata[] = new char[(off - i) + 1]; + for (j = i; j < off; j++) { + strdata[j - i] = (data[j] == '\t') ? '\t' : ' '; + } + strdata[off - i] = '^'; + outputln(new String(strdata)); + } + errors = null; + } + + /** + * Output a string. This can either be an error message or something for debugging. + * This should be used instead of print. + */ + public void output(String msg) { + int len = msg.length(); + for (int i = 0; i < len; i++) { + out.write(msg.charAt(i)); + } + out.flush(); + } + + /** + * Output a string. This can either be an error message or something for debugging. + * This should be used instead of println. + */ + public void outputln(String msg) { + output((msg == null ? "" : msg) + "\n"); + } + + /** + * Issue an error. source - the input source, usually a file name string offset - the + * offset in the source of the error err - the error number (as defined in this + * interface) arg1 - an optional argument to the error (null if not applicable) arg2 - + * a second optional argument to the error (null if not applicable) arg3 - a third + * optional argument to the error (null if not applicable) + */ + /** + * Issue an error + */ + public void error(int where, String err, Object arg1, Object arg2, Object arg3) { + String msg; + if (err.startsWith("warn.")) { + if (nowarn) { + return; + } + nwarnings++; + msg = "Warning: "; + } else { + err = "err." + err; + nerrors++; + msg = "Error: "; + } + msg = msg + errorString(err, arg1, arg2, arg3); + traceln(msg); + insertError(where, msg); + } + + public final void error(int where, String err, Object arg1, Object arg2) { + error(where, err, arg1, arg2, null); + } + + public final void error(int where, String err, Object arg1) { + error(where, err, arg1, null, null); + } + + public final void error(int where, String err) { + error(where, err, null, null, null); + } + + public final void error(String err, Object arg1, Object arg2, Object arg3) { + error(pos, err, arg1, arg2, arg3); + } + + public final void error(String err, Object arg1, Object arg2) { + error(pos, err, arg1, arg2, null); + } + + public final void error(String err, Object arg1) { + error(pos, err, arg1, null, null); + } + + public final void error(String err) { + error(pos, err, null, null, null); + } + + public final String errorStr(String err, Object arg1, Object arg2, Object arg3) { + return errorString(err, arg1, arg2, arg3); + } + + public final String errorStr(String err, Object arg1, Object arg2) { + return errorStr(err, arg1, arg2, null); + } + + public final String errorStr(String err, Object arg1) { + return errorStr(err, arg1, null, null); + } + + public final String errorStr(String err) { + return errorStr(err, null, null, null); + } + + /*============================================================== trace */ + public boolean isTraceEnabled() { + return traceFlag; + } + + public boolean isDebugEnabled() { + return debugInfoFlag; + } + + void trace(String message) { + if (traceFlag) { + output(message); + } + } + + void traceln(String message) { + if (traceFlag) { + outputln(message); + } + } + +} // end Environment