nx_frontmatter.nx source
↩ module page · 99 lines · 3682 B
1// nx_frontmatter.nx -- splits "---\n<yaml>\n---\n<body>" into YAML
2// + body slices. Mirrors what nishi-pages/build/build.py load_doc()
3// did in Python; substrate-native + bounded + auditable.
4//
5// Wire format (mandatory):
6// src[0..3] == "---\n" (3 dashes + newline)
7// src[3..yaml_end] == YAML subset bytes
8// src[yaml_end..yaml_end+4] == "\n---" (terminator) OR "\n---\n"
9// src[yaml_end+5..] == body bytes (markdown, plain text, anything)
10//
11// Returns:
12// yaml_off / yaml_len = slice of the YAML subset block
13// body_off / body_len = slice of the body bytes
14//
15// Used by:
16// nishi-pages content/posts/*.md, content/pages/*.md (YAML front-
17// matter + markdown body)
18//
19// Per cardinal feedback-defensive-at-boundaries: input must START
20// with literal "---\n" or NX_FM_NO_FRONTMATTER returns; YAML term
21// must be present or NX_FM_UNTERMINATED returns.
22
23// nx_safety_envelope:
24// intended_use: reusable YAML-frontmatter splitter for nishi-pages content
25// sil_target: SIL2
26// evidence: bench/nx_frontmatter_smoke.nx exercises 3 cases
27// verdict: NOT_YET_EVALUATED -- pending smoke
28
29import "nx_syscalls_x86_64.nx"
30
31// ---- Sealed verdicts ----
32
33const NX_FM_OK: i64 = 0
34const NX_FM_BAD_INPUT: i64 = 1 // src null / len < 4
35const NX_FM_NO_FRONTMATTER: i64 = 2 // doesn't start with "---\n"
36const NX_FM_UNTERMINATED: i64 = 3 // no closing "\n---" found
37const NX_FM_VERDICT_N: i64 = 4
38
39func _fm_match4(src: *u8, off: i64, n: i64,
40 a: i64, b: i64, c: i64, d: i64) -> i64 {
41 if off + 4 > n { return 0 }
42 if src[off] != (a & 0xFF) as u8 { return 0 }
43 if src[off + 1] != (b & 0xFF) as u8 { return 0 }
44 if src[off + 2] != (c & 0xFF) as u8 { return 0 }
45 if src[off + 3] != (d & 0xFF) as u8 { return 0 }
46 return 1
47}
48
49// Split src into frontmatter YAML + body.
50// On NX_FM_OK, *yaml_off..*yaml_len is the YAML and *body_off..*body_len
51// is the body. All offsets are RELATIVE to src.
52//
53// Tolerant of optional trailing "\n" after the second "---".
54func nx_frontmatter_split(src: *u8, src_n: i64,
55 yaml_off: *i64, yaml_len: *i64,
56 body_off: *i64, body_len: *i64) -> i64 {
57 if src as i64 == 0 { return NX_FM_BAD_INPUT }
58 if src_n < 4 { return NX_FM_BAD_INPUT }
59
60 // Header: "---\n" (0x2D 0x2D 0x2D 0x0A)
61 if _fm_match4(src, 0, src_n, 0x2D, 0x2D, 0x2D, 0x0A) == 0 {
62 return NX_FM_NO_FRONTMATTER
63 }
64
65 // Find terminator: scan for "\n---" starting at offset 4 (just
66 // past the "---\n" header). The \n we find IS the line terminator
67 // of the last YAML line.
68 var p: i64 = 4
69 var term: i64 = -1
70 while p + 4 <= src_n {
71 // "\n---" = 0x0A 0x2D 0x2D 0x2D
72 if src[p] == 0x0A {
73 if src[p + 1] == 0x2D {
74 if src[p + 2] == 0x2D {
75 if src[p + 3] == 0x2D { term = p; p = src_n }
76 }
77 }
78 }
79 p = p + 1
80 }
81 if term < 0 { return NX_FM_UNTERMINATED }
82
83 // YAML = src[4..term+1] (include the trailing \n so each YAML line
84 // ends with \n -- the YAML parser needs that).
85 yaml_off[0] = 4
86 yaml_len[0] = (term + 1) - 4
87
88 // Body starts AFTER second "---", optional trailing \n, optional leading \n.
89 var body_start: i64 = term + 4 // skip "\n---"
90 // Optional trailing newline after the closing "---".
91 if body_start < src_n {
92 if src[body_start] == 0x0A { body_start = body_start + 1 }
93 }
94 body_off[0] = body_start
95 body_len[0] = src_n - body_start
96 if body_len[0] < 0 { body_len[0] = 0 }
97
98 return NX_FM_OK
99}