docs: function read(lexer, precedence) {
  
    precedence = precedence || 0;
  
    var form = read_via_closest_dialect(lexer);
  
    // are we a prefix unary operator?
    var leftForm = form;
    if(sl.isAtom(form)) {
      var opSpec = getOperatorSpecFor(form, lexer.dialects);
      if(opSpec && isEnabled(opSpec.prefix) && opSpec.prefix.transform &&
        // "nospace" prefix ops must butt up against their arg so
        // "--i" not "-- i" this way we can't confuse e.g. (- x y)
        //  with (-x y)
        (!opSpec.options || !opSpec.options.nospace || !lexer.onwhitespace(-1)))
      {
        leftForm = opSpec.prefix.transform(lexer, opSpec.prefix, form);
      }
    }
  
    // note flipped check below from < to > because our precedences
    // are currently as you see them here: http://www.scriptingmaster.com/javascript/operator-precedence.asp
    // not as you see them here:  http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
    var token, opSpecObj;
    while(!lexer.eos() && (token = lexer.peek_token()) &&
      (opSpecObj = getOperatorSpecFor(token.text, lexer.dialects)) &&
      opSpecObj && (isEnabled(opSpecObj.infix) || isEnabled(opSpecObj.postfix)))
    {
      // make sure we don't misinterpet e.g. "(get ++i)" as "(get++ i)"
     if(opSpecObj.prefix && opSpecObj.postfix &&
       (lexer.onwhitespace(-1) && !lexer.onwhitespace(token.text.length)))
     {
       break; // let it be prefix next time round
     }
  
      // we don't distinguish infix from postfix below:
      var opSpec = opSpecObj.infix || opSpecObj.postfix;
  
      // we only keep scanning if we're hitting *higher* precedence
      if((opSpec.precedence || 0) <= precedence) {
        trace("read of infix/postfix stopping because op precedence " + (opSpec.precedence || 0) +
              " is <= the current precendence of " + precedence);
        break; // stop scanning
      }
  
      token = lexer.next_token();
      leftForm = opSpec.transform(lexer, opSpec, leftForm, sl.atom(token));
    }
  
    if(sl.isList(leftForm)) {
      // now that we've finished reading the list,
      // pop any local dialects whose scope has ended
      pop_local_dialects(lexer, leftForm);
    }
  
    return leftForm;
  }