docs: function parenfree(arity, options) {
    options = options || {};
    return function(lexer) {
      var token = lexer.next_token();
      var fnName = options.alternate || token.text;
      var formlist = sl.list(fnName);
      formlist.setOpening(token);
  
      while(formlist.length < arity + 1) {
        var nextform;
        if(options.parenthesized && options.parenthesized === formlist.length) {
          // "wrapped" here because something like (true) returns simply "true"
          nextform = read_wrapped_delimited_list(lexer, '(', ')');
        }
        // note brackets are *optional* if there's a single expression body
        else if(options.bracketed && options.bracketed === formlist.length
          && lexer.on('{'))
        {
          nextform = read_delimited_list(lexer, '{', '}');
          formlist.pushFromArray(nextform);
          nextform = undefined;  // we've added the forms so no need to below
        }
        else {
          nextform = read(lexer);
        }
  
        // some directives" don't return an actual form:
        if(nextform && !isignorableform(nextform)) {
          formlist.push(nextform);
        }
      }
  
      if(options.validate) {
        options.validate(lexer, formlist);
      }
  
      // this list was read paren free!
      //   (add metadata useful in case they're an old lisp
      //   hacker and used parens *anyway*)
      formlist.__parenoptional = true;
  
      // note we don't set the closing token's line/col
      // position - since there *is* no closing paren!
      return formlist;
    }
  }