diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-01-16 13:01:36 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-01-16 13:01:36 -0500 |
| commit | fbe6af81fdb1b964bb0c28f51de2458800b8274c (patch) | |
| tree | 6d65a49b911ba665a7e2c28c6619d1aa6517a744 /src/dump_analysis.cpp | |
| parent | 230d27c1cd00e7adf0ccfca2c8bb73ae1779aa4c (diff) | |
| parent | 7e5e767ba0fdde91dd66690168eff96b75c28e33 (diff) | |
| download | zig-fbe6af81fdb1b964bb0c28f51de2458800b8274c.tar.gz zig-fbe6af81fdb1b964bb0c28f51de2458800b8274c.zip | |
Merge remote-tracking branch 'origin/master' into llvm10
Diffstat (limited to 'src/dump_analysis.cpp')
| -rw-r--r-- | src/dump_analysis.cpp | 1364 |
1 files changed, 1364 insertions, 0 deletions
diff --git a/src/dump_analysis.cpp b/src/dump_analysis.cpp new file mode 100644 index 0000000000..c31438b658 --- /dev/null +++ b/src/dump_analysis.cpp @@ -0,0 +1,1364 @@ +/* + * Copyright (c) 2019 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#include "dump_analysis.hpp" +#include "compiler.hpp" +#include "analyze.hpp" +#include "config.h" +#include "ir.hpp" +#include "codegen.hpp" + +enum JsonWriterState { + JsonWriterStateInvalid, + JsonWriterStateValue, + JsonWriterStateArrayStart, + JsonWriterStateArray, + JsonWriterStateObjectStart, + JsonWriterStateObject, +}; + +#define JSON_MAX_DEPTH 10 + +struct JsonWriter { + size_t state_index; + FILE *f; + const char *one_indent; + const char *nl; + JsonWriterState state[JSON_MAX_DEPTH]; +}; + +static void jw_init(JsonWriter *jw, FILE *f, const char *one_indent, const char *nl) { + jw->state_index = 1; + jw->f = f; + jw->one_indent = one_indent; + jw->nl = nl; + jw->state[0] = JsonWriterStateInvalid; + jw->state[1] = JsonWriterStateValue; +} + +static void jw_nl_indent(JsonWriter *jw) { + assert(jw->state_index >= 1); + fprintf(jw->f, "%s", jw->nl); + for (size_t i = 0; i < jw->state_index - 1; i += 1) { + fprintf(jw->f, "%s", jw->one_indent); + } +} + +static void jw_push_state(JsonWriter *jw, JsonWriterState state) { + jw->state_index += 1; + assert(jw->state_index < JSON_MAX_DEPTH); + jw->state[jw->state_index] = state; +} + +static void jw_pop_state(JsonWriter *jw) { + assert(jw->state_index != 0); + jw->state_index -= 1; +} + +static void jw_begin_array(JsonWriter *jw) { + assert(jw->state[jw->state_index] == JsonWriterStateValue); + fprintf(jw->f, "["); + jw->state[jw->state_index] = JsonWriterStateArrayStart; +} + +static void jw_begin_object(JsonWriter *jw) { + assert(jw->state[jw->state_index] == JsonWriterStateValue); + fprintf(jw->f, "{"); + jw->state[jw->state_index] = JsonWriterStateObjectStart; +} + +static void jw_array_elem(JsonWriter *jw) { + switch (jw->state[jw->state_index]) { + case JsonWriterStateInvalid: + case JsonWriterStateValue: + case JsonWriterStateObjectStart: + case JsonWriterStateObject: + zig_unreachable(); + case JsonWriterStateArray: + fprintf(jw->f, ","); + // fallthrough + case JsonWriterStateArrayStart: + jw->state[jw->state_index] = JsonWriterStateArray; + jw_push_state(jw, JsonWriterStateValue); + jw_nl_indent(jw); + return; + } + zig_unreachable(); +} + +static void jw_write_escaped_string(JsonWriter *jw, const char *s) { + fprintf(jw->f, "\""); + for (;; s += 1) { + switch (*s) { + case 0: + fprintf(jw->f, "\""); + return; + case '"': + fprintf(jw->f, "\\\""); + continue; + case '\t': + fprintf(jw->f, "\\t"); + continue; + case '\r': + fprintf(jw->f, "\\r"); + continue; + case '\n': + fprintf(jw->f, "\\n"); + continue; + case '\b': + fprintf(jw->f, "\\b"); + continue; + case '\f': + fprintf(jw->f, "\\f"); + continue; + case '\\': + fprintf(jw->f, "\\\\"); + continue; + default: + fprintf(jw->f, "%c", *s); + continue; + } + } +} + +static void jw_object_field(JsonWriter *jw, const char *name) { + switch (jw->state[jw->state_index]) { + case JsonWriterStateInvalid: + case JsonWriterStateValue: + case JsonWriterStateArray: + case JsonWriterStateArrayStart: + zig_unreachable(); + case JsonWriterStateObject: + fprintf(jw->f, ","); + // fallthrough + case JsonWriterStateObjectStart: + jw->state[jw->state_index] = JsonWriterStateObject; + jw_push_state(jw, JsonWriterStateValue); + jw_nl_indent(jw); + jw_write_escaped_string(jw, name); + fprintf(jw->f, ": "); + return; + } + zig_unreachable(); +} + +static void jw_end_array(JsonWriter *jw) { + switch (jw->state[jw->state_index]) { + case JsonWriterStateInvalid: + case JsonWriterStateValue: + case JsonWriterStateObjectStart: + case JsonWriterStateObject: + zig_unreachable(); + case JsonWriterStateArrayStart: + fprintf(jw->f, "]"); + jw_pop_state(jw); + return; + case JsonWriterStateArray: + jw_nl_indent(jw); + jw_pop_state(jw); + fprintf(jw->f, "]"); + return; + } + zig_unreachable(); +} + + +static void jw_end_object(JsonWriter *jw) { + switch (jw->state[jw->state_index]) { + case JsonWriterStateInvalid: + zig_unreachable(); + case JsonWriterStateValue: + zig_unreachable(); + case JsonWriterStateArray: + zig_unreachable(); + case JsonWriterStateArrayStart: + zig_unreachable(); + case JsonWriterStateObjectStart: + fprintf(jw->f, "}"); + jw_pop_state(jw); + return; + case JsonWriterStateObject: + jw_nl_indent(jw); + jw_pop_state(jw); + fprintf(jw->f, "}"); + return; + } + zig_unreachable(); +} + +static void jw_null(JsonWriter *jw) { + assert(jw->state[jw->state_index] == JsonWriterStateValue); + fprintf(jw->f, "null"); + jw_pop_state(jw); +} + +static void jw_bool(JsonWriter *jw, bool x) { + assert(jw->state[jw->state_index] == JsonWriterStateValue); + if (x) { + fprintf(jw->f, "true"); + } else { + fprintf(jw->f, "false"); + } + jw_pop_state(jw); +} + +static void jw_int(JsonWriter *jw, int64_t x) { + assert(jw->state[jw->state_index] == JsonWriterStateValue); + if (x > 4503599627370496 || x < -4503599627370496) { + fprintf(jw->f, "\"%" ZIG_PRI_i64 "\"", x); + } else { + fprintf(jw->f, "%" ZIG_PRI_i64, x); + } + jw_pop_state(jw); +} + +static void jw_bigint(JsonWriter *jw, const BigInt *x) { + assert(jw->state[jw->state_index] == JsonWriterStateValue); + Buf *str = buf_alloc(); + bigint_append_buf(str, x, 10); + + if (bigint_fits_in_bits(x, 52, true)) { + fprintf(jw->f, "%s", buf_ptr(str)); + } else { + fprintf(jw->f, "\"%s\"", buf_ptr(str)); + } + jw_pop_state(jw); + + buf_destroy(str); +} + +static void jw_string(JsonWriter *jw, const char *s) { + assert(jw->state[jw->state_index] == JsonWriterStateValue); + jw_write_escaped_string(jw, s); + jw_pop_state(jw); +} + + +static void tree_print(FILE *f, ZigType *ty, size_t indent); + +static int compare_type_abi_sizes_desc(const void *a, const void *b) { + uint64_t size_a = (*(ZigType * const*)(a))->abi_size; + uint64_t size_b = (*(ZigType * const*)(b))->abi_size; + if (size_a > size_b) + return -1; + if (size_a < size_b) + return 1; + return 0; +} + +static void start_child(FILE *f, size_t indent) { + fprintf(f, "\n"); + for (size_t i = 0; i < indent; i += 1) { + fprintf(f, " "); + } +} + +static void start_peer(FILE *f, size_t indent) { + fprintf(f, ",\n"); + for (size_t i = 0; i < indent; i += 1) { + fprintf(f, " "); + } +} + +static void tree_print_struct(FILE *f, ZigType *struct_type, size_t indent) { + ZigList<ZigType *> children = {}; + uint64_t sum_from_fields = 0; + for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { + TypeStructField *field = struct_type->data.structure.fields[i]; + children.append(field->type_entry); + sum_from_fields += field->type_entry->abi_size; + } + qsort(children.items, children.length, sizeof(ZigType *), compare_type_abi_sizes_desc); + + start_peer(f, indent); + fprintf(f, "\"padding\": \"%" ZIG_PRI_u64 "\"", struct_type->abi_size - sum_from_fields); + + start_peer(f, indent); + fprintf(f, "\"fields\": ["); + + for (size_t i = 0; i < children.length; i += 1) { + if (i == 0) { + start_child(f, indent + 1); + } else { + start_peer(f, indent + 1); + } + fprintf(f, "{"); + + ZigType *child_type = children.at(i); + tree_print(f, child_type, indent + 2); + + start_child(f, indent + 1); + fprintf(f, "}"); + } + + start_child(f, indent); + fprintf(f, "]"); +} + +static void tree_print(FILE *f, ZigType *ty, size_t indent) { + start_child(f, indent); + fprintf(f, "\"type\": \"%s\"", buf_ptr(&ty->name)); + + start_peer(f, indent); + fprintf(f, "\"sizef\": \""); + zig_pretty_print_bytes(f, ty->abi_size); + fprintf(f, "\""); + + start_peer(f, indent); + fprintf(f, "\"size\": \"%" ZIG_PRI_usize "\"", ty->abi_size); + + switch (ty->id) { + case ZigTypeIdFnFrame: + return tree_print_struct(f, ty->data.frame.locals_struct, indent); + case ZigTypeIdStruct: + return tree_print_struct(f, ty, indent); + default: + start_child(f, indent); + return; + } +} + +void zig_print_stack_report(CodeGen *g, FILE *f) { + if (g->largest_frame_fn == nullptr) { + fprintf(f, "{\"error\": \"No async function frames in entire compilation.\"}\n"); + return; + } + fprintf(f, "{"); + tree_print(f, g->largest_frame_fn->frame_type, 1); + + start_child(f, 0); + fprintf(f, "}\n"); +} + +struct AnalDumpCtx { + CodeGen *g; + JsonWriter jw; + + ZigList<ZigType *> type_list; + HashMap<const ZigType *, uint32_t, type_ptr_hash, type_ptr_eql> type_map; + + ZigList<ZigPackage *> pkg_list; + HashMap<const ZigPackage *, uint32_t, pkg_ptr_hash, pkg_ptr_eql> pkg_map; + + ZigList<Buf *> file_list; + HashMap<Buf *, uint32_t, buf_hash, buf_eql_buf> file_map; + + ZigList<Tld *> decl_list; + HashMap<const Tld *, uint32_t, tld_ptr_hash, tld_ptr_eql> decl_map; + + ZigList<ZigFn *> fn_list; + HashMap<const ZigFn *, uint32_t, fn_ptr_hash, fn_ptr_eql> fn_map; + + ZigList<AstNode *> node_list; + HashMap<const AstNode *, uint32_t, node_ptr_hash, node_ptr_eql> node_map; + + ZigList<ErrorTableEntry *> err_list; + HashMap<const ErrorTableEntry *, uint32_t, err_ptr_hash, err_ptr_eql> err_map; +}; + +static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty); +static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value); + +static void anal_dump_poke_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value) { + Error err; + if (value->type != ty) { + return; + } + if ((err = ir_resolve_lazy(ctx->g, source_node, value))) { + codegen_report_errors_and_exit(ctx->g); + } + if (value->special == ConstValSpecialUndef) { + return; + } + if (value->special == ConstValSpecialRuntime) { + return; + } + switch (ty->id) { + case ZigTypeIdMetaType: { + ZigType *val_ty = value->data.x_type; + (void)anal_dump_get_type_id(ctx, val_ty); + return; + } + default: + return; + } + zig_unreachable(); +} + +static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty) { + uint32_t type_id = ctx->type_list.length; + auto existing_entry = ctx->type_map.put_unique(ty, type_id); + if (existing_entry == nullptr) { + ctx->type_list.append(ty); + } else { + type_id = existing_entry->value; + } + return type_id; +} + +static uint32_t anal_dump_get_pkg_id(AnalDumpCtx *ctx, ZigPackage *pkg) { + assert(pkg != nullptr); + uint32_t pkg_id = ctx->pkg_list.length; + auto existing_entry = ctx->pkg_map.put_unique(pkg, pkg_id); + if (existing_entry == nullptr) { + ctx->pkg_list.append(pkg); + } else { + pkg_id = existing_entry->value; + } + return pkg_id; +} + +static uint32_t anal_dump_get_file_id(AnalDumpCtx *ctx, Buf *file) { + uint32_t file_id = ctx->file_list.length; + auto existing_entry = ctx->file_map.put_unique(file, file_id); + if (existing_entry == nullptr) { + ctx->file_list.append(file); + } else { + file_id = existing_entry->value; + } + return file_id; +} + +static uint32_t anal_dump_get_node_id(AnalDumpCtx *ctx, AstNode *node) { + uint32_t node_id = ctx->node_list.length; + auto existing_entry = ctx->node_map.put_unique(node, node_id); + if (existing_entry == nullptr) { + ctx->node_list.append(node); + } else { + node_id = existing_entry->value; + } + return node_id; +} + +static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) { + uint32_t fn_id = ctx->fn_list.length; + auto existing_entry = ctx->fn_map.put_unique(fn, fn_id); + if (existing_entry == nullptr) { + ctx->fn_list.append(fn); + + // poke the fn + (void)anal_dump_get_type_id(ctx, fn->type_entry); + (void)anal_dump_get_node_id(ctx, fn->proto_node); + } else { + fn_id = existing_entry->value; + } + return fn_id; +} + +static uint32_t anal_dump_get_err_id(AnalDumpCtx *ctx, ErrorTableEntry *err) { + uint32_t err_id = ctx->err_list.length; + auto existing_entry = ctx->err_map.put_unique(err, err_id); + if (existing_entry == nullptr) { + ctx->err_list.append(err); + } else { + err_id = existing_entry->value; + } + return err_id; +} + +static uint32_t anal_dump_get_decl_id(AnalDumpCtx *ctx, Tld *tld) { + uint32_t decl_id = ctx->decl_list.length; + auto existing_entry = ctx->decl_map.put_unique(tld, decl_id); + if (existing_entry == nullptr) { + ctx->decl_list.append(tld); + + if (tld->import != nullptr) { + (void)anal_dump_get_type_id(ctx, tld->import); + } + + // poke the types + switch (tld->id) { + case TldIdVar: { + TldVar *tld_var = reinterpret_cast<TldVar *>(tld); + ZigVar *var = tld_var->var; + + if (var != nullptr) { + (void)anal_dump_get_type_id(ctx, var->var_type); + + if (var->const_value != nullptr) { + anal_dump_poke_value(ctx, var->decl_node, var->var_type, var->const_value); + } + } + break; + } + case TldIdFn: { + TldFn *tld_fn = reinterpret_cast<TldFn *>(tld); + ZigFn *fn = tld_fn->fn_entry; + + if (fn != nullptr) { + (void)anal_dump_get_type_id(ctx, fn->type_entry); + } + break; + } + default: + break; + } + + } else { + decl_id = existing_entry->value; + } + return decl_id; +} + +static void anal_dump_type_ref(AnalDumpCtx *ctx, ZigType *ty) { + uint32_t type_id = anal_dump_get_type_id(ctx, ty); + jw_int(&ctx->jw, type_id); +} + +static void anal_dump_pkg_ref(AnalDumpCtx *ctx, ZigPackage *pkg) { + uint32_t pkg_id = anal_dump_get_pkg_id(ctx, pkg); + jw_int(&ctx->jw, pkg_id); +} + +static void anal_dump_file_ref(AnalDumpCtx *ctx, Buf *file) { + uint32_t file_id = anal_dump_get_file_id(ctx, file); + jw_int(&ctx->jw, file_id); +} + +static void anal_dump_node_ref(AnalDumpCtx *ctx, AstNode *node) { + uint32_t node_id = anal_dump_get_node_id(ctx, node); + jw_int(&ctx->jw, node_id); +} + +static void anal_dump_fn_ref(AnalDumpCtx *ctx, ZigFn *fn) { + uint32_t fn_id = anal_dump_get_fn_id(ctx, fn); + jw_int(&ctx->jw, fn_id); +} + +static void anal_dump_err_ref(AnalDumpCtx *ctx, ErrorTableEntry *err) { + uint32_t err_id = anal_dump_get_err_id(ctx, err); + jw_int(&ctx->jw, err_id); +} + +static void anal_dump_decl_ref(AnalDumpCtx *ctx, Tld *tld) { + uint32_t decl_id = anal_dump_get_decl_id(ctx, tld); + jw_int(&ctx->jw, decl_id); +} + +static void anal_dump_pkg(AnalDumpCtx *ctx, ZigPackage *pkg) { + JsonWriter *jw = &ctx->jw; + + Buf full_path_buf = BUF_INIT; + os_path_join(&pkg->root_src_dir, &pkg->root_src_path, &full_path_buf); + Buf *resolve_paths[] = { &full_path_buf, }; + Buf *resolved_path = buf_alloc(); + *resolved_path = os_path_resolve(resolve_paths, 1); + + auto import_entry = ctx->g->import_table.maybe_get(resolved_path); + if (!import_entry) { + return; + } + + jw_array_elem(jw); + jw_begin_object(jw); + + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&pkg->pkg_path)); + + jw_object_field(jw, "file"); + anal_dump_file_ref(ctx, resolved_path); + + jw_object_field(jw, "main"); + anal_dump_type_ref(ctx, import_entry->value); + + jw_object_field(jw, "table"); + jw_begin_object(jw); + auto it = pkg->package_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + ZigPackage *child_pkg = entry->value; + if (child_pkg != nullptr) { + jw_object_field(jw, buf_ptr(entry->key)); + anal_dump_pkg_ref(ctx, child_pkg); + } + } + jw_end_object(jw); + + jw_end_object(jw); +} + +static void anal_dump_decl(AnalDumpCtx *ctx, Tld *tld) { + JsonWriter *jw = &ctx->jw; + + bool make_obj = tld->id == TldIdVar || tld->id == TldIdFn; + if (make_obj) { + jw_array_elem(jw); + jw_begin_object(jw); + + jw_object_field(jw, "import"); + anal_dump_type_ref(ctx, tld->import); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, tld->source_node); + + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(tld->name)); + } + + switch (tld->id) { + case TldIdVar: { + TldVar *tld_var = reinterpret_cast<TldVar *>(tld); + ZigVar *var = tld_var->var; + + if (var != nullptr) { + jw_object_field(jw, "kind"); + if (var->src_is_const) { + jw_string(jw, "const"); + } else { + jw_string(jw, "var"); + } + + if (var->is_thread_local) { + jw_object_field(jw, "threadlocal"); + jw_bool(jw, true); + } + + jw_object_field(jw, "type"); + anal_dump_type_ref(ctx, var->var_type); + + if (var->const_value != nullptr) { + jw_object_field(jw, "value"); + anal_dump_value(ctx, var->decl_node, var->var_type, var->const_value); + } + } + break; + } + case TldIdFn: { + TldFn *tld_fn = reinterpret_cast<TldFn *>(tld); + ZigFn *fn = tld_fn->fn_entry; + + if (fn != nullptr) { + jw_object_field(jw, "kind"); + jw_string(jw, "const"); + + jw_object_field(jw, "type"); + anal_dump_type_ref(ctx, fn->type_entry); + + jw_object_field(jw, "value"); + anal_dump_fn_ref(ctx, fn); + } + break; + } + default: + break; + } + + if (make_obj) { + jw_end_object(jw); + } +} + +static void anal_dump_file(AnalDumpCtx *ctx, Buf *file) { + JsonWriter *jw = &ctx->jw; + jw_string(jw, buf_ptr(file)); +} + +static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value) { + Error err; + + if (value->type != ty) { + jw_null(&ctx->jw); + return; + } + if ((err = ir_resolve_lazy(ctx->g, source_node, value))) { + codegen_report_errors_and_exit(ctx->g); + } + if (value->special == ConstValSpecialUndef) { + jw_string(&ctx->jw, "undefined"); + return; + } + if (value->special == ConstValSpecialRuntime) { + jw_null(&ctx->jw); + return; + } + switch (ty->id) { + case ZigTypeIdMetaType: { + ZigType *val_ty = value->data.x_type; + anal_dump_type_ref(ctx, val_ty); + return; + } + case ZigTypeIdFn: { + if (value->data.x_ptr.special == ConstPtrSpecialFunction) { + ZigFn *val_fn = value->data.x_ptr.data.fn.fn_entry; + anal_dump_fn_ref(ctx, val_fn); + } else { + jw_null(&ctx->jw); + } + return; + } + default: + jw_null(&ctx->jw); + return; + } + zig_unreachable(); +} + +static void anal_dump_pointer_attrs(AnalDumpCtx *ctx, ZigType *ty) { + JsonWriter *jw = &ctx->jw; + if (ty->data.pointer.explicit_alignment != 0) { + jw_object_field(jw, "align"); + jw_int(jw, ty->data.pointer.explicit_alignment); + } + if (ty->data.pointer.is_const) { + jw_object_field(jw, "const"); + jw_bool(jw, true); + } + if (ty->data.pointer.is_volatile) { + jw_object_field(jw, "volatile"); + jw_bool(jw, true); + } + if (ty->data.pointer.allow_zero) { + jw_object_field(jw, "allowZero"); + jw_bool(jw, true); + } + if (ty->data.pointer.host_int_bytes != 0) { + jw_object_field(jw, "hostIntBytes"); + jw_int(jw, ty->data.pointer.host_int_bytes); + + jw_object_field(jw, "bitOffsetInHost"); + jw_int(jw, ty->data.pointer.bit_offset_in_host); + } + + jw_object_field(jw, "elem"); + anal_dump_type_ref(ctx, ty->data.pointer.child_type); +} + +static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) { + JsonWriter *jw = &ctx->jw; + jw_array_elem(jw); + jw_begin_object(jw); + + jw_object_field(jw, "kind"); + jw_int(jw, type_id_index(ty)); + + switch (ty->id) { + case ZigTypeIdMetaType: + case ZigTypeIdBool: + case ZigTypeIdEnumLiteral: + break; + case ZigTypeIdStruct: { + if (ty->data.structure.special == StructSpecialSlice) { + jw_object_field(jw, "len"); + jw_int(jw, 2); + anal_dump_pointer_attrs(ctx, ty->data.structure.fields[slice_ptr_index]->type_entry); + break; + } + + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, ty->data.structure.decl_node); + + { + jw_object_field(jw, "pubDecls"); + jw_begin_array(jw); + + ScopeDecls *decls_scope = ty->data.structure.decls_scope; + auto it = decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *tld = entry->value; + if (tld->visib_mod == VisibModPub) { + jw_array_elem(jw); + anal_dump_decl_ref(ctx, tld); + } + } + jw_end_array(jw); + } + + { + jw_object_field(jw, "privDecls"); + jw_begin_array(jw); + + ScopeDecls *decls_scope = ty->data.structure.decls_scope; + auto it = decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *tld = entry->value; + if (tld->visib_mod == VisibModPrivate) { + jw_array_elem(jw); + anal_dump_decl_ref(ctx, tld); + } + } + jw_end_array(jw); + } + + if (ty->data.structure.src_field_count != 0) { + jw_object_field(jw, "fields"); + jw_begin_array(jw); + + for(size_t i = 0; i < ty->data.structure.src_field_count; i += 1) { + jw_array_elem(jw); + anal_dump_type_ref(ctx, ty->data.structure.fields[i]->type_entry); + } + jw_end_array(jw); + } + + if (ty->data.structure.root_struct != nullptr) { + Buf *path_buf = ty->data.structure.root_struct->path; + + jw_object_field(jw, "file"); + anal_dump_file_ref(ctx, path_buf); + } + break; + } + case ZigTypeIdUnion: { + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, ty->data.unionation.decl_node); + + { + jw_object_field(jw, "pubDecls"); + jw_begin_array(jw); + + ScopeDecls *decls_scope = ty->data.unionation.decls_scope; + auto it = decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *tld = entry->value; + if (tld->visib_mod == VisibModPub) { + jw_array_elem(jw); + anal_dump_decl_ref(ctx, tld); + } + } + jw_end_array(jw); + } + + { + jw_object_field(jw, "privDecls"); + jw_begin_array(jw); + + ScopeDecls *decls_scope = ty->data.unionation.decls_scope; + auto it = decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *tld = entry->value; + if (tld->visib_mod == VisibModPrivate) { + jw_array_elem(jw); + anal_dump_decl_ref(ctx, tld); + } + } + jw_end_array(jw); + } + + if (ty->data.unionation.src_field_count != 0) { + jw_object_field(jw, "fields"); + jw_begin_array(jw); + + for(size_t i = 0; i < ty->data.unionation.src_field_count; i += 1) { + jw_array_elem(jw); + anal_dump_type_ref(ctx, ty->data.unionation.fields[i].type_entry); + } + jw_end_array(jw); + } + break; + } + case ZigTypeIdEnum: { + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, ty->data.enumeration.decl_node); + + { + jw_object_field(jw, "pubDecls"); + jw_begin_array(jw); + + ScopeDecls *decls_scope = ty->data.enumeration.decls_scope; + auto it = decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *tld = entry->value; + if (tld->visib_mod == VisibModPub) { + jw_array_elem(jw); + anal_dump_decl_ref(ctx, tld); + } + } + jw_end_array(jw); + } + + { + jw_object_field(jw, "privDecls"); + jw_begin_array(jw); + + ScopeDecls *decls_scope = ty->data.enumeration.decls_scope; + auto it = decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *tld = entry->value; + if (tld->visib_mod == VisibModPrivate) { + jw_array_elem(jw); + anal_dump_decl_ref(ctx, tld); + } + } + jw_end_array(jw); + } + + if (ty->data.enumeration.src_field_count != 0) { + jw_object_field(jw, "fields"); + jw_begin_array(jw); + + for(size_t i = 0; i < ty->data.enumeration.src_field_count; i += 1) { + jw_array_elem(jw); + jw_bigint(jw, &ty->data.enumeration.fields[i].value); + } + jw_end_array(jw); + } + break; + } + case ZigTypeIdFloat: { + jw_object_field(jw, "bits"); + jw_int(jw, ty->data.floating.bit_count); + break; + } + case ZigTypeIdInt: { + if (ty->data.integral.is_signed) { + jw_object_field(jw, "i"); + } else { + jw_object_field(jw, "u"); + } + jw_int(jw, ty->data.integral.bit_count); + break; + } + case ZigTypeIdFn: { + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + + jw_object_field(jw, "generic"); + jw_bool(jw, ty->data.fn.is_generic); + + if (ty->data.fn.fn_type_id.return_type != nullptr) { + jw_object_field(jw, "ret"); + anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.return_type); + } + + if (ty->data.fn.fn_type_id.param_count != 0) { + jw_object_field(jw, "args"); + jw_begin_array(jw); + for (size_t i = 0; i < ty->data.fn.fn_type_id.param_count; i += 1) { + jw_array_elem(jw); + if (ty->data.fn.fn_type_id.param_info[i].type != nullptr) { + anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.param_info[i].type); + } else { + jw_null(jw); + } + } + jw_end_array(jw); + } + break; + } + case ZigTypeIdOptional: { + jw_object_field(jw, "child"); + anal_dump_type_ref(ctx, ty->data.maybe.child_type); + break; + } + case ZigTypeIdPointer: { + switch (ty->data.pointer.ptr_len) { + case PtrLenSingle: + break; + case PtrLenUnknown: + jw_object_field(jw, "len"); + jw_int(jw, 1); + break; + case PtrLenC: + jw_object_field(jw, "len"); + jw_int(jw, 3); + break; + } + anal_dump_pointer_attrs(ctx, ty); + break; + } + case ZigTypeIdErrorSet: { + if (type_is_global_error_set(ty)) { + break; + } + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + + if (ty->data.error_set.infer_fn != nullptr) { + jw_object_field(jw, "fn"); + anal_dump_fn_ref(ctx, ty->data.error_set.infer_fn); + } + jw_object_field(jw, "errors"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ty->data.error_set.err_count; i += 1) { + jw_array_elem(jw); + ErrorTableEntry *err = ty->data.error_set.errors[i]; + anal_dump_err_ref(ctx, err); + } + jw_end_array(jw); + break; + } + case ZigTypeIdErrorUnion: { + jw_object_field(jw, "err"); + anal_dump_type_ref(ctx, ty->data.error_union.err_set_type); + + jw_object_field(jw, "payload"); + anal_dump_type_ref(ctx, ty->data.error_union.payload_type); + + break; + } + case ZigTypeIdArray: { + jw_object_field(jw, "len"); + jw_int(jw, ty->data.array.len); + + jw_object_field(jw, "elem"); + anal_dump_type_ref(ctx, ty->data.array.child_type); + break; + } + default: + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&ty->name)); + break; + } + jw_end_object(jw); +} + +static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) { + JsonWriter *jw = &ctx->jw; + + jw_begin_object(jw); + + jw_object_field(jw, "file"); + anal_dump_file_ref(ctx, node->owner->data.structure.root_struct->path); + + jw_object_field(jw, "line"); + jw_int(jw, node->line); + + jw_object_field(jw, "col"); + jw_int(jw, node->column); + + const Buf *doc_comments_buf = nullptr; + const Buf *name_buf = nullptr; + const ZigList<AstNode *> *field_nodes = nullptr; + bool is_var_args = false; + bool is_noalias = false; + bool is_comptime = false; + + switch (node->type) { + case NodeTypeParamDecl: + doc_comments_buf = &node->data.param_decl.doc_comments; + name_buf = node->data.param_decl.name; + is_var_args = node->data.param_decl.is_var_args; + is_noalias = node->data.param_decl.is_noalias; + is_comptime = node->data.param_decl.is_comptime; + break; + case NodeTypeFnProto: + doc_comments_buf = &node->data.fn_proto.doc_comments; + field_nodes = &node->data.fn_proto.params; + is_var_args = node->data.fn_proto.is_var_args; + break; + case NodeTypeVariableDeclaration: + doc_comments_buf = &node->data.variable_declaration.doc_comments; + break; + case NodeTypeErrorSetField: + doc_comments_buf = &node->data.err_set_field.doc_comments; + break; + case NodeTypeStructField: + doc_comments_buf = &node->data.struct_field.doc_comments; + name_buf = node->data.struct_field.name; + break; + case NodeTypeContainerDecl: + field_nodes = &node->data.container_decl.fields; + doc_comments_buf = &node->data.container_decl.doc_comments; + break; + default: + break; + } + + if (doc_comments_buf != nullptr && doc_comments_buf->list.length != 0) { + jw_object_field(jw, "docs"); + jw_string(jw, buf_ptr(doc_comments_buf)); + } + + if (name_buf != nullptr) { + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(name_buf)); + } + + if (field_nodes != nullptr) { + jw_object_field(jw, "fields"); + jw_begin_array(jw); + for (size_t i = 0; i < field_nodes->length; i += 1) { + jw_array_elem(jw); + anal_dump_node_ref(ctx, field_nodes->at(i)); + } + jw_end_array(jw); + } + + if (is_var_args) { + jw_object_field(jw, "varArgs"); + jw_bool(jw, true); + } + + if (is_comptime) { + jw_object_field(jw, "comptime"); + jw_bool(jw, true); + } + + if (is_noalias) { + jw_object_field(jw, "noalias"); + jw_bool(jw, true); + } + + jw_end_object(jw); +} + +static void anal_dump_err(AnalDumpCtx *ctx, const ErrorTableEntry *err) { + JsonWriter *jw = &ctx->jw; + + jw_begin_object(jw); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, err->decl_node); + + jw_object_field(jw, "name"); + jw_string(jw, buf_ptr(&err->name)); + + jw_end_object(jw); +} + +static void anal_dump_fn(AnalDumpCtx *ctx, ZigFn *fn) { + JsonWriter *jw = &ctx->jw; + + jw_begin_object(jw); + + jw_object_field(jw, "src"); + anal_dump_node_ref(ctx, fn->proto_node); + + jw_object_field(jw, "type"); + anal_dump_type_ref(ctx, fn->type_entry); + + jw_end_object(jw); +} + +void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const char *nl) { + Error err; + AnalDumpCtx ctx = {}; + ctx.g = g; + JsonWriter *jw = &ctx.jw; + jw_init(jw, f, one_indent, nl); + ctx.type_map.init(16); + ctx.pkg_map.init(16); + ctx.file_map.init(16); + ctx.decl_map.init(16); + ctx.node_map.init(16); + ctx.fn_map.init(16); + ctx.err_map.init(16); + + jw_begin_object(jw); + + jw_object_field(jw, "typeKinds"); + jw_begin_array(jw); + for (size_t i = 0; i < type_id_len(); i += 1) { + jw_array_elem(jw); + jw_string(jw, type_id_name(type_id_at_index(i))); + } + jw_end_array(jw); + + jw_object_field(jw, "params"); + jw_begin_object(jw); + { + jw_object_field(jw, "zigId"); + + Buf *compiler_id; + if ((err = get_compiler_id(&compiler_id))) { + fprintf(stderr, "Unable to determine compiler id: %s\n", err_str(err)); + exit(1); + } + jw_string(jw, buf_ptr(compiler_id)); + + jw_object_field(jw, "zigVersion"); + jw_string(jw, ZIG_VERSION_STRING); + + jw_object_field(jw, "builds"); + jw_begin_array(jw); + jw_array_elem(jw); + jw_begin_object(jw); + jw_object_field(jw, "target"); + Buf triple_buf = BUF_INIT; + target_triple_zig(&triple_buf, g->zig_target); + jw_string(jw, buf_ptr(&triple_buf)); + jw_end_object(jw); + jw_end_array(jw); + + jw_object_field(jw, "rootName"); + jw_string(jw, buf_ptr(g->root_out_name)); + } + jw_end_object(jw); + + jw_object_field(jw, "rootPkg"); + anal_dump_pkg_ref(&ctx, g->main_pkg); + + // Poke the functions + for (size_t i = 0; i < g->fn_defs.length; i += 1) { + ZigFn *fn = g->fn_defs.at(i); + (void)anal_dump_get_fn_id(&ctx, fn); + } + + jw_object_field(jw, "calls"); + jw_begin_array(jw); + { + ZigList<ZigVar *> var_stack = {}; + + auto it = g->memoized_fn_eval_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + var_stack.resize(0); + ZigFn *fn = nullptr; + + Scope *scope = entry->key; + while (scope != nullptr) { + if (scope->id == ScopeIdVarDecl) { + ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var; + var_stack.append(var); + } else if (scope->id == ScopeIdFnDef) { + fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry; + break; + } + scope = scope->parent; + } + ZigValue *result = entry->value; + + assert(fn != nullptr); + + jw_array_elem(jw); + jw_begin_object(jw); + + jw_object_field(jw, "fn"); + anal_dump_fn_ref(&ctx, fn); + + jw_object_field(jw, "result"); + { + jw_begin_object(jw); + + jw_object_field(jw, "type"); + anal_dump_type_ref(&ctx, result->type); + + jw_object_field(jw, "value"); + anal_dump_value(&ctx, scope->source_node, result->type, result); + + jw_end_object(jw); + } + + if (var_stack.length != 0) { + jw_object_field(jw, "args"); + jw_begin_array(jw); + + while (var_stack.length != 0) { + ZigVar *var = var_stack.pop(); + + jw_array_elem(jw); + jw_begin_object(jw); + + jw_object_field(jw, "type"); + anal_dump_type_ref(&ctx, var->var_type); + + jw_object_field(jw, "value"); + anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value); + + jw_end_object(jw); + } + jw_end_array(jw); + } + + jw_end_object(jw); + } + + var_stack.deinit(); + } + jw_end_array(jw); + + jw_object_field(jw, "packages"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.pkg_list.length; i += 1) { + anal_dump_pkg(&ctx, ctx.pkg_list.at(i)); + } + jw_end_array(jw); + + jw_object_field(jw, "types"); + jw_begin_array(jw); + + for (uint32_t i = 0; i < ctx.type_list.length; i += 1) { + ZigType *ty = ctx.type_list.at(i); + anal_dump_type(&ctx, ty); + } + jw_end_array(jw); + + jw_object_field(jw, "decls"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.decl_list.length; i += 1) { + Tld *decl = ctx.decl_list.at(i); + anal_dump_decl(&ctx, decl); + } + jw_end_array(jw); + + jw_object_field(jw, "fns"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) { + ZigFn *fn = ctx.fn_list.at(i); + jw_array_elem(jw); + anal_dump_fn(&ctx, fn); + } + jw_end_array(jw); + + jw_object_field(jw, "errors"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.err_list.length; i += 1) { + const ErrorTableEntry *err = ctx.err_list.at(i); + jw_array_elem(jw); + anal_dump_err(&ctx, err); + } + jw_end_array(jw); + + jw_object_field(jw, "astNodes"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.node_list.length; i += 1) { + const AstNode *node = ctx.node_list.at(i); + jw_array_elem(jw); + anal_dump_node(&ctx, node); + } + jw_end_array(jw); + + jw_object_field(jw, "files"); + jw_begin_array(jw); + for (uint32_t i = 0; i < ctx.file_list.length; i += 1) { + Buf *file = ctx.file_list.at(i); + jw_array_elem(jw); + anal_dump_file(&ctx, file); + } + jw_end_array(jw); + + jw_end_object(jw); +} |
