11cb0ef41Sopenharmony_ci'use strict' 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci// The ABNF grammar in the spec is totally ambiguous. 41cb0ef41Sopenharmony_ci// 51cb0ef41Sopenharmony_ci// This parser follows the operator precedence defined in the 61cb0ef41Sopenharmony_ci// `Order of Precedence and Parentheses` section. 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_cimodule.exports = function (tokens) { 91cb0ef41Sopenharmony_ci var index = 0 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci function hasMore () { 121cb0ef41Sopenharmony_ci return index < tokens.length 131cb0ef41Sopenharmony_ci } 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci function token () { 161cb0ef41Sopenharmony_ci return hasMore() ? tokens[index] : null 171cb0ef41Sopenharmony_ci } 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci function next () { 201cb0ef41Sopenharmony_ci if (!hasMore()) { 211cb0ef41Sopenharmony_ci throw new Error() 221cb0ef41Sopenharmony_ci } 231cb0ef41Sopenharmony_ci index++ 241cb0ef41Sopenharmony_ci } 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci function parseOperator (operator) { 271cb0ef41Sopenharmony_ci var t = token() 281cb0ef41Sopenharmony_ci if (t && t.type === 'OPERATOR' && operator === t.string) { 291cb0ef41Sopenharmony_ci next() 301cb0ef41Sopenharmony_ci return t.string 311cb0ef41Sopenharmony_ci } 321cb0ef41Sopenharmony_ci } 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci function parseWith () { 351cb0ef41Sopenharmony_ci if (parseOperator('WITH')) { 361cb0ef41Sopenharmony_ci var t = token() 371cb0ef41Sopenharmony_ci if (t && t.type === 'EXCEPTION') { 381cb0ef41Sopenharmony_ci next() 391cb0ef41Sopenharmony_ci return t.string 401cb0ef41Sopenharmony_ci } 411cb0ef41Sopenharmony_ci throw new Error('Expected exception after `WITH`') 421cb0ef41Sopenharmony_ci } 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci function parseLicenseRef () { 461cb0ef41Sopenharmony_ci // TODO: Actually, everything is concatenated into one string 471cb0ef41Sopenharmony_ci // for backward-compatibility but it could be better to return 481cb0ef41Sopenharmony_ci // a nice structure. 491cb0ef41Sopenharmony_ci var begin = index 501cb0ef41Sopenharmony_ci var string = '' 511cb0ef41Sopenharmony_ci var t = token() 521cb0ef41Sopenharmony_ci if (t.type === 'DOCUMENTREF') { 531cb0ef41Sopenharmony_ci next() 541cb0ef41Sopenharmony_ci string += 'DocumentRef-' + t.string + ':' 551cb0ef41Sopenharmony_ci if (!parseOperator(':')) { 561cb0ef41Sopenharmony_ci throw new Error('Expected `:` after `DocumentRef-...`') 571cb0ef41Sopenharmony_ci } 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci t = token() 601cb0ef41Sopenharmony_ci if (t.type === 'LICENSEREF') { 611cb0ef41Sopenharmony_ci next() 621cb0ef41Sopenharmony_ci string += 'LicenseRef-' + t.string 631cb0ef41Sopenharmony_ci return { license: string } 641cb0ef41Sopenharmony_ci } 651cb0ef41Sopenharmony_ci index = begin 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci function parseLicense () { 691cb0ef41Sopenharmony_ci var t = token() 701cb0ef41Sopenharmony_ci if (t && t.type === 'LICENSE') { 711cb0ef41Sopenharmony_ci next() 721cb0ef41Sopenharmony_ci var node = { license: t.string } 731cb0ef41Sopenharmony_ci if (parseOperator('+')) { 741cb0ef41Sopenharmony_ci node.plus = true 751cb0ef41Sopenharmony_ci } 761cb0ef41Sopenharmony_ci var exception = parseWith() 771cb0ef41Sopenharmony_ci if (exception) { 781cb0ef41Sopenharmony_ci node.exception = exception 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci return node 811cb0ef41Sopenharmony_ci } 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci function parseParenthesizedExpression () { 851cb0ef41Sopenharmony_ci var left = parseOperator('(') 861cb0ef41Sopenharmony_ci if (!left) { 871cb0ef41Sopenharmony_ci return 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci var expr = parseExpression() 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci if (!parseOperator(')')) { 931cb0ef41Sopenharmony_ci throw new Error('Expected `)`') 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci return expr 971cb0ef41Sopenharmony_ci } 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci function parseAtom () { 1001cb0ef41Sopenharmony_ci return ( 1011cb0ef41Sopenharmony_ci parseParenthesizedExpression() || 1021cb0ef41Sopenharmony_ci parseLicenseRef() || 1031cb0ef41Sopenharmony_ci parseLicense() 1041cb0ef41Sopenharmony_ci ) 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci function makeBinaryOpParser (operator, nextParser) { 1081cb0ef41Sopenharmony_ci return function parseBinaryOp () { 1091cb0ef41Sopenharmony_ci var left = nextParser() 1101cb0ef41Sopenharmony_ci if (!left) { 1111cb0ef41Sopenharmony_ci return 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci if (!parseOperator(operator)) { 1151cb0ef41Sopenharmony_ci return left 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci var right = parseBinaryOp() 1191cb0ef41Sopenharmony_ci if (!right) { 1201cb0ef41Sopenharmony_ci throw new Error('Expected expression') 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci return { 1231cb0ef41Sopenharmony_ci left: left, 1241cb0ef41Sopenharmony_ci conjunction: operator.toLowerCase(), 1251cb0ef41Sopenharmony_ci right: right 1261cb0ef41Sopenharmony_ci } 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci } 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci var parseAnd = makeBinaryOpParser('AND', parseAtom) 1311cb0ef41Sopenharmony_ci var parseExpression = makeBinaryOpParser('OR', parseAnd) 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci var node = parseExpression() 1341cb0ef41Sopenharmony_ci if (!node || hasMore()) { 1351cb0ef41Sopenharmony_ci throw new Error('Syntax error') 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci return node 1381cb0ef41Sopenharmony_ci} 139