code wiki / (root) / nx_xbrl_lib.nx

nx_xbrl_lib.nx source

↩ module page · 113 lines · 4811 B

1// nx_xbrl_lib.nx -- F987: XBRL financial-fact parse + accounting-identity validation. 2// 3// SEC filings are tagged in XBRL: <us-gaap:Assets contextRef=... unitRef=usd decimals=0>1000000</us-gaap:Assets>. 4// The sovereign property is that the parsed facts are CROSS-CHECKED against the accounting identity 5// (Assets == Liabilities + StockholdersEquity), so a mis-tagged or internally-inconsistent filing is 6// FLAGGED rather than fed blindly into a valuation. The same fail-closed discipline as the derived 7// statements: a balance sheet -- even one someone else prepared and tagged -- must balance, or it is 8// rejected. These parsed integers are exactly what feeds the distress (Altman Z) and stewardship engines 9// with GROUNDED numbers instead of hand-entered ones. 10// 11// ATTRIBUTE-AWARE + NAMESPACE-AWARE by word boundary: matching <us-gaap:Assets checks the next byte is 12// '>' or whitespace, so it never mis-matches <us-gaap:AssetsCurrent>. That boundary check is the whole 13// correctness of a tag parser and it is done explicitly. 14// 15// FAIL-CLOSED: a missing required fact is a rejection (a sentinel), not a zero -- a balance sheet with 16// no Assets tag is not a balance sheet with zero assets. 17// 18// SCOPE (declared): parses fact text + validates the balance identity. Full XBRL (contexts, dimensions, 19// calculation linkbases, negative decimals scaling) is a declared follow-on. Values are whole units here. 20// DRY: composes nx_iso20022_lib (iso_find/iso_len). license_tier: ORIGINAL LIB. 21 22import "nx_iso20022_lib.nx" 23 24const XB_NO_FACT: i64 = 0 - 999999999 // sentinel: a required fact is absent (fail-closed) 25 26// parse a signed integer from text (whole units). 27func xb_atoi(s: *u8) -> i64 { 28 var v: i64 = 0 29 var i: i64 = 0 30 var neg: i64 = 0 31 if s[0] == (45 as u8) { neg = 1; i = 1 } 32 while s[i] != (0 as u8) { 33 if s[i] >= 48 as u8 { if s[i] <= 57 as u8 { v = v * 10 + (s[i] - 48) } } 34 i = i + 1 35 } 36 if neg == 1 { return 0 - v } 37 return v 38} 39 40// extract the text of <concept ...>text</concept> (attribute- and namespace-boundary aware). 41// returns length, or -1 if the concept is absent. out must be sized for the value. 42func xbrl_fact(xml: *u8, xl: i64, concept: *u8, out: *u8) -> i64 { 43 // opentag = "<concept" (no '>' -- attributes may follow) 44 let ot: *u8 = sys_mmap(256) 45 ot[0] = 60 as u8 46 var ol: i64 = 1 47 var ci: i64 = 0 48 while concept[ci] != (0 as u8) { ot[ol] = concept[ci]; ol = ol + 1; ci = ci + 1 } 49 ot[ol] = 0 as u8 50 // closetag = "</concept>" 51 let ct: *u8 = sys_mmap(256) 52 ct[0] = 60 as u8 53 ct[1] = 47 as u8 54 var cl: i64 = 2 55 ci = 0 56 while concept[ci] != (0 as u8) { ct[cl] = concept[ci]; cl = cl + 1; ci = ci + 1 } 57 ct[cl] = 62 as u8 58 cl = cl + 1 59 ct[cl] = 0 as u8 60 let gtneedle: *u8 = ">" as *u8 61 var i: i64 = 0 62 var go: i64 = 1 63 while go == 1 { 64 let p: i64 = iso_find(xml, xl, ot, ol, i) 65 if p < 0 { return 0 - 1 } 66 let after: i64 = p + ol 67 var boundary: i64 = 0 68 if after < xl { 69 if xml[after] == (62 as u8) { boundary = 1 } // '>' 70 if xml[after] == (32 as u8) { boundary = 1 } // ' ' 71 if xml[after] == (9 as u8) { boundary = 1 } // tab 72 } 73 if boundary == 1 { 74 let gt: i64 = iso_find(xml, xl, gtneedle, 1, after) 75 if gt < 0 { return 0 - 1 } 76 let cs: i64 = gt + 1 77 let ce: i64 = iso_find(xml, xl, ct, cl, cs) 78 if ce < 0 { return 0 - 1 } 79 var t: i64 = 0 80 var q: i64 = cs 81 while q < ce { out[t] = xml[q]; t = t + 1; q = q + 1 } 82 out[t] = 0 as u8 83 return t 84 } 85 i = p + 1 86 } 87 return 0 - 1 88} 89 90// parse a concept's value as an integer; XB_NO_FACT if absent (fail-closed). 91func xbrl_fact_int(xml: *u8, xl: i64, concept: *u8) -> i64 { 92 let buf: *u8 = sys_mmap(64) 93 if xbrl_fact(xml, xl, concept, buf) < 0 { return XB_NO_FACT } 94 return xb_atoi(buf) 95} 96 97// ★VALIDATE the balance-sheet identity from the tagged facts. 98// writes assets/liabilities/equity/variance to out[0..3]. 99// returns 0 if Assets == Liabilities + Equity; XB_NO_FACT if any of the three is missing (fail-closed); 100// otherwise the non-zero variance (the filing does not balance -- flag it). 101func xbrl_check_balance(xml: *u8, xl: i64, out: *i64) -> i64 { 102 let a: i64 = xbrl_fact_int(xml, xl, "us-gaap:Assets" as *u8) 103 let l: i64 = xbrl_fact_int(xml, xl, "us-gaap:Liabilities" as *u8) 104 let e: i64 = xbrl_fact_int(xml, xl, "us-gaap:StockholdersEquity" as *u8) 105 if a == XB_NO_FACT { return XB_NO_FACT } 106 if l == XB_NO_FACT { return XB_NO_FACT } 107 if e == XB_NO_FACT { return XB_NO_FACT } 108 out[0] = a 109 out[1] = l 110 out[2] = e 111 out[3] = a - (l + e) 112 return out[3] 113}