/******************************************************************************* * 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; } }