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
- }
|