https://github.com/jainmohit2001/coding-challenges/tree/master/src/2
Building the JSON parser step by step would be more complex than building a fully-fledged parser in this challenge.
So I started building a complete JSON parser right from the start.
The JSON parser can be considered an accumulation of various recursive functions(that behave like state diagrams). On every step, we find what type of data we are trying to parse and then call the corresponding function that parses that datatype while moving the index of the current character and returns with the value of the parsed string.
First, we need to define the different datatypes we will work with. We have JSONObject
, JSONValue
, and JSONArray
, the basic building blocks.
https://github.com/jainmohit2001/coding-challenges/blob/master/src/2/types.ts
JSONObject
: This is a dictionary where each key is of type string
and the corresponding value is of type JSONValue
.JSONArray
: This is a list of elements, each having type as JSONValue
.JSONValue
: This consists of the basic types provided by TS - string
, number
, boolean
, null
, object
, and finally JSONObject
and JSONArray
themselves.We also need to define various types of characters (or tokens) that we can expect in a given string/file. We are only defining the characters that are relevant for parsing JSON objects.
https://github.com/jainmohit2001/coding-challenges/blob/master/src/2/tokens.ts
After reviewing the JSON documentation and understanding how each type(previously declared) is parsed in a state diagram, I started by declaring various functions and their responsibilities as follows:
class JsonParser {
private pos = 0; // Represents the current index in the string
private input: string; // Represents the string that needs to be parsed
public parse(): JSONValue {}
private parseValue(): JSONValue {}
private parseObject(): JSONObject {}
private parsePair(): { key: string; value: JSONValue } {}
private parseArray(): JSONArray {}
private parseString(): string {}
private parseEscape(): string {}
private parseTrue(): boolean {}
private parseFalse(): boolean {}
private parseNull(): null {}
private parseNumber(): number {}
private parseDigits(allowMultipleZerosAtPrefix: boolean = false): string {}
private consumeWhitespace() {}
private consume(expected?: string, skip: boolean = true) {}
private hasNext(): boolean {}
private currentToken(): string {}
private isControlCode(): boolean {}
}