1 | 'use strict'
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | module.exports = function (tokens) {
|
9 | var index = 0
|
10 |
|
11 | function hasMore () {
|
12 | return index < tokens.length
|
13 | }
|
14 |
|
15 | function token () {
|
16 | return hasMore() ? tokens[index] : null
|
17 | }
|
18 |
|
19 | function next () {
|
20 | if (!hasMore()) {
|
21 | throw new Error()
|
22 | }
|
23 | index++
|
24 | }
|
25 |
|
26 | function parseOperator (operator) {
|
27 | var t = token()
|
28 | if (t && t.type === 'OPERATOR' && operator === t.string) {
|
29 | next()
|
30 | return t.string
|
31 | }
|
32 | }
|
33 |
|
34 | function parseWith () {
|
35 | if (parseOperator('WITH')) {
|
36 | var t = token()
|
37 | if (t && t.type === 'EXCEPTION') {
|
38 | next()
|
39 | return t.string
|
40 | }
|
41 | throw new Error('Expected exception after `WITH`')
|
42 | }
|
43 | }
|
44 |
|
45 | function parseLicenseRef () {
|
46 |
|
47 |
|
48 |
|
49 | var begin = index
|
50 | var string = ''
|
51 | var t = token()
|
52 | if (t.type === 'DOCUMENTREF') {
|
53 | next()
|
54 | string += 'DocumentRef-' + t.string + ':'
|
55 | if (!parseOperator(':')) {
|
56 | throw new Error('Expected `:` after `DocumentRef-...`')
|
57 | }
|
58 | }
|
59 | t = token()
|
60 | if (t.type === 'LICENSEREF') {
|
61 | next()
|
62 | string += 'LicenseRef-' + t.string
|
63 | return {license: string}
|
64 | }
|
65 | index = begin
|
66 | }
|
67 |
|
68 | function parseLicense () {
|
69 | var t = token()
|
70 | if (t && t.type === 'LICENSE') {
|
71 | next()
|
72 | var node = {license: t.string}
|
73 | if (parseOperator('+')) {
|
74 | node.plus = true
|
75 | }
|
76 | var exception = parseWith()
|
77 | if (exception) {
|
78 | node.exception = exception
|
79 | }
|
80 | return node
|
81 | }
|
82 | }
|
83 |
|
84 | function parseParenthesizedExpression () {
|
85 | var left = parseOperator('(')
|
86 | if (!left) {
|
87 | return
|
88 | }
|
89 |
|
90 | var expr = parseExpression()
|
91 |
|
92 | if (!parseOperator(')')) {
|
93 | throw new Error('Expected `)`')
|
94 | }
|
95 |
|
96 | return expr
|
97 | }
|
98 |
|
99 | function parseAtom () {
|
100 | return (
|
101 | parseParenthesizedExpression() ||
|
102 | parseLicenseRef() ||
|
103 | parseLicense()
|
104 | )
|
105 | }
|
106 |
|
107 | function makeBinaryOpParser (operator, nextParser) {
|
108 | return function parseBinaryOp () {
|
109 | var left = nextParser()
|
110 | if (!left) {
|
111 | return
|
112 | }
|
113 |
|
114 | if (!parseOperator(operator)) {
|
115 | return left
|
116 | }
|
117 |
|
118 | var right = parseBinaryOp()
|
119 | if (!right) {
|
120 | throw new Error('Expected expression')
|
121 | }
|
122 | return {
|
123 | left: left,
|
124 | conjunction: operator.toLowerCase(),
|
125 | right: right
|
126 | }
|
127 | }
|
128 | }
|
129 |
|
130 | var parseAnd = makeBinaryOpParser('AND', parseAtom)
|
131 | var parseExpression = makeBinaryOpParser('OR', parseAnd)
|
132 |
|
133 | var node = parseExpression()
|
134 | if (!node || hasMore()) {
|
135 | throw new Error('Syntax error')
|
136 | }
|
137 | return node
|
138 | }
|