/*******************************************************************************
* Copyright (c) 2015 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.utils.parse;
public class LexingUtils {
/**
* Consume until given delimiter char is found (also included).
*/
public static <E extends Exception> String consumeUntilDelimiterOrEOS(IBasicCharSource<E> reader,
char delimiter) throws E {
return consumeUntilDelimiterOrEOS(reader, delimiter, delimiter);
}
/**
* Consume until given delimiter char is found (also included).
* Given escapeChar can escape itself, and delimiter
*/
public static <E extends Exception> String consumeUntilDelimiterOrEOS(IBasicCharSource<E> reader,
char delimiter, char escapeChar) throws E {
StringBuilder sb = new StringBuilder();
consumeUntilDelimiter_intoStringBuilder(reader, delimiter, escapeChar, sb);
return sb.toString();
}
public static <E extends Exception> boolean consumeUntilDelimiter_intoStringBuilder(IBasicCharSource<E> reader,
char delimiter, char escapeChar,
StringBuilder sb) throws E {
while(reader.hasCharAhead()) {
char consumedChar = reader.nextChar();
if(consumedChar == delimiter) {
return false;
}
else if(consumedChar == escapeChar && reader.hasCharAhead()) {
char secondChar = reader.lookaheadChar();
if(secondChar == delimiter || secondChar == escapeChar) {
reader.nextChar();
sb.append(secondChar);
continue;
}
}
sb.append(consumedChar);
}
return true;
}
public static <E extends Exception> void advanceDelimitedString(ICharSource<E> reader,
char delimiter, char escapeChar) throws E {
while(reader.hasCharAhead()) {
char consumedChar = reader.nextChar();
if(consumedChar == delimiter) {
break;
}
else if(consumedChar == escapeChar) {
reader.consumeAny(); // consumed escaped char
}
}
}
/* ----------------- whitespace ----------------- */
public static <E extends Exception> int skipWhitespace(IBasicCharSource<E> reader) throws E {
int count = 0;
while(Character.isWhitespace(reader.lookahead())) {
reader.consume();
count++;
}
return count;
}
public static <E extends Exception> int countWhitespace(ICharSource<E> reader) throws E {
int count = 0;
while(Character.isWhitespace(reader.lookahead(count))) {
count++;
}
return count;
}
public static <E extends Exception> int skipWhitespaceExceptNL(IBasicCharSource<E> reader) throws E {
int count = 0;
while(Character.isWhitespace(reader.lookahead())) {
if(reader.lookahead() == '\n' || reader.lookahead() == '\r') {
break;
}
reader.consume();
count++;
}
return count;
}
/* ----------------- Identifier helpers ----------------- */
public static <E extends Exception> String tryConsumeJavaIdentifier(ICharSource<E> reader) throws E {
int length = matchJavaIdentifier(reader);
if(length == 0) {
return null;
}
return reader.consumeString(length);
}
/**
* @return length of token matching a Java identifier. Zero if nothing matches
*/
public static <E extends Exception> int matchJavaIdentifier(ICharSource<E> reader) throws E {
int length = 0;
int la = reader.lookahead(length);
if(la == -1 || !Character.isJavaIdentifierStart(la)) {
return length;
}
length++;
while(true) {
la = reader.lookahead(length);
if(la == -1 || !Character.isJavaIdentifierPart(la)) {
break;
}
length++;
}
return length;
}
public static <E extends Exception> String readJavaIdentifier(ICharSource<E> reader) throws E {
int length = matchJavaIdentifier(reader);
return reader.consumeString(length);
}
/* ----------------- Line helpers ----------------- */
public static <E extends Exception> String determineNewlineSequenceAt(ICharSource<E> reader,
int offset) throws E {
int la = reader.lookahead(offset);
if(la == -1) {
return "";
}
if(la == '\n') {
return "\n";
}
if(la == '\r') {
if(reader.lookahead(offset + 1) == '\n') {
return "\r\n";
}
return "\r";
}
return null;
}
public static <E extends Exception> String stringUntilNewline(ICharSource<E> reader) throws E {
return stringUntilNewline(reader, 0);
}
public static <E extends Exception> String stringUntilNewline(ICharSource<E> reader, int offset) throws E {
int endPos = offset;
while(true) {
if(determineNewlineSequenceAt(reader, endPos) != null) {
break;
}
endPos++;
}
return reader.lookaheadString(offset, endPos - offset);
}
public static <E extends Exception> String consumeLine(ICharSource<E> reader) throws E {
int offset = 0;
if(reader.lookaheadIsEOS()) {
return null;
}
String line = stringUntilNewline(reader, offset);
reader.consumeAhead(line);
reader.consumeAhead(determineNewlineSequenceAt(reader, offset));
return line;
}
}