aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-08-29 21:25:03 +0900
committernsfisis <nsfisis@gmail.com>2025-08-29 21:49:56 +0900
commitb678465c11517a5342b1ec5aa4fe21570f13a3ed (patch)
tree6ef19e02b1cf18f5ac451e6104f6e20b475a6f52 /src
parent8f352553faec69a6f29854898b93be47604aff28 (diff)
downloadducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.tar.gz
ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.tar.zst
ducc-b678465c11517a5342b1ec5aa4fe21570f13a3ed.zip
feat: add utility function to dump any internal object as JSON
Diffstat (limited to 'src')
-rw-r--r--src/ast.c6
-rw-r--r--src/ast.h1
-rw-r--r--src/io.c12
-rw-r--r--src/io.h3
-rw-r--r--src/json.c107
-rw-r--r--src/json.h34
-rw-r--r--src/preprocess.c39
-rw-r--r--src/token.c57
-rw-r--r--src/token.h5
9 files changed, 213 insertions, 51 deletions
diff --git a/src/ast.c b/src/ast.c
index 662052f..33faff1 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -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;
diff --git a/src/ast.h b/src/ast.h
index 90fdeb0..8940aee 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -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);
diff --git a/src/io.c b/src/io.c
index 859e046..5530ab7 100644
--- a/src/io.c
+++ b/src/io.c
@@ -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;
diff --git a/src/io.h b/src/io.h
index 8a96b59..89394bf 100644
--- a/src/io.h
+++ b/src/io.h
@@ -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 &macros->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 = &macros->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