| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 | 'use strict'// The ABNF grammar in the spec is totally ambiguous.//// This parser follows the operator precedence defined in the// `Order of Precedence and Parentheses` section.module.exports = function (tokens) {  var index = 0  function hasMore () {    return index < tokens.length  }  function token () {    return hasMore() ? tokens[index] : null  }  function next () {    if (!hasMore()) {      throw new Error()    }    index++  }  function parseOperator (operator) {    var t = token()    if (t && t.type === 'OPERATOR' && operator === t.string) {      next()      return t.string    }  }  function parseWith () {    if (parseOperator('WITH')) {      var t = token()      if (t && t.type === 'EXCEPTION') {        next()        return t.string      }      throw new Error('Expected exception after `WITH`')    }  }  function parseLicenseRef () {    // TODO: Actually, everything is concatenated into one string    // for backward-compatibility but it could be better to return    // a nice structure.    var begin = index    var string = ''    var t = token()    if (t.type === 'DOCUMENTREF') {      next()      string += 'DocumentRef-' + t.string + ':'      if (!parseOperator(':')) {        throw new Error('Expected `:` after `DocumentRef-...`')      }    }    t = token()    if (t.type === 'LICENSEREF') {      next()      string += 'LicenseRef-' + t.string      return { license: string }    }    index = begin  }  function parseLicense () {    var t = token()    if (t && t.type === 'LICENSE') {      next()      var node = { license: t.string }      if (parseOperator('+')) {        node.plus = true      }      var exception = parseWith()      if (exception) {        node.exception = exception      }      return node    }  }  function parseParenthesizedExpression () {    var left = parseOperator('(')    if (!left) {      return    }    var expr = parseExpression()    if (!parseOperator(')')) {      throw new Error('Expected `)`')    }    return expr  }  function parseAtom () {    return (      parseParenthesizedExpression() ||      parseLicenseRef() ||      parseLicense()    )  }  function makeBinaryOpParser (operator, nextParser) {    return function parseBinaryOp () {      var left = nextParser()      if (!left) {        return      }      if (!parseOperator(operator)) {        return left      }      var right = parseBinaryOp()      if (!right) {        throw new Error('Expected expression')      }      return {        left: left,        conjunction: operator.toLowerCase(),        right: right      }    }  }  var parseAnd = makeBinaryOpParser('AND', parseAtom)  var parseExpression = makeBinaryOpParser('OR', parseAnd)  var node = parseExpression()  if (!node || hasMore()) {    throw new Error('Syntax error')  }  return node}
 |