docs: function _first(productions) {
    var FIRST = new Map((0, _jsItertools.map)(function (key) {
      return [key, new Set()];
    }, productions.keys()));
    var updated = true;
  
    while (updated) {
      updated = false;
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;
  
      try {
        for (var _iterator = productions[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var _step$value = _slicedToArray(_step.value, 2),
              i = _step$value[0],
              rules = _step$value[1];
  
          var _iteratorNormalCompletion2 = true;
          var _didIteratorError2 = false;
          var _iteratorError2 = undefined;
  
          try {
            for (var _iterator2 = rules.values()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
              var rule = _step2.value;
              var read = true;
              var _iteratorNormalCompletion3 = true;
              var _didIteratorError3 = false;
              var _iteratorError3 = undefined;
  
              try {
                for (var _iterator3 = rule[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
                  var x = _step3.value;
                  if (!read) break;
                  read = false;
                  if (x.type === 'leaf') updated |= (0, _util.setadd)(FIRST.get(i), x.terminal);else {
                    updated |= (0, _util.setaddall)(FIRST.get(i), (0, _jsItertools.filter)(function (y) {
                      return y !== _grammar.EW;
                    }, FIRST.get(x.nonterminal)));
                    read |= (0, _jsItertools.any)((0, _jsItertools.map)(function (y) {
                      return y === _grammar.EW;
                    }, FIRST.get(x.nonterminal)));
                  }
                }
              } catch (err) {
                _didIteratorError3 = true;
                _iteratorError3 = err;
              } finally {
                try {
                  if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
                    _iterator3.return();
                  }
                } finally {
                  if (_didIteratorError3) {
                    throw _iteratorError3;
                  }
                }
              }
  
              if (read) updated |= (0, _util.setadd)(FIRST.get(i), _grammar.EW);
            }
          } catch (err) {
            _didIteratorError2 = true;
            _iteratorError2 = err;
          } finally {
            try {
              if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
                _iterator2.return();
              }
            } finally {
              if (_didIteratorError2) {
                throw _iteratorError2;
              }
            }
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    }
  
    return FIRST;
  }