// build JSON object hierarchy JSON * JSON::parse_private(Lexer *lexer) { // check token to determine what JSON type to construct Json_Token token = lexer->get_token(); switch (token) { case Object_start_token: return parse_object(lexer); case Array_start_token: return parse_array(lexer); case String_token: return new_string(lexer->token_src, lexer->token_len); case Null_token: return new_null(); case True_token: return new_boolean(true); case False_token: return new_boolean(false); case Float_token: return new_float(lexer->float_num); case Unsigned_token: return new_unsigned(lexer->unsigned_num); case Signed_token: return new_signed(lexer->signed_num); default: Serial.println(F("JSON syntax error")); } return null; }
// Parses a pair, assuming the opening left parenthesis has already been read. static struct ParseResult parse_pair(const char *text) { struct ParseResult result; result.err_type = -1; const char *s = text; s += skip_whitespace(s); if (*s == ')') { s++; result.expr = new_null(); goto chars_read; } struct ParseResult first = parse(s); s += first.chars_read; if (first.err_type != -1) { result.err_type = first.err_type; goto chars_read; } if (*s == '.') { s++; struct ParseResult second = parse(s); s += second.chars_read; if (second.err_type != -1) { result.err_type = second.err_type; release_expression(first.expr); goto chars_read; } if (*s != ')') { result.err_type = *s ? ERR_EXPECTED_RPAREN : ERR_UNEXPECTED_EOI; release_expression(first.expr); goto chars_read; } s++; result.expr = new_pair(first.expr, second.expr); } else { struct ParseResult rest = parse_pair(s); s += rest.chars_read; if (rest.err_type != -1) { result.err_type = rest.err_type; release_expression(first.expr); goto chars_read; } result.expr = new_pair(first.expr, rest.expr); } chars_read: result.chars_read = (size_t)(s - text); return result; }
// Parses any expression. struct ParseResult parse(const char *text) { struct ParseResult result; result.err_type = PARSE_SUCCESS; const char *s = text; s += skip_whitespace(s); size_t len; switch (*s) { case '\0': result.err_type = ERR_UNEXPECTED_EOI; break; case '(': s++; result = parse_pair(s); s += result.chars_read; break; case ')': result.err_type = ERR_UNEXPECTED_RPAREN; break; case '.': result.err_type = ERR_INVALID_DOT; break; case '#': len = skip_symbol(s + 1); if (len == 1 && s[1] == 't') { s += 2; result.expr = new_boolean(true); } else if (len == 1 && s[1] == 'f') { s += 2; result.expr = new_boolean(false); } else if (len > 2 && s[1] == '\\') { char c = parse_char_name(s + 2, len - 1); if (c == '\0') { s += 2; result.err_type = ERR_UNKNOWN_CHARACTER; } else { s += 1 + len; result.expr = new_character(c); } } else if (s[1] == '\\' && s[2] && !isspace(s[2])) { result.expr = new_character(s[2]); s += 3; } else { result.err_type = ERR_INVALID_LITERAL; } break; case '\'': s++; result = parse(s); s += result.chars_read; if (result.err_type == PARSE_SUCCESS) { result.expr = new_pair( new_stdmacro(F_QUOTE), new_pair(result.expr, new_null())); } break; case '`': s++; result = parse(s); s += result.chars_read; if (result.err_type == PARSE_SUCCESS) { result.expr = new_pair( new_stdmacro(F_QUASIQUOTE), new_pair(result.expr, new_null())); } break; case ',': s++; enum StandardMacro stdmacro = F_UNQUOTE; if (*s == '@') { s++; stdmacro = F_UNQUOTE_SPLICING; } result = parse(s); s += result.chars_read; if (result.err_type == PARSE_SUCCESS) { result.expr = new_pair( new_stdmacro(stdmacro), new_pair(result.expr, new_null())); } break; case '"': s++; len = skip_string(s); if (!(s[len-1] == '\\' && (len < 2 || s[len-2] == '\\')) && s[len] == '"') { result.expr = parse_string(s, len); } else { result.err_type = ERR_UNEXPECTED_EOI; } s += len; s++; break; default:; len = skip_symbol(s); assert(len > 0); Number number; if (parse_number(s, len, &number)) { result.expr = new_number(number); } else { InternId symbol_id = intern_string_n(s, len); result.expr = new_symbol(symbol_id); } s += len; break; } if (result.err_type == PARSE_SUCCESS) { s += skip_whitespace(s); assert(s > text); } result.chars_read = (size_t)(s - text); return result; }