Skip to content

Handle 'null' with defaults #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions examples/03_parsing_database.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ bool parse_person(Jimp *jimp, Person *p)
if (!jimp_object_begin(jimp)) return false;
while (jimp_object_member(jimp)) {
if (strcmp(jimp->member, "name") == 0) {
if (!jimp_string(jimp, &p->name)) return false;
if (!jimp_string(jimp, &p->name, NULL)) return false;
} else if (strcmp(jimp->member, "age") == 0) {
if (!jimp_number(jimp, &p->age)) return false;
if (!jimp_number(jimp, &p->age, 0)) return false;
} else if (strcmp(jimp->member, "location") == 0) {
if (!jimp_string(jimp, &p->location)) return false;
if (!jimp_string(jimp, &p->location, NULL)) return false;
} else if (strcmp(jimp->member, "body_count") == 0) {
if (!jimp_number(jimp, &p->body_count)) return false;
if (!jimp_number(jimp, &p->body_count, 0)) return false;
} else {
jimp_unknown_member(jimp);
return false;
Expand Down Expand Up @@ -93,7 +93,7 @@ int main()
if (!jimp_array_begin(&jimp)) return 1;
while (jimp_array_item(&jimp)) {
double x = 0;
if (!jimp_number(&jimp, &x)) return 1;
if (!jimp_number(&jimp, &x, 0)) return 1;
da_append(&xs, x);
}
if (!jimp_array_end(&jimp)) return 1;
Expand Down
132 changes: 132 additions & 0 deletions examples/04_parsing_defaults.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include <stdio.h>
#include <stdbool.h>
#define NOB_IMPLEMENTATION
#define NOB_STRIP_PREFIX
#include "../thirdparty/nob.h"
#define JIMP_IMPLEMENTATION
#include "../jimp.h"

typedef struct {
const char *name;
double age;
const char *location;
double body_count;
} Person;

typedef struct {
Person *items;
size_t count;
size_t capacity;
} People;

bool parse_person(Jimp *jimp, Person *p)
{
if (!jimp_object_begin(jimp)) return false;
while (jimp_object_member(jimp)) {
if (strcmp(jimp->member, "name") == 0) {
if (!jimp_string(jimp, &p->name, strdup("Default Name"))) return false;
} else if (strcmp(jimp->member, "age") == 0) {
if (!jimp_number(jimp, &p->age, 18)) return false;
} else if (strcmp(jimp->member, "location") == 0) {
if (!jimp_string(jimp, &p->location, strdup("UNKNOWN"))) return false;
} else if (strcmp(jimp->member, "body_count") == 0) {
if (!jimp_number(jimp, &p->body_count, 69)) return false;
} else {
jimp_unknown_member(jimp);
return false;
}
}
return jimp_object_end(jimp);
}

bool parse_people(Jimp *jimp, People *ps)
{
if (!jimp_array_begin(jimp)) return false;
while (jimp_array_item(jimp)) {
Person p = {0}; // jimp_object_* uses this value as its default
if (!parse_person(jimp, &p)) return false;
da_append(ps, p);
}
if (!jimp_array_end(jimp)) return false;

return true;
}

void print_person(const Person *p)
{
printf("name = %s\n", p->name);
printf("age = %lf\n", p->age);
printf("location = %s\n", p->location);
printf("body_count = %lf\n", p->body_count);
}

typedef struct {
long *items;
size_t count;
size_t capacity;
} Numbers;

int main()
{
const char *file_path = "database_default.json";
String_Builder sb = {0};
if (!read_entire_file(file_path, &sb)) return 1;
Jimp jimp = {
.file_path = file_path,
.start = sb.items,
.end = sb.items + sb.count,
.point = sb.items,
};

People ps = {0};
Numbers xs = {0};
Numbers xs_null = {0};
if (!jimp_object_begin(&jimp)) return 1;
while (jimp_object_member(&jimp)) {
if (strcmp(jimp.member, "profile") == 0) {
if (!parse_people(&jimp, &ps)) return 1;
} else if (strcmp(jimp.member, "number") == 0) {
if (!jimp_array_begin(&jimp)) return 1;
while (jimp_array_item(&jimp)) {
double x;
if (!jimp_number(&jimp, &x, 0)) return 1;
da_append(&xs, x);
}
if (!jimp_array_end(&jimp)) return 1;
} else if (strcmp(jimp.member, "array_null") == 0) {
// The default for array is an empty array
if (!jimp_array_begin(&jimp)) return 1;
while (jimp_array_item(&jimp)) {
double x;
if (!jimp_number(&jimp, &x, 0)) return 1;
da_append(&xs_null, x);
}
if (!jimp_array_end(&jimp)) return 1;
} else {
jimp_unknown_member(&jimp);
return 1;
}
}
if (!jimp_object_end(&jimp)) return 1;

da_foreach(Person, p, &ps) {
print_person(p);
printf("\n");
}
printf("------------------------------\n");
da_foreach(long, x, &xs) {
printf("%ld ", *x);
}
printf("\n");
printf("------------------------------\n");
if(xs_null.count == 0) {
printf("[]\n");
} else {
da_foreach(long, x, &xs_null) {
printf("%ld ", *x);
}
}
printf("\n");

return 0;
}
5 changes: 4 additions & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CFLAGS=-Wall -Wextra -Wswitch-enum -ggdb

.PHONY: all
all: 01_from_readme 02_binary_tree 03_parsing_database
all: 01_from_readme 02_binary_tree 03_parsing_database 04_parsing_defaults

01_from_readme: 01_from_readme.c ../jim.h
$(CC) $(CFLAGS) -o 01_from_readme 01_from_readme.c
Expand All @@ -11,3 +11,6 @@ all: 01_from_readme 02_binary_tree 03_parsing_database

03_parsing_database: 03_parsing_database.c ../jimp.h ../thirdparty/nob.h
$(CC) $(CFLAGS) -o 03_parsing_database 03_parsing_database.c

04_parsing_defaults: 04_parsing_defaults.c ../jimp.h ../thirdparty/nob.h
$(CC) $(CFLAGS) -o 04_parsing_defaults 04_parsing_defaults.c
26 changes: 26 additions & 0 deletions examples/database_default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"number": [69, 420, null, 80085],
"array_null": null,
"profile": [
{
"location": "Wonderland",
"location": "Wonderland",
"body_count": 150,
"name": "Alice Smith",
"age": 34
},
{
"name": null,
"age": 45,
"location": "Atlantis",
"body_count": null
},
{
"name": "Ian Malcolm",
"age": 60,
"location": null,
"body_count": 400
},
null
]
}
107 changes: 74 additions & 33 deletions jimp.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ typedef struct {
double number;

const char *member;
bool value_is_null;
} Jimp;

// TODO: how do null-s fit into this entire system?
bool jimp_bool(Jimp *jimp, bool *boolean);
bool jimp_number(Jimp *jimp, double *number);
bool jimp_string(Jimp *jimp, const char **string);
bool jimp_bool(Jimp *jimp, bool *boolean, bool defaultt);
bool jimp_number(Jimp *jimp, double *number, double defaultt);
bool jimp_string(Jimp *jimp, const char **string, const char*defaultt);
bool jimp_object_begin(Jimp *jimp);
bool jimp_object_member(Jimp *jimp);
bool jimp_object_end(Jimp *jimp);
Expand Down Expand Up @@ -200,37 +200,50 @@ void jimp_diagf(Jimp *jimp, const char *fmt, ...)

static const char *jimp__token_kind(Jimp_Token token)
{
switch (token) {
case JIMP_EOF: return "end of input";
case JIMP_INVALID: return "invalid";
case JIMP_OCURLY: return "{";
case JIMP_CCURLY: return "}";
case JIMP_OBRACKET: return "[";
case JIMP_CBRACKET: return "]";
case JIMP_COMMA: return ",";
case JIMP_COLON: return ":";
case JIMP_TRUE: return "true";
case JIMP_FALSE: return "false";
case JIMP_NULL: return "null";
case JIMP_STRING: return "string";
case JIMP_NUMBER: return "number";
}
assert(0 && "unreachable");
return NULL;
switch (token) {
case JIMP_EOF: return "end of input";
case JIMP_INVALID: return "invalid";
case JIMP_OCURLY: return "{";
case JIMP_CCURLY: return "}";
case JIMP_OBRACKET: return "[";
case JIMP_CBRACKET: return "]";
case JIMP_COMMA: return ",";
case JIMP_COLON: return ":";
case JIMP_TRUE: return "true";
case JIMP_FALSE: return "false";
case JIMP_NULL: return "null";
case JIMP_STRING: return "string";
case JIMP_NUMBER: return "number";
}
assert(0 && "unreachable");
return NULL;
}

bool jimp_array_begin(Jimp *jimp)
{
return jimp__get_and_expect_token(jimp, JIMP_OBRACKET);
if (!jimp__get_token(jimp)) return false;
if(jimp->token == JIMP_NULL) {
jimp->value_is_null = true;
return true;
} else if(jimp->token != JIMP_OBRACKET) {
jimp_diagf(jimp, "ERROR: expected `%s` or `%s`, but got `%s`\n", jimp__token_kind(JIMP_OBRACKET), jimp__token_kind(JIMP_NULL), jimp__token_kind(jimp->token));
return false;
}
return true;
}

bool jimp_array_end(Jimp *jimp)
{
if(jimp->value_is_null) {
jimp->value_is_null = false;
return true;
}
return jimp__get_and_expect_token(jimp, JIMP_CBRACKET);
}

bool jimp_array_item(Jimp *jimp)
{
if(jimp->value_is_null) return false;
const char *point = jimp->point;
if (!jimp__get_token(jimp)) return false;
if (jimp->token == JIMP_COMMA) return true;
Expand All @@ -249,11 +262,19 @@ void jimp_unknown_member(Jimp *jimp)

bool jimp_object_begin(Jimp *jimp)
{
return jimp__get_and_expect_token(jimp, JIMP_OCURLY);
if (!jimp__get_token(jimp)) return false;
if(jimp->token == JIMP_NULL) {
jimp->value_is_null = true;
} else if(jimp->token != JIMP_OCURLY) {
jimp_diagf(jimp, "ERROR: expected `%s` or `%s`, but got `%s`\n", jimp__token_kind(JIMP_OCURLY), jimp__token_kind(JIMP_NULL), jimp__token_kind(jimp->token));
return false;
}
return true;
}

bool jimp_object_member(Jimp *jimp)
{
if(jimp->value_is_null) return false;
const char *point = jimp->point;
if (!jimp__get_token(jimp)) return false;
if (jimp->token == JIMP_COMMA) {
Expand All @@ -274,34 +295,54 @@ bool jimp_object_member(Jimp *jimp)

bool jimp_object_end(Jimp *jimp)
{
if(jimp->value_is_null) {
jimp->value_is_null = false;
return true;
}
return jimp__get_and_expect_token(jimp, JIMP_CCURLY);
}

bool jimp_string(Jimp *jimp, const char **string)
bool jimp_string(Jimp *jimp, const char **string, const char*defaultt)
{
if (!jimp__get_and_expect_token(jimp, JIMP_STRING)) return false;
*string = strdup(jimp->string);
if (!jimp__get_token(jimp)) return false;
if(jimp->token == JIMP_NULL) {
*string = defaultt;
} else if(jimp->token == JIMP_STRING) {
*string = strdup(jimp->string);
} else {
jimp_diagf(jimp, "ERROR: expected `%s` or `%s`, but got `%s`\n", jimp__token_kind(JIMP_STRING), jimp__token_kind(JIMP_NULL), jimp__token_kind(jimp->token));
return false;
}
return true;
}

bool jimp_bool(Jimp *jimp, bool *boolean)
bool jimp_bool(Jimp *jimp, bool *boolean, bool defaultt)
{
jimp__get_token(jimp);
if (jimp->token == JIMP_TRUE) {
if (!jimp__get_token(jimp)) return false;
if(jimp->token == JIMP_NULL) {
*boolean = defaultt;
} else if (jimp->token == JIMP_TRUE) {
*boolean = true;
} else if (jimp->token == JIMP_FALSE) {
*boolean = false;
} else {
jimp_diagf(jimp, "ERROR: expected boolean, but got `%s`\n", jimp__token_kind(jimp->token));
jimp_diagf(jimp, "ERROR: expected boolean or `%s`, but got `%s`\n", jimp__token_kind(JIMP_NULL), jimp__token_kind(jimp->token));
return false;
}
return true;
}

bool jimp_number(Jimp *jimp, double *number)
bool jimp_number(Jimp *jimp, double *number, double defaultt)
{
if (!jimp__get_and_expect_token(jimp, JIMP_NUMBER)) return false;
*number = jimp->number;
if (!jimp__get_token(jimp)) return false;
if(jimp->token == JIMP_NULL) {
*number = defaultt;
} else if(jimp->token == JIMP_NUMBER) {
*number = jimp->number;
} else {
jimp_diagf(jimp, "ERROR: expected `%s` or `%s`, but got `%s`\n", jimp__token_kind(JIMP_NUMBER), jimp__token_kind(JIMP_NULL), jimp__token_kind(jimp->token));
return false;
}
return true;
}

Expand Down