75 lines
1.7 KiB
Plaintext
75 lines
1.7 KiB
Plaintext
const SYMBOL_MATCH = 'SYMBOL_MATCH'
|
|
|
|
export default class TokenStream {
|
|
constructor(nodes, parent) {
|
|
this.index = 0
|
|
this.nodes = nodes
|
|
this.functionName = parent != null ? parent.value : null
|
|
this.lastValue = null
|
|
this.rewindIndex = -1
|
|
}
|
|
|
|
hasTokens() {
|
|
return this.index <= this.nodes.length - 1
|
|
}
|
|
|
|
[SYMBOL_MATCH](...tokenDescriptors) {
|
|
if (!this.hasTokens()) return null
|
|
|
|
const node = this.nodes[this.index]
|
|
|
|
for (let i = 0; i < tokenDescriptors.length; i += 1) {
|
|
const tokenDescriptor = tokenDescriptors[i]
|
|
const value = tokenDescriptor(node)
|
|
if (value !== null) {
|
|
this.index += 1
|
|
this.lastValue = value
|
|
return value
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
matches(...tokenDescriptors) {
|
|
return this[SYMBOL_MATCH](...tokenDescriptors) !== null
|
|
}
|
|
|
|
expect(...tokenDescriptors) {
|
|
const value = this[SYMBOL_MATCH](...tokenDescriptors)
|
|
return value !== null ? value : this.throw()
|
|
}
|
|
|
|
matchesFunction() {
|
|
const node = this.nodes[this.index]
|
|
if (node.type !== 'function') return null
|
|
const value = new TokenStream(node.nodes, node)
|
|
this.index += 1
|
|
this.lastValue = null
|
|
return value
|
|
}
|
|
|
|
expectFunction() {
|
|
const value = this.matchesFunction()
|
|
return value !== null ? value : this.throw()
|
|
}
|
|
|
|
expectEmpty() {
|
|
if (this.hasTokens()) this.throw()
|
|
}
|
|
|
|
throw() {
|
|
throw new Error(`Unexpected token type: ${this.nodes[this.index].type}`)
|
|
}
|
|
|
|
saveRewindPoint() {
|
|
this.rewindIndex = this.index
|
|
}
|
|
|
|
rewind() {
|
|
if (this.rewindIndex === -1) throw new Error('Internal error')
|
|
this.index = this.rewindIndex
|
|
this.lastValue = null
|
|
}
|
|
}
|