3 // The ABNF grammar in the spec is totally ambiguous.
5 // This parser follows the operator precedence defined in the
6 // `Order of Precedence and Parentheses` section.
8 module.exports = function (tokens) {
12 return index < tokens.length
16 return hasMore() ? tokens[index] : null
26 function parseOperator (operator) {
28 if (t && t.type === 'OPERATOR' && operator === t.string) {
34 function parseWith () {
35 if (parseOperator('WITH')) {
37 if (t && t.type === 'EXCEPTION') {
41 throw new Error('Expected exception after `WITH`')
45 function parseLicenseRef () {
46 // TODO: Actually, everything is concatenated into one string
47 // for backward-compatibility but it could be better to return
52 if (t.type === 'DOCUMENTREF') {
54 string += 'DocumentRef-' + t.string + ':'
55 if (!parseOperator(':')) {
56 throw new Error('Expected `:` after `DocumentRef-...`')
60 if (t.type === 'LICENSEREF') {
62 string += 'LicenseRef-' + t.string
63 return { license: string }
68 function parseLicense () {
70 if (t && t.type === 'LICENSE') {
72 var node = { license: t.string }
73 if (parseOperator('+')) {
76 var exception = parseWith()
78 node.exception = exception
84 function parseParenthesizedExpression () {
85 var left = parseOperator('(')
90 var expr = parseExpression()
92 if (!parseOperator(')')) {
93 throw new Error('Expected `)`')
99 function parseAtom () {
101 parseParenthesizedExpression() ||
107 function makeBinaryOpParser (operator, nextParser) {
108 return function parseBinaryOp () {
109 var left = nextParser()
114 if (!parseOperator(operator)) {
118 var right = parseBinaryOp()
120 throw new Error('Expected expression')
124 conjunction: operator.toLowerCase(),
130 var parseAnd = makeBinaryOpParser('AND', parseAtom)
131 var parseExpression = makeBinaryOpParser('OR', parseAnd)
133 var node = parseExpression()
134 if (!node || hasMore()) {
135 throw new Error('Syntax error')