A JSON parser
Stage 3 of 7v3 · 47951496

Numbers without shortcuts

Implement JSON's grammar for integers, fractions and exponents.

The project contract

Your program must read one JSON document from standard input. If it is valid, write that same value to standard output serialized as compact JSON and exit with code 0. If it is not valid, write nothing to stdout, explain the error on stderr and exit with a code other than 0.

The tester runs, from the project root, the commands you declare in shipcode.yml:

challenge: json-parser
build: your-build-command # optional
run: your-run-command

Do not use your standard library's JSON parser, nor an equivalent dependency. You may use its data types and a serializer at the end: what you are building is the lexical and syntactic analysis.

Your goal

Add numbers following the JSON grammar: optional sign, integer part, optional fraction and optional exponent. Convert the lexeme to your language's numeric type only after you have validated its shape.

The edges matter

JSON does not allow +1, .5, 01, 1., NaN or Infinity. The leading zero is a special case: either the integer is exactly zero, or it starts between 1 and 9 and continues with digits.

Make each part advance the cursor only once it has recognized what it requires. If a period shows up, there must be at least one digit after it; if e or E shows up, the exponent needs digits too, even when it carries a sign.

Read the rule as a path

A JSON number has ordered pieces: an optional minus sign, a required integer, an optional fraction with at least one digit, and an optional exponent with required digits. The exact text occupied by the number is its lexeme. Validate that lexeme before converting it with your language's numeric tools.

Incremental implementation

Start with 0 and positive integers. Add multiple digits, then the minus sign, then fractions, and finally exponents. After every step try one input that should pass and one that should fail.

Remember: 0 and -0 are valid; 01, +1, .5, 1., NaN, and Infinity are not. 1e3, 1E+3, and 1e-3 are valid, while 1e is incomplete.

Keep locating the lexeme separate from converting it. When debugging, identify whether the cursor was reading the sign, integer, fraction, or exponent.

Before the tests

Try 0, -42, 3.14, 6.02e23, 01, +1, .5, 1., 1e, and 1e-2x.

Acceptance criteria

  • Accepts negative integers, fractions and exponents.
  • Rejects leading zeros and incomplete parts.
  • Consumes the whole number and leaves the cursor right after it.
  • Keeps a reasonable numeric result for the type you chose.

Run shipcode test --stage 02-numeros once your edge cases already fail in a controlled way.