TAO: interactive parser

This is a demonstration of a basic parser and unparser for TAO. JavaScript needs to be enabled for it to work. If any errors occur, they will appear in your web browser’s console.

example:
parse
 
unparse

Source code

The parser is implemented in simple JavaScript. The implementation can be used as a reference for more advanced parsers.

Note that in JavaScript:

function meta(input) {
  return input.at('[') || input.at('`') || input.at(']')
}
function op(input) {
  if (input.at('`')) { input.next()
    if (input.done()) input.error('op')
    return ['op', input.next()]
  }
}
function note(input) {
  if (meta(input)) input.error('note')
  let note = input.next()
  while (true) {
    if (input.done() || meta(input)) return ['note', note]
    note += input.next()
  }
}
function tree(input) {
  if (input.at('[')) { input.next()
    const tree = tao(input.until(']'))
    input.next()
    return ['tree', tree]
  }
}
function tao(input) {
  const tao = []
  while (true) {
    if (input.done()) return ['tao', tao]
    tao.push(tree(input) || op(input) || note(input))
  }
}

function parse(str) {
  const {length} = str
  let position = 0
  const input = {
    done() { return position >= length },
    at(symbol) { return str[position] === symbol },
    next() { return str[position++] },
    save() { saved = position },
    error(name) { throw Error(`ERROR: malformed ${name} at ${position}.`) },
    // returns a shallow copy of input with a replaced done() method
    // the new method uses the original one
    until(symbol) {
      const saved = position
      return {...input,
        done() {
          if (input.done()) throw Error(
            `ERROR: since ${saved} expected ${JSON.stringify(symbol)} before end of input`
          )
          return input.at(symbol)
        }
      }
    }
  }
  return tao(input)
}
function unparse(ast) {
    const [tag, value] = ast
    if (tag === 'tao') return value.reduce((acc, next) => acc + unparse(next), "")
    if (tag === 'tree') return '[' + unparse(value) + ']'
    if (tag === 'note') return value
    if (tag === 'op') return '`' + value

    throw Error(`Invalid JSON AST of TAO: ${JSON.stringify(ast)}`)
}