diff --git a/tutorial01/leptjson.c b/tutorial01/leptjson.c index 5299fe1d..08138a76 100644 --- a/tutorial01/leptjson.c +++ b/tutorial01/leptjson.c @@ -24,10 +24,36 @@ static int lept_parse_null(lept_context* c, lept_value* v) { return LEPT_PARSE_OK; } +static int lept_parse_true(lept_context* c, lept_value* v) +{ + EXPECT(c, 't'); + if (c->json[0] != 'r' || c->json[1] != 'u' || c->json[2] != 'e') + { + return LEPT_PARSE_INVALID_VALUE; + } + c->json += 3; + v->type = LEPT_TRUE; + return LEPT_PARSE_OK; +} + +static int lept_parse_false(lept_context* c, lept_value* v) +{ + EXPECT(c, 'f'); + if (c->json[0] != 'a' || c->json[1] != 'l' || c->json[2] != 's' || c->json[3] != 'e') + { + return LEPT_PARSE_INVALID_VALUE; + } + c->json += 4; + v->type = LEPT_FALSE; + return LEPT_PARSE_OK; +} + static int lept_parse_value(lept_context* c, lept_value* v) { switch (*c->json) { case 'n': return lept_parse_null(c, v); - case '\0': return LEPT_PARSE_EXPECT_VALUE; + case 't': return lept_parse_true(c, v); + case 'f': return lept_parse_false(c, v); + case '\0': return LEPT_PARSE_EXPECT_VALUE; default: return LEPT_PARSE_INVALID_VALUE; } } @@ -38,7 +64,20 @@ int lept_parse(lept_value* v, const char* json) { c.json = json; v->type = LEPT_NULL; lept_parse_whitespace(&c); - return lept_parse_value(&c, v); + int r = lept_parse_value(&c, v); + + // check after a value and a whitespace, if there still a value + if (r == LEPT_PARSE_OK) + { + lept_parse_whitespace(&c); + + if (*(c.json) != '\0') + { + r = LEPT_PARSE_ROOT_NOT_SINGULAR; + } + } + + return r; } lept_type lept_get_type(const lept_value* v) { diff --git a/tutorial01/test.c b/tutorial01/test.c index e7672181..43952a30 100644 --- a/tutorial01/test.c +++ b/tutorial01/test.c @@ -27,6 +27,22 @@ static void test_parse_null() { EXPECT_EQ_INT(LEPT_NULL, lept_get_type(&v)); } +static void test_parse_true() +{ + lept_value v; + v.type = LEPT_NULL; + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "true")); + EXPECT_EQ_INT(LEPT_TRUE, lept_get_type(&v)); +} + +static void test_parse_false() +{ + lept_value v; + v.type = LEPT_NULL; + EXPECT_EQ_INT(LEPT_PARSE_OK, lept_parse(&v, "false")); + EXPECT_EQ_INT(LEPT_FALSE, lept_get_type(&v)); +} + static void test_parse_expect_value() { lept_value v; @@ -59,6 +75,8 @@ static void test_parse_root_not_singular() { static void test_parse() { test_parse_null(); + test_parse_true(); + test_parse_false(); test_parse_expect_value(); test_parse_invalid_value(); test_parse_root_not_singular(); diff --git a/tutorial02/leptjson.c b/tutorial02/leptjson.c index 7693e43b..66794a53 100644 --- a/tutorial02/leptjson.c +++ b/tutorial02/leptjson.c @@ -1,6 +1,7 @@ #include "leptjson.h" #include /* assert() */ #include /* NULL, strtod() */ +#include /* strlen() */ #define EXPECT(c, ch) do { assert(*c->json == (ch)); c->json++; } while(0) @@ -15,49 +16,112 @@ static void lept_parse_whitespace(lept_context* c) { c->json = p; } -static int lept_parse_true(lept_context* c, lept_value* v) { - EXPECT(c, 't'); - if (c->json[0] != 'r' || c->json[1] != 'u' || c->json[2] != 'e') - return LEPT_PARSE_INVALID_VALUE; - c->json += 3; - v->type = LEPT_TRUE; +static int lept_parse_literal(lept_context* c, lept_value* v, const char *literal) +{ + assert(literal != NULL); + EXPECT(c, literal[0]); + const char *p = literal; + size_t len = strlen(literal) - 1; + for (size_t i = 0; i < len; i++) + { + if (literal[i + 1] != c->json[i]) + { + return LEPT_PARSE_INVALID_VALUE; + } + } + c->json += len; + switch (literal[0]) + { + case 't': + v->type = LEPT_TRUE; + break; + case 'f': + v->type = LEPT_FALSE; + break; + case 'n': + v->type = LEPT_NULL; + break; + } return LEPT_PARSE_OK; } -static int lept_parse_false(lept_context* c, lept_value* v) { - EXPECT(c, 'f'); - if (c->json[0] != 'a' || c->json[1] != 'l' || c->json[2] != 's' || c->json[3] != 'e') - return LEPT_PARSE_INVALID_VALUE; - c->json += 4; - v->type = LEPT_FALSE; - return LEPT_PARSE_OK; -} - -static int lept_parse_null(lept_context* c, lept_value* v) { - EXPECT(c, 'n'); - if (c->json[0] != 'u' || c->json[1] != 'l' || c->json[2] != 'l') - return LEPT_PARSE_INVALID_VALUE; - c->json += 3; - v->type = LEPT_NULL; - return LEPT_PARSE_OK; -} +#define ISDIGIT(ch) ((ch) >= '0' && (ch) <= '9') +#define ISDIGIT1TO9(ch) ((ch) >= '1' && (ch) <= '9') static int lept_parse_number(lept_context* c, lept_value* v) { char* end; - /* \TODO validate number */ - v->n = strtod(c->json, &end); - if (c->json == end) + const char *p = c->json; + // minus sign + if (*p == '-') + { + p++; + } + // integer + if (*p == '0') + { + p++; + } + else if (ISDIGIT1TO9(*p)) + { + p++; + while (ISDIGIT(*p)) + { + p++; + } + } + else + { + return LEPT_PARSE_INVALID_VALUE; + } + // decimal digits + if (*p == '.') + { + p++; + if (!ISDIGIT(*p)) + { + return LEPT_PARSE_INVALID_VALUE; + } + p++; + while (ISDIGIT(*p)) + { + p++; + } + } + // exponent + if (*p == 'e' || *p == 'E') + { + p++; + if (*p == '+' || *p == '-') + { + p++; + } + if (!ISDIGIT(*p)) + { + return LEPT_PARSE_INVALID_VALUE; + } + p++; + while (ISDIGIT(*p)) + { + p++; + } + } + + if (p == c->json) + { return LEPT_PARSE_INVALID_VALUE; - c->json = end; + } + + v->n = strtod(c->json, NULL); + c->json = p; v->type = LEPT_NUMBER; return LEPT_PARSE_OK; } static int lept_parse_value(lept_context* c, lept_value* v) { switch (*c->json) { - case 't': return lept_parse_true(c, v); - case 'f': return lept_parse_false(c, v); - case 'n': return lept_parse_null(c, v); + case 't': return lept_parse_literal(c, v, "true"); + case 'f': return lept_parse_literal(c, v, "false"); + case 'n': return lept_parse_literal(c, v, "null"); default: return lept_parse_number(c, v); case '\0': return LEPT_PARSE_EXPECT_VALUE; } diff --git a/tutorial02/test.c b/tutorial02/test.c index 6e3ebed2..9f994668 100644 --- a/tutorial02/test.c +++ b/tutorial02/test.c @@ -70,6 +70,10 @@ static void test_parse_number() { TEST_NUMBER(1.234E+10, "1.234E+10"); TEST_NUMBER(1.234E-10, "1.234E-10"); TEST_NUMBER(0.0, "1e-10000"); /* must underflow */ + TEST_NUMBER(5E-324, "5E-324"); + TEST_NUMBER(2.2250738585072009E-308, "2.2250738585072009E-308"); + TEST_NUMBER(2.2250738585072014E-308, "2.2250738585072014E-308"); + TEST_NUMBER(1.7976931348623157E308, "1.7976931348623157E308"); } #define TEST_ERROR(error, json)\ @@ -89,7 +93,7 @@ static void test_parse_invalid_value() { TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nul"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "?"); -#if 0 + /* invalid number */ TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+0"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "+1"); @@ -99,18 +103,18 @@ static void test_parse_invalid_value() { TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "inf"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "NAN"); TEST_ERROR(LEPT_PARSE_INVALID_VALUE, "nan"); -#endif + } static void test_parse_root_not_singular() { TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "null x"); -#if 0 + /* invalid number */ TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0123"); /* after zero should be '.' or nothing */ TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0x0"); TEST_ERROR(LEPT_PARSE_ROOT_NOT_SINGULAR, "0x123"); -#endif + } static void test_parse_number_too_big() {