11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_civar licenses = []
41cb0ef41Sopenharmony_ci  .concat(require('spdx-license-ids'))
51cb0ef41Sopenharmony_ci  .concat(require('spdx-license-ids/deprecated'))
61cb0ef41Sopenharmony_civar exceptions = require('spdx-exceptions')
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_cimodule.exports = function (source) {
91cb0ef41Sopenharmony_ci  var index = 0
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci  function hasMore () {
121cb0ef41Sopenharmony_ci    return index < source.length
131cb0ef41Sopenharmony_ci  }
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci  // `value` can be a regexp or a string.
161cb0ef41Sopenharmony_ci  // If it is recognized, the matching source string is returned and
171cb0ef41Sopenharmony_ci  // the index is incremented. Otherwise `undefined` is returned.
181cb0ef41Sopenharmony_ci  function read (value) {
191cb0ef41Sopenharmony_ci    if (value instanceof RegExp) {
201cb0ef41Sopenharmony_ci      var chars = source.slice(index)
211cb0ef41Sopenharmony_ci      var match = chars.match(value)
221cb0ef41Sopenharmony_ci      if (match) {
231cb0ef41Sopenharmony_ci        index += match[0].length
241cb0ef41Sopenharmony_ci        return match[0]
251cb0ef41Sopenharmony_ci      }
261cb0ef41Sopenharmony_ci    } else {
271cb0ef41Sopenharmony_ci      if (source.indexOf(value, index) === index) {
281cb0ef41Sopenharmony_ci        index += value.length
291cb0ef41Sopenharmony_ci        return value
301cb0ef41Sopenharmony_ci      }
311cb0ef41Sopenharmony_ci    }
321cb0ef41Sopenharmony_ci  }
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci  function skipWhitespace () {
351cb0ef41Sopenharmony_ci    read(/[ ]*/)
361cb0ef41Sopenharmony_ci  }
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  function operator () {
391cb0ef41Sopenharmony_ci    var string
401cb0ef41Sopenharmony_ci    var possibilities = ['WITH', 'AND', 'OR', '(', ')', ':', '+']
411cb0ef41Sopenharmony_ci    for (var i = 0; i < possibilities.length; i++) {
421cb0ef41Sopenharmony_ci      string = read(possibilities[i])
431cb0ef41Sopenharmony_ci      if (string) {
441cb0ef41Sopenharmony_ci        break
451cb0ef41Sopenharmony_ci      }
461cb0ef41Sopenharmony_ci    }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci    if (string === '+' && index > 1 && source[index - 2] === ' ') {
491cb0ef41Sopenharmony_ci      throw new Error('Space before `+`')
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    return string && {
531cb0ef41Sopenharmony_ci      type: 'OPERATOR',
541cb0ef41Sopenharmony_ci      string: string
551cb0ef41Sopenharmony_ci    }
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  function idstring () {
591cb0ef41Sopenharmony_ci    return read(/[A-Za-z0-9-.]+/)
601cb0ef41Sopenharmony_ci  }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  function expectIdstring () {
631cb0ef41Sopenharmony_ci    var string = idstring()
641cb0ef41Sopenharmony_ci    if (!string) {
651cb0ef41Sopenharmony_ci      throw new Error('Expected idstring at offset ' + index)
661cb0ef41Sopenharmony_ci    }
671cb0ef41Sopenharmony_ci    return string
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  function documentRef () {
711cb0ef41Sopenharmony_ci    if (read('DocumentRef-')) {
721cb0ef41Sopenharmony_ci      var string = expectIdstring()
731cb0ef41Sopenharmony_ci      return { type: 'DOCUMENTREF', string: string }
741cb0ef41Sopenharmony_ci    }
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  function licenseRef () {
781cb0ef41Sopenharmony_ci    if (read('LicenseRef-')) {
791cb0ef41Sopenharmony_ci      var string = expectIdstring()
801cb0ef41Sopenharmony_ci      return { type: 'LICENSEREF', string: string }
811cb0ef41Sopenharmony_ci    }
821cb0ef41Sopenharmony_ci  }
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  function identifier () {
851cb0ef41Sopenharmony_ci    var begin = index
861cb0ef41Sopenharmony_ci    var string = idstring()
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci    if (licenses.indexOf(string) !== -1) {
891cb0ef41Sopenharmony_ci      return {
901cb0ef41Sopenharmony_ci        type: 'LICENSE',
911cb0ef41Sopenharmony_ci        string: string
921cb0ef41Sopenharmony_ci      }
931cb0ef41Sopenharmony_ci    } else if (exceptions.indexOf(string) !== -1) {
941cb0ef41Sopenharmony_ci      return {
951cb0ef41Sopenharmony_ci        type: 'EXCEPTION',
961cb0ef41Sopenharmony_ci        string: string
971cb0ef41Sopenharmony_ci      }
981cb0ef41Sopenharmony_ci    }
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci    index = begin
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  // Tries to read the next token. Returns `undefined` if no token is
1041cb0ef41Sopenharmony_ci  // recognized.
1051cb0ef41Sopenharmony_ci  function parseToken () {
1061cb0ef41Sopenharmony_ci    // Ordering matters
1071cb0ef41Sopenharmony_ci    return (
1081cb0ef41Sopenharmony_ci      operator() ||
1091cb0ef41Sopenharmony_ci      documentRef() ||
1101cb0ef41Sopenharmony_ci      licenseRef() ||
1111cb0ef41Sopenharmony_ci      identifier()
1121cb0ef41Sopenharmony_ci    )
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  var tokens = []
1161cb0ef41Sopenharmony_ci  while (hasMore()) {
1171cb0ef41Sopenharmony_ci    skipWhitespace()
1181cb0ef41Sopenharmony_ci    if (!hasMore()) {
1191cb0ef41Sopenharmony_ci      break
1201cb0ef41Sopenharmony_ci    }
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci    var token = parseToken()
1231cb0ef41Sopenharmony_ci    if (!token) {
1241cb0ef41Sopenharmony_ci      throw new Error('Unexpected `' + source[index] +
1251cb0ef41Sopenharmony_ci                      '` at offset ' + index)
1261cb0ef41Sopenharmony_ci    }
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci    tokens.push(token)
1291cb0ef41Sopenharmony_ci  }
1301cb0ef41Sopenharmony_ci  return tokens
1311cb0ef41Sopenharmony_ci}
132