nx_edgar_lib.nx source
↩ module page · 138 lines · 5487 B
1// nx_edgar_lib.nx -- F986: SEC EDGAR real-data extraction. GROUNDED, NOT MADE UP.
2//
3// The sovereign fetcher reaches data.sec.gov over our own TLS (proven live: Apple StockholdersEquity
4// pulled 200 OK, current through the latest 10-Q). This parses the SEC companyconcept JSON so the
5// valuation engines run on REAL filings instead of hand-entered figures -- the operator's standing rule
6// for the whole finance arc. Every extracted fact carries its PROVENANCE: the form (10-K/10-Q) and the
7// filing date, so a number is always traceable to a specific SEC filing, never a floating assertion.
8//
9// ★FAIL-CLOSED + COMPOSES the pipeline: the no-value sentinel EDGAR_NOVAL is the SAME value nx_xbrl and
10// nx_piotroski use for a missing fact (-999999999). So an unparseable or empty response flows through as
11// "missing" -- the F-score reads INCOMPLETE, the identity check refuses -- rather than silently becoming a
12// zero that would corrupt a valuation. Fetch failure never turns into a fabricated financial fact.
13//
14// SCOPE (declared): extracts the LATEST fact value + its provenance and the entity name from the
15// companyconcept JSON. Full submissions parsing, all periods, and unit handling beyond USD are follow-ons.
16// Strings/keys are built at runtime (NishiLang literals cannot hold a double-quote). license_tier: ORIGINAL LIB.
17
18import "nx_matter_lib.nx"
19
20const EDGAR_NOVAL: i64 = 0 - 999999999 // no value found (matches nx_xbrl XB_NO_FACT / nx_piotroski PIO_NA)
21const EDGAR_Q: i64 = 34 // double-quote
22const EDGAR_COLON: i64 = 58
23
24func edgar_read(path: *u8, buf: *u8, cap: i64) -> i64 {
25 let fd: i64 = sys_openat_rd(path)
26 if fd < 0 { return 0 - 1 }
27 var n: i64 = 0
28 var go: i64 = 1
29 while go == 1 {
30 let base: i64 = buf as i64
31 let r: i64 = sys_read(fd, (base + n) as *u8, cap - n)
32 if r <= 0 { go = 0 } else { n = n + r }
33 if n >= cap { go = 0 }
34 }
35 sys_close(fd)
36 return n
37}
38
39// build the JSON key-needle "<key>": at runtime (quotes cannot be string literals). returns len.
40func edgar_mkkey(key: *u8, out: *u8) -> i64 {
41 out[0] = EDGAR_Q as u8
42 var o: i64 = 1
43 var i: i64 = 0
44 while key[i] != (0 as u8) { out[o] = key[i]; o = o + 1; i = i + 1 }
45 out[o] = EDGAR_Q as u8
46 o = o + 1
47 out[o] = EDGAR_COLON as u8
48 o = o + 1
49 out[o] = 0 as u8
50 return o
51}
52
53// index of the LAST occurrence of needle in hay[0..hl), or -1.
54func edgar_find_last(hay: *u8, hl: i64, needle: *u8, nl: i64) -> i64 {
55 var last: i64 = 0 - 1
56 var i: i64 = 0
57 while i + nl <= hl {
58 var j: i64 = 0
59 while j < nl {
60 if hay[i + j] == needle[j] { j = j + 1 } else { j = nl + 1 }
61 }
62 if j == nl { last = i }
63 i = i + 1
64 }
65 return last
66}
67
68// index of the FIRST occurrence of needle in hay[0..hl), or -1.
69func edgar_find_first(hay: *u8, hl: i64, needle: *u8, nl: i64) -> i64 {
70 var i: i64 = 0
71 while i + nl <= hl {
72 var j: i64 = 0
73 while j < nl {
74 if hay[i + j] == needle[j] { j = j + 1 } else { j = nl + 1 }
75 }
76 if j == nl { return i }
77 i = i + 1
78 }
79 return 0 - 1
80}
81
82// integer value after the LAST "<key>": in the JSON. EDGAR_NOVAL if the key is absent or not numeric.
83func edgar_num_last(json: *u8, jl: i64, key: *u8) -> i64 {
84 let nk: *u8 = sys_mmap(128)
85 let nl: i64 = edgar_mkkey(key, nk)
86 let p: i64 = edgar_find_last(json, jl, nk, nl)
87 if p < 0 { return EDGAR_NOVAL }
88 var i: i64 = p + nl
89 var neg: i64 = 0
90 if i < jl { if json[i] == (45 as u8) { neg = 1; i = i + 1 } }
91 var v: i64 = 0
92 var any: i64 = 0
93 var go: i64 = 1
94 while go == 1 {
95 if i >= jl { go = 0 } else {
96 let c: i64 = json[i] as i64
97 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); any = 1; i = i + 1 } else { go = 0 } } else { go = 0 }
98 }
99 }
100 if any == 0 { return EDGAR_NOVAL }
101 if neg == 1 { return 0 - v }
102 return v
103}
104
105// string value after a "<key>":" ; helper takes the located index p (or -1). returns len or -1.
106func edgar_str_at(json: *u8, jl: i64, p: i64, nl: i64, out: *u8) -> i64 {
107 if p < 0 { return 0 - 1 }
108 var i: i64 = p + nl
109 if i >= jl { return 0 - 1 }
110 if json[i] != (EDGAR_Q as u8) { return 0 - 1 }
111 i = i + 1
112 var t: i64 = 0
113 var go: i64 = 1
114 while go == 1 {
115 if i >= jl { go = 0 } else {
116 if json[i] == (EDGAR_Q as u8) { go = 0 } else { out[t] = json[i]; t = t + 1; i = i + 1 }
117 }
118 }
119 out[t] = 0 as u8
120 return t
121}
122
123func edgar_str_last(json: *u8, jl: i64, key: *u8, out: *u8) -> i64 {
124 let nk: *u8 = sys_mmap(128)
125 let nl: i64 = edgar_mkkey(key, nk)
126 return edgar_str_at(json, jl, edgar_find_last(json, jl, nk, nl), nl, out)
127}
128func edgar_str_first(json: *u8, jl: i64, key: *u8, out: *u8) -> i64 {
129 let nk: *u8 = sys_mmap(128)
130 let nl: i64 = edgar_mkkey(key, nk)
131 return edgar_str_at(json, jl, edgar_find_first(json, jl, nk, nl), nl, out)
132}
133
134// ★convenience accessors over a companyconcept JSON.
135func edgar_latest_value(json: *u8, jl: i64) -> i64 { return edgar_num_last(json, jl, "val" as *u8) }
136func edgar_entity(json: *u8, jl: i64, out: *u8) -> i64 { return edgar_str_first(json, jl, "entityName" as *u8, out) }
137func edgar_latest_form(json: *u8, jl: i64, out: *u8) -> i64 { return edgar_str_last(json, jl, "form" as *u8, out) }
138func edgar_latest_filed(json: *u8, jl: i64, out: *u8) -> i64 { return edgar_str_last(json, jl, "filed" as *u8, out) }