/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.felix.gogo.runtime; public class BaseTokenizer { protected static final char EOT = (char) -1; protected final Token text; protected short line; protected short column; protected char ch; protected int index; public BaseTokenizer(CharSequence text) { this.text = text instanceof Token ? (Token) text : new Token(text); getch(); } public Token text() { return text; } protected void find(char target, char deeper) { final short sLine = line; final short sCol = column; int level = 1; while (level != 0) { if (eot()) { throw new EOFError(sLine, sCol, "unexpected eof found in the middle of a compound for '" + deeper + target + "'", "compound", Character.toString(target)); // TODO: fill context correctly } getch(); if (ch == '\\') { escape(); continue; } if (ch == target) { level--; } else { if (ch == deeper) { level++; } else { if (ch == '"' || ch == '\'' || ch == '`') { skipQuote(); } } } } } protected char escape() { assert '\\' == ch; final short sLine = line; final short sCol = column; switch (getch()) { case 'u': getch(); int nb = 0; for (int i = 0; i < 4; i++) { char ch = Character.toUpperCase(this.ch); if (ch >= '0' && ch <= '9') { nb = nb * 16 + (ch - '0'); getch(); continue; } if (ch >= 'A' && ch <= 'F') { nb = nb * 16 + (ch - 'A' + 10); getch(); continue; } if (ch == 0) { throw new EOFError(sLine, sCol, "unexpected EOT in \\ escape", "escape", "0"); } else { throw new SyntaxError(sLine, sCol, "bad unicode", text); } } index--; return (char) nb; case EOT: throw new EOFError(sLine, sCol, "unexpected EOT in \\ escape", "escape", " "); case '\n': return '\0'; // line continuation case '\\': case '\'': case '"': case '$': return ch; default: return ch; } } protected void skipQuote() { assert '\'' == ch || '"' == ch; final char quote = ch; final short sLine = line; final short sCol = column; while (getch() != EOT) { if (quote == ch) { return; } if ((quote == '"') && ('\\' == ch)) escape(); } throw new EOFError(sLine, sCol, "unexpected EOT looking for matching quote: " + quote, quote == '"' ? "dquote" : "quote", Character.toString(quote)); } protected void skipSpace() { skipSpace(false); } @SuppressWarnings("StatementWithEmptyBody") protected void skipSpace(boolean skipNewLines) { while (true) { while (isBlank(ch)) { getch(); } // skip continuation lines, but not other escapes if (('\\' == ch) && (peek() == '\n')) { getch(); getch(); continue; } if (skipNewLines && ('\n' == ch)) { getch(); continue; } if (skipNewLines && ('\r' == ch) && (peek() == '\n')) { getch(); getch(); continue; } // skip comments if (('/' == ch) || ('#' == ch)) { if (('#' == ch) || (peek() == '/')) { while ((getch() != EOT) && ('\n' != ch)) { } continue; } else if ('*' == peek()) { short sLine = line; short sCol = column; getch(); while ((getch() != EOT) && !(('*' == ch) && (peek() == '/'))) { } if (EOT == ch) { throw new EOFError(sLine, sCol, "unexpected EOT looking for closing comment: */", "comment", "*/"); } getch(); getch(); continue; } } break; } } protected boolean isBlank(char ch) { return ' ' == ch || '\t' == ch; } protected boolean eot() { return index >= text.length(); } protected char getch() { return ch = getch(false); } protected char peek() { return getch(true); } protected char getch(boolean peek) { if (eot()) { if (!peek) { ++index; ch = EOT; } return EOT; } int current = index; char c = text.charAt(index++); // if (('\r' == c) && !eot() && (text.charAt(index) == '\n')) // c = text.charAt(index++); if (peek) { index = current; } else if ('\n' == c) { ++line; column = 0; } else ++column; return c; } }