/* * Copyright (c) 2017, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.oracle.truffle.nfi.types; final class Lexer { public enum Token { OPENPAREN("("), CLOSEPAREN(")"), OPENBRACKET("["), CLOSEBRACKET("]"), COLON(":"), COMMA(","), OR("|"), ELLIPSIS("..."), IDENTIFIER("identifier"), STRING("string"), INVALID(null), EOF("EOF"); private final String name; Token(String name) { this.name = name; } public String getName() { return name; } } private final CharSequence source; private int position; private int curTokenStart; private int curTokenEnd; private Token nextToken; private int nextTokenStart; Lexer(CharSequence source) { this.source = source; this.position = 0; lex(); } public Token next() { Token curToken = nextToken; lex(); return curToken; } public Token peek() { return nextToken; } public String currentValue() { if (curTokenEnd > source.length()) { return "<EOF>"; } else { return source.subSequence(curTokenStart, curTokenEnd).toString(); } } private boolean atEnd() { return position >= source.length(); } private char ch() { if (atEnd()) { return 0; } else { return source.charAt(position); } } private void lex() { curTokenStart = nextTokenStart; curTokenEnd = position; if (nextToken == Token.STRING) { // cut off string delimiters curTokenStart++; curTokenEnd--; } while (Character.isWhitespace(ch())) { position++; } nextTokenStart = position; nextToken = getNextToken(); } private static boolean isIdentStartChar(char c) { return Character.isAlphabetic(c) || c == '/' || c == '_'; } private static boolean isIdentChar(char c) { // @formatter:off return Character.isAlphabetic(c) || Character.isDigit(c) || c == '/' || c == '.' // for filenames || c == '_'; // @formatter:on } private Token getNextToken() { if (isIdentStartChar(ch())) { do { position++; } while (isIdentChar(ch())); return Token.IDENTIFIER; } else { char c = ch(); position++; switch (c) { case 0: return Token.EOF; case '(': return Token.OPENPAREN; case ')': return Token.CLOSEPAREN; case '[': return Token.OPENBRACKET; case ']': return Token.CLOSEBRACKET; case ':': return Token.COLON; case ',': return Token.COMMA; case '|': return Token.OR; case '.': if (ch() == '.') { position++; if (ch() == '.') { position++; return Token.ELLIPSIS; } } return Token.INVALID; case '"': case '\'': while (!atEnd()) { if (ch() == c) { position++; return Token.STRING; } position++; } return Token.INVALID; default: return Token.INVALID; } } } }