#include "js.h" #include "str.h" static void comma(tobi_sb *sb, int *first) { if (*first) { *first = 0; } else { tobi_sb_ch(sb, ','); } } static void node(tobi_sb *sb, const tobi_ir *n) { int first = 1; tobi_sb_ch(sb, '{'); comma(sb, &first); tobi_sb_add(sb, "\"kind\":"); tobi_json_string(sb, tobi_ir_kind_name(n->kind)); comma(sb, &first); tobi_sb_printf(sb, "\"id\":%zu", n->id); if (n->parent_id != 0) { comma(sb, &first); tobi_sb_printf(sb, "\"parent_id\":%zu", n->parent_id); comma(sb, &first); tobi_sb_printf(sb, "\"parent_index\":%zu", n->parent_index); } comma(sb, &first); tobi_sb_printf(sb, "\"offset\":%zu", n->off); comma(sb, &first); tobi_sb_printf(sb, "\"length\":%zu", n->len); if (n->name) { comma(sb, &first); tobi_sb_add(sb, "\"name\":"); tobi_json_string(sb, n->name); } if (n->path) { comma(sb, &first); tobi_sb_add(sb, "\"path\":"); tobi_json_string(sb, n->path); } if (n->scope) { comma(sb, &first); tobi_sb_add(sb, "\"scope\":"); tobi_json_string(sb, n->scope); } if (n->str) { comma(sb, &first); tobi_sb_add(sb, "\"string\":"); tobi_json_string(sb, n->str); } if (n->target) { comma(sb, &first); tobi_sb_add(sb, "\"target\":"); tobi_json_string(sb, n->target); } if (n->has_source && n->source) { comma(sb, &first); tobi_sb_add(sb, "\"source\":"); tobi_json_string(sb, n->source); comma(sb, &first); tobi_sb_printf(sb, "\"input_index\":%zu", n->input_index); } if (n->kind == TOBI_IR_INTEGER || n->kind == TOBI_IR_PACKAGE || n->kind == TOBI_IR_FIELD || n->kind == TOBI_IR_FIELD_ELEM || n->kind == TOBI_IR_CALL || n->kind == TOBI_IR_OPREGION || n->kind == TOBI_IR_RESOURCE) { comma(sb, &first); tobi_sb_printf(sb, "\"value\":%llu", (unsigned long long)n->value); } if (n->raw_op) { comma(sb, &first); tobi_sb_printf(sb, "\"raw_opcode\":%u", n->raw_op); } if (n->kind == TOBI_IR_METHOD) { comma(sb, &first); tobi_sb_printf(sb, "\"args\":%u", n->method_args); comma(sb, &first); tobi_sb_printf(sb, "\"serialized\":%s", n->method_serialized ? "true" : "false"); comma(sb, &first); tobi_sb_printf(sb, "\"sync\":%u", n->method_sync); } if (n->bit_len || n->access_type || n->lock_rule || n->update_rule) { comma(sb, &first); tobi_sb_printf(sb, "\"bit_offset\":%llu", (unsigned long long)n->bit_off); comma(sb, &first); tobi_sb_printf(sb, "\"bit_length\":%llu", (unsigned long long)n->bit_len); comma(sb, &first); tobi_sb_printf(sb, "\"access_type\":%u", n->access_type); comma(sb, &first); tobi_sb_printf(sb, "\"lock_rule\":%u", n->lock_rule); comma(sb, &first); tobi_sb_printf(sb, "\"update_rule\":%u", n->update_rule); } comma(sb, &first); tobi_sb_add(sb, "\"children\":["); for (size_t i = 0; i < n->child_len; i++) { if (i) { tobi_sb_ch(sb, ','); } node(sb, n->child[i]); } tobi_sb_add(sb, "]}"); } static void namespace_emit(tobi_sb *sb, const tobi_parse_result *res) { tobi_sb_add(sb, "\"namespace\":["); for (size_t i = 0; i < res->ns.len; i++) { const tobi_ns_ent *e = &res->ns.items[i]; if (i) { tobi_sb_ch(sb, ','); } tobi_sb_add(sb, "{\"kind\":"); tobi_json_string(sb, tobi_ns_kind_name(e->kind)); tobi_sb_add(sb, ",\"path\":"); tobi_json_string(sb, e->path); tobi_sb_add(sb, ",\"name\":"); tobi_json_string(sb, e->name); tobi_sb_add(sb, ",\"owner\":"); tobi_json_string(sb, e->owner); tobi_sb_printf(sb, ",\"offset\":%zu,\"args\":%u,\"flags\":%u,\"external\":%s", e->off, e->args, e->flags, e->external ? "true" : "false"); if (e->target) { tobi_sb_add(sb, ",\"target\":"); tobi_json_string(sb, e->target); } if (e->has_source && e->source) { tobi_sb_add(sb, ",\"source\":"); tobi_json_string(sb, e->source); tobi_sb_printf(sb, ",\"input_index\":%zu", e->input_index); } tobi_sb_ch(sb, '}'); } tobi_sb_ch(sb, ']'); } static void meta_obj(tobi_sb *sb, const tobi_input_meta *meta) { tobi_sb_ch(sb, '{'); tobi_sb_printf(sb, "\"is_table\":%s,", meta->is_table ? "true" : "false"); tobi_sb_add(sb, "\"source\":"); tobi_json_string(sb, meta->source); tobi_sb_add(sb, ",\"signature\":"); tobi_json_string(sb, meta->signature); tobi_sb_printf(sb, ",\"table_length\":%zu,\"aml_offset\":%zu,\"aml_length\":%zu," "\"revision\":%u,\"checksum_byte\":%u,\"checksum_sum\":%u," "\"checksum_valid\":%s,\"header_hash\":%u,\"aml_hash\":%u,", meta->table_len, meta->aml_off, meta->aml_len, (unsigned)meta->revision, (unsigned)meta->checksum_byte, (unsigned)meta->checksum_sum, meta->checksum_valid ? "true" : "false", meta->header_hash, meta->aml_hash); tobi_sb_add(sb, "\"oem_id\":"); tobi_json_string(sb, meta->oem_id); tobi_sb_add(sb, ",\"oem_table_id\":"); tobi_json_string(sb, meta->oem_table_id); tobi_sb_printf(sb, ",\"oem_revision\":%u,", meta->oem_revision); tobi_sb_add(sb, "\"creator_id\":"); tobi_json_string(sb, meta->creator_id); tobi_sb_printf(sb, ",\"creator_revision\":%u}", meta->creator_revision); } static void inputs_emit(tobi_sb *sb, const tobi_parse_result *res) { tobi_sb_add(sb, "\"inputs\":["); for (size_t i = 0; i < res->input_len; i++) { if (i) { tobi_sb_ch(sb, ','); } meta_obj(sb, &res->inputs[i]); } tobi_sb_ch(sb, ']'); } char *tobi_js_emit(const tobi_parse_result *res) { tobi_sb sb; tobi_sb_init(&sb); tobi_sb_add(&sb, "{\"meta\":"); meta_obj(&sb, &res->meta); tobi_sb_ch(&sb, ','); inputs_emit(&sb, res); tobi_sb_ch(&sb, ','); tobi_sb_add(&sb, "\"diagnostics\":["); for (size_t i = 0; i < res->diag.len; i++) { if (i) { tobi_sb_ch(&sb, ','); } tobi_sb_printf(&sb, "{\"level\":"); tobi_json_string(&sb, tobi_diag_level_name(res->diag.items[i].level)); tobi_sb_printf(&sb, ",\"offset\":%zu,\"message\":", res->diag.items[i].off); tobi_json_string(&sb, res->diag.items[i].msg); if (res->diag.items[i].has_source && res->diag.items[i].source) { tobi_sb_add(&sb, ",\"source\":"); tobi_json_string(&sb, res->diag.items[i].source); tobi_sb_printf(&sb, ",\"input_index\":%zu", res->diag.items[i].input_index); } tobi_sb_ch(&sb, '}'); } tobi_sb_add(&sb, "],"); namespace_emit(&sb, res); tobi_sb_add(&sb, ",\"ir\":"); if (res->root) { node(&sb, res->root); } else { tobi_sb_add(&sb, "null"); } tobi_sb_add(&sb, "}\n"); return tobi_sb_take(&sb); }