kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 26a7338891273c9c3c5d5b7b3a0710b002bc9bd3
parent 58cae09b4b02e5c3df711540a0572f21f7da59db
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed,  3 Jun 2026 10:30:28 -0700

toy: table-drive dot-const parsers, flag loops, mem-xfer scaffolding

Fold nine .name->enum if/else-if parsers onto a shared ToyConstRow table
plus toy_lookup_const/toy_parse_dot_const helpers, reuse the same table for
the three flag-mask loops via toy_parse_flag_set, and merge the byte-identical
memcpy/memmove builtins into toy_parse_mem_copy_move(is_move). Diagnostics,
IDENT-vs-keyword strictness, and the memset specifics are preserved.

(cherry picked from commit 5ecac80632017e970727ab0d01468e098470357b)

Diffstat:
Mlang/toy/asm.c | 55+++++++++++++++++++------------------------------------
Mlang/toy/attrs.c | 31+++++++++----------------------
Mlang/toy/builtins.c | 289++++++++++++++++++++++++++++---------------------------------------------------
Mlang/toy/expr.c | 170++++++++++++++++++++++++++++---------------------------------------------------
Mlang/toy/internal.h | 32++++++++++++++++++++++++++++++++
Mlang/toy/parser_core.c | 49+++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 270 insertions(+), 356 deletions(-)

diff --git a/lang/toy/asm.c b/lang/toy/asm.c @@ -279,33 +279,22 @@ static int toy_asm_record_field_by_name(ToyParser* p, KitCgTypeId record_ty, } static int toy_parse_asm_flags(ToyParser* p, uint32_t* flags) { + static const ToyConstRow rows[] = { + {"volatile", KIT_CG_ASM_VOLATILE}, + {"pure", KIT_CG_ASM_PURE}, + {"nomem", KIT_CG_ASM_NOMEM}, + {"readonly", KIT_CG_ASM_READONLY}, + {"preserves_flags", KIT_CG_ASM_PRESERVES_FLAGS}, + {"nostack", KIT_CG_ASM_NOSTACK}, + {"noreturn", KIT_CG_ASM_NORETURN}, + }; if (!toy_expect_ident(p, "flags") || !toy_parser_expect(p, TOK_LPAREN)) { toy_error(p, p->cur.loc, "expected flags(...)"); return 0; } - while (p->cur.kind != TOK_RPAREN && p->cur.kind != TOK_EOF) { - KitSym name; - if (!toy_parse_attr_dot_name(p, &name)) return 0; - if (toy_sym_is(p, name, "volatile")) - *flags |= KIT_CG_ASM_VOLATILE; - else if (toy_sym_is(p, name, "pure")) - *flags |= KIT_CG_ASM_PURE; - else if (toy_sym_is(p, name, "nomem")) - *flags |= KIT_CG_ASM_NOMEM; - else if (toy_sym_is(p, name, "readonly")) - *flags |= KIT_CG_ASM_READONLY; - else if (toy_sym_is(p, name, "preserves_flags")) - *flags |= KIT_CG_ASM_PRESERVES_FLAGS; - else if (toy_sym_is(p, name, "nostack")) - *flags |= KIT_CG_ASM_NOSTACK; - else if (toy_sym_is(p, name, "noreturn")) - *flags |= KIT_CG_ASM_NORETURN; - else { - toy_error(p, p->cur.loc, "unknown asm flag"); - return 0; - } - if (!toy_parser_match(p, TOK_COMMA)) break; - } + if (!toy_parse_flag_set(p, rows, sizeof rows / sizeof rows[0], "asm flag", 0, + flags)) + return 0; if (!toy_parser_expect(p, TOK_RPAREN)) { toy_error(p, p->cur.loc, "expected ')' after asm flags"); return 0; @@ -314,24 +303,18 @@ static int toy_parse_asm_flags(ToyParser* p, uint32_t* flags) { } static int toy_parse_asm_clobber_abi(ToyParser* p, uint32_t* clobber_abi_sets) { + static const ToyConstRow rows[] = { + {"caller_saved", KIT_CG_ASM_CLOBBER_ABI_CALLER_SAVED}, + {"callee_saved", KIT_CG_ASM_CLOBBER_ABI_CALLEE_SAVED}, + }; if (!toy_expect_ident(p, "clobber_abi") || !toy_parser_expect(p, TOK_LPAREN)) { toy_error(p, p->cur.loc, "expected clobber_abi(...)"); return 0; } - while (p->cur.kind != TOK_RPAREN && p->cur.kind != TOK_EOF) { - KitSym name; - if (!toy_parse_attr_dot_name(p, &name)) return 0; - if (toy_sym_is(p, name, "caller_saved")) - *clobber_abi_sets |= KIT_CG_ASM_CLOBBER_ABI_CALLER_SAVED; - else if (toy_sym_is(p, name, "callee_saved")) - *clobber_abi_sets |= KIT_CG_ASM_CLOBBER_ABI_CALLEE_SAVED; - else { - toy_error(p, p->cur.loc, "unknown asm clobber ABI"); - return 0; - } - if (!toy_parser_match(p, TOK_COMMA)) break; - } + if (!toy_parse_flag_set(p, rows, sizeof rows / sizeof rows[0], + "asm clobber ABI", 0, clobber_abi_sets)) + return 0; if (!toy_parser_expect(p, TOK_RPAREN)) { toy_error(p, p->cur.loc, "expected ')' after asm clobber ABI"); return 0; diff --git a/lang/toy/attrs.c b/lang/toy/attrs.c @@ -51,29 +51,16 @@ static int toy_parse_attr_string_arg(ToyParser* p, KitSym* out) { } int toy_parse_callconv_const(ToyParser* p, KitCgCallConv* out) { - KitSym name; - if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { - toy_error(p, p->cur.loc, "expected call convention"); + static const ToyConstRow rows[] = { + {"target_c", KIT_CG_CC_TARGET_C}, {"sysv", KIT_CG_CC_SYSV}, + {"win64", KIT_CG_CC_WIN64}, {"aapcs", KIT_CG_CC_AAPCS}, + {"wasm", KIT_CG_CC_WASM}, {"interrupt", KIT_CG_CC_INTERRUPT}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, + "call convention", "call convention", &v)) return 0; - } - name = toy_tok_sym(p, p->cur); - toy_parser_advance(p); - if (toy_sym_is(p, name, "target_c")) - *out = KIT_CG_CC_TARGET_C; - else if (toy_sym_is(p, name, "sysv")) - *out = KIT_CG_CC_SYSV; - else if (toy_sym_is(p, name, "win64")) - *out = KIT_CG_CC_WIN64; - else if (toy_sym_is(p, name, "aapcs")) - *out = KIT_CG_CC_AAPCS; - else if (toy_sym_is(p, name, "wasm")) - *out = KIT_CG_CC_WASM; - else if (toy_sym_is(p, name, "interrupt")) - *out = KIT_CG_CC_INTERRUPT; - else { - toy_error(p, p->cur.loc, "unknown call convention"); - return 0; - } + *out = (KitCgCallConv)v; return 1; } diff --git a/lang/toy/builtins.c b/lang/toy/builtins.c @@ -10,17 +10,9 @@ static KitCgMemAccess toy_mem_access_align(ToyParser* p, KitCgTypeId type, } static int toy_parse_mem_flags_tail(ToyParser* p, KitCgMemAccess* access) { - while (toy_parser_match(p, TOK_COMMA)) { - KitSym flag; - if (!toy_parse_attr_dot_name(p, &flag)) return 0; - if (toy_sym_is(p, flag, "volatile")) - access->flags |= KIT_CG_MEM_VOLATILE; - else { - toy_error(p, p->cur.loc, "unknown memory access flag"); - return 0; - } - } - return 1; + static const ToyConstRow rows[] = {{"volatile", KIT_CG_MEM_VOLATILE}}; + return toy_parse_flag_set(p, rows, sizeof rows / sizeof rows[0], + "memory access flag", 1, &access->flags); } static void toy_store_top_to_local(ToyParser* p, KitCgLocal local, @@ -151,72 +143,45 @@ static int toy_parse_optional_access_arg(ToyParser* p, KitCgMemAccess* access) { } static int toy_parse_mem_order(ToyParser* p, KitCgMemOrder* out) { - KitSym name; - if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { - toy_error(p, p->cur.loc, "expected memory order"); - return 0; - } - name = toy_tok_sym(p, p->cur); - toy_parser_advance(p); - if (toy_sym_is(p, name, "relaxed")) - *out = KIT_CG_MO_RELAXED; - else if (toy_sym_is(p, name, "consume")) - *out = KIT_CG_MO_CONSUME; - else if (toy_sym_is(p, name, "acquire")) - *out = KIT_CG_MO_ACQUIRE; - else if (toy_sym_is(p, name, "release")) - *out = KIT_CG_MO_RELEASE; - else if (toy_sym_is(p, name, "acq_rel")) - *out = KIT_CG_MO_ACQ_REL; - else if (toy_sym_is(p, name, "seq_cst")) - *out = KIT_CG_MO_SEQ_CST; - else { - toy_error(p, p->cur.loc, "unknown memory order"); + static const ToyConstRow rows[] = { + {"relaxed", KIT_CG_MO_RELAXED}, {"consume", KIT_CG_MO_CONSUME}, + {"acquire", KIT_CG_MO_ACQUIRE}, {"release", KIT_CG_MO_RELEASE}, + {"acq_rel", KIT_CG_MO_ACQ_REL}, {"seq_cst", KIT_CG_MO_SEQ_CST}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, + "memory order", "memory order", &v)) return 0; - } + *out = (KitCgMemOrder)v; return 1; } static int toy_parse_atomic_op(ToyParser* p, KitCgAtomicOp* out) { - KitSym name; - if (!toy_parse_attr_dot_name(p, &name)) return 0; - if (toy_sym_is(p, name, "xchg")) - *out = KIT_CG_ATOMIC_XCHG; - else if (toy_sym_is(p, name, "add")) - *out = KIT_CG_ATOMIC_ADD; - else if (toy_sym_is(p, name, "sub")) - *out = KIT_CG_ATOMIC_SUB; - else if (toy_sym_is(p, name, "and")) - *out = KIT_CG_ATOMIC_AND; - else if (toy_sym_is(p, name, "or")) - *out = KIT_CG_ATOMIC_OR; - else if (toy_sym_is(p, name, "xor")) - *out = KIT_CG_ATOMIC_XOR; - else if (toy_sym_is(p, name, "nand")) - *out = KIT_CG_ATOMIC_NAND; - else { - toy_error(p, p->cur.loc, "unknown atomic op"); + static const ToyConstRow rows[] = { + {"xchg", KIT_CG_ATOMIC_XCHG}, {"add", KIT_CG_ATOMIC_ADD}, + {"sub", KIT_CG_ATOMIC_SUB}, {"and", KIT_CG_ATOMIC_AND}, + {"or", KIT_CG_ATOMIC_OR}, {"xor", KIT_CG_ATOMIC_XOR}, + {"nand", KIT_CG_ATOMIC_NAND}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 0, NULL, + "atomic op", &v)) return 0; - } + *out = (KitCgAtomicOp)v; return 1; } static int toy_parse_cmpxchg_strength(ToyParser* p, int* weak_out) { - KitSym name; - if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { - toy_error(p, p->cur.loc, "expected compare-exchange strength"); + static const ToyConstRow rows[] = { + {"strong", 0}, + {"weak", 1}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, + "compare-exchange strength", + "compare-exchange strength", &v)) return 0; - } - name = toy_tok_sym(p, p->cur); - toy_parser_advance(p); - if (toy_sym_is(p, name, "strong")) - *weak_out = 0; - else if (toy_sym_is(p, name, "weak")) - *weak_out = 1; - else { - toy_error(p, p->cur.loc, "unknown compare-exchange strength"); - return 0; - } + *weak_out = (int)v; return 1; } @@ -394,24 +359,19 @@ static KitCgTypeId toy_parse_call_builtin(ToyParser* p) { } static int toy_parse_barrier_scope(ToyParser* p, KitCgBarrierScope* out) { - KitSym name; - if (!toy_parse_attr_dot_name(p, &name)) return 0; - if (toy_sym_is(p, name, "full")) - *out = KIT_CG_BARRIER_FULL; - else if (toy_sym_is(p, name, "inner")) - *out = KIT_CG_BARRIER_INNER; - else if (toy_sym_is(p, name, "inner_store")) - *out = KIT_CG_BARRIER_INNER_STORE; - else if (toy_sym_is(p, name, "outer")) - *out = KIT_CG_BARRIER_OUTER; - else if (toy_sym_is(p, name, "outer_store")) - *out = KIT_CG_BARRIER_OUTER_STORE; - else if (toy_sym_is(p, name, "non_share")) - *out = KIT_CG_BARRIER_NON_SHARE; - else { - toy_error(p, p->cur.loc, "unknown barrier scope"); + static const ToyConstRow rows[] = { + {"full", KIT_CG_BARRIER_FULL}, + {"inner", KIT_CG_BARRIER_INNER}, + {"inner_store", KIT_CG_BARRIER_INNER_STORE}, + {"outer", KIT_CG_BARRIER_OUTER}, + {"outer_store", KIT_CG_BARRIER_OUTER_STORE}, + {"non_share", KIT_CG_BARRIER_NON_SHARE}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 0, NULL, + "barrier scope", &v)) return 0; - } + *out = (KitCgBarrierScope)v; return 1; } @@ -1079,6 +1039,63 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, return KIT_CG_TYPE_NONE; } +/* memcpy and memmove are identical except for the constant-size emission: + * memcpy lowers to kit_cg_memcpy, memmove to kit_cg_memmove. The dynamic path + * is byte-for-byte shared (both emit a forward element loop). */ +static KitCgTypeId toy_parse_mem_copy_move(ToyParser* p, int is_move) { + KitCgTypeId dst, src; + int64_t size = 0, align = 0; + int dynamic_size = 0, dynamic_align = 0; + KitCgLocal dst_local = KIT_CG_LOCAL_NONE; + KitCgLocal src_local = KIT_CG_LOCAL_NONE; + KitCgLocal size_local = KIT_CG_LOCAL_NONE; + KitCgMemAccess access; + KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); + KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); + toy_parser_advance(p); + dst = toy_parse_expr(p); + if (dst == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; + src = toy_parse_expr(p); + if (src == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; + if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { + if (!toy_parse_number_arg(p, &size)) return KIT_CG_TYPE_NONE; + } else { + KitCgTypeId size_ty = toy_parse_expr(p); + if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; + if (size_ty != p->int_type) { + toy_error(p, p->cur.loc, "memory size must be i64"); + return KIT_CG_TYPE_NONE; + } + dynamic_size = 1; + size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); + toy_store_top_to_local(p, size_local, p->int_type); + } + if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) + return KIT_CG_TYPE_NONE; + access = toy_mem_access_align(p, p->int_type, (uint32_t)align); + if (!toy_parse_mem_flags_tail(p, &access)) return KIT_CG_TYPE_NONE; + if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; + if (dynamic_size || dynamic_align) { + if (!dynamic_size) { + size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); + toy_store_const_to_local(p, size_local, p->int_type, (uint64_t)size); + } + src_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); + kit_cg_bitcast(p->cg, u8_ptr_ty); + toy_store_top_to_local(p, src_local, u8_ptr_ty); + dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); + kit_cg_bitcast(p->cg, u8_ptr_ty); + toy_store_top_to_local(p, dst_local, u8_ptr_ty); + toy_emit_dynamic_memory_loop(p, dst_local, src_local, size_local, 0, 0); + return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); + } + if (is_move) + kit_cg_memmove(p->cg, (uint64_t)size, access, access); + else + kit_cg_memcpy(p->cg, (uint64_t)size, access, access); + return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); +} + KitCgTypeId toy_parse_memory_builtin_call(ToyParser* p, KitSym name, int* recognized) { *recognized = 1; @@ -1135,111 +1152,9 @@ KitCgTypeId toy_parse_memory_builtin_call(ToyParser* p, KitSym name, return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); } - if (toy_sym_is(p, name, "memcpy")) { - KitCgTypeId dst, src; - int64_t size = 0, align = 0; - int dynamic_size = 0, dynamic_align = 0; - KitCgLocal dst_local = KIT_CG_LOCAL_NONE; - KitCgLocal src_local = KIT_CG_LOCAL_NONE; - KitCgLocal size_local = KIT_CG_LOCAL_NONE; - KitCgMemAccess access; - KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); - KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); - toy_parser_advance(p); - dst = toy_parse_expr(p); - if (dst == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) - return KIT_CG_TYPE_NONE; - src = toy_parse_expr(p); - if (src == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) - return KIT_CG_TYPE_NONE; - if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { - if (!toy_parse_number_arg(p, &size)) return KIT_CG_TYPE_NONE; - } else { - KitCgTypeId size_ty = toy_parse_expr(p); - if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; - if (size_ty != p->int_type) { - toy_error(p, p->cur.loc, "memory size must be i64"); - return KIT_CG_TYPE_NONE; - } - dynamic_size = 1; - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_top_to_local(p, size_local, p->int_type); - } - if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) - return KIT_CG_TYPE_NONE; - access = toy_mem_access_align(p, p->int_type, (uint32_t)align); - if (!toy_parse_mem_flags_tail(p, &access)) return KIT_CG_TYPE_NONE; - if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; - if (dynamic_size || dynamic_align) { - if (!dynamic_size) { - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_const_to_local(p, size_local, p->int_type, (uint64_t)size); - } - src_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); - kit_cg_bitcast(p->cg, u8_ptr_ty); - toy_store_top_to_local(p, src_local, u8_ptr_ty); - dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); - kit_cg_bitcast(p->cg, u8_ptr_ty); - toy_store_top_to_local(p, dst_local, u8_ptr_ty); - toy_emit_dynamic_memory_loop(p, dst_local, src_local, size_local, 0, 0); - return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); - } - kit_cg_memcpy(p->cg, (uint64_t)size, access, access); - return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); - } + if (toy_sym_is(p, name, "memcpy")) return toy_parse_mem_copy_move(p, 0); - if (toy_sym_is(p, name, "memmove")) { - KitCgTypeId dst, src; - int64_t size = 0, align = 0; - int dynamic_size = 0, dynamic_align = 0; - KitCgLocal dst_local = KIT_CG_LOCAL_NONE; - KitCgLocal src_local = KIT_CG_LOCAL_NONE; - KitCgLocal size_local = KIT_CG_LOCAL_NONE; - KitCgMemAccess access; - KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); - KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); - toy_parser_advance(p); - dst = toy_parse_expr(p); - if (dst == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) - return KIT_CG_TYPE_NONE; - src = toy_parse_expr(p); - if (src == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) - return KIT_CG_TYPE_NONE; - if (p->cur.kind == TOK_NUMBER && !p->cur.is_float) { - if (!toy_parse_number_arg(p, &size)) return KIT_CG_TYPE_NONE; - } else { - KitCgTypeId size_ty = toy_parse_expr(p); - if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; - if (size_ty != p->int_type) { - toy_error(p, p->cur.loc, "memory size must be i64"); - return KIT_CG_TYPE_NONE; - } - dynamic_size = 1; - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_top_to_local(p, size_local, p->int_type); - } - if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) - return KIT_CG_TYPE_NONE; - access = toy_mem_access_align(p, p->int_type, (uint32_t)align); - if (!toy_parse_mem_flags_tail(p, &access)) return KIT_CG_TYPE_NONE; - if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; - if (dynamic_size || dynamic_align) { - if (!dynamic_size) { - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_const_to_local(p, size_local, p->int_type, (uint64_t)size); - } - src_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); - kit_cg_bitcast(p->cg, u8_ptr_ty); - toy_store_top_to_local(p, src_local, u8_ptr_ty); - dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); - kit_cg_bitcast(p->cg, u8_ptr_ty); - toy_store_top_to_local(p, dst_local, u8_ptr_ty); - toy_emit_dynamic_memory_loop(p, dst_local, src_local, size_local, 0, 0); - return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); - } - kit_cg_memmove(p->cg, (uint64_t)size, access, access); - return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); - } + if (toy_sym_is(p, name, "memmove")) return toy_parse_mem_copy_move(p, 1); if (toy_sym_is(p, name, "atomic_fence")) { KitCgMemOrder order; diff --git a/lang/toy/expr.c b/lang/toy/expr.c @@ -348,131 +348,79 @@ int toy_parse_switch_label_value(ToyParser* p, KitCgTypeId selector_ty, } int toy_parse_symbol_feature_const(ToyParser* p, KitCgSymbolFeature* out) { - KitSym name; - if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { - toy_error(p, p->cur.loc, "expected symbol feature"); - return 0; - } - name = toy_tok_sym(p, p->cur); - toy_parser_advance(p); - if (toy_sym_is(p, name, "weak")) - *out = KIT_CG_SYMFEAT_WEAK; - else if (toy_sym_is(p, name, "protected_visibility")) - *out = KIT_CG_SYMFEAT_PROTECTED_VISIBILITY; - else if (toy_sym_is(p, name, "dllimport")) - *out = KIT_CG_SYMFEAT_DLLIMPORT; - else if (toy_sym_is(p, name, "dllexport")) - *out = KIT_CG_SYMFEAT_DLLEXPORT; - else if (toy_sym_is(p, name, "comdat")) - *out = KIT_CG_SYMFEAT_COMDAT; - else if (toy_sym_is(p, name, "common")) - *out = KIT_CG_SYMFEAT_COMMON; - else if (toy_sym_is(p, name, "merge_sections")) - *out = KIT_CG_SYMFEAT_MERGE_SECTIONS; - else if (toy_sym_is(p, name, "constructor_priority")) - *out = KIT_CG_SYMFEAT_CONSTRUCTOR_PRIORITY; - else if (toy_sym_is(p, name, "tls_local_exec")) - *out = KIT_CG_SYMFEAT_TLS_LOCAL_EXEC; - else if (toy_sym_is(p, name, "tls_initial_exec")) - *out = KIT_CG_SYMFEAT_TLS_INITIAL_EXEC; - else if (toy_sym_is(p, name, "tls_local_dynamic")) - *out = KIT_CG_SYMFEAT_TLS_LOCAL_DYNAMIC; - else if (toy_sym_is(p, name, "tls_general_dynamic")) - *out = KIT_CG_SYMFEAT_TLS_GENERAL_DYNAMIC; - else { - toy_error(p, p->cur.loc, "unknown symbol feature"); + static const ToyConstRow rows[] = { + {"weak", KIT_CG_SYMFEAT_WEAK}, + {"protected_visibility", KIT_CG_SYMFEAT_PROTECTED_VISIBILITY}, + {"dllimport", KIT_CG_SYMFEAT_DLLIMPORT}, + {"dllexport", KIT_CG_SYMFEAT_DLLEXPORT}, + {"comdat", KIT_CG_SYMFEAT_COMDAT}, + {"common", KIT_CG_SYMFEAT_COMMON}, + {"merge_sections", KIT_CG_SYMFEAT_MERGE_SECTIONS}, + {"constructor_priority", KIT_CG_SYMFEAT_CONSTRUCTOR_PRIORITY}, + {"tls_local_exec", KIT_CG_SYMFEAT_TLS_LOCAL_EXEC}, + {"tls_initial_exec", KIT_CG_SYMFEAT_TLS_INITIAL_EXEC}, + {"tls_local_dynamic", KIT_CG_SYMFEAT_TLS_LOCAL_DYNAMIC}, + {"tls_general_dynamic", KIT_CG_SYMFEAT_TLS_GENERAL_DYNAMIC}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, + "symbol feature", "symbol feature", &v)) return 0; - } + *out = (KitCgSymbolFeature)v; return 1; } int toy_parse_backend_feature_const(ToyParser* p, uint64_t* out) { - KitSym name; - if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { - toy_error(p, p->cur.loc, "expected backend feature"); - return 0; - } - name = toy_tok_sym(p, p->cur); - toy_parser_advance(p); - if (toy_sym_is(p, name, "unaligned_memory")) - *out = KIT_CG_BACKEND_UNALIGNED_MEMORY; - else if (toy_sym_is(p, name, "strict_alignment")) - *out = KIT_CG_BACKEND_STRICT_ALIGNMENT; - else if (toy_sym_is(p, name, "red_zone")) - *out = KIT_CG_BACKEND_RED_ZONE; - else if (toy_sym_is(p, name, "simd")) - *out = KIT_CG_BACKEND_SIMD; - else if (toy_sym_is(p, name, "pointer_auth")) - *out = KIT_CG_BACKEND_POINTER_AUTH; - else if (toy_sym_is(p, name, "branch_protection")) - *out = KIT_CG_BACKEND_BRANCH_PROTECTION; - else { - toy_error(p, p->cur.loc, "unknown backend feature"); - return 0; - } - return 1; + static const ToyConstRow rows[] = { + {"unaligned_memory", KIT_CG_BACKEND_UNALIGNED_MEMORY}, + {"strict_alignment", KIT_CG_BACKEND_STRICT_ALIGNMENT}, + {"red_zone", KIT_CG_BACKEND_RED_ZONE}, + {"simd", KIT_CG_BACKEND_SIMD}, + {"pointer_auth", KIT_CG_BACKEND_POINTER_AUTH}, + {"branch_protection", KIT_CG_BACKEND_BRANCH_PROTECTION}, + }; + return toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, + "backend feature", "backend feature", out); } int toy_parse_intrinsic_const(ToyParser* p, KitCgIntrinsic* out) { - KitSym name; - if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { - toy_error(p, p->cur.loc, "expected intrinsic name"); - return 0; - } - name = toy_tok_sym(p, p->cur); - toy_parser_advance(p); - if (toy_sym_is(p, name, "cpu_nop")) - *out = KIT_CG_INTRIN_CPU_NOP; - else if (toy_sym_is(p, name, "cpu_yield")) - *out = KIT_CG_INTRIN_CPU_YIELD; - else if (toy_sym_is(p, name, "wfi")) - *out = KIT_CG_INTRIN_WFI; - else if (toy_sym_is(p, name, "wfe")) - *out = KIT_CG_INTRIN_WFE; - else if (toy_sym_is(p, name, "sev")) - *out = KIT_CG_INTRIN_SEV; - else if (toy_sym_is(p, name, "isb")) - *out = KIT_CG_INTRIN_ISB; - else if (toy_sym_is(p, name, "dmb")) - *out = KIT_CG_INTRIN_DMB; - else if (toy_sym_is(p, name, "dsb")) - *out = KIT_CG_INTRIN_DSB; - else if (toy_sym_is(p, name, "irq_save")) - *out = KIT_CG_INTRIN_IRQ_SAVE; - else if (toy_sym_is(p, name, "irq_restore")) - *out = KIT_CG_INTRIN_IRQ_RESTORE; - else if (toy_sym_is(p, name, "irq_enable")) - *out = KIT_CG_INTRIN_IRQ_ENABLE; - else if (toy_sym_is(p, name, "irq_disable")) - *out = KIT_CG_INTRIN_IRQ_DISABLE; - else if (toy_sym_is(p, name, "syscall")) - *out = KIT_CG_INTRIN_SYSCALL; - else if (toy_sym_is(p, name, "coro_switch")) - *out = KIT_CG_INTRIN_CORO_SWITCH; - else { - toy_error(p, p->cur.loc, "unknown intrinsic"); + static const ToyConstRow rows[] = { + {"cpu_nop", KIT_CG_INTRIN_CPU_NOP}, + {"cpu_yield", KIT_CG_INTRIN_CPU_YIELD}, + {"wfi", KIT_CG_INTRIN_WFI}, + {"wfe", KIT_CG_INTRIN_WFE}, + {"sev", KIT_CG_INTRIN_SEV}, + {"isb", KIT_CG_INTRIN_ISB}, + {"dmb", KIT_CG_INTRIN_DMB}, + {"dsb", KIT_CG_INTRIN_DSB}, + {"irq_save", KIT_CG_INTRIN_IRQ_SAVE}, + {"irq_restore", KIT_CG_INTRIN_IRQ_RESTORE}, + {"irq_enable", KIT_CG_INTRIN_IRQ_ENABLE}, + {"irq_disable", KIT_CG_INTRIN_IRQ_DISABLE}, + {"syscall", KIT_CG_INTRIN_SYSCALL}, + {"coro_switch", KIT_CG_INTRIN_CORO_SWITCH}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 1, + "intrinsic name", "intrinsic", &v)) return 0; - } + *out = (KitCgIntrinsic)v; return 1; } int toy_parse_rounding_const(ToyParser* p, KitCgRounding* out) { - KitSym name; - if (!toy_parse_attr_dot_name(p, &name)) return 0; - if (toy_sym_is(p, name, "default")) - *out = KIT_CG_ROUND_DEFAULT; - else if (toy_sym_is(p, name, "nearest_even")) - *out = KIT_CG_ROUND_NEAREST_EVEN; - else if (toy_sym_is(p, name, "toward_zero")) - *out = KIT_CG_ROUND_TOWARD_ZERO; - else if (toy_sym_is(p, name, "down")) - *out = KIT_CG_ROUND_DOWN; - else if (toy_sym_is(p, name, "up")) - *out = KIT_CG_ROUND_UP; - else { - toy_error(p, p->cur.loc, "unknown rounding mode"); + static const ToyConstRow rows[] = { + {"default", KIT_CG_ROUND_DEFAULT}, + {"nearest_even", KIT_CG_ROUND_NEAREST_EVEN}, + {"toward_zero", KIT_CG_ROUND_TOWARD_ZERO}, + {"down", KIT_CG_ROUND_DOWN}, + {"up", KIT_CG_ROUND_UP}, + }; + uint64_t v; + if (!toy_parse_dot_const(p, rows, sizeof rows / sizeof rows[0], 0, NULL, + "rounding mode", &v)) return 0; - } + *out = (KitCgRounding)v; return 1; } diff --git a/lang/toy/internal.h b/lang/toy/internal.h @@ -319,6 +319,38 @@ void toy_error(ToyParser* p, KitSrcLoc loc, const char* fmt, ...); void toy_set_loc(ToyParser* p); KitSym toy_tok_sym(ToyParser* p, ToyToken tok); int toy_sym_is(ToyParser* p, KitSym sym, const char* name); + +/* A single ".name" -> value row for the dot-const tables. The value is widened + * to uint64_t so one table type serves every enum/flag domain; thin typed + * wrappers narrow it back at the call site. */ +typedef struct { + const char* name; + uint64_t value; +} ToyConstRow; + +/* Map an already-interned token sym against a const table, interning each row + * name once. On a hit, sets *out and returns 1; on a miss, raises + * "unknown <what>" and returns 0. */ +int toy_lookup_const(ToyParser* p, KitSym tok, const ToyConstRow* rows, size_t n, + const char* what, uint64_t* out); + +/* Parse a ".name" dot-const and resolve it via `rows`. When `strict_ident` is + * set the name must be a bare identifier ("expected <expected>" on failure); + * otherwise keyword tokens are also accepted (via toy_parse_attr_dot_name). On + * an unknown name, raises "unknown <unknown>". */ +int toy_parse_dot_const(ToyParser* p, const ToyConstRow* rows, size_t n, + int strict_ident, const char* expected, + const char* unknown, uint64_t* out); + +/* Parse a comma-separated run of ".name" flags, OR-ing each matched row value + * into *mask. When `comma_prefixed` is set, every item must be introduced by a + * comma and the loop stops at the first non-comma (the mem-flags tail form). + * Otherwise the run continues until ')' or EOF with comma separators (the asm + * group form); the caller owns the surrounding parentheses. Unknown names raise + * "unknown <unknown>". */ +int toy_parse_flag_set(ToyParser* p, const ToyConstRow* rows, size_t n, + const char* unknown, int comma_prefixed, uint32_t* mask); + int toy_expect_comma(ToyParser* p); int toy_skip_attr_list_ex(ToyParser* p, int* has_static); int toy_skip_attr_list(ToyParser* p); diff --git a/lang/toy/parser_core.c b/lang/toy/parser_core.c @@ -416,6 +416,55 @@ int toy_sym_is(ToyParser* p, KitSym sym, const char* name) { return sym == kit_sym_intern(p->c, kit_slice_cstr(name)); } +int toy_lookup_const(ToyParser* p, KitSym tok, const ToyConstRow* rows, size_t n, + const char* what, uint64_t* out) { + size_t i; + for (i = 0; i < n; ++i) { + if (tok == kit_sym_intern(p->c, kit_slice_cstr(rows[i].name))) { + *out = rows[i].value; + return 1; + } + } + toy_error(p, p->cur.loc, "unknown %s", what); + return 0; +} + +int toy_parse_dot_const(ToyParser* p, const ToyConstRow* rows, size_t n, + int strict_ident, const char* expected, + const char* unknown, uint64_t* out) { + KitSym tok; + if (strict_ident) { + if (!toy_parser_expect(p, TOK_DOT) || p->cur.kind != TOK_IDENT) { + toy_error(p, p->cur.loc, "expected %s", expected); + return 0; + } + tok = toy_tok_sym(p, p->cur); + toy_parser_advance(p); + } else { + (void)expected; + if (!toy_parse_attr_dot_name(p, &tok)) return 0; + } + return toy_lookup_const(p, tok, rows, n, unknown, out); +} + +int toy_parse_flag_set(ToyParser* p, const ToyConstRow* rows, size_t n, + const char* unknown, int comma_prefixed, uint32_t* mask) { + for (;;) { + KitSym name; + uint64_t value; + if (comma_prefixed) { + if (!toy_parser_match(p, TOK_COMMA)) break; + } else if (p->cur.kind == TOK_RPAREN || p->cur.kind == TOK_EOF) { + break; + } + if (!toy_parse_attr_dot_name(p, &name)) return 0; + if (!toy_lookup_const(p, name, rows, n, unknown, &value)) return 0; + *mask |= (uint32_t)value; + if (!comma_prefixed && !toy_parser_match(p, TOK_COMMA)) break; + } + return 1; +} + int toy_skip_attr_list_ex(ToyParser* p, int* has_static) { int bracket_depth = 0; int paren_depth = 0;