private Token pullNumber(int firstChar) throws ProblemException {
            StringBuilder sb = new StringBuilder();
            sb.appendCodePoint(firstChar);
            boolean containedDecimalOrE = false;
            int c = nextCharRaw();
            while (c != -1 && numberChars.indexOf(c) >= 0) {
                if (c == '.' || c == 'e' || c == 'E')
                    containedDecimalOrE = true;
                sb.appendCodePoint(c);
                c = nextCharRaw();
            }
            // the last character we looked at wasn't part of the number, put it
            // back
            putBack(c);
            String s = sb.toString();
            try {
                if (containedDecimalOrE) {
                    // force floating point representation
                    return Tokens.newDouble(lineOrigin, Double.parseDouble(s), s);
                } else {
                    // this should throw if the integer is too large for Long
                    return Tokens.newLong(lineOrigin, Long.parseLong(s), s);
                }
            } catch (NumberFormatException e) {
                // not a number after all, see if it's an unquoted string.
                for (char u : s.toCharArray()) {
                    if (notInUnquotedText.indexOf(u) >= 0)
                        throw problem(asString(u), "Reserved character '" + asString(u)
                                      + "' is not allowed outside quotes", true /* suggestQuotes */);
                }
                // no evil chars so we just decide this was a string and
                // not a number.
                return Tokens.newUnquotedText(lineOrigin, s);
            }
        }