72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import { TemplateToken } from "."
|
|
import { MappingToken } from "./mapping-token"
|
|
import { SequenceToken } from "./sequence-token"
|
|
import { TokenType } from "./types"
|
|
|
|
export class TraversalState {
|
|
private readonly _token: TemplateToken
|
|
private index = -1
|
|
private isKey = false
|
|
public readonly parent: TraversalState | undefined
|
|
public current: TemplateToken | undefined
|
|
public currentKey: TemplateToken | undefined
|
|
|
|
public constructor(parent: TraversalState | undefined, token: TemplateToken) {
|
|
this.parent = parent
|
|
this._token = token
|
|
this.current = token
|
|
}
|
|
|
|
public moveNext(omitKeys: boolean): boolean {
|
|
switch (this._token.templateTokenType) {
|
|
case TokenType.Sequence: {
|
|
const sequence = this._token as SequenceToken
|
|
if (++this.index < sequence.count) {
|
|
this.current = sequence.get(this.index)
|
|
return true
|
|
}
|
|
this.current = undefined
|
|
return false
|
|
}
|
|
|
|
case TokenType.Mapping: {
|
|
const mapping = this._token as MappingToken
|
|
|
|
// Already returned the key, now return the value
|
|
if (this.isKey) {
|
|
this.isKey = false
|
|
this.currentKey = this.current
|
|
this.current = mapping.get(this.index).value
|
|
return true
|
|
}
|
|
|
|
// Move next
|
|
if (++this.index < mapping.count) {
|
|
// Skip the key, return the value
|
|
if (omitKeys) {
|
|
this.isKey = false
|
|
this.currentKey = mapping.get(this.index).key
|
|
this.current = mapping.get(this.index).value
|
|
return true
|
|
}
|
|
|
|
// Return the key
|
|
this.isKey = true
|
|
this.currentKey = undefined
|
|
this.current = mapping.get(this.index).key
|
|
return true
|
|
}
|
|
|
|
this.currentKey = undefined
|
|
this.current = undefined
|
|
return false
|
|
}
|
|
|
|
default:
|
|
throw new Error(
|
|
`Unexpected token type '${this._token.templateTokenType}' when traversing state`
|
|
)
|
|
}
|
|
}
|
|
}
|