package wax-lib
Source file identifier.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43(* Whether [s] is a valid Wax identifier. Called once per name during Wasm-to-Wax name assignment (thousands of times on a large module), so it must not allocate: a manual UTF-8 scan replaces the old [Sedlexing.Utf8.from_string] + [match%sedlex], which built a fresh lexbuf (and its refill buffer) per call. It fuses the coarse structural rule the sedlex [ident] regexp enforced with the strict XID check {!invalid_identifier_char} did separately: an ASCII scalar must be an identifier character in the right position; a non-ASCII scalar must satisfy [XID_Start] (first) or [XID_Continue] (rest) — the coarse rule admitted any non-ASCII scalar and the XID check then narrowed it, so requiring XID directly is equivalent. A leading ['_'] needs at least one further character, matching the regexp's [ '_', Plus id_cont_c ] alternative. *) let is_valid s = let n = String.length s in let ascii_start c = (c >= Char.code 'a' && c <= Char.code 'z') || (c >= Char.code 'A' && c <= Char.code 'Z') in let ascii_cont c = ascii_start c || (c >= Char.code '0' && c <= Char.code '9') || c = Char.code '_' || c = Char.code '\'' in let rec cont i = if i >= n then true else let d = String.get_utf_8_uchar s i in if not (Uchar.utf_decode_is_valid d) then false else let c = Uchar.to_int (Uchar.utf_decode_uchar d) in let ok = if c < 0x80 then ascii_cont c else Xid.is_xid_continue c in ok && cont (i + Uchar.utf_decode_length d) in n > 0 && let d = String.get_utf_8_uchar s 0 in Uchar.utf_decode_is_valid d && let c = Uchar.to_int (Uchar.utf_decode_uchar d) in let len = Uchar.utf_decode_length d in if c < 0x80 then if c = Char.code '_' then len < n && cont len else ascii_start c && cont len else Xid.is_xid_start c && cont len