Reading — step 1 of 5
Read
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:
- Python —
intorfloatby the rule above; ints are arbitrary precision, so9999999999999999survives exactly. - JavaScript — everything is an IEEE-754 double. Integers are exact only up to 2^53 (9007199254740992);
JSON.parse("9999999999999999")silently becomes10000000000000000. This is why APIs ship 64-bit IDs as strings. - Go —
float64by 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
true → True, false → False, null → None. 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…