| /// |
| /// 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) |
| } |
| } |