docs: function(context: ParserContext): ?Token {
      // this is goofy, because it needs to recognize things like "foo = true ? :true :not_true"
      // and detect that :not_true is not a symbol
      if (
        context.reader.peek() !== ":" ||
        !/[a-zA-Z_]/.test(context.reader.peekWithOffset(1))
      )
        return null;
  
      // basically look backward until a line break not preceded by an operator or
      // a comma
      const walker = context.getTokenWalker();
      let parenCount = 0;
      const count = walker.index - 1;
      while (walker.hasPrev()) {
        const token = walker.prev();
        if (token.name === "operator") {
          if (parenCount === 0)
            if (token.value === "?" && walker.index < count) {
              // this is a ternary operator, not a symbol
              return null;
            } else if (token.value === ":") {
              break;
            }
        } else if (token.name === "punctuation") {
          switch (token.value) {
            case "(":
              parenCount--;
              break;
            case ")":
              parenCount++;
              break;
          }
        } else if (token.name === "default" && /\n/.test(token.value)) {
          if (walker.hasPrev()) {
            const prevToken = walker.peek(-1);
            if (
              prevToken.name === "operator" ||
              (prevToken.name === "punctuation" && prevToken.value === ",")
            )
              // line continuation
              continue;
          }
          break;
        }
      }
  
      // read the symbol
      let symbol = context.reader.read();
      while (!context.reader.isEOF() && /\w/.test(context.reader.peek()))
        symbol += context.reader.read();
      return context.createToken("symbol", symbol);
    }