function gen(token, groups) {
    var stack, str, n, i, l;

    switch (token.type) {


      case types.ROOT:
      case types.GROUP:
        // Ignore lookaheads for now.
        if (token.followedBy || token.notFollowedBy) { return ''; }

        // Insert placeholder until group string is generated.
        if (token.remember && token.groupNumber === undefined) {
          token.groupNumber = groups.push(null) - 1;
        }

        stack = token.options ?
          randSelect.call(this, token.options) : token.stack;

        str = '';
        for (i = 0, l = stack.length; i < l; i++) {
          str += gen.call(this, stack[i], groups);
        }

        if (token.remember) {
          groups[token.groupNumber] = str;
        }
        return str;


      case types.POSITION:
        // Do nothing for now.
        return '';


      case types.SET:
        var expandedSet = expand.call(this, token);
        if (!expandedSet.length) { return ''; }
        return String.fromCharCode(randSelect.call(this, expandedSet));


      case types.REPETITION:
        // Randomly generate number between min and max.
        n = this.randInt(token.min,
                token.max === Infinity ? token.min + this.max : token.max);

        str = '';
        for (i = 0; i < n; i++) {
          str += gen.call(this, token.value, groups);
        }

        return str;


      case types.REFERENCE:
        return groups[token.value - 1] || '';


      case types.CHAR:
        var code = this.ignoreCase && randBool.call(this) ?
          toOtherCase(token.value) : token.value;
        return String.fromCharCode(code);
    }
  }
Generate random string modeled after given tokens.

@param {Object} token
@param {Array.<String>} groups
@return {String}