| 2 | |
| 3 | |
| 4 | export default class StringSource{ |
| 5 | constructor(str){ |
| 6 | this.line = 1; |
| 7 | this.cols = 0; |
| 8 | this.buffer = str; |
| 9 | //a boundary pointer to indicate where from the buffer dat should be read |
| 10 | // data before this pointer can be deleted to free the memory |
| 11 | this.startIndex = 0; |
| 12 | } |
| 13 | |
| 14 | readCh() { |
| 15 | return this.buffer[this.startIndex++]; |
| 16 | } |
| 17 | |
| 18 | readChAt(index) { |
| 19 | return this.buffer[this.startIndex+index]; |
| 20 | } |
| 21 | |
| 22 | readStr(n,from){ |
| 23 | if(typeof from === "undefined") from = this.startIndex; |
| 24 | return this.buffer.substring(from, from + n); |
| 25 | } |
| 26 | |
| 27 | readUpto(stopStr) { |
| 28 | const inputLength = this.buffer.length; |
| 29 | const stopLength = stopStr.length; |
| 30 | |
| 31 | for (let i = this.startIndex; i < inputLength; i++) { |
| 32 | let match = true; |
| 33 | for (let j = 0; j < stopLength; j++) { |
| 34 | if (this.buffer[i + j] !== stopStr[j]) { |
| 35 | match = false; |
| 36 | break; |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | if (match) { |
| 41 | const result = this.buffer.substring(this.startIndex, i); |
| 42 | this.startIndex = i + stopLength; |
| 43 | return result; |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | throw new Error(`Unexpected end of source. Reading '${stopStr}'`); |
| 48 | } |
| 49 | |
| 50 | readUptoCloseTag(stopStr) { //stopStr: "</tagname" |
| 51 | const inputLength = this.buffer.length; |
| 52 | const stopLength = stopStr.length; |
| 53 | let stopIndex = 0; |
| 54 | //0: non-matching, 1: matching stop string, 2: matching closing |
| 55 | let match = 0; |
| 56 | |
| 57 | for (let i = this.startIndex; i < inputLength; i++) { |
| 58 | if(match === 1){//initial part matched |
| 59 | if(stopIndex === 0) stopIndex = i; |
| 60 | if(this.buffer[i] === ' ' || this.buffer[i] === '\t') continue; |
| 61 | else if(this.buffer[i] === '>'){ |
nothing calls this directly
no outgoing calls
no test coverage detected