import Char from 'typescript-char' ; import { isLineBreak , isWhiteSpace } from './characters' ; export class CharacterStream { private _text : string ; private _position : number ; private _currentChar : number ; private _isEndOfStream : boolean ; constructor ( text ) { this . _text = text ; this . _position = 0 ; this . _currentChar = text . length > 0 ? text . charCodeAt ( 0 ) : 0 ; this . _isEndOfStream = text . length === 0 ; } getText ( ) { return this . _text ; } get position ( ) : number { return this . _position ; } set position ( value ) { this . _position = value ; this . _checkBounds ( ) ; } get currentChar ( ) : number { return this . _currentChar ; } getCurrentChar ( ) { return this . _currentChar ; } get nextChar ( ) : number { return this . position + 1 < this . _text . length ? this . _text . charCodeAt ( this . position + 1 ) : 0 ; } get prevChar ( ) : number { return this . position - 1 >= 0 ? this . _text . charCodeAt ( this . position - 1 ) : 0 ; } isEndOfStream ( ) { return this . _isEndOfStream ; } lookAhead ( offset ) { const pos = this . _position + offset ; return pos < 0 || pos >= this . _text . length ? 0 : this . _text . charCodeAt ( pos ) ; } advance ( offset ) { this . position += offset ; } moveNext ( ) { if ( this . _position < this . _text . length - 1 ) { this . _position += 1 ; this . _currentChar = this . _text . charCodeAt ( this . _position ) ; return true ; } this . advance ( 1 ) ; return ! this . isEndOfStream ( ) ; } isAtWhiteSpace ( ) { return isWhiteSpace ( this . currentChar ) ; } isAtLineBreak ( ) { return isLineBreak ( this . currentChar ) ; } skipLineBreak ( ) { if ( this . _currentChar === Char . CarriageReturn ) { this . moveNext ( ) ; if ( this . currentChar === Char . LineFeed ) { this . moveNext ( ) ; } } else if ( this . _currentChar === Char . LineFeed ) { this . moveNext ( ) ; } } skipWhitespace ( ) { while ( ! this . isEndOfStream ( ) && this . isAtWhiteSpace ( ) ) { this . moveNext ( ) ; } } skipToEol ( ) { while ( ! this . isEndOfStream ( ) && ! this . isAtLineBreak ( ) ) { this . moveNext ( ) ; } } skipToWhitespace ( ) { while ( ! this . isEndOfStream ( ) && ! this . isAtWhiteSpace ( ) ) { this . moveNext ( ) ; } } charCodeAt ( index ) { return this . _text . charCodeAt ( index ) ; } get length ( ) : number { return this . _text . length ; } private _checkBounds ( ) { if ( this . _position < 0 ) { this . _position = 0 ; } this . _isEndOfStream = this . _position >= this . _text . length ; if ( this . _isEndOfStream ) { this . _position = this . _text . length ; } this . _currentChar = this . _isEndOfStream ? 0 : this . _text . charCodeAt ( this . _position ) ; } }