Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class Stream {
- constructor(tokens) {
- this.tokens = tokens
- this.pos = 0
- }
- get next() {
- return this.tokens[this.pos++] || ''
- }
- cancel() {
- this.pos--
- }
- get done() {
- return this.pos >= this.tokens.length
- }
- get rest() {
- return this.tokens.slice(this.pos)
- }
- transaction(fn) {
- const rpos = this.pos
- const ret = fn()
- if (ret === failure) {
- this.pos = rpos
- return failure
- }
- return ret
- }
- }
- const failure = Symbol('failure')
- const ignore = Symbol('ignore')
- const eq = str => stream => stream.transaction(() => stream.next == str ? ignore : failure)
- const re = regex => fn => stream => stream.transaction(() => {
- const ret = stream.next.match(regex)
- if (!ret) return failure
- return fn(ret)
- })
- const assembly = (...parsers) => stream => stream.transaction(() => {
- console.log('assembly')
- let result = ignore
- for (const parser of parsers) {
- result = parser(result)(stream)
- if (result == failure)
- return failure
- }
- return result
- })
- const chain = (...parsers) => fn => stream => stream.transaction(() => {
- const arr = []
- for (const parser of parsers) {
- const result = parser(stream)
- if (result == failure)
- return failure
- if (result != ignore)
- arr.push(result)
- }
- return fn(...arr)
- })
- const choice = (...parsers) => stream => {
- for (const parser of parsers) {
- const result = parser(stream)
- if (result != failure)
- return result
- }
- return failure
- }
- const repeatRange = parser => (low, high = Number.MAX_SAFE_INTEGER) => stream => stream.transaction(() => {
- const arr = []
- let i = 0
- for (; i < high; i++) {
- const result = parser(stream)
- if (result == failure)
- break
- if (result != ignore)
- arr.push(result)
- }
- if (i < low || i > high) return failure
- return arr
- })
- const repeat = parser => number => repeatRange(parser)(number, number)
- const many = parser => repeatRange(parser)(1)
- const zeroOrMany = parser => repeatRange(parser)(0)
- const maybe = parser => repeatRange(parser)(0, 1)
- const must = parser => repeatRange(parser)(1, 1)
- const packer = parser => fn => stream => {
- const ret = parser(stream)
- if (ret === failure)
- return failure
- return fn(ret)
- }
- const $log = (...param) => stream => {
- console.log(...param, stream.rest)
- return ignore
- }
- const $lazy = fn => a => b => fn(a)(b)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement