Files
2026-09-09 20:00:11 -04:00

142 lines
6.3 KiB
C

#ifdef INTELLISENSE_DIRECTIVES
# pragma once
# include "duffle/dsl.h"
# include "duffle/memory.h"
# include "duffle/text.h"
#endif
typedef Enum_(U1, X8616_InfoKind) {
x8616_info_note = 0x0,
x8616_info_warning = 0x1,
x8616_info_error = 0x2,
};
typedef Enum_(U1, X8616_InfoCode) {
x8616_info_none = 0x00,
x8616_info_invalid_opcode = 0x01,
x8616_info_invalid_opcode_extension = 0x02,
x8616_info_invalid_post_opcode = 0x03,
x8616_info_truncated_instruction = 0x04,
x8616_info_output_full = 0x05,
x8616_info_gen_multiple_payloads = 0x06,
x8616_info_gen_body_cap_exceeded = 0x07,
x8616_info_gen_aux_cap_exceeded = 0x08,
x8616_info_gen_ambiguous_decode = 0x09,
x8616_info_gen_dispatch_mismatch = 0x0A,
x8616_info_serialize_bad_request = 0x0B,
x8616_info_serialize_invalid_record = 0x0C,
x8616_info_serialize_unsupported_form = 0x0D,
x8616_info_serialize_output_full = 0x0E,
x8616_info_parse_bad_request = 0x0F,
x8616_info_parse_syntax = 0x10,
x8616_info_parse_unknown_mnemonic = 0x11,
x8616_info_parse_output_full = 0x12,
x8616_info_parse_invalid_record = 0x13,
x8616_info_parse_unsupported_form = 0x14,
x8616_info_encode_bad_request = 0x15,
x8616_info_encode_invalid_record = 0x16,
x8616_info_encode_output_full = 0x17,
x8616_info_count,
};
/* The hot path stores structured diagnostic facts only.
Human-readable text is a projection of those facts. */
typedef Struct_(X8616_InfoMsg) {
X8616_InfoMsg* next;
X8616_InfoKind kind;
X8616_InfoCode code;
U2 source_size;
U4 source_offset;
U4 expected;
U4 actual;
Str8 text;
};
/* Static templates use the same <identifier> vocabulary as Duffle's str8_fmt_ktl_buf path.
The decoder itself never expands these. */
RO_ global Str8 x8616_info_templates[x8616_info_count] = {
[x8616_info_none] = slit8(""),
[x8616_info_invalid_opcode] = slit8("Header <actual> is not in the Part 1 8086 decode table at <offset>."),
[x8616_info_invalid_opcode_extension] = slit8("Opcode extension <actual> does not match the selected encoding at <offset>."),
[x8616_info_invalid_post_opcode] = slit8("Post-opcode byte <actual> does not match expected <expected> at <offset>."),
[x8616_info_truncated_instruction] = slit8("Instruction at <offset> needs <expected> bytes; <actual> are available."),
[x8616_info_output_full] = slit8("Decoded-instruction output is full: capacity <expected>, produced <actual>."),
[x8616_info_gen_multiple_payloads] = slit8("Encoding <offset> describes more than one stream payload."),
[x8616_info_gen_body_cap_exceeded] = slit8("Encoding <offset> requires <actual> body bytes; decoder body capacity is <expected>."),
[x8616_info_gen_aux_cap_exceeded] = slit8("Generated auxiliary decode table exceeds capacity <expected>."),
[x8616_info_gen_ambiguous_decode] = slit8("Decode is ambiguous for header/second-byte key <offset>: plans <expected> and <actual>."),
[x8616_info_gen_dispatch_mismatch] = slit8("Generated dispatch mismatch for header/second-byte key <offset>: expected <expected>, actual <actual>."),
[x8616_info_serialize_bad_request] = slit8("Serialize request is missing instructions, output, scratch, or info arena."),
[x8616_info_serialize_invalid_record] = slit8("Serialize record <offset> is not printable (op <actual>)."),
[x8616_info_serialize_unsupported_form] = slit8("Serialize record <offset> has an unsupported display form (op <actual>)."),
[x8616_info_serialize_output_full] = slit8("Serialize output is full at record <offset>: capacity <expected>, produced <actual>."),
[x8616_info_parse_bad_request] = slit8("Parse request is missing source, output, or info arena."),
[x8616_info_parse_syntax] = slit8("Parse syntax error at <offset>."),
[x8616_info_parse_unknown_mnemonic] = slit8("Unknown mnemonic at <offset>."),
[x8616_info_parse_output_full] = slit8("Parse output is full: capacity <expected>, produced <actual>."),
[x8616_info_parse_invalid_record] = slit8("Parse record at <offset> is not a valid instruction (op <actual>)."),
[x8616_info_parse_unsupported_form] = slit8("Parse record at <offset> has an unsupported form (op <actual>)."),
[x8616_info_encode_bad_request] = slit8("Encode request is missing instructions, output, or info arena."),
[x8616_info_encode_invalid_record] = slit8("Encode record <offset> is invalid or truncated (op <actual>)."),
[x8616_info_encode_output_full] = slit8("Encode output is full at record <offset>: capacity <expected>, produced <actual>."),
};
typedef Struct_(X8616_InfoList) {
X8616_InfoMsg* first;
X8616_InfoMsg* last;
U4 count;
U4 error_count;
U4 warning_count;
U4 dropped_count;
};
I_ Str8 x8616_info_template(X8616_InfoCode code) { return code < x8616_info_count ? x8616_info_templates[code] : x8616_info_templates[x8616_info_none]; }
FI_ void x8616_info_push(FArena_R scratch
, X8616_InfoList_R msgs
, X8616_InfoKind kind
, X8616_InfoCode code
, U4 source_offset
, U2 source_size
, U4 expected
, U4 actual
){
assert(scratch != nullptr);
msgs->count += 1;
msgs->error_count += kind == x8616_info_error;
msgs->warning_count += kind == x8616_info_warning;
U4 allocation_size = align_pow2(S_(X8616_InfoMsg), MEM_ALIGNMENT_DEFAULT);
U4 left = scratch->capacity - scratch->used;
if (allocation_size > left) { ++ msgs->dropped_count; return; }
X8616_InfoMsg_R msg = farena_push_type(scratch, X8616_InfoMsg);
// msg[0] = (X8616_InfoMsg){0};
msg->kind = kind;
msg->code = code;
msg->source_offset = source_offset;
msg->source_size = source_size;
msg->expected = expected;
msg->actual = actual;
msg->text = x8616_info_template(code);
sll_queue_push_n(msgs->first, msgs->last, msg, next);
}
typedef Struct_(X8616_InfoTextValues) { Str8 offset; Str8 expected; Str8 actual; };
FI_ Str8
x8616_info_render(Slice output, X8616_InfoMsg_R msg, X8616_InfoTextValues values) {
KTL_Slot_Str8 slots[] = {
{ ktl_str8_key("offset"), values.offset },
{ ktl_str8_key("expected"), values.expected },
{ ktl_str8_key("actual"), values.actual },
};
return str8_fmt_ktl_buf(output, ktl_str8_from_arr(slots), msg->text);
}