A JSON parser built from scratch in Haskell using parser combinators.
Parses any valid JSON input into a typed Haskell AST:
data JSON = JSONNULL
| JSONBool Bool
| JSONNumber Double
| JSONString String
| JSONArray [JSON]
| JSONObject [(String, JSON)]parseJSON :: String -> Either String JSON
parseJSON "null" -- Right JSONNULL
parseJSON "42" -- Right (JSONNumber 42.0)
parseJSON "[1, true, \"hello\"]" -- Right (JSONArray [...])
parseJSON "{\"key\": 42}" -- Right (JSONObject [...])
parseJSON "invalid" -- Left "..."- All JSON types:
null, booleans, numbers, strings, arrays, objects - Full string escape support:
\",\\,\/,\n,\t,\r,\b,\f,\uXXXX - Numbers as
Double: integers, negatives, floats, scientific notation (1.5e+10) - Strict number validation: no leading zeros, no trailing dot, no multiple signs
- Descriptive error messages via
Either String - Recursive: arbitrarily nested arrays and objects
The core type is a simple newtype:
newtype JSONParser a = JSONParser { runJSONParser :: String -> Either String (a, String) }Functor, Applicative, and Alternative instances are implemented from scratch with no parsing libraries, only Control.Applicative and Data.Char from the standard library. Parsers are composed from small primitives (charParser, spanParser, many) into the full JSON grammar.
cabal runReads from example.json in the project root and prints the parsed AST.
- Error messages point to the last-attempted alternative rather than the actual failure site — a consequence of the
Alternativeinstance discarding earlier errors - No
\uXXXXsurrogate pair support - Numbers use
Doubleso integer values display as42.0