data-exchange
資料交換
json — JSON 解析與產生
json 以堆配置的節點池(json-pool)保存 JSON 樹,支援巢狀陣列與物件、字串/數值/布林/null 標量、轉義字元與指數格式數字。節點池改用動態 vec,沒有固定容量上限——節點總數與單一節點的子元素數僅受可用記憶體限制。高級介面以 json 結構體封裝節點池與根節點索引;其 pool 欄位標註 #{inline=false}(指標欄位),使 json 可按值安全回傳與複製。
; 解析:回傳 ?json(ok=成功,err=失敗並附原因)
j = json.parse('{"name":"Alice","age":30,"items":[1,2,3],"active":true}')
j: {
ok -> {
name, found = it.get-str('name') ; 取標量:get-str / get-num / get-bool / get-i64
age, ok2 = it.get-i64('age') ; 整數取值
items = it.get('items') ; 取子節點,回傳 ?json
s = it.stringify() ; 序列化回字串
}
err(e) -> print(e)
}
; 產生:從空 json 開始,逐步 set / arr-push
j2 = json.new()
j2.set-str('key', 'value')
j2.set-i64('count', 3)
j2.arr-push-str('a')
print(j2.stringify())
高級 API(json 結構體)
json.new()— 建立空(null)jsonjson.parse(s)— 解析,回傳?json;失敗時err分支帶具體原因(empty input/parse error/trailing characters)j.stringify()— 序列化為字串- 取值:
j.get-str(key)/j.get-num(key)/j.get-bool(key)/j.get-i64(key)(回傳(val, ok));j.get(key)回傳子節點?json - 標量直取(root 為標量時):
j.str()/j.num()/j.bool()/j.i64()/j.str-val() - 寫入:
j.set-str(key,val)/j.set-num/j.set-i64/j.set-bool/j.set-null/j.set-key(key, val json) - 陣列:
j.arr-get(i)/j.arr-len()/j.arr-push(val json)/j.arr-push-str/j.arr-push-num/j.arr-push-bool - 物件列舉:
j.obj-len()/j.obj-key(i)/j.obj-keys-str()/j.delete-key(key) - 型別判定:
j.kind()及j.is-null()/j.is-obj()/j.is-arr()/j.is-str()/j.is-num()/j.is-bool()
池容量(無固定上限)
早期版本以固定陣列作池,硬限制 JSON-MAX-NODES = 128 / JSON-MAX-CHILDREN = 32,超出即靜默失敗。現已全面改為堆 vec:
- 節點總數、每節點子元素數皆無上限,僅受可用記憶體限制。
json.parse只在真正的語法錯誤時回傳err,不再有「池耗盡」錯誤分支。j.set*/j.arr-push*僅在建構目標型別不符時回傳false(例如對非物件節點 set、對非陣列節點 push)。j.overflowed()為向後相容而保留,現恆回傳false。
json的複製語意(#{inline=false}):pool是指標欄位,j.get/j.arr-get回傳的子節點json會深拷貝整個池,是父池的獨立快照——對快照的寫入不會回寫父節點。另因?json(option)在match時會消費其值,對同一個 option 重複match會進入nil分支;若需對同一解析結果多次操作,請在單一match內完成,或先以一個json區域變數承接it。
低階 API(json-pool / json-value)
直接以節點索引操作,池作為區域變數使用(單層結構體按值回傳/複製安全):
p = json.new-pool();或p = json-pool {}後p.init()(把nodes/strs/ec/ek/en各 vec 初始化為with-len(0))idx = p.alloc()— 分配新節點並回傳索引(堆 vec 自動擴容)p.add-child(node-idx, child-idx, key)— 以邊表(ec/ek/en單向鏈表)附加子元素,無每節點上限node-idx, next-pos, ok = p.parse(s, pos)— 從pos解析一個值,回傳節點索引val-idx, ok = p.get-key(obj-idx, key);p.arr-get(arr-idx, i);p.arr-len(arr-idx)p.get-kind(idx)/p.get-str(idx)/p.get-num(idx)/p.get-bool(idx)p.set-key(obj-idx, key, val-idx);p.copy-tree(src, idx)(遞迴深拷貝子樹)p.stringify(node-idx)— 序列化指定節點
toml — TOML 1.0 解析與產生
toml 以 toml-doc 保存 TOML 文件,支援註解、bare/quoted/dotted keys、普通表格、array-of-tables、basic/literal/multiline strings、各種整數進位、浮點數、布林值、日期時間、陣列與 inline table。未提供專用 Nolang 型別的值會保留原始字面值。
cfg = toml.parse('title = "Nolang"\n[server]\nport = 8080\n[[server.backends]]\nname = "local"')
doc = toml.new()
doc.put('name', '"nolang"')
doc.put('server.port', '8080')
doc.put('enabled', 'true')
raw = toml.get(doc, 'server.port')
text = toml.stringify(doc)
常用函式:
toml.new()— 建立空文件toml.parse(text)— 解析並回傳?toml-docdoc.put(key, raw-value)— 驗證並新增/更新 TOML 值toml.get(doc, key)— 取得原始值toml.get-str、toml.get-i64、toml.get-f64、toml.get-bool— 取得 scalar 值toml.stringify(doc)— 序列化文件
文件上限為 4 個 key、2 個普通表格、2 個 array-of-tables;key 最長 32 bytes,value 最長 128 bytes。
yaml — YAML 1.2 解析與產生
yaml 以節點池(yaml-pool)保存 YAML 1.2 core schema 的文件樹,支援塊映射、塊序列、流式集合([...] / {...})、單引號/雙引號/plain 標量、塊標量(| / > 與 - / + chomping)、註解、文件標記(--- / ...)與多文檔、錨點(&)與別名(*)、合併鍵 <<、顯式鍵(? k)、型別推斷(null / bool / int / float / .inf / .nan)、點號路徑查詢,以及 JSON / YAML 序列化。
doc ?yaml = yaml.parse('name: Alice\nserver:\n port: 8080\ntags:\n - a\n - b\n')
doc: {
nil -> print('nil')
err -> print(it)
-> {
name, ok = it.find-str('name')
port, ok2 = it.find-i64('server.port')
print(name)
print(port.to-str())
print(it.to-json())
print(it.to-yaml())
}
}
常用函式與方法:
yaml.parse(text)/yaml.parse-all(text)— 解析,回傳?yaml(err分支帶line L, column C位置)yaml.valid-of(text)/yaml.error-of(text)— 只做校驗,不構造文件yaml.strip-bom(text)— 去掉 UTF-8 BOMdoc-count()/doc(i)— 多文檔訪問kind()、is-null()、is-bool()、is-int()、is-float()、is-nan()、is-str()、is-seq()、is-map()、len()、text()、tag()、anchor()、line-of()— 節點資訊str()、i64()、f64()、bool()、scalar-text()— 取值,一律回傳(值, ok)at(i)、value(i)、key(i)、key-node(i)、get(key)、find(path)— 取子節點 / 鍵get-str/get-i64/get-f64/get-bool、find-str/find-i64/find-f64/find-bool— 便捷取值to-json()、to-json-all()、to-yaml()、stringify()、source-of()— 序列化
節點類型常量:YAML-KIND-NULL / BOOL / INT / FLOAT / STR / SEQ / MAP(0–6);標量風格常量 YAML-STYLE-PLAIN / SINGLE / DOUBLE / LITERAL / FOLDED / ALIAS(0–5)與 YAML-STYLE-BLOCK / FLOW(6–7)。
注意一:子節點視圖以
(out yaml, ok bool)回傳,而不是?yaml。這是 API 風格的選擇,不是所有權限制——子節點與父文檔共享節點池本來就是安全的。取值一律建議用find-str/find-i64這類路徑便捷函式。注意二:巢狀 match 裡
it是按層還原的。內層 match 的臂會把it重新綁到自己的主體(臂體必須看到內層值),但該臂一結束it就還原成外層臂的主體,所以下面這種寫法是安全的:d ?yaml = yaml.parse(src)d: {nil -> print('nil')err -> print(it)-> {print(it.find-str('a')) ; 外層 it = 文件v ?yaml = it.at(0)v: {nil -> print('none')err -> print('err')-> print(it.find-str('b')) ; 內層 it = 子節點}print(it.find-str('c')) ; ✅ it 已還原成文件}}唯一的例外是最外層的 match:它結束後
it仍保留最後一個臂的值(不會還原),所以不要在 match 之外依賴it。需要跨層使用時,仍可顯式存到具名區域變數(doc = it),或用析構綁定ok(v) -> ...。注意三:
.nan會被解析成真正的 NaN(f64()回傳 NaN,x != x為真)。JSON 沒有 NaN,所以to-json()對它輸出null;to-yaml()輸出.nan。