|
|
@ -77,7 +77,11 @@ const defaultDelimitersClose = new Uint8Array([125, 125]) // "}}" |
|
|
|
/** All the states the tokenizer can be in. */ |
|
|
|
const enum State { |
|
|
|
Text = 1, |
|
|
|
|
|
|
|
// interpolation
|
|
|
|
InterpolationOpen, |
|
|
|
Interpolation, |
|
|
|
InterpolationClose, |
|
|
|
|
|
|
|
// Tags
|
|
|
|
BeforeTagName, // After <
|
|
|
@ -288,38 +292,55 @@ export default class Tokenizer { |
|
|
|
this.sectionStart = this.index |
|
|
|
} else if (c === CharCodes.Amp) { |
|
|
|
this.startEntity() |
|
|
|
} else if (this.matchDelimiter(c, this.delimiterOpen)) { |
|
|
|
if (this.index > this.sectionStart) { |
|
|
|
this.cbs.ontext(this.sectionStart, this.index) |
|
|
|
} |
|
|
|
this.state = State.Interpolation |
|
|
|
this.sectionStart = this.index |
|
|
|
this.index += this.delimiterOpen.length - 1 |
|
|
|
} else if (c === this.delimiterOpen[0]) { |
|
|
|
this.state = State.InterpolationOpen |
|
|
|
this.delimiterIndex = 0 |
|
|
|
this.stateInterpolationOpen(c) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public delimiterOpen: Uint8Array = defaultDelimitersOpen |
|
|
|
public delimiterClose: Uint8Array = defaultDelimitersClose |
|
|
|
private matchDelimiter(c: number, delimiter: Uint8Array): boolean { |
|
|
|
if (c === delimiter[0]) { |
|
|
|
const l = delimiter.length |
|
|
|
for (let i = 1; i < l; i++) { |
|
|
|
if (this.buffer.charCodeAt(this.index + i) !== delimiter[i]) { |
|
|
|
return false |
|
|
|
private delimiterIndex = -1 |
|
|
|
|
|
|
|
private stateInterpolationOpen(c: number): void { |
|
|
|
if (c === this.delimiterOpen[this.delimiterIndex]) { |
|
|
|
if (this.delimiterIndex === this.delimiterOpen.length - 1) { |
|
|
|
const start = this.index + 1 - this.delimiterOpen.length |
|
|
|
if (start > this.sectionStart) { |
|
|
|
this.cbs.ontext(this.sectionStart, start) |
|
|
|
} |
|
|
|
this.state = State.Interpolation |
|
|
|
this.sectionStart = start |
|
|
|
} else { |
|
|
|
this.delimiterIndex++ |
|
|
|
} |
|
|
|
return true |
|
|
|
} else { |
|
|
|
this.state = State.Text |
|
|
|
this.stateText(c) |
|
|
|
} |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
private stateInterpolation(c: number): void { |
|
|
|
if (this.matchDelimiter(c, this.delimiterClose)) { |
|
|
|
this.index += this.delimiterClose.length |
|
|
|
this.cbs.oninterpolation(this.sectionStart, this.index) |
|
|
|
this.state = State.Text |
|
|
|
this.sectionStart = this.index |
|
|
|
this.stateText(this.buffer.charCodeAt(this.index)) |
|
|
|
if (c === this.delimiterClose[0]) { |
|
|
|
this.state = State.InterpolationClose |
|
|
|
this.delimiterIndex = 0 |
|
|
|
this.stateInterpolationClose(c) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private stateInterpolationClose(c: number) { |
|
|
|
if (c === this.delimiterClose[this.delimiterIndex]) { |
|
|
|
if (this.delimiterIndex === this.delimiterClose.length - 1) { |
|
|
|
this.cbs.oninterpolation(this.sectionStart, this.index + 1) |
|
|
|
this.state = State.Text |
|
|
|
this.sectionStart = this.index + 1 |
|
|
|
} else { |
|
|
|
this.delimiterIndex++ |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.state = State.Interpolation |
|
|
|
this.stateInterpolation(c) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -815,10 +836,18 @@ export default class Tokenizer { |
|
|
|
this.stateText(c) |
|
|
|
break |
|
|
|
} |
|
|
|
case State.InterpolationOpen: { |
|
|
|
this.stateInterpolationOpen(c) |
|
|
|
break |
|
|
|
} |
|
|
|
case State.Interpolation: { |
|
|
|
this.stateInterpolation(c) |
|
|
|
break |
|
|
|
} |
|
|
|
case State.InterpolationClose: { |
|
|
|
this.stateInterpolationClose(c) |
|
|
|
break |
|
|
|
} |
|
|
|
case State.SpecialStartSequence: { |
|
|
|
this.stateSpecialStartSequence(c) |
|
|
|
break |
|
|
|