![JAR search and dependency download from the Maven repository](/logo.png)
org.vesalainen.parser.util.Input Maven / Gradle / Ivy
Show all versions of lpg Show documentation
/*
* Copyright (C) 2014 Timo Vesalainen
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.vesalainen.parser.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackReader;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.Buffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Deque;
import java.util.EnumSet;
import java.util.zip.Checksum;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
import org.vesalainen.bcc.model.El;
import org.vesalainen.bcc.model.Typ;
import org.vesalainen.grammar.GTerminal;
import org.vesalainen.io.Pushbackable;
import org.vesalainen.io.Rewindable;
import org.vesalainen.lang.Primitives;
import org.vesalainen.nio.channels.ReadableByteChannelFactory;
import org.vesalainen.parser.ParserConstants;
import org.vesalainen.parser.ParserFeature;
import static org.vesalainen.parser.ParserFeature.*;
import org.vesalainen.parser.annotation.ParserContext;
import org.vesalainen.regex.Range;
import org.vesalainen.regex.SyntaxErrorException;
import org.xml.sax.InputSource;
/**
* A base class for parser input
*
* @author Timo Vesalainen
* @param Input type. Reader, InputStream, String,...
* @param
*/
public abstract class Input implements InputReader
{
private static final int BufferSize = 8192;
private static long FileLengthLimit = 100000;
protected B buffer1;
protected B buffer2;
protected B[] array1; // 1 length buffer
protected B[] array2; // 2 length buffer
protected int size; // size of ring buffer (=buffer.length)
protected int end; // position of last actual read char
protected int cursor; // position of current input
protected IncludeLevel includeLevel = new IncludeLevel();
protected Deque includeStack;
protected int length; // length of current input
protected int findSkip; // number of characters the find can skip after unsucces
protected int findMark = -1; // position where find could have last accessed the string
protected int waterMark = 0; // lowest position where buffer can be reused
protected EnumSet features;
protected Checksum checksum;
protected abstract int get(int index);
protected abstract void set(int index, int value);
protected abstract int fill(I input, B[] array) throws IOException;
protected abstract void unread(I input) throws IOException;
protected abstract void close(I input) throws IOException;
/**
* Makes room in buffer for insert.
* @param ln
*/
protected abstract void makeRoom(int ln);
protected Input(EnumSet features)
{
this.features = features;
}
public static InputReader getInstance(URI uri, int size, Charset cs, EnumSet features) throws FileNotFoundException, IOException
{
return getInstance(ReadableByteChannelFactory.getInstance(uri), size, cs, features);
}
public static InputReader getInstance(URI uri, int size, String cs, EnumSet features) throws FileNotFoundException, IOException
{
return getInstance(ReadableByteChannelFactory.getInstance(uri), size, Charset.forName(cs), features);
}
public static InputReader getInstance(URL url, int size, String cs, EnumSet features) throws FileNotFoundException, IOException
{
return getInstance(ReadableByteChannelFactory.getInstance(url), size, Charset.forName(cs), features);
}
public static InputReader getInstance(URL url, int size, Charset cs, EnumSet features) throws FileNotFoundException, IOException
{
return getInstance(ReadableByteChannelFactory.getInstance(url), size, cs, features);
}
/**
* Creates an InputReader
* @param file
* @param size
* @return
* @throws FileNotFoundException
*/
public static InputReader getInstance(File file, int size) throws IOException
{
return getInstance(file, size, Charset.defaultCharset(), EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
* @param file
* @param size
* @param features
* @return
* @throws FileNotFoundException
*/
public static InputReader getInstance(File file, int size, EnumSet features) throws IOException
{
return getInstance(file, size, Charset.defaultCharset(), features);
}
/**
* Creates an InputReader
* @param file
* @param size
* @param cs
* @return
* @throws FileNotFoundException
*/
public static InputReader getInstance(File file, int size, String cs) throws IOException
{
return getInstance(file, size, Charset.forName(cs), EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
* @param file
* @param size
* @param cs
* @param features
* @return
* @throws FileNotFoundException
*/
public static InputReader getInstance(File file, int size, String cs, EnumSet features) throws IOException
{
return getInstance(file, size, Charset.forName(cs), features);
}
/**
* Creates an InputReader
* @param file
* @param size
* @param cs
* @return
* @throws FileNotFoundException
*/
public static InputReader getInstance(File file, int size, Charset cs) throws IOException
{
return getInstance(file, size, cs, EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
* @param file
* @param size
* @param cs
* @param features
* @return
* @throws FileNotFoundException
*/
public static InputReader getInstance(File file, int size, Charset cs, EnumSet features) throws IOException
{
return getInstance(ReadableByteChannelFactory.getInstance(file), size, cs, features);
}
/**
* Creates an InputReader
* @param is
* @param size
* @return
* @throws java.io.IOException
*/
public static InputReader getInstance(InputStream is, int size) throws IOException
{
return getInstance(Channels.newChannel(is), size, Charset.defaultCharset(), EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader with default charset
* @param is
* @param size size of inner ring buffer
* @param features EnumSet
* @return
* @throws java.io.IOException
* @see org.vesalainen.parser.ParserFeature
* @see org.vesalainen.util.EnumSetFlagger
*/
public static InputReader getInstance(InputStream is, int size, EnumSet features) throws IOException
{
return getInstance(Channels.newChannel(is), size, Charset.defaultCharset(), features);
}
/**
* Creates an InputReader
* @param is
* @param size
* @param cs
* @return
* @throws java.io.IOException
*/
public static InputReader getInstance(InputStream is, int size, String cs) throws IOException
{
return getInstance(Channels.newChannel(is), size, Charset.forName(cs), EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
* @param is
* @param size size of inner ring buffer
* @param cs Character set
* @param features EnumSet
* @return
* @throws java.io.IOException
* @see org.vesalainen.parser.ParserFeature
* @see org.vesalainen.util.EnumSetFlagger
*/
public static InputReader getInstance(InputStream is, int size, String cs, EnumSet features) throws IOException
{
return getInstance(Channels.newChannel(is), size, Charset.forName(cs), features);
}
/**
* Creates an InputReader
* @param is
* @param size
* @param cs
* @return
* @throws java.io.IOException
*/
public static InputReader getInstance(InputStream is, int size, Charset cs) throws IOException
{
return getInstance(Channels.newChannel(is), size, cs, EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
* @param is
* @param size
* @param cs
* @param features EnumSet
* @return
* @throws java.io.IOException
* @see org.vesalainen.parser.ParserFeature
* @see org.vesalainen.util.EnumSetFlagger
*/
public static InputReader getInstance(InputStream is, int size, Charset cs, EnumSet features) throws IOException
{
return getInstance(Channels.newChannel(is), size, cs, features);
}
/**
* Creates an InputReader
* @param in
* @param size
* @return
*/
public static InputReader getInstance(Reader in, int size)
{
return getInstance(in, size, EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
* @param in
* @param size
* @param features
* @return
* @see org.vesalainen.parser.ParserFeature
* @see org.vesalainen.util.EnumSetFlagger
*/
public static InputReader getInstance(Reader in, int size, EnumSet features)
{
return new ReadableInput(getFeaturedReader(in, size, features), size, features);
}
/**
* Creates an InputReader
* @param in
* @param shared Shared ringbuffer.
* @return
*/
public static InputReader getInstance(Reader in, char[] shared)
{
EnumSet features = EnumSet.noneOf(ParserFeature.class);
return new ReadableInput(getFeaturedReader(in, shared.length, features), shared, features);
}
/**
* Creates an InputReader
* @param text
* @return
*/
public static InputReader getInstance(CharSequence text)
{
return getInstance(text, EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
*
* @param text
* @param features
* @return
* @see org.vesalainen.parser.ParserFeature
* @see org.vesalainen.util.EnumSetFlagger
*/
public static InputReader getInstance(CharSequence text, EnumSet features)
{
if (features.contains(UsePushback))
{
return new ReadableInput(text, text.length()*2, features);
}
else
{
return new ReadableInput(text, features);
}
}
/**
* Creates an InputReader
* @param text
* @param size
* @return
*/
public static InputReader getInstance(CharSequence text, int size)
{
return getInstance(text, size, EnumSet.noneOf(ParserFeature.class));
}
/**
* Creates an InputReader
* @param text
* @param size
* @param features EnumSet
* @return
* @see org.vesalainen.parser.ParserFeature
* @see org.vesalainen.util.EnumSetFlagger
*/
public static InputReader getInstance(CharSequence text, int size, EnumSet features)
{
return new ReadableInput(text, size, features);
}
/**
* Creates an InputReader
* @param array
* @param features EnumSet
* @return
* @see org.vesalainen.parser.ParserFeature
* @see org.vesalainen.util.EnumSetFlagger
*/
public static InputReader getInstance(char[] array, EnumSet features)
{
return new ReadableInput(array, features);
}
public static InputReader getInstance(ScatteringByteChannel input, int size, String cs, EnumSet features) throws IOException
{
return getInstance(input, size, Charset.forName(cs), features);
}
public static InputReader getInstance(ScatteringByteChannel input, int size, Charset cs, EnumSet features) throws IOException
{
if (canUseUsAscii(cs, features))
{
return new ScatteringByteChannelInput(input, size, features);
}
else
{
return new ReadableInput(getFeaturedReadable(input, cs, features), size, features);
}
}
public static InputReader getInstance(ReadableByteChannel input, int size, Charset cs, EnumSet features) throws IOException
{
if (input instanceof ScatteringByteChannel)
{
if (input instanceof FileChannel)
{
FileChannel fc = (FileChannel) input;
if (canUseUsAscii(cs, features) && fc.size()> FileLengthLimit)
{
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
return new ScatteringByteChannelInput(mbb, features);
}
}
ScatteringByteChannel sbc = (ScatteringByteChannel) input;
return getInstance(sbc, size, cs, features);
}
else
{
return new ReadableInput(getFeaturedReadable(input, cs, features), size, features);
}
}
/**
* Creates an InputReader
* @param input
* @param size Ringbuffer size
* @return
* @throws IOException
*/
public static InputReader getInstance(InputSource input, int size) throws IOException
{
EnumSet features = EnumSet.of(UseInclude, UsePushback, UseModifiableCharset);
InputReader inputReader = null;
Reader reader = input.getCharacterStream();
if (reader != null)
{
inputReader = new ReadableInput(getFeaturedReader(reader, size, features), size, features);
}
else
{
InputStream is = input.getByteStream();
String encoding = input.getEncoding();
if (is != null)
{
if (encoding != null)
{
inputReader = getInstance(is, size, encoding, features);
}
else
{
inputReader = getInstance(is, size, StandardCharsets.US_ASCII, features);
}
}
else
{
String sysId = input.getSystemId();
try
{
URI uri = new URI(sysId);
if (encoding != null)
{
inputReader = getInstance(uri, size, Charset.forName(encoding), features);
}
else
{
inputReader = getInstance(uri, size, StandardCharsets.US_ASCII, features);
}
}
catch (URISyntaxException ex)
{
throw new IOException(ex);
}
}
}
inputReader.setSource(input.getSystemId());
return inputReader;
}
private static boolean canUseUsAscii(Charset cs, EnumSet features)
{
return ( StandardCharsets.US_ASCII.contains(cs) &&
!(
features.contains(UseModifiableCharset) ||
features.contains(UpperCase) ||
features.contains(LowerCase) ||
features.contains(UsePushback) ||
features.contains(UseInclude)
)
);
}
protected static Readable getFeaturedReadable(ReadableByteChannel channel, Charset cs, EnumSet features)
{
if (features.contains(UpperCase) || features.contains(LowerCase))
{
return new CaseChangePushbackByteChannelReadable(channel, cs, BufferSize, features.contains(UseDirectBuffer), !features.contains(UseModifiableCharset), features.contains(UpperCase));
}
else
{
if (features.contains(UsePushback))
{
return new PushbackByteChannelReadable(channel, cs, BufferSize, features.contains(UseDirectBuffer), !features.contains(UseModifiableCharset));
}
else
{
return new ByteChannelReadable(channel, cs, BufferSize, features.contains(UseDirectBuffer), !features.contains(UseModifiableCharset));
}
}
}
protected static Reader getFeaturedReader(Reader reader, int size, EnumSet features)
{
if (features.contains(UpperCase) || features.contains(LowerCase))
{
checkRecoverable(reader);
reader = new CaseChangeReader(reader, features.contains(UpperCase));
}
if (features.contains(UsePushback) || features.contains(UseInclude))
{
checkRecoverable(reader);
reader = new PushbackReader(reader, size);
}
return reader;
}
/**
* Set current character set. Only supported with byte input!
* @param cs
* @param fixedCharset
* @see org.vesalainen.parser.ParserFeature#UseModifiableCharset
*/
@Override
public void setCharset(String cs, boolean fixedCharset)
{
setCharset(Charset.forName(cs), fixedCharset);
}
/**
* Set current character set. Only supported with byte input!
* @param cs
* @param fixedCharset
* @see org.vesalainen.parser.ParserFeature#UseModifiableCharset
*/
@Override
public void setCharset(Charset cs, boolean fixedCharset)
{
if (includeLevel.in instanceof ModifiableCharset)
{
ModifiableCharset sr = (ModifiableCharset) includeLevel.in;
sr.setCharset(cs, fixedCharset);
}
else
{
throw new UnsupportedOperationException("setting charset not supported with current input "+includeLevel.in);
}
}
/**
* Set's the source of current input
* @param source A string describing the input source, like filename.
*/
@Override
public void setSource(String source)
{
includeLevel.source = source;
}
/**
* Get's the source of current input
* @return A string describing the input source, like filename.
*/
@Override
public String getSource()
{
return includeLevel.source;
}
private static void checkRecoverable(Object in)
{
if (in instanceof Recoverable)
{
throw new UnsupportedOperationException("Recoverable not supported with current features.");
}
}
@Override
public void recover() throws SyntaxErrorException, IOException
{
if (! tryRecover())
{
throwSyntaxErrorException(null);
}
}
@Override
public void recover(@ParserContext(ParserConstants.THROWABLE) Throwable thr) throws SyntaxErrorException, IOException
{
if (! tryRecover())
{
throwSyntaxErrorException(thr);
}
}
@Override
public void recover(
@ParserContext(ParserConstants.ExpectedDescription) String expecting,
@ParserContext(ParserConstants.LastToken) String token) throws SyntaxErrorException, IOException
{
if (! tryRecover())
{
throwSyntaxErrorException(expecting, token);
}
}
private boolean tryRecover() throws IOException
{
if (includeLevel.in instanceof Recoverable)
{
Recoverable recoverable = (Recoverable) includeLevel.in;
if (recoverable.recover(
getErrorMessage(),
getSource(),
getLineNumber(),
getColumnNumber()))
{
clear();
end = cursor;
return true;
}
}
return false;
}
@Override
public void throwSyntaxErrorException() throws SyntaxErrorException
{
throwSyntaxErrorException(null);
}
@Override
public void throwSyntaxErrorException(@ParserContext(ParserConstants.THROWABLE) Throwable thr) throws SyntaxErrorException
{
String source = includeLevel.source;
if (features.contains(UseOffsetLocatorException))
{
throw new OffsetLocatorException("syntax error", source, getStart(), getEnd(), thr);
}
else
{
int line = getLineNumber();
int column = getColumnNumber();
throw new LineLocatorException(
getErrorMessage(),
source,
line,
column,
thr
);
}
}
private String getErrorMessage()
{
return "source: "+includeLevel.source+"\n"+
"syntax error at line "+includeLevel.line+": pos "+includeLevel.column+
"\n"+
getLine()+
"\n"+
pointer(getColumnNumber());
}
@Override
public void throwSyntaxErrorException(
@ParserContext(ParserConstants.ExpectedDescription) String expecting,
@ParserContext(ParserConstants.LastToken) String token) throws SyntaxErrorException
{
String source = includeLevel.source;
if (features.contains(UseOffsetLocatorException))
{
throw new OffsetLocatorException("Expected: '"+expecting+"' got "+token+"='"+getString()+"'", source, getStart(), getEnd());
}
else
{
int line = getLineNumber();
int column = getColumnNumber();
throw new LineLocatorException("source: "+source+"\n"+
"Expected: '"+expecting+"' at line "+line+": pos "+column+
"\n"+
getLine()+
"\n"+
pointer(getColumnNumber())+
"\n got "+token+"='"+getString()+"'",
source,
line,
column
);
}
}
private String pointer(int p)
{
StringBuilder sb = new StringBuilder();
for (int ii=1;ii can be constructed later by using
* getString(int fieldRef) or getCharSequence(fieldRef) methods.
*
*
Note! If buffer size is too small the fieldRef might not be available.
*
*
Same effect is by storing start = getStart() and len = getLength() and
* later calling getString(start, end) as long as the circular buffer is not
* reused.
* @return
*/
@Override
public int getFieldRef()
{
if (size > 0xffff)
{
throw new IllegalArgumentException("fieldref not supported when buffer size is >65535");
}
return (cursor-length) % size + length * 0x10000;
}
/**
* @deprecated This methods usage is unclear
* @param fieldRef1
* @param fieldRef2
* @return
*/
public int concat(int fieldRef1, int fieldRef2)
{
int l1 = fieldRef1>>16;
int s1 = fieldRef1 & 0xffff;
int l2 = fieldRef2>>16;
int s2 = fieldRef2 & 0xffff;
return (s1) % size + (l1+l2) * 0x10000;
}
/**
* @deprecated This methods usage is unclear
* @param fieldRef
* @param buf
* @return
*/
public boolean equals(int fieldRef, char[] buf)
{
int l = fieldRef>>16;
int s = fieldRef & 0xffff;
for (int ii=0;ii>16);
}
/**
* Returns a CharSequence matched with fieldRef.
* @param fieldRef
* @return
*/
@Override
public CharSequence getCharSequence(int fieldRef)
{
return getCharSequence(fieldRef & 0xffff, fieldRef>>16);
}
/**
* Returns buffered data as String. Buffered data is ready in array.
* @return
*/
@Override
public String buffered()
{
return getString(cursor, end-cursor);
}
/**
* Returns a CharSequence
* @param s Start
* @param l Length
* @return
*/
@Override
public CharSequence getCharSequence(int s, int l)
{
return new CharSequenceImpl(s, l);
}
@Override
public String getLine()
{
int c = includeLevel.column;
if (cursor-c < end-size)
{
int len = size / 2;
return "... "+getString(end-len, len);
}
else
{
return getString(cursor-c, end-(cursor-c));
}
}
/**
* Returns the input data after last release call
* @return
*/
@Override
public String getInput()
{
return getString(cursor-length, length);
}
@Override
public String toString()
{
return getInput();
}
/**
* get a char from input buffer.
* @param offset 0 is last read char.
* @return
* @throws IOException
*/
@Override
public int peek(int offset) throws IOException
{
int target = cursor + offset - 1;
if (target - end > size || target < end - size || target < 0)
{
throw new IllegalArgumentException("offset "+offset+" out of buffer");
}
if (target >= end)
{
int la = 0;
while (target >= end)
{
int cc = read();
if (cc == -1)
{
if (target+la == end)
{
return -1;
}
else
{
throw new IOException("eof");
}
}
la++;
}
rewind(la);
}
return get(target);
}
/**
* Set how many characters we can skip after failed find.
* @param acceptStart
*/
@Override
public void setAcceptStart(int acceptStart)
{
findSkip = acceptStart;
}
/**
* Marks to position where find could accept the input.
*/
@Override
public void findAccept()
{
findMark = cursor;
}
/**
* Unread to the last findMark. Used after successful find.
* @throws java.io.IOException
*/
@Override
public void findPushback() throws IOException
{
assert findMark >= 0;
rewind(cursor-findMark);
}
/**
* Resets positions suitable for next find. Used after failed find to continue at next
* character.
* @throws IOException
*/
@Override
public void findRecover() throws IOException
{
assert findSkip >= 0;
if (findSkip > 0)
{
rewind(length-findSkip);
}
length = 0;
}
/**
* Rewinds cursor position count characters. Used for unread.
* @param count
* @throws IOException
*/
@Override
public void rewind(int count) throws IOException
{
if (count < 0)
{
throw new IllegalArgumentException("negative rewind "+count);
}
cursor -= count;
if (cursor < end - size || cursor < 0)
{
throw new IOException("insufficient room in the pushback buffer");
}
length -= count;
if (length < 0)
{
throw new IOException("rewinding past input");
}
int ld = 0;
for (int ii=0;ii 0)
{
int l = includeLevel.line;
includeLevel.line = l - ld;
int c = 0;
int start = Math.max(0, end-size);
for (int ii=cursor;ii>=start;ii--)
{
if (get(ii) == '\n')
{
break;
}
c++;
}
includeLevel.column = c;
}
else
{
int c = includeLevel.column;
includeLevel.column = c - count;
}
}
@Override
public void unread() throws IOException
{
rewind(length);
}
@Override
public void unreadLa(int len) throws IOException
{
length += len;
rewind(length);
}
@Override
public void unread(int c) throws IOException
{
rewind(1);
}
@Override
public void read(int times) throws IOException
{
for (int ii=0;ii= end)
{
if (includeLevel.in == null)
{
return -1;
}
int cp = cursor % size;
int len = size-(cursor-waterMark);
int il;
if (len > size - cp)
{
buffer1.position(cp);
buffer1.limit(size);
buffer2.position(0);
buffer2.limit(len-(size-cp));
if (!buffer1.hasRemaining() && !buffer2.hasRemaining())
{
throw new UnderflowException("Buffer size="+size+" too small for operation");
}
il = fill(includeLevel.in, array2);
}
else
{
buffer1.position(cp);
buffer1.limit(cp+len);
if (!buffer1.hasRemaining())
{
throw new UnderflowException("Buffer size="+size+" too small for operation");
}
il = fill(includeLevel.in, array1);
}
if (il == -1)
{
if (includeStack != null)
{
while (!includeStack.isEmpty() && il == -1)
{
close(includeLevel.in);
includeLevel = includeStack.pop();
return read();
}
}
return -1;
}
if (il == 0)
{
throw new IOException("No input! Use blocking mode?");
}
buffer1.clear();
buffer2.clear();
end+=il;
if (end < 0)
{
throw new IOException("end = "+end);
}
}
int rc = get(cursor++);
if (cursor < 0)
{
throw new IOException("cursor = "+cursor);
}
includeLevel.forward(rc);
length++;
if (length > size)
{
throw new IOException("input size "+length+" exceeds buffer size "+size);
}
return rc;
}
@Override
public void reRead(int count) throws IOException
{
if (count < 0)
{
throw new IOException("count="+count);
}
assert cursor <= end;
for (int ii=0;ii= end)
{
throw new IOException("reRead's unread data");
}
int rc = get(cursor++);
includeLevel.forward(rc);
length++;
if (length > size)
{
throw new IOException("input size "+length+" exceeds buffer size "+size);
}
}
}
/**
* Clears input. After that continues to next input token.
*/
@Override
public void clear()
{
updateChecksum();
length = 0;
findSkip = 0;
findMark = -1;
waterMark = cursor;
}
@Override
public void close() throws IOException
{
if (includeStack != null)
{
while (!includeStack.isEmpty())
{
close(includeStack.pop().in);
}
}
if (includeLevel.in != null)
{
close(includeLevel.in);
}
}
/**
* @deprecated Will be removed
* @param type
* @param terminal
* @return
*/
public static ExecutableElement getParseMethod(TypeMirror type, GTerminal terminal)
{
if (Typ.isPrimitive(type))
{
String name = type.getKind().name().toLowerCase();
int radix = terminal.getBase();
if (radix != 10)
{
if (radix > 0)
{
name = name+"Radix"+radix;
}
else
{
radix = -radix;
name = name+"Radix2C"+radix;
}
}
return El.getMethod(InputReader.class, "parse"+name.toUpperCase().substring(0, 1)+name.substring(1));
}
else
{
if (Typ.isSameType(type, Typ.String))
{
return El.getMethod(InputReader.class, "getString");
}
throw new IllegalArgumentException("no parse method for non primitive type "+type+" at "+terminal);
}
}
/**
* Returns true if content is string 'true' ignoring case
* @return
*/
@Override
public boolean parseBoolean()
{
return Primitives.parseBoolean(this);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public boolean parseBoolean(int s, int l)
{
return Primitives.parseBoolean(getCharSequence(s, l));
}
/**
* Returns the only character of string
* @return
*/
@Override
public char parseChar()
{
return Primitives.parseChar(this);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public char parseChar(int s, int l)
{
return Primitives.parseChar(getCharSequence(s, l));
}
/**
* Parses string content to byte "6" -> 6
* Minus is allowed as first character
* @return
*/
@Override
public byte parseByte()
{
return Primitives.parseByte(this);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public byte parseByte(int s, int l)
{
return Primitives.parseByte(getCharSequence(s, l));
}
/**
* Parses string content to short "123" -> 123
* Minus is allowed as first character
* @return
*/
@Override
public short parseShort()
{
return Primitives.parseShort(this);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public short parseShort(int s, int l)
{
return Primitives.parseShort(getCharSequence(s, l));
}
/**
* Parses string content to int "123" -> 123
* Minus is allowed as first character
* @return
*/
@Override
public int parseInt()
{
return Primitives.parseInt(this);
}
/**
* Parses string content to int "011" -> 3
*
* Conversion is 1-complement
* @return
*/
@Override
public int parseIntRadix2()
{
return Primitives.parseInt(this, 2);
}
/**
* Parses string content to int "111" -> -1
*
*
Conversion is 2-complement
* @return
*/
@Override
public int parseIntRadix2C2()
{
return Primitives.parseInt(this, -2);
}
/**
* Parses string content to int "011" -> 3
*
*
Conversion is 1-complement
* @return
*/
@Override
public long parseLongRadix2()
{
return Primitives.parseLong(this, 2);
}
/**
* Parses string content to int "111" -> -1
*
*
Conversion is 2-complement
* @return
*/
@Override
public long parseLongRadix2C2()
{
return Primitives.parseLong(this, -2);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public int parseInt(int s, int l)
{
return Primitives.parseInt(getCharSequence(s, l));
}
/**
* Converts binary to int
* @param s
* @param l
* @param radix
* @return
*/
@Override
public int parseInt(int s, int l, int radix)
{
return Primitives.parseInt(getCharSequence(s, l), radix);
}
@Override
public long parseLong(int s, int l, int radix)
{
return Primitives.parseLong(getCharSequence(s, l), radix);
}
/**
* Parses string content to long "123" -> 123
* Minus is allowed as first character
* @return
*/
@Override
public long parseLong()
{
return Primitives.parseLong(this);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public long parseLong(int s, int l)
{
return Primitives.parseLong(getCharSequence(s, l));
}
/**
* Parses string content to float "123.456" -> 123.456
* Minus is allowed as first character.
* Decimal separator is dot (.)
* Scientific notation is supported. E.g -1.23456E-9
* @return
*/
@Override
public float parseFloat()
{
return Primitives.parseFloat(this);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public float parseFloat(int s, int l)
{
return Primitives.parseFloat(getCharSequence(s, l));
}
/**
* Parses string content to double "123.456" -> 123.456
* Minus is allowed as first character.
* Decimal separator is dot (.)
* Scientific notation is supported. E.g -1.23456E-9
* @return
*/
@Override
public double parseDouble()
{
return Primitives.parseDouble(this);
}
/**
* Converts part of input
* @param s Start position starting at 0
* @param l Length
* @return
*/
@Override
public double parseDouble(int s, int l)
{
return Primitives.parseDouble(getCharSequence(s, l));
}
@Override
public boolean isAtBoundary(int t) throws IOException
{
Range.BoundaryType type = Range.BoundaryType.values()[t];
switch (type)
{
case BOL:
return includeLevel.startOfLine();
case EOL:
return ((includeLevel.startOfLine() || !isLineSeparator(peek(0))) && isLineSeparator(peek(1)));
case WB:
return ((includeLevel.startOfLine() || !Character.isLetter(peek(0))) && Character.isLetter(peek(1)));
case NWB:
return ((!includeLevel.startOfLine() && Character.isLetter(peek(0))) && !Character.isLetter(peek(1)));
case BOI:
return end == 0;
case EOPM:
throw new UnsupportedOperationException();
case EOIL:
int cc = peek(1);
return isLineSeparator(cc) || cc == -1;
case EOI:
return peek(1) == -1;
default:
throw new IllegalArgumentException("unknown boundary "+type);
}
}
private boolean isLineSeparator(int cc)
{
return cc == '\r' || cc == '\n';
}
@Override
public int getLineNumber()
{
return includeLevel.line;
}
@Override
public int getColumnNumber()
{
return includeLevel.column;
}
@Override
public String getEncoding()
{
if (includeLevel.in instanceof ByteChannelReadable)
{
ByteChannelReadable sr = (ByteChannelReadable) includeLevel.in;
return sr.getCharset().name();
}
return null;
}
@Override
public int length()
{
return length;
}
@Override
public char charAt(int i)
{
if (i<0 || i>=length)
{
throw new IllegalArgumentException(i+" index out of range");
}
return (char) get((cursor-length+i));
}
@Override
public CharSequence subSequence(int s, int e)
{
if (s<0 || s>e || s>=length || e>=length)
{
throw new IllegalArgumentException("("+s+", "+e+") index out of range");
}
return new CharSequenceImpl(cursor-length+s, e-s);
}
@Override
public void setChecksum(Checksum checksum)
{
this.checksum = checksum;
}
protected void updateChecksum()
{
if (checksum != null)
{
int start = cursor - length;
for (int ii=0;ii= l || i < 0)
{
throw new IllegalArgumentException("index "+i+" out of range");
}
return (char) get((s+i));
}
@Override
public CharSequence subSequence(int s, int e)
{
if (s < 0 || s >= l || e < 0 || e >= l)
{
throw new IllegalArgumentException("Illegal sub range");
}
return new CharSequenceImpl(this.s+s, e-s);
}
@Override
public String toString()
{
return getString(s, l);
}
}
}