.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / spdx-expression-parse / parse.js
1 'use strict'
2
3 // The ABNF grammar in the spec is totally ambiguous.
4 //
5 // This parser follows the operator precedence defined in the
6 // `Order of Precedence and Parentheses` section.
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     // TODO: Actually, everything is concatenated into one string
47     // for backward-compatibility but it could be better to return
48     // a nice structure.
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 }