Skip to content
Parsing Scalar Values
step 1/5

Reading — step 1 of 5

Read

~2 min readParsing Values

Parsing Scalar Values

With tokens in hand, the parser's core is one dispatch function. Everything in JSON hangs off parseValue:

parseValue():
    if peek() == "{":            return parseObject()
    if peek() == "[":            return parseArray()
    if peek() is STRING:         return consume().value
    if peek() is NUMBER:         return int_or_float(consume().value)
    if peek() is TRUE/FALSE/NULL: consume(); return True/False/None
    error: unexpected token

This lesson covers the scalar arms. Note that since 2017, RFC 8259 allows any value at the top level — 42, "hi", and null are complete JSON documents (the older RFC 4627 required an object or array; some legacy parsers still do).

Numbers: the type is decided by the text

JSON number literals are conceptually arbitrary-precision decimals; every parser coerces them into some host type. The standard rule, which you will implement: if the literal contains a ., e, or E, it becomes a float; otherwise an int. So 1e3 parses to 1000.0 (a float — the exponent forces it), while 42 stays an exact int.

What other ecosystems do with the same text is a genuine interop minefield:

  • Pythonint or float by the rule above; ints are arbitrary precision, so 9999999999999999 survives exactly.
  • JavaScript — everything is an IEEE-754 double. Integers are exact only up to 2^53 (9007199254740992); JSON.parse("9999999999999999") silently becomes 10000000000000000. This is why APIs ship 64-bit IDs as strings.
  • Gofloat64 by default; Decoder.UseNumber() keeps the raw text for precision-sensitive work.

One quirk worth knowing: -0 is valid JSON. Parsed as an int in Python it collapses to plain 0 (int("-0") == 0); as a float it would stay -0.0.

Keywords map to host singletons

trueTrue, falseFalse, nullNone. Lowercase only — True, TRUE, Null are not JSON. And NaN/Infinity are not in the grammar at all: strict parsers reject them (JSON.parse('NaN') throws a SyntaxError), even though Python's json accepts them by default as a non-standard extension.

The trap: Python's own converters are far more lenient than JSON. float("Infinity") succeeds, float("+5") succeeds, int("1_0") is 10. If you lean on them, guard the input first — the starter routes through int()/float() and relies on the error branch to catch garbage; the next lesson builds the real validator.

Your exercise

Parse one scalar per line and print it in Python repr conventions: single-quoted strings, capitalized True/False/None. Here is the grader-caught mistake, and it is sitting in the starter itself: the shipped main() special-cases booleans and null to print lowercase true/false/null — but the tests expect input true to print exactly True and input null to print exactly None. Delete those three branches and print repr(v) for every successful parse. Keep the error text character-for-character: input garbage must print ERR not a JSON literal: 'garbage'. And check the number rule against the hidden tests: -0 prints 0, 1e3 prints 1000.0, 1.5e10 prints 15000000000.0.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…