code wiki / (root) / nx_rfc_ingest.nx

nx_rfc_ingest.nx source

↩ module page · 206 lines · 7027 B

1// nx_rfc_ingest.nx -- ingest IETF RFC plaintext. 2// 3// RFCs (rfc-editor.org) are PD-equivalent under the IETF Trust Legal 4// Provisions and are an enormous source of clean, well-specified 5// algorithms. This parser walks plaintext .txt files and extracts 6// numbered section headers, which in practice name the algorithms and 7// procedures defined within the RFC. 8// 9// Recognized pattern (line-anchored): 10// ^[ ]{0,3}<digits>(\.<digits>)*\.?[ ]+<Title>... 11// Examples: 12// "1. Executive Summary" 13// "3.1. Algorithm Description" 14// "4.1.1. Step Definition" 15// 16// The decl `name` is the title text (whitespace trimmed). 17// 18// genealogy_id: ietf_trust_legal_provisions_2025 19// lineage_id: plaintext_section_header_parser 20 21// nx_safety_envelope: 22// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 23// sil_target: SIL1 24// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 25// verdict: NOT_YET_EVALUATED 26 27import "nx_syscalls.nx" 28import "nx_tier.nx" 29 30// ===== sealed kinds ================================================= 31 32const NX_RFC_KIND_SECTION: nx_int = 1 33const NX_RFC_KIND_DEFINITION: nx_int = 2 34 35const NX_RFC_MAX_NAME_LEN: nx_int = 256 36const NX_RFC_MAX_DECLS: nx_int = 65536 37 38// ===== entry structures ============================================= 39 40struct RfcDecl { 41 kind: nx_int, 42 name: *u8, 43} 44 45const NX_RFC_DECL_BYTES: nx_int = 16 46 47struct RfcDb { 48 decls: *RfcDecl, 49 n_decls: nx_int, 50 capacity: nx_int, 51} 52 53func nx_rfc_db_alloc() -> *RfcDb { 54 let raw: *u8 = sys_mmap(24) 55 let db: *RfcDb = raw as *RfcDb 56 db.decls = (sys_mmap((NX_RFC_MAX_DECLS as nx_size) * (NX_RFC_DECL_BYTES as nx_size))) as *RfcDecl 57 db.n_decls = 0 58 db.capacity = NX_RFC_MAX_DECLS 59 return db 60} 61 62func nx_rfc_decl_at(db: *RfcDb, i: nx_int) -> *RfcDecl { 63 return (((db.decls as nx_size) + (i as nx_size) * (NX_RFC_DECL_BYTES as nx_size)) as *RfcDecl) 64} 65 66// ===== helpers ====================================================== 67 68// Is a byte a decimal digit? 69func nx_rfc_is_digit(c: nx_int) -> nx_int { 70 if c < 0x30 { return 0 } 71 if c > 0x39 { return 0 } 72 return 1 73} 74 75// Sanitize a title character for use as an identifier-like name: 76// alphanumeric stays; space + punctuation -> '_'; trim trailing _. 77func nx_rfc_sanitize_char(c: nx_int) -> nx_int { 78 if c >= 0x30 { if c <= 0x39 { return c } } // 0-9 79 if c >= 0x41 { if c <= 0x5A { return c } } // A-Z 80 if c >= 0x61 { if c <= 0x7A { return c } } // a-z 81 return 0x5F // '_' 82} 83 84// Skip leading whitespace within [pos, eol). Returns the first non-ws 85// index. Whitespace = space (0x20) or tab (0x09). 86func nx_rfc_skip_ws(buf: *u8, pos: nx_int, eol: nx_int) -> nx_int { 87 var p: nx_int = pos 88 var done: nx_int = 0 89 while done == 0 { 90 if p >= eol { done = 1 } 91 if done == 0 { 92 let c: nx_int = buf[p] as nx_int 93 if c == 0x20 { p = p + 1 } 94 if c == 0x09 { p = p + 1 } 95 if c != 0x20 { 96 if c != 0x09 { done = 1 } 97 } 98 } 99 } 100 return p 101} 102 103// Check whether the line [pos, eol) matches the section-header pattern: 104// optional 0-3 spaces, digits + dots (e.g., "3.1.2"), optional final dot, 105// one or more spaces, then title text. 106// Returns the index where the title starts (after the dot-leader and spaces), 107// or -1 if no match. 108func nx_rfc_section_title_start(buf: *u8, pos: nx_int, eol: nx_int) -> nx_int { 109 let after_ws: nx_int = nx_rfc_skip_ws(buf, pos, eol) 110 if after_ws >= eol { return -1 } 111 if nx_rfc_is_digit(buf[after_ws] as nx_int) == 0 { return -1 } 112 // Must have at most 3 leading spaces (this excludes deeply-indented 113 // pseudocode that happens to start with a digit). 114 if (after_ws - pos) > 3 { return -1 } 115 var p: nx_int = after_ws 116 var saw_digit: nx_int = 0 117 var saw_dot: nx_int = 0 118 var done: nx_int = 0 119 while done == 0 { 120 if p >= eol { done = 1 } 121 if done == 0 { 122 let c: nx_int = buf[p] as nx_int 123 if nx_rfc_is_digit(c) == 1 { saw_digit = 1; p = p + 1 } 124 if c == 0x2E { saw_dot = 1; p = p + 1 } // '.' 125 if c != 0x2E { 126 if nx_rfc_is_digit(c) == 0 { done = 1 } 127 } 128 } 129 } 130 if saw_digit == 0 { return -1 } 131 if saw_dot == 0 { return -1 } // require at least one '.' (filters bare line numbers) 132 // Need at least one space after the dot-leader. 133 if p >= eol { return -1 } 134 let c2: nx_int = buf[p] as nx_int 135 if c2 != 0x20 { if c2 != 0x09 { return -1 } } 136 return nx_rfc_skip_ws(buf, p, eol) 137} 138 139// Copy title text into out (sanitized, trimmed of trailing _). Caps at 140// NX_RFC_MAX_NAME_LEN. Returns the written length. 141func nx_rfc_emit_title(buf: *u8, lo: nx_int, eol: nx_int, out: *u8) -> nx_int { 142 var i: nx_int = 0 143 var p: nx_int = lo 144 while p < eol { 145 if i < (NX_RFC_MAX_NAME_LEN - 1) { 146 let c: nx_int = buf[p] as nx_int 147 // Page-number filler: trailing spaces + final number. 148 // Stop at runs of more than 2 spaces (typical TOC dot-leader). 149 if c == 0x20 { 150 if p + 1 < eol { 151 if buf[p + 1] == 0x20 { 152 // Two-or-more spaces -> end of meaningful title. 153 p = eol + 1 154 } 155 } 156 } 157 if p <= eol { 158 out[i] = nx_rfc_sanitize_char(c) as u8 159 i = i + 1 160 } 161 } 162 p = p + 1 163 } 164 // Trim trailing underscores. 165 while i > 0 { 166 if out[i - 1] == 0x5F { i = i - 1 } 167 if out[i - 1] != 0x5F { out[i] = 0; return i } 168 } 169 out[i] = 0 170 return i 171} 172 173// ===== ingest driver ================================================ 174 175func nx_rfc_ingest_corpus(buf: *u8, len: nx_int) -> *RfcDb { 176 let db: *RfcDb = nx_rfc_db_alloc() 177 var pos: nx_int = 0 178 while pos < len { 179 // Find end of line. 180 var eol: nx_int = pos 181 var done: nx_int = 0 182 while done == 0 { 183 if eol >= len { done = 1 } 184 if done == 0 { 185 if buf[eol] == 10 { done = 1 } 186 if done == 0 { eol = eol + 1 } 187 } 188 } 189 // Try the section-header pattern. 190 let tstart: nx_int = nx_rfc_section_title_start(buf, pos, eol) 191 if tstart >= 0 { 192 if db.n_decls < db.capacity { 193 let name_buf: *u8 = sys_mmap(NX_RFC_MAX_NAME_LEN as nx_size) 194 let n_emitted: nx_int = nx_rfc_emit_title(buf, tstart, eol, name_buf) 195 if n_emitted > 0 { 196 let d: *RfcDecl = nx_rfc_decl_at(db, db.n_decls) 197 d.kind = NX_RFC_KIND_SECTION 198 d.name = name_buf 199 db.n_decls = db.n_decls + 1 200 } 201 } 202 } 203 pos = eol + 1 204 } 205 return db 206}