Skip to content
Parsing Arrays
step 1/5

Reading — step 1 of 5

Read

~2 min readContainers: Arrays & Objects

Parsing Arrays

The first container. Its grammar:

array = "[" [ value *( "," value ) ] "]"

Read the ABNF the way the parser will execute it: after [, either the array ends immediately, or there is a value, then zero or more of (comma, value), then ]. The comma is a separator, never a terminator — that single fact generates half of JSON's rejection cases.

parseArray():
    expect "["
    if peek() == "]": consume(); return []
    out = [parseValue()]
    while peek() == ",":
        consume(",")
        out.append(parseValue())    # a value MUST follow every comma
    expect "]"
    return out

The invariant to internalize: after consuming a comma you are obligated to parse a value. If the next token is ], that is the trailing-comma error — [1, 2,] is invalid JSON, full stop, even though JavaScript and JSON5 allow it. (Copy-pasting a JS literal into a .json file is the classic way to hit this.) Symmetrically, [,1] fails because the first thing after [ must be a value or ], and [1 2] fails at expect time because neither , nor ] follows the first value.

Everything else falls out of recursion:

  • Heterogeneous by design. [1, "two", true, null, [3, 4]] is fine; elements each go through parseValue, which does not care what its neighbors were.
  • Nesting costs nothing. parseArray calls parseValue which may call parseArray — mutual recursion mirrors the grammar exactly. Resist flattening this into a hand-rolled state machine; the recursive shape is the readable, verifiable one (a later lesson deals with adversarial depth).
  • Whitespace between any two tokens. [ 1 , 2 ], even split across lines, tokenizes identically to [1,2].

The trap is a loop that treats the comma as optional garnish, e.g. "keep parsing values while there are values, skip commas whenever seen". That accepts [1,] and [1 2] and [,] alike. The grammar-shaped loop above cannot: each comma commits you to one more value.

Your exercise

Parse one array per line and print the Python repr of the resulting list — that formatting is free: repr of [1, "two", True, None] is exactly the expected [1, 'two', True, None], single quotes and capitalized keywords included; do not hand-format. Two grader-caught mistakes: (1) [1, 2,] must print exactly ERR trailing comma — raise ValueError("trailing comma") when ] appears where the post-comma value should be; (2) hidden test [1.5e2, -0.5] must print [150.0, -0.5] — your element parser must apply the scalar rule (./e/E present → float, else int), so reuse the previous lesson's number handling instead of shortcutting with int(). One note: the starter imports the stdlib json module — leave it unused; the output format is repr, and parsing with it defeats the exercise.

Discussion

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

Sign in to post a comment or reply.

Loading…