blob: 6120ccf520cff7594349b5cb9dc543d7f1f6035c [file] [log] [blame] [edit]
///
/// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
/// Use of this file is governed by the BSD 3-clause license that
/// can be found in the LICENSE.txt file in the project root.
///
///
/// Vacuum all input from a _java.io.Reader_/_java.io.InputStream_ and then treat it
/// like a `char[]` buffer. Can also pass in a _String_ or
/// `char[]` to use.
///
/// If you need encoding, pass in stream/reader with correct encoding.
///
public class ANTLRInputStream: CharStream {
///
/// The data being scanned
///
internal let data: [UnicodeScalar]
///
/// How many unicode scalars are actually in the buffer
///
internal var n: Int
///
/// 0...n-1 index into string of next char
///
internal var p = 0
///
/// What is name or source of this char stream?
///
public var name: String?
public init() {
n = 0
data = []
}
///
/// Copy data in string to a local char array
///
public init(_ input: String) {
self.data = Array(input.unicodeScalars)
self.n = data.count
}
///
/// This is the preferred constructor for strings as no data is copied
///
public init(_ data: [UnicodeScalar], _ numberOfActualUnicodeScalarsInArray: Int) {
self.data = data
self.n = numberOfActualUnicodeScalarsInArray
}
///
/// This is only for backward compatibility that accepts array of `Character`.
/// Use `init(_ data: [UnicodeScalar], _ numberOfActualUnicodeScalarsInArray: Int)` instead.
///
public init(_ data: [Character], _ numberOfActualUnicodeScalarsInArray: Int) {
let string = String(data)
self.data = Array(string.unicodeScalars)
self.n = numberOfActualUnicodeScalarsInArray
}
public func reset() {
p = 0
}
public func consume() throws {
if p >= n {
assert(LA(1) == ANTLRInputStream.EOF, "Expected: LA(1)==IntStream.EOF")
throw ANTLRError.illegalState(msg: "cannot consume EOF")
}
// print("prev p="+p+", c="+(char)data[p]);
if p < n {
p += 1
//print("p moves to "+p+" (c='"+(char)data[p]+"')");
}
}
public func LA(_ i: Int) -> Int {
var i = i
if i == 0 {
return 0 // undefined
}
if i < 0 {
i += 1 // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
if (p + i - 1) < 0 {
return ANTLRInputStream.EOF// invalid; no char before first char
}
}
if (p + i - 1) >= n {
//print("char LA("+i+")=EOF; p="+p);
return ANTLRInputStream.EOF
}
//print("char LA("+i+")="+(char)data[p+i-1]+"; p="+p);
//print("LA("+i+"); p="+p+" n="+n+" data.length="+data.length);
return Int(data[p + i - 1].value)
}
public func LT(_ i: Int) -> Int {
return LA(i)
}
///
/// Return the current input symbol index 0...n where n indicates the
/// last symbol has been read. The index is the index of char to
/// be returned from LA(1).
///
public func index() -> Int {
return p
}
public func size() -> Int {
return n
}
///
/// mark/release do nothing; we have entire buffer
///
public func mark() -> Int {
return -1
}
public func release(_ marker: Int) {
}
///
/// consume() ahead until p==index; can't just set p=index as we must
/// update line and charPositionInLine. If we seek backwards, just set p
///
public func seek(_ index: Int) throws {
var index = index
if index <= p {
p = index // just jump; don't update stream state (line, ...)
return
}
// seek forward, consume until p hits index or n (whichever comes first)
index = min(index, n)
while p < index {
try consume()
}
}
public func getText(_ interval: Interval) -> String {
let start = interval.a
if start >= n {
return ""
}
let stop = min(n, interval.b + 1)
var unicodeScalarView = String.UnicodeScalarView()
unicodeScalarView.append(contentsOf: data[start ..< stop])
return String(unicodeScalarView)
}
public func getSourceName() -> String {
return name ?? ANTLRInputStream.UNKNOWN_SOURCE_NAME
}
public func toString() -> String {
var unicodeScalarView = String.UnicodeScalarView()
unicodeScalarView.append(contentsOf: data)
return String(unicodeScalarView)
}
}