diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-08-29 21:25:03 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-08-29 21:49:56 +0900 |
| commit | b678465c11517a5342b1ec5aa4fe21570f13a3ed (patch) | |
| tree | 6ef19e02b1cf18f5ac451e6104f6e20b475a6f52 | |
| parent | 8f352553faec69a6f29854898b93be47604aff28 (diff) | |
| download | ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.tar.gz ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.tar.zst ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.zip | |
feat: add utility function to dump any internal object as JSON
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | src/ast.c | 6 | ||||
| -rw-r--r-- | src/ast.h | 1 | ||||
| -rw-r--r-- | src/io.c | 12 | ||||
| -rw-r--r-- | src/io.h | 3 | ||||
| -rw-r--r-- | src/json.c | 107 | ||||
| -rw-r--r-- | src/json.h | 34 | ||||
| -rw-r--r-- | src/preprocess.c | 39 | ||||
| -rw-r--r-- | src/token.c | 57 | ||||
| -rw-r--r-- | src/token.h | 5 |
10 files changed, 214 insertions, 51 deletions
@@ -9,6 +9,7 @@ OBJECTS := \ $(BUILD_DIR)/codegen.o \ $(BUILD_DIR)/common.o \ $(BUILD_DIR)/io.o \ + $(BUILD_DIR)/json.o \ $(BUILD_DIR)/parse.o \ $(BUILD_DIR)/preprocess.o \ $(BUILD_DIR)/sys.o \ @@ -29,12 +29,6 @@ const char* type_kind_stringify(TypeKind k) { unreachable(); } -void type_dump(Type* ty) { - fprintf(stderr, "Type {\n"); - fprintf(stderr, " kind = %s\n", type_kind_stringify(ty->kind)); - fprintf(stderr, "}\n"); -} - Type* type_new(TypeKind kind) { Type* ty = calloc(1, sizeof(Type)); ty->kind = kind; @@ -33,7 +33,6 @@ struct Type { }; typedef struct Type Type; -void type_dump(Type* ty); Type* type_new(TypeKind kind); Type* type_new_ptr(Type* base); Type* type_new_array(Type* elem, int size); @@ -1,5 +1,17 @@ #include "io.h" #include "common.h" +#include "json.h" + +void sourcelocation_build_json(JsonBuilder* builder, SourceLocation* loc) { + jsonbuilder_object_start(builder); + jsonbuilder_object_member_start(builder, "filename"); + jsonbuilder_string(builder, loc->filename); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_member_start(builder, "line"); + jsonbuilder_integer(builder, loc->line); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_end(builder); +} InFile* infile_open(const char* filename) { FILE* in; @@ -1,6 +1,7 @@ #ifndef DUCC_IO_H #define DUCC_IO_H +#include "json.h" #include "std.h" struct SourceLocation { @@ -9,6 +10,8 @@ struct SourceLocation { }; typedef struct SourceLocation SourceLocation; +void sourcelocation_build_json(JsonBuilder* builder, SourceLocation* loc); + struct InFile { const char* buf; int pos; diff --git a/src/json.c b/src/json.c new file mode 100644 index 0000000..8abeea7 --- /dev/null +++ b/src/json.c @@ -0,0 +1,107 @@ +#include "json.h" +#include "common.h" + +struct JsonBuilder { + StrBuilder buf; + BOOL has_output_element[256]; + int depth; +}; + +JsonBuilder* jsonbuilder_new() { + JsonBuilder* b = calloc(1, sizeof(JsonBuilder)); + strbuilder_init(&b->buf); + return b; +} + +const char* jsonbuilder_get_output(JsonBuilder* b) { + return b->buf.buf; +} + +static void emit_comma_if_needed(JsonBuilder* b) { + if (b->has_output_element[b->depth - 1]) { + strbuilder_append_char(&b->buf, ','); + } +} + +void jsonbuilder_object_start(JsonBuilder* b) { + strbuilder_append_char(&b->buf, '{'); + b->has_output_element[b->depth++] = FALSE; +} + +void jsonbuilder_object_end(JsonBuilder* b) { + b->depth--; + strbuilder_append_char(&b->buf, '}'); +} + +void jsonbuilder_object_member_start(JsonBuilder* b, const char* key) { + emit_comma_if_needed(b); + jsonbuilder_string(b, key); + strbuilder_append_char(&b->buf, ':'); +} + +void jsonbuilder_object_member_end(JsonBuilder* b) { + b->has_output_element[b->depth - 1] = TRUE; +} + +void jsonbuilder_array_start(JsonBuilder* b) { + strbuilder_append_char(&b->buf, '['); + b->has_output_element[b->depth++] = FALSE; +} + +void jsonbuilder_array_end(JsonBuilder* b) { + b->depth--; + strbuilder_append_char(&b->buf, ']'); +} + +void jsonbuilder_array_element_start(JsonBuilder* b) { + emit_comma_if_needed(b); +} + +void jsonbuilder_array_element_end(JsonBuilder* b) { + b->has_output_element[b->depth - 1] = TRUE; +} + +void jsonbuilder_null(JsonBuilder* b) { + strbuilder_append_string(&b->buf, "null"); +} + +void jsonbuilder_boolean(JsonBuilder* b, BOOL value) { + strbuilder_append_string(&b->buf, value ? "true" : "false"); +} + +void jsonbuilder_integer(JsonBuilder* b, int value) { + char buf[32]; + sprintf(buf, "%d", value); + strbuilder_append_string(&b->buf, buf); +} + +void jsonbuilder_string(JsonBuilder* b, const char* value) { + if (!value) { + jsonbuilder_null(b); + return; + } + + strbuilder_append_char(&b->buf, '"'); + + for (const char* p = value; *p; p++) { + if (*p == '"') { + strbuilder_append_string(&b->buf, "\\\""); + } else if (*p == '\\') { + strbuilder_append_string(&b->buf, "\\\\"); + } else if (*p == '\b') { + strbuilder_append_string(&b->buf, "\\b"); + } else if (*p == '\f') { + strbuilder_append_string(&b->buf, "\\f"); + } else if (*p == '\n') { + strbuilder_append_string(&b->buf, "\\n"); + } else if (*p == '\r') { + strbuilder_append_string(&b->buf, "\\r"); + } else if (*p == '\t') { + strbuilder_append_string(&b->buf, "\\t"); + } else { + strbuilder_append_char(&b->buf, *p); + } + } + + strbuilder_append_char(&b->buf, '"'); +} diff --git a/src/json.h b/src/json.h new file mode 100644 index 0000000..b542f4a --- /dev/null +++ b/src/json.h @@ -0,0 +1,34 @@ +#ifndef DUCC_JSON_H +#define DUCC_JSON_H + +#include "std.h" + +struct JsonBuilder; +typedef struct JsonBuilder JsonBuilder; + +JsonBuilder* jsonbuilder_new(); +const char* jsonbuilder_get_output(JsonBuilder* b); + +void jsonbuilder_object_start(JsonBuilder* b); +void jsonbuilder_object_end(JsonBuilder* b); +void jsonbuilder_object_member_start(JsonBuilder* b, const char* key); +void jsonbuilder_object_member_end(JsonBuilder* b); + +void jsonbuilder_array_start(JsonBuilder* b); +void jsonbuilder_array_end(JsonBuilder* b); +void jsonbuilder_array_element_start(JsonBuilder* b); +void jsonbuilder_array_element_end(JsonBuilder* b); + +void jsonbuilder_null(JsonBuilder* b); +void jsonbuilder_boolean(JsonBuilder* b, BOOL value); +void jsonbuilder_integer(JsonBuilder* b, int value); +void jsonbuilder_string(JsonBuilder* b, const char* value); + +#define JSON_DUMP(x, f) \ + do { \ + JsonBuilder* _builder = jsonbuilder_new(); \ + f(_builder, (x)); \ + fprintf(stderr, "%s", jsonbuilder_get_output(_builder)); \ + } while (0) + +#endif diff --git a/src/preprocess.c b/src/preprocess.c index 3c71a53..fdc64d9 100644 --- a/src/preprocess.c +++ b/src/preprocess.c @@ -77,22 +77,6 @@ static Macro* macros_push_new(MacroArray* macros) { return ¯os->data[macros->len++]; } -static void macros_dump(MacroArray* macros) { - fprintf(stderr, "MacroArray {\n"); - fprintf(stderr, " len = %zu\n", macros->len); - fprintf(stderr, " data = [\n"); - for (int i = 0; i < macros->len; ++i) { - Macro* m = ¯os->data[i]; - fprintf(stderr, " Macro {\n"); - fprintf(stderr, " kind = %s\n", macro_kind_stringify(m->kind)); - fprintf(stderr, " name = %s\n", m->name); - fprintf(stderr, " replacements = TODO\n"); - fprintf(stderr, " }\n"); - } - fprintf(stderr, " ]\n"); - fprintf(stderr, "}\n"); -} - static void add_predefined_macros(MacroArray* macros) { Macro* m; @@ -875,19 +859,11 @@ static BOOL preprocess_if_group_or_elif_group(Preprocessor* pp, int directive_to Token* macro_name; if (consume_pp_token_if(pp, TokenKind_paren_l)) { skip_whitespaces(pp); - macro_name = next_pp_token(pp); - if (macro_name->kind != TokenKind_ident) { - fatal_error("invalid defined"); - } + macro_name = expect_pp_token(pp, TokenKind_ident); skip_whitespaces(pp); - if (next_pp_token(pp)->kind != TokenKind_paren_r) { - fatal_error("invalid defined"); - } + expect_pp_token(pp, TokenKind_paren_r); } else { - macro_name = next_pp_token(pp); - if (macro_name->kind != TokenKind_ident) { - fatal_error("invalid defined"); - } + macro_name = expect_pp_token(pp, TokenKind_ident); } BOOL is_defined = find_macro(pp, macro_name->value.string) != -1; TokenArray defined_results; @@ -1249,15 +1225,6 @@ static void remove_pp_directives(Preprocessor* pp) { } } -static void pp_dump(Token* t, BOOL include_whitespace) { - for (; t->kind != TokenKind_eof; ++t) { - if (t->kind == TokenKind_whitespace && !include_whitespace) { - continue; - } - fprintf(stderr, "%s\n", token_stringify(t)); - } -} - static char* get_ducc_include_path() { const char* self_dir = get_self_dir(); char* buf = calloc(strlen(self_dir) + strlen("/../include") + 1, sizeof(char)); diff --git a/src/token.c b/src/token.c index 70e4a41..74105f3 100644 --- a/src/token.c +++ b/src/token.c @@ -1,5 +1,6 @@ #include "token.h" #include "common.h" +#include "json.h" const char* token_kind_stringify(TokenKind k) { if (k == TokenKind_eof) @@ -283,28 +284,53 @@ BOOL is_pp_directive(TokenKind k) { k == TokenKind_pp_directive_warning; } -const char* token_stringify(Token* t) { - TokenKind k = t->kind; +const char* token_stringify(Token* tok) { + TokenKind k = tok->kind; if (k == TokenKind_pp_directive_non_directive) { - char* buf = calloc(strlen(t->value.string) + 1 + 1, sizeof(char)); - sprintf(buf, "#%s", t->value.string); + char* buf = calloc(strlen(tok->value.string) + 1 + 1, sizeof(char)); + sprintf(buf, "#%s", tok->value.string); return buf; } else if (k == TokenKind_literal_int) { const char* kind_str = token_kind_stringify(k); char* buf = calloc(10 + strlen(kind_str) + 3 + 1, sizeof(char)); - sprintf(buf, "%d (%s)", t->value.integer, kind_str); + sprintf(buf, "%d (%s)", tok->value.integer, kind_str); return buf; } else if (k == TokenKind_other || k == TokenKind_character_constant || k == TokenKind_ident || k == TokenKind_literal_str) { const char* kind_str = token_kind_stringify(k); - char* buf = calloc(strlen(t->value.string) + strlen(kind_str) + 3 + 1, sizeof(char)); - sprintf(buf, "%s (%s)", t->value.string, kind_str); + char* buf = calloc(strlen(tok->value.string) + strlen(kind_str) + 3 + 1, sizeof(char)); + sprintf(buf, "%s (%s)", tok->value.string, kind_str); return buf; } else { return token_kind_stringify(k); } } +void token_build_json(JsonBuilder* builder, Token* tok) { + jsonbuilder_object_start(builder); + jsonbuilder_object_member_start(builder, "kind"); + jsonbuilder_string(builder, token_kind_stringify(tok->kind)); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_member_start(builder, "value"); + if (tok->kind == TokenKind_pp_directive_non_directive) { + char* buf = calloc(strlen(tok->value.string) + 1 + 1, sizeof(char)); + sprintf(buf, "#%s", tok->value.string); + jsonbuilder_string(builder, buf); + } else if (tok->kind == TokenKind_literal_int) { + jsonbuilder_integer(builder, tok->value.integer); + } else if (tok->kind == TokenKind_other || tok->kind == TokenKind_character_constant || + tok->kind == TokenKind_ident || tok->kind == TokenKind_literal_str) { + jsonbuilder_string(builder, tok->value.string); + } else { + jsonbuilder_null(builder); + } + jsonbuilder_object_member_end(builder); + jsonbuilder_object_member_start(builder, "loc"); + sourcelocation_build_json(builder, &tok->loc); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_end(builder); +} + void tokens_init(TokenArray* tokens, size_t capacity) { tokens->len = 0; tokens->capacity = capacity; @@ -330,3 +356,20 @@ Token* tokens_pop(TokenArray* tokens) { if (tokens->len != 0) tokens->len--; } + +void tokens_build_json(JsonBuilder* builder, TokenArray* tokens) { + jsonbuilder_object_start(builder); + jsonbuilder_object_member_start(builder, "len"); + jsonbuilder_integer(builder, tokens->len); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_member_start(builder, "data"); + jsonbuilder_array_start(builder); + for (int i = 0; i < tokens->len; ++i) { + jsonbuilder_array_element_start(builder); + token_build_json(builder, &tokens->data[i]); + jsonbuilder_array_element_end(builder); + } + jsonbuilder_array_end(builder); + jsonbuilder_object_member_end(builder); + jsonbuilder_object_end(builder); +} diff --git a/src/token.h b/src/token.h index 7e78dfa..7a624fb 100644 --- a/src/token.h +++ b/src/token.h @@ -2,6 +2,7 @@ #define DUCC_TOKEN_H #include "io.h" +#include "json.h" enum TokenKind { TokenKind_eof, @@ -162,7 +163,8 @@ struct Token { }; typedef struct Token Token; -const char* token_stringify(Token* t); +const char* token_stringify(Token* tok); +void token_build_json(JsonBuilder* builder, Token* tok); struct TokenArray { size_t len; @@ -175,5 +177,6 @@ void tokens_init(TokenArray* tokens, size_t capacity); void tokens_reserve(TokenArray* tokens, size_t size); Token* tokens_push_new(TokenArray* tokens); Token* tokens_pop(TokenArray* tokens); +void tokens_build_json(JsonBuilder* builder, TokenArray* tokens); #endif |
