Skip to main content

sml/
lib.rs

1// SPDX-License-Identifier: MulanPSL-2.0
2//! SML — SNOWARE Markup Language (Rust 实现, crate 名 `sml`)
3//!
4//! 声明式数据/配置格式, JSON/YAML 的替代品。语法与 Soup 生态的
5//! `lib/sml.soup` (Lua) 对齐:
6//!
7//! ```sml
8//! firstName: John
9//! age: 27
10//! address:
11//! {
12//!     streetAddress: "21 2nd Street"
13//!     state: NY
14//! }
15//! phoneNumbers: [ { type: home } { type: office } ]
16//! @base { region: cn-north-1 }
17//! server web { &base port: 8080 }
18//! ```
19//!
20//! 特性:
21//! - 引号可选 (裸词即字符串)
22//! - 块冒号可省 (`address { }` ≡ `address: { }`)
23//! - 数组分隔灵活 (逗号可选)
24//! - 片段继承 (`@name { }` 定义 / `&name` 引用)
25//! - `include "path"` 引入外部文件(见 [`parse_file`])
26//! - `$env.VAR` 环境变量内联
27//! - `#` 行注释
28//! - 类型自识别: true/false -> bool, null -> None, 数字 -> i64/f64, 其余 -> String
29//!
30//! 值模型: `Value` 枚举 (与 JSON 同构, 另加 `__type`/`__name` 裸块元数据)。
31//!
32//! # 纯解析 vs 文件解析
33//!
34//! [`parse`] 是**纯函数**(只吃字符串,不做 IO),因此不含 include 处理。
35//! 需要 include 时用 [`parse_file`],它会先展开指令再交给 `parse`。
36//! 这样设计保证了 `parse` 的可嵌入性(如 WASM / 沙箱内无文件系统)。
37//!
38//! # Cargo features
39//!
40//! - `serde`(默认关闭):`Value` 实现 `Serialize`/`Deserialize`,可与
41//!   serde_json / serde_yaml / toml 等任意 serde 后端互通;同时提供
42//!   [`serde::from_str`] / [`serde::from_value`] / [`serde::to_value`] /
43//!   [`serde::to_string`] 桥接函数,任何 `#[derive(serde::Deserialize)]`
44//!   类型都能像 toml-rs 一样一键从 SML 反序列化(无需 `SmlDeserialize`)。
45//! - `derive`(默认开启):提供 [`SmlSerialize`] / [`SmlDeserialize`]
46//!   两个 derive 宏,把自定义结构体/枚举「自然地」序列化为 SML,
47//!   无需引入 serde。
48//!
49//! ```toml
50//! sml-rs = { version = "0.2", features = ["serde"] }
51//! # 不需要宏时可关闭默认 feature,回到完全零依赖:
52//! sml-rs = { version = "0.2", default-features = false }
53//! ```
54
55use std::collections::BTreeMap;
56use std::fmt;
57use std::path::{Path, PathBuf};
58
59// ---------------------------------------------------------------------------
60// 值模型
61// ---------------------------------------------------------------------------
62
63#[derive(Debug, Clone, PartialEq)]
64pub enum Value {
65    Null,
66    Bool(bool),
67    Int(i64),
68    Float(f64),
69    Str(String),
70    Array(Vec<Value>),
71    /// 对象/块; `__type` / `__name` 裸块元数据以保留字键存放
72    Object(BTreeMap<String, Value>),
73}
74
75impl Value {
76    /// 对象字段按需取 (支持 "." 点路径)
77    pub fn get(&self, path: &str) -> Option<&Value> {
78        let mut cur = self;
79        for seg in path.split('.') {
80            match cur {
81                Value::Object(m) => cur = m.get(seg)?,
82                _ => return None,
83            }
84        }
85        Some(cur)
86    }
87    /// 字符串视图 (字符串直接返回; 其它返回 None)
88    pub fn as_str(&self) -> Option<&str> {
89        match self {
90            Value::Str(s) => Some(s),
91            _ => None,
92        }
93    }
94}
95
96impl fmt::Display for Value {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        write!(f, "{}", to_sml(self))
99    }
100}
101
102// ---------------------------------------------------------------------------
103// 契约(Contract)—— 可选的 schema 层
104//
105// SML 本身是纯数据格式(与 JSON/YAML 同层),值模型只有 7 种类型,
106// **不具备**结构体定义、枚举、字段约束等类型系统能力。
107// 契约是在此之上的**可选校验层**,用于给块加上结构与取值约束:
108//
109// ```sml
110// @contract Server {
111//     host: str                      # 必填
112//     port: int default 8080         # 带默认值
113//     tls: bool default true
114//     tags: [str] optional           # 可选
115//     status: enum [ active retired ]
116//     ratio: num min 0 max 1
117// }
118//
119// database {
120//     @is Server                     # 应用契约
121//     host: db1.internal
122//     status: active
123// }
124// ```
125//
126// 语义:
127// - `@contract Name { ... }` 定义契约(不进主树)
128// - `@is Name` 在当前块应用契约:缺失字段用 default 填充;
129//   缺少且无默认值的必填字段、类型不符、枚举值越界、数值越 min/max 均报错
130// - 契约须在 `@is` **之前**定义(顺序依赖,与片段继承一致)
131// - 不使用契约时行为完全不变,因此**向后兼容**
132// ---------------------------------------------------------------------------
133
134/// 契约中的字段类型
135#[derive(Debug, Clone, PartialEq)]
136pub enum TypeSpec {
137    /// 任意类型
138    Any,
139    /// 引用另一个契约(**组合**)——字段值须是块,并递归按被引用契约校验。
140    /// 用组合而非继承:契约之间不共享字段,而是「字段的类型是另一个契约」。
141    /// 语法上复用裸词(写被引用的契约名),因此不引入任何新 token:
142    ///     @contract Address { city: str }
143    ///     @contract Server { address: Address }
144    ContractRef(String),
145    Str,
146    Int,
147    /// 数值:int 或 float 均可
148    Num,
149    Bool,
150    /// 数组,元素须为指定类型
151    Array(Box<TypeSpec>),
152    /// 枚举:取值须在给定列表中
153    Enum(Vec<String>),
154}
155
156impl TypeSpec {
157    fn name(&self) -> String {
158        match self {
159            TypeSpec::Any => "any".into(),
160            TypeSpec::Str => "str".into(),
161            TypeSpec::Int => "int".into(),
162            TypeSpec::Num => "num".into(),
163            TypeSpec::Bool => "bool".into(),
164            TypeSpec::Array(inner) => format!("[{}]", inner.name()),
165            TypeSpec::Enum(vals) => format!("enum [{}]", vals.join(" ")),
166            TypeSpec::ContractRef(name) => name.clone(),
167        }
168    }
169}
170
171/// 契约中的字段规格
172#[derive(Debug, Clone)]
173pub struct FieldSpec {
174    pub ty: TypeSpec,
175    /// 是否必填(默认 true)
176    pub required: bool,
177    /// 缺失时填充的默认值
178    pub default: Option<Value>,
179    /// 数值下界(含)
180    pub min: Option<f64>,
181    /// 数值上界(含)
182    pub max: Option<f64>,
183}
184
185/// 契约(schema):一组字段规格
186#[derive(Debug, Clone)]
187pub struct Contract {
188    pub name: String,
189    pub fields: BTreeMap<String, FieldSpec>,
190    /// 是否允许契约未声明的字段。
191    /// **默认 false(严格)**:额外字段一律报错,可及早发现拼写错误
192    /// (如 `prot` 误写为 `port`)。确需放宽时须**显式**写 `loose`。
193    pub allow_extra: bool,
194}
195
196/// 校验值是否符合类型规格。
197/// `contracts` 供 `ContractRef`(组合)递归查找被引用契约。
198fn check_type(
199    contract: &str,
200    field: &str,
201    spec: &FieldSpec,
202    v: &Value,
203    contracts: &BTreeMap<String, Contract>,
204) -> Result<(), String> {
205    // 组合:字段值是块,递归按被引用的契约校验(含填默认值)
206    if let TypeSpec::ContractRef(ref_name) = &spec.ty {
207        return match v {
208            Value::Object(_) => {
209                let mut sub = match v {
210                    Value::Object(m) => m.clone(),
211                    _ => unreachable!(),
212                };
213                let target = contracts.get(ref_name).ok_or_else(|| {
214                    format!(
215                        "sml: 字段 `{}` 引用了未定义的契约 `{}`(契约 `{}`)",
216                        field, ref_name, contract
217                    )
218                })?;
219                apply_contract(target, &mut sub, contracts)?;
220                Ok(())
221            }
222            _ => Err(format!(
223                "sml: 字段 `{}` 应为块并按契约 `{}` 校验,实际为 {}(契约 `{}`)",
224                field,
225                ref_name,
226                value_kind(v),
227                contract
228            )),
229        };
230    }
231
232    let ok = match (&spec.ty, v) {
233        (TypeSpec::Any, _) => true,
234        (TypeSpec::Str, Value::Str(_)) => true,
235        (TypeSpec::Int, Value::Int(_)) => true,
236        (TypeSpec::Num, Value::Int(_)) | (TypeSpec::Num, Value::Float(_)) => true,
237        (TypeSpec::Bool, Value::Bool(_)) => true,
238        (TypeSpec::Enum(vals), Value::Str(s)) => vals.iter().any(|x| x == s),
239        // 裸词数字会被 coerce 成 Int/Float,故枚举也接受被 coerce 成标量的情形
240        (TypeSpec::Enum(vals), Value::Int(i)) => vals.iter().any(|x| x == &i.to_string()),
241        (TypeSpec::Array(inner), Value::Array(items)) => items.iter().all(|it| {
242            check_type(
243                contract,
244                field,
245                &FieldSpec { ty: (**inner).clone(), required: true, default: None, min: None, max: None },
246                it,
247                contracts,
248            )
249            .is_ok()
250        }),
251        _ => false,
252    };
253    if !ok {
254        return Err(format!(
255            "sml: 字段 `{}` 类型应为 {},实际为 {}(契约 `{}`)",
256            field,
257            spec.ty.name(),
258            value_kind(v),
259            contract
260        ));
261    }
262    // 数值区间
263    if spec.min.is_some() || spec.max.is_some() {
264        let n = match v {
265            Value::Int(i) => Some(*i as f64),
266            Value::Float(f) => Some(*f),
267            _ => None,
268        };
269        if let Some(n) = n {
270            if let Some(lo) = spec.min {
271                if n < lo {
272                    return Err(format!(
273                        "sml: 字段 `{}` 值 {} 小于下界 {}(契约 `{}`)",
274                        field, n, lo, contract
275                    ));
276                }
277            }
278            if let Some(hi) = spec.max {
279                if n > hi {
280                    return Err(format!(
281                        "sml: 字段 `{}` 值 {} 大于上界 {}(契约 `{}`)",
282                        field, n, hi, contract
283                    ));
284                }
285            }
286        }
287    }
288    Ok(())
289}
290
291fn value_kind(v: &Value) -> &'static str {
292    match v {
293        Value::Null => "null",
294        Value::Bool(_) => "bool",
295        Value::Int(_) => "int",
296        Value::Float(_) => "float",
297        Value::Str(_) => "str",
298        Value::Array(_) => "array",
299        Value::Object(_) => "object",
300    }
301}
302
303/// 对块应用契约:填充默认值 + 校验 + 严格性检查。
304///
305/// **严格为默认**:契约未声明的字段会被拒绝,除非契约显式标记 `loose`。
306/// 这样拼错的字段名(如 `prot`)会立即报错,而不是被静默忽略。
307fn apply_contract(
308    c: &Contract,
309    node: &mut BTreeMap<String, Value>,
310    contracts: &BTreeMap<String, Contract>,
311) -> Result<(), String> {
312    // 1) 严格性:未声明字段一律拒绝(组合字段本身已在 fields 声明,其
313    //    内部字段由被引用契约在自己的 apply_contract 中负责校验)
314    if !c.allow_extra {
315        for k in node.keys() {
316            if !c.fields.contains_key(k) {
317                return Err(format!(
318                    "sml: 字段 `{}` 未在契约 `{}` 中声明(严格模式;如需允许额外字段请在契约名后写 `loose`)",
319                    k, c.name
320                ));
321            }
322        }
323    }
324    // 2) 逐字段:填默认值 + 类型/枚举/区间/组合校验
325    for (k, spec) in &c.fields {
326        match node.get(k) {
327            None => {
328                if let Some(d) = &spec.default {
329                    node.insert(k.clone(), d.clone());
330                } else if spec.required {
331                    return Err(format!(
332                        "sml: 字段 `{}` 必填但缺失(契约 `{}`)",
333                        k, c.name
334                    ));
335                }
336            }
337            Some(v) => {
338                // 组合会回填子块默认值,故需要可变副本
339                if matches!(spec.ty, TypeSpec::ContractRef(_)) {
340                    // 先按**原值**校验必须是块,否则会退化成
341                    // 「子字段缺失」这类误导性错误
342                    check_type(&c.name, k, spec, v, contracts)?;
343                    let mut sub = match v {
344                        Value::Object(m) => m.clone(),
345                        _ => unreachable!("check_type 已保证为块"),
346                    };
347                    check_type_contract_ref(&c.name, k, spec, &mut sub, contracts)?;
348                    node.insert(k.clone(), Value::Object(sub));
349                } else {
350                    check_type(&c.name, k, spec, v, contracts)?;
351                }
352            }
353        }
354    }
355    Ok(())
356}
357
358/// 对「组合字段」递归应用被引用契约(会回填子块默认值)
359fn check_type_contract_ref(
360    contract: &str,
361    field: &str,
362    spec: &FieldSpec,
363    sub: &mut BTreeMap<String, Value>,
364    contracts: &BTreeMap<String, Contract>,
365) -> Result<(), String> {
366    let ref_name = match &spec.ty {
367        TypeSpec::ContractRef(n) => n.clone(),
368        _ => return Ok(()),
369    };
370    let target = contracts.get(&ref_name).ok_or_else(|| {
371        format!(
372            "sml: 字段 `{}` 引用了未定义的契约 `{}`(契约 `{}`)",
373            field, ref_name, contract
374        )
375    })?;
376    // 先做基础类型校验(值须为块),再递归应用
377    check_type(contract, field, spec, &Value::Object(sub.clone()), contracts)?;
378    apply_contract(target, sub, contracts)
379}
380
381// ---------------------------------------------------------------------------
382// 解析: 词法 + 递归下降
383// ---------------------------------------------------------------------------
384
385#[derive(Debug, Clone, PartialEq)]
386enum Tok {
387    LBrace,  // {
388    RBrace,  // }
389    LBrack,  // [
390    RBrack,  // ]
391    Comma,   // ,
392    Colon,   // :
393    At,      // @
394    Str(String),   // 引号串 (已解码)
395    Word(String),  // 裸词
396}
397
398fn tokenize(text: &str) -> Result<Vec<Tok>, String> {
399    let mut toks = Vec::new();
400    let mut chars = text.chars().peekable();
401    let mut buf = String::new();
402    let mut flush = |buf: &mut String, toks: &mut Vec<Tok>| {
403        if !buf.is_empty() {
404            toks.push(Tok::Word(std::mem::take(buf)));
405        }
406    };
407    while let Some(c) = chars.next() {
408        match c {
409            '#' => {
410                // 单行注释到行尾
411                for c2 in chars.by_ref() {
412                    if c2 == '\n' {
413                        break;
414                    }
415                }
416            }
417            '-' => {
418                // `--` 单行注释到行尾;否则作为普通字符
419                if chars.peek() == Some(&'-') {
420                    chars.next(); // 吃掉第二个 -
421                    for c2 in chars.by_ref() {
422                        if c2 == '\n' {
423                            break;
424                        }
425                    }
426                } else {
427                    buf.push(c);
428                }
429            }
430            '/' => {
431                match chars.peek() {
432                    // `//` 单行注释到行尾
433                    Some('/') => {
434                        chars.next(); // 吃掉第二个 /
435                        for c2 in chars.by_ref() {
436                            if c2 == '\n' {
437                                break;
438                            }
439                        }
440                    }
441                    // `/*` 多行注释,直到 `*/`
442                    Some('*') => {
443                        chars.next(); // 吃掉 *
444                        loop {
445                            match chars.next() {
446                                Some('*') => {
447                                    if chars.peek() == Some(&'/') {
448                                        chars.next();
449                                        break;
450                                    }
451                                }
452                                Some(_) => {}
453                                None => break,
454                            }
455                        }
456                    }
457                    // 否则作为普通字符(如路径 a/b/c)
458                    _ => buf.push(c),
459                }
460            }
461            '_' => {
462                // `_*` 多行注释,直到 `*_`;否则作为普通字符
463                if chars.peek() == Some(&'*') {
464                    chars.next(); // 吃掉 *
465                    loop {
466                        match chars.next() {
467                            Some('*') => {
468                                if chars.peek() == Some(&'_') {
469                                    chars.next();
470                                    break;
471                                }
472                            }
473                            Some(_) => {}
474                            None => break,
475                        }
476                    }
477                } else {
478                    buf.push(c);
479                }
480            }
481            '"' => {
482                flush(&mut buf, &mut toks);
483                let mut s = String::new();
484                loop {
485                    match chars.next() {
486                        Some('"') => break,
487                        Some('\\') => {
488                            // 转义:\n \t \r \0 \" \\ \u{XXXX} \uXXXX
489                            match chars.next() {
490                                Some('n') => s.push('\n'),
491                                Some('t') => s.push('\t'),
492                                Some('r') => s.push('\r'),
493                                Some('0') => s.push('\0'),
494                                Some('"') => s.push('"'),
495                                Some('\\') => s.push('\\'),
496                                Some('u') => {
497                                    let mut hex = String::new();
498                                    // 支持 \u{XXXX} 或 \uXXXX
499                                    if chars.peek() == Some(&'{') {
500                                        chars.next();
501                                        for c2 in chars.by_ref() {
502                                            if c2 == '}' {
503                                                break;
504                                            }
505                                            hex.push(c2);
506                                        }
507                                    } else {
508                                        for _ in 0..4 {
509                                            if let Some(c2) = chars.next() {
510                                                hex.push(c2);
511                                            }
512                                        }
513                                    }
514                                    if let Ok(cp) = u32::from_str_radix(&hex, 16) {
515                                        if let Some(ch) = char::from_u32(cp) {
516                                            s.push(ch);
517                                        }
518                                    }
519                                }
520                                Some(other) => s.push(other),
521                                None => break,
522                            }
523                        }
524                        Some(other) => s.push(other),
525                        None => break,
526                    }
527                }
528                toks.push(Tok::Str(s));
529            }
530            '{' => {
531                flush(&mut buf, &mut toks);
532                toks.push(Tok::LBrace);
533            }
534            '}' => {
535                flush(&mut buf, &mut toks);
536                toks.push(Tok::RBrace);
537            }
538            '[' => {
539                flush(&mut buf, &mut toks);
540                toks.push(Tok::LBrack);
541            }
542            ']' => {
543                flush(&mut buf, &mut toks);
544                toks.push(Tok::RBrack);
545            }
546            ',' => {
547                flush(&mut buf, &mut toks);
548                toks.push(Tok::Comma);
549            }
550            ':' => {
551                flush(&mut buf, &mut toks);
552                toks.push(Tok::Colon);
553            }
554            '@' => {
555                // `@` 仅当位于**词首**时才是片段定义标记(`@base { ... }`)。
556                // 出现在词中间时(典型如邮箱 `a@b.c`)必须作为普通字符保留:
557                // 否则 `a@b.c` 会被切成 `Word("a")` + `At` + `Word("b.c")`,
558                // 后半段在解析时被丢弃,导致邮箱静默损坏为 `a`。
559                if buf.is_empty() {
560                    toks.push(Tok::At);
561                } else {
562                    buf.push(c);
563                }
564            }
565            ' ' | '\t' | '\n' | '\r' => {
566                flush(&mut buf, &mut toks);
567            }
568            _ => {
569                buf.push(c);
570            }
571        }
572    }
573    flush(&mut buf, &mut toks);
574    Ok(toks)
575}
576
577/// 把裸词 `w` 转为 Value。
578///
579/// 受 `features` 控制:关闭 `BarewordStr` 后纯字符串裸词(如 `John`)被拒绝,
580/// 必须写作 `"John"`;仍允许的非字符串裸词:bool / null / 数字 /
581/// 片段引用 `&x`(需 `fragment`)/ 环境变量 `$env.X`(需 `env`)。
582fn coerce_word(
583    w: &str,
584    fragments: &BTreeMap<String, Value>,
585    features: FeatureSet,
586    ns_prefix: &str,
587) -> Result<Value, String> {
588    match w {
589        "true" => return Ok(Value::Bool(true)),
590        "false" => return Ok(Value::Bool(false)),
591        "null" => return Ok(Value::Null),
592        _ => {}
593    }
594    // $env.VAR 内联(需 env 特性)
595    if let Some(ev) = w.strip_prefix("$env.") {
596        if !features.has(Feature::Env) {
597            return Err(format!("sml: 当前特性集禁用了 `$env`(env),裸词 `{}` 无法解析", w));
598        }
599        return Ok(Value::Str(std::env::var(ev).unwrap_or_default()));
600    }
601    // 片段引用 &name(需 fragment 特性)。命名空间隔离:先查裸名,再逐级查 ns 前缀。
602    if let Some(name) = w.strip_prefix('&') {
603        if !features.has(Feature::Fragment) {
604            return Err(format!("sml: 当前特性集禁用了片段引用(fragment),`{}` 无法解析", w));
605        }
606        if let Some(v) = fragments.get(name) {
607            return Ok(v.clone());
608        }
609        // 逐级回退:ui.form.foo → form.foo → foo
610        if !ns_prefix.is_empty() {
611            let mut probe = ns_prefix.to_string();
612            loop {
613                let full = format!("{probe}.{name}");
614                if let Some(v) = fragments.get(&full) {
615                    return Ok(v.clone());
616                }
617                match probe.rfind('.') {
618                    Some(idx) => probe.truncate(idx),
619                    None => break,
620                }
621            }
622        }
623        return Ok(Value::Str(w.to_string()));
624    }
625    // 数字: int / float / 科学计数
626    if let Ok(i) = w.parse::<i64>() {
627        return Ok(Value::Int(i));
628    }
629    if let Ok(f) = w.parse::<f64>() {
630        return Ok(Value::Float(f));
631    }
632    if !features.has(Feature::BarewordStr) {
633        return Err(format!(
634            "sml: 字符串必须加引号,裸词 `{}` 应写作 `\"{}\"`(特性 bareword-string 已禁用)",
635            w, w
636        ));
637    }
638    Ok(Value::Str(w.to_string()))
639}
640
641struct Parser {
642    toks: Vec<Tok>,
643    i: usize,
644    fragments: BTreeMap<String, Value>,
645    /// 契约表:名 -> 契约。由 `@contract Name { ... }` 填充
646    contracts: BTreeMap<String, Contract>,
647    /// 生效特性集(已与调用方允许范围交集)
648    features: FeatureSet,
649    /// 命名空间栈:每个块(含 include `as ns` 产生的块)的名字依次入栈。
650    /// 宏/契约注册与引用时,按栈路径加前缀(如 `ui.form.Button`),
651    /// 使命名空间真正隔离宏,而非仅隔离数据键值。
652    ns_stack: Vec<String>,
653}
654
655impl Parser {
656    /// 当前命名空间前缀(栈路径用 "." 连接,空栈返回空串)
657    fn ns_prefix(&self) -> String {
658        if self.ns_stack.is_empty() {
659            String::new()
660        } else {
661            self.ns_stack.join(".")
662        }
663    }
664
665    /// 把裸名套上当前命名空间前缀(若栈非空)
666    fn qualify(&self, name: &str) -> String {
667        let p = self.ns_prefix();
668        if p.is_empty() {
669            name.to_string()
670        } else {
671            format!("{p}.{name}")
672        }
673    }
674
675    fn peek(&self) -> Option<&Tok> {
676        self.toks.get(self.i)
677    }
678    fn next(&mut self) -> Option<Tok> {
679        let t = self.toks.get(self.i).cloned();
680        if t.is_some() {
681            self.i += 1;
682        }
683        t
684    }
685
686    /// 解析契约体:逐条读 `field: <类型> [修饰符...]`
687    fn parse_contract_body(&mut self) -> Result<BTreeMap<String, FieldSpec>, String> {
688        let mut fields: BTreeMap<String, FieldSpec> = BTreeMap::new();
689        loop {
690            match self.peek().cloned() {
691                None | Some(Tok::RBrace) => {
692                    self.next();
693                    break;
694                }
695                Some(Tok::Comma) => {
696                    self.next();
697                }
698                _ => {
699                    let key = match self.next() {
700                        Some(Tok::Word(s)) | Some(Tok::Str(s)) => s,
701                        other => {
702                            return Err(format!("sml: 契约字段期望键, 得 {:?}", other))
703                        }
704                    };
705                    if self.peek() == Some(&Tok::Colon) {
706                        self.next();
707                    } else {
708                        return Err(format!("sml: 契约字段 `{}` 后须有冒号", key));
709                    }
710                    let spec = self.parse_field_spec()?;
711                    fields.insert(key, spec);
712                }
713            }
714        }
715        Ok(fields)
716    }
717
718    /// 解析单个字段的类型与修饰符
719    fn parse_field_spec(&mut self) -> Result<FieldSpec, String> {
720        let ty = match self.next() {
721            Some(Tok::Word(w)) => match w.as_str() {
722                "str" => TypeSpec::Str,
723                "int" => TypeSpec::Int,
724                "num" => TypeSpec::Num,
725                "bool" => TypeSpec::Bool,
726                "any" => TypeSpec::Any,
727                "enum" => {
728                    if self.peek() != Some(&Tok::LBrack) {
729                        return Err("sml: `enum` 后须为 [ ... ]".into());
730                    }
731                    self.next();
732                    let mut vals = Vec::new();
733                    loop {
734                        match self.peek().cloned() {
735                            None | Some(Tok::RBrack) => {
736                                self.next();
737                                break;
738                            }
739                            Some(Tok::Comma) => {
740                                self.next();
741                            }
742                            Some(Tok::Word(s)) | Some(Tok::Str(s)) => {
743                                vals.push(s);
744                                self.next();
745                            }
746                            _ => {
747                                self.next();
748                            }
749                        }
750                    }
751                    TypeSpec::Enum(vals)
752                }
753                // 非内置类型名 -> 视为**契约引用**(组合)。
754                // 这样「字段的类型是另一个契约」复用裸词表达,不引入新 token。
755                // 被引用的契约可在之后定义(校验发生在 @is 时,而非定义时)。
756                other => TypeSpec::ContractRef(other.to_string()),
757            },
758            Some(Tok::LBrack) => {
759                let inner = match self.next() {
760                    Some(Tok::Word(w)) => match w.as_str() {
761                        "str" => TypeSpec::Str,
762                        "int" => TypeSpec::Int,
763                        "num" => TypeSpec::Num,
764                        "bool" => TypeSpec::Bool,
765                        "any" => TypeSpec::Any,
766                        other => {
767                            return Err(format!("sml: 未知数组元素类型 `{}`", other))
768                        }
769                    },
770                    other => {
771                        return Err(format!("sml: 数组元素类型期望标识符, 得 {:?}", other))
772                    }
773                };
774                if self.peek() == Some(&Tok::RBrack) {
775                    self.next();
776                }
777                TypeSpec::Array(Box::new(inner))
778            }
779            other => return Err(format!("sml: 字段类型期望标识符, 得 {:?}", other)),
780        };
781
782        // 修饰符:required / optional / default <值> / min <数> / max <数>
783        let mut required = true;
784        let mut default = None;
785        let mut min = None;
786        let mut max = None;
787        loop {
788            // 若当前是 `标识符 :` 则视为下一个字段的开始,停止读修饰符
789            let is_next_field = matches!(self.peek(), Some(Tok::Word(_)))
790                && matches!(self.toks.get(self.i + 1), Some(Tok::Colon));
791            if is_next_field {
792                break;
793            }
794            match self.peek().cloned() {
795                Some(Tok::Word(w)) => match w.as_str() {
796                    "optional" => {
797                        required = false;
798                        self.next();
799                    }
800                    "required" => {
801                        required = true;
802                        self.next();
803                    }
804                    "default" => {
805                        self.next();
806                        default = Some(match self.next() {
807                            Some(Tok::Word(w2)) => coerce_word(&w2, &self.fragments, self.features, &self.ns_prefix())?,
808                            Some(Tok::Str(s)) => Value::Str(s),
809                            other => {
810                                return Err(format!("sml: default 期望值, 得 {:?}", other))
811                            }
812                        });
813                    }
814                    "min" => {
815                        self.next();
816                        min = Some(self.parse_spec_number()?);
817                    }
818                    "max" => {
819                        self.next();
820                        max = Some(self.parse_spec_number()?);
821                    }
822                    _ => break,
823                },
824                _ => break,
825            }
826        }
827        Ok(FieldSpec { ty, required, default, min, max })
828    }
829
830    fn parse_spec_number(&mut self) -> Result<f64, String> {
831        match self.next() {
832            Some(Tok::Word(w)) => {
833                w.parse::<f64>().map_err(|_| format!("sml: 期望数字, 得 `{}`", w))
834            }
835            other => Err(format!("sml: 期望数字, 得 {:?}", other)),
836        }
837    }
838
839    /// 解析对象/块, 直到遇到 closing (None=顶层)
840    fn parse_block(&mut self, closing: Option<Tok>) -> Result<Value, String> {
841        let mut node: BTreeMap<String, Value> = BTreeMap::new();
842        // 块内若声明了 `@is Name`,在块解析完成后应用契约
843        let mut applied_contract: Option<String> = None;
844        loop {
845            let tok = match self.peek().cloned() {
846                None => break,
847                Some(t) => t,
848            };
849            match tok {
850                Tok::RBrace | Tok::RBrack => {
851                    if let Some(cl) = &closing {
852                        if *cl == tok {
853                            self.next();
854                            break;
855                        }
856                    }
857                    // 顶层遇右括号也停
858                    break;
859                }
860                Tok::Comma => {
861                    self.next();
862                }
863                Tok::At => {
864                    // @name { ... } 片段定义 (不进主树)
865                    self.next();
866                    let fname = match self.next() {
867                        Some(Tok::Word(s)) | Some(Tok::Str(s)) => s,
868                        _ => return Err("sml: @ 后需片段名".into()),
869                    };
870                    if self.peek() == Some(&Tok::Colon) {
871                        self.next();
872                    }
873                    // —— 契约定义:`@contract Name { ... }` ——
874                    if fname == "contract" {
875                        if !self.features.has(Feature::Contract) {
876                            return Err("@contract 需要特性 `contract`,但当前特性集已禁用".into());
877                        }
878                        let cname = match self.next() {
879                            Some(Tok::Word(s)) | Some(Tok::Str(s)) => s,
880                            other => {
881                                return Err(format!("sml: @contract 后须契约名, 得 {:?}", other))
882                            }
883                        };
884                        // 可选修饰符 `loose`:显式允许契约未声明的字段。
885                        // 严格是默认,放宽必须写出来(复用裸词,不引入新 token)。
886                        let mut allow_extra = false;
887                        if let Some(Tok::Word(w)) = self.peek().cloned() {
888                            if w == "loose" {
889                                allow_extra = true;
890                                self.next();
891                            }
892                        }
893                        if self.peek() != Some(&Tok::LBrace) {
894                            return Err(format!("sml: @contract {} 后须 {{ ... }}", cname));
895                        }
896                        self.next();
897                        let fields = self.parse_contract_body()?;
898                        // 命名空间前缀隔离:块内的契约按当前 ns 栈路径注册
899                        self.contracts.insert(
900                            self.qualify(&cname),
901                            Contract {
902                                name: self.qualify(&cname),
903                                fields,
904                                allow_extra,
905                            },
906                        );
907                        continue;
908                    }
909                    // —— 契约应用:`@is Name`(在当前块内)——
910                    if fname == "is" {
911                        if !self.features.has(Feature::Contract) {
912                            return Err("@is 需要特性 `contract`,但当前特性集已禁用".into());
913                        }
914                        let cname = match self.next() {
915                            Some(Tok::Word(s)) | Some(Tok::Str(s)) => s,
916                            other => {
917                                return Err(format!("sml: @is 后须契约名, 得 {:?}", other))
918                            }
919                        };
920                        // 命名空间隔离:先按裸名查,再按当前 ns 前缀查
921                        let resolved = if self.contracts.contains_key(&cname) {
922                            cname.clone()
923                        } else {
924                            self.qualify(&cname)
925                        };
926                        applied_contract = Some(resolved);
927                        continue;
928                    }
929                    // 可选 type [name] 参数
930                    let mut ftype: Option<String> = None;
931                    let mut farg: Option<String> = None;
932                    if let Some(Tok::Word(s)) = self.peek().cloned() {
933                        if *self.peek().unwrap() != Tok::LBrace {
934                            self.next();
935                            ftype = Some(s);
936                            if let Some(Tok::Word(s2)) = self.peek().cloned() {
937                                if *self.peek().unwrap() != Tok::LBrace {
938                                    self.next();
939                                    farg = Some(s2);
940                                }
941                            }
942                        }
943                    }
944                    if self.peek() == Some(&Tok::LBrace) {
945                        self.next();
946                        let mut sub = match self.parse_block(Some(Tok::RBrace))? {
947                            Value::Object(m) => m,
948                            other => {
949                                let mut m = BTreeMap::new();
950                                m.insert("_value".into(), other);
951                                m
952                            }
953                        };
954                        if let Some(t) = ftype {
955                            sub.insert("__type".into(), Value::Str(t));
956                        }
957                        if let Some(a) = farg {
958                            sub.insert("__name".into(), Value::Str(a));
959                        }
960                        if !self.features.has(Feature::Fragment) {
961                            return Err(format!(
962                                "sml: 片段定义 `@{}` 需要特性 `fragment`,但当前特性集已禁用",
963                                fname
964                            ));
965                        }
966                        // 命名空间前缀隔离:片段定义按当前 ns 栈路径注册
967                        self.fragments.insert(self.qualify(&fname), Value::Object(sub));
968                    }
969                }
970                _ => {
971                    // key
972                    let key = match self.next() {
973                        Some(Tok::Word(s)) | Some(Tok::Str(s)) => s,
974                        other => return Err(format!("sml: 期望键, 得 {:?}", other)),
975                    };
976                    let colon = self.peek() == Some(&Tok::Colon);
977                    if colon {
978                        self.next();
979                    }
980                    let val = self.parse_value(&key, colon)?;
981                    // 同名冲突 -> 提升为数组
982                    if let Some(existing) = node.get_mut(&key) {
983                        match existing {
984                            Value::Array(a) => a.push(val),
985                            _ => {
986                                let old = node.remove(&key).unwrap();
987                                node.insert(key, Value::Array(vec![old, val]));
988                            }
989                        }
990                    } else {
991                        node.insert(key, val);
992                    }
993                }
994            }
995        }
996        // 块结束:若声明了 `@is`,应用契约(填默认值 + 校验 + 严格性检查)
997        if let Some(cname) = applied_contract {
998            let c = self
999                .contracts
1000                .get(&cname)
1001                .cloned()
1002                .ok_or_else(|| format!("sml: 未定义的契约 `{}`", cname))?;
1003            apply_contract(&c, &mut node, &self.contracts)?;
1004        }
1005        Ok(Value::Object(node))
1006    }
1007
1008    /// 解析一个值 (在 key 之后)
1009    fn parse_value(&mut self, key: &str, colon: bool) -> Result<Value, String> {
1010        // 无冒号且后继是裸词: 可能是裸块 `type [name] { }`
1011        if !colon && matches!(self.peek(), Some(Tok::Word(_))) {
1012            // 预扫描: 收集参数直到 { / 结束; 若发现 { 则按裸块处理
1013            let mut probe = self.i;
1014            let mut found_block = false;
1015            while probe < self.toks.len() {
1016                match &self.toks[probe] {
1017                    Tok::Word(_) | Tok::Str(_) => probe += 1,
1018                    Tok::LBrace => {
1019                        found_block = true;
1020                        break;
1021                    }
1022                    _ => break,
1023                }
1024            }
1025            if found_block {
1026                // 裸块: key 为类型, 参数在 { 前
1027                let mut args: Vec<Value> = Vec::new();
1028                while let Some(t) = self.peek().cloned() {
1029                    match t {
1030                        Tok::Word(w) => {
1031                            args.push(coerce_word(&w, &self.fragments, self.features, &self.ns_prefix())?);
1032                            self.next();
1033                        }
1034                        Tok::Str(_) => {
1035                            if let Some(Tok::Str(s)) = self.next() {
1036                                args.push(Value::Str(s));
1037                            }
1038                        }
1039                        _ => break,
1040                    }
1041                }
1042                if self.peek() == Some(&Tok::LBrace) {
1043                    self.next();
1044                    // 进入子块 = 进入该 block 名字的命名空间
1045                    self.ns_stack.push(key.to_string());
1046                    let mut sub = self.parse_block(Some(Tok::RBrace))?;
1047                    self.ns_stack.pop();
1048                    if let Value::Object(m) = &mut sub {
1049                        m.insert("__type".into(), Value::Str(key.to_string()));
1050                        if args.len() == 1 {
1051                            m.insert("__name".into(), args.remove(0));
1052                        }
1053                    }
1054                    return Ok(sub);
1055                }
1056            }
1057        }
1058        match self.peek().cloned() {
1059            Some(Tok::LBrace) => {
1060                self.next();
1061                self.parse_block(Some(Tok::RBrace))
1062            }
1063            Some(Tok::LBrack) => {
1064                self.next();
1065                self.parse_array()
1066            }
1067            Some(tok @ (Tok::Word(_) | Tok::Str(_))) => {
1068                let v = match tok {
1069                    Tok::Word(w) => coerce_word(&w, &self.fragments, self.features, &self.ns_prefix())?,
1070                    Tok::Str(s) => {
1071                        let ev = s.strip_prefix("$env.");
1072                        match ev {
1073                            Some(name) => Value::Str(std::env::var(name).unwrap_or_default()),
1074                            None => Value::Str(s),
1075                        }
1076                    }
1077                    _ => unreachable!(),
1078                };
1079                self.next();
1080                Ok(v)
1081            }
1082            // 键后无值: `key }` / `key ]` / `key ,` / 行尾 —— key 本身即值 (片段引用/裸词)
1083            Some(Tok::RBrace) | Some(Tok::RBrack) | Some(Tok::Comma) | None => {
1084                if colon {
1085                    // 有冒号但无值: 空值
1086                    Ok(Value::Null)
1087                } else {
1088                    Ok(coerce_word(key, &self.fragments, self.features, &self.ns_prefix())?)
1089                }
1090            }
1091            _ => Err("sml: 语法错误".into()),
1092        }
1093    }
1094
1095    fn parse_array(&mut self) -> Result<Value, String> {
1096        let mut arr = Vec::new();
1097        loop {
1098            match self.peek().cloned() {
1099                None => break,
1100                Some(Tok::RBrack) => {
1101                    self.next();
1102                    break;
1103                }
1104                Some(Tok::Comma) => {
1105                    self.next();
1106                }
1107                Some(Tok::LBrace) => {
1108                    self.next();
1109                    arr.push(self.parse_block(Some(Tok::RBrace))?);
1110                }
1111                Some(Tok::Word(w)) => {
1112                    arr.push(coerce_word(&w, &self.fragments, self.features, &self.ns_prefix())?);
1113                    self.next();
1114                }
1115                Some(Tok::Str(_)) => {
1116                    if let Some(Tok::Str(s)) = self.next() {
1117                        arr.push(Value::Str(s));
1118                    }
1119                }
1120                _ => break,
1121            }
1122        }
1123        Ok(Value::Array(arr))
1124    }
1125}
1126
1127/// SML 语法版本
1128///
1129/// SML 源于 eclog,演进中通过 `@version` 声明文档遵循的语法版本,
1130/// 使解析器能在将来引入 v2 不兼容语法时仍正确读取旧文档。
1131#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1132pub enum Version {
1133    /// v1:初始公开版本。字符串可裸写(`name: John`),自动识别类型。
1134    V1,
1135    /// v2:草案版,引入「字符串必须显式引号」的不兼容语法(与 v3 同语义)。
1136    V2,
1137    /// v3:正式版。取消自动字符串无引号,自由文本必须写作 `"..."`;
1138    ///     数字 / bool / null / 片段引用 `&x` / 环境变量 `$env.X` 仍为裸词。
1139    V3,
1140}
1141
1142impl Version {
1143    /// 当前实现支持的最新版本
1144    pub const CURRENT: Version = Version::V3;
1145
1146    /// 是否要求字符串显式引号(v2 / v3 为严格模式)
1147    pub fn strict_strings(self) -> bool {
1148        self >= Version::V2
1149    }
1150
1151    /// 解析版本字面量(`v1`/`1`、`v2`/`2`、`v3`/`3`)
1152    fn from_word(w: &str) -> Option<Version> {
1153        match w {
1154            "v1" | "1" => Some(Version::V1),
1155            "v2" | "2" => Some(Version::V2),
1156            "v3" | "3" => Some(Version::V3),
1157            _ => None,
1158        }
1159    }
1160
1161    /// 版本名(用于错误信息与序列化回显)
1162    pub fn name(self) -> &'static str {
1163        match self {
1164            Version::V1 => "v1",
1165            Version::V2 => "v2",
1166            Version::V3 => "v3",
1167        }
1168    }
1169}
1170
1171impl fmt::Display for Version {
1172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1173        f.write_str(self.name())
1174    }
1175}
1176
1177// ===========================================================================
1178// 特性集 (FeatureSet)
1179//
1180// 文档可通过 `@feature` 指令在「版本基线」之上做**裁剪**(窄化),调用方也可
1181// 通过 `parse_with_features` / `parse_allowed` 限制接受的子集。文档不能扩宽
1182// 调用方给出的范围——否则 `@feature` 就成了绕过限制的后门。
1183//
1184// 为保证五端(Rust/C/JS/C++/Lua)实现一致且易于维护,特性名与位定义集中
1185// 在此(见 [`FEATURES`] 表)。新增特性只需在表中加一行,并在对应 parser 处
1186// 用 `ps.features.has(Feature::Xxx)` 判定即可,无需散落大量 if。
1187// ===========================================================================
1188
1189/// 单个特性标识。与 [`FEATURES`] 表一一对应;改表即改全端。
1190#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1191pub enum Feature {
1192    /// 裸词即字符串(v1 行为)。v2/v3 关闭后字符串必须加引号。
1193    BarewordStr,
1194    /// `include "x.sml"` 文件包含。
1195    Include,
1196    /// `$env.VAR` 环境变量内插。
1197    Env,
1198    /// `@contract` / `@is` 契约系统。
1199    Contract,
1200    /// `&frag` / `@frag` 片段复用。
1201    Fragment,
1202    /// 顶层裸数组 `[ ... ]`(无键)。
1203    TopArray,
1204    /// `include "x.sml" as ns` 命名空间包含(高优先级前缀)。
1205    Namespace,
1206    /// 无扩展名的 `include "foo"` 默认等价于 `include "foo.sml" as foo`。
1207    ImplicitNs,
1208    /// 逗号分隔的多目标 `include "a", "b" as y` 与 `import` 别名。
1209    MultiInclude,
1210    /// 通配 `include "dir/*.sml"`(glob)。
1211    GlobInclude,
1212    /// 正则匹配 `include /re/`(需 `regex-include`)。
1213    RegexInclude,
1214    /// 扩展名重写 `include "x.conf" -> "x.sml"`(将非 sml 当 sml 解析)。
1215    ExtRewrite,
1216}
1217
1218/// 返回全部已注册特性的名字,顺序与 [`FEATURES`](即特性位序)一致。
1219///
1220/// C-ABI 的 `sml_feature_name(bit)` 依赖此顺序,测试中有对应守护用例。
1221pub fn feature_names() -> Vec<&'static str> {
1222    FEATURES.iter().map(|(n, _)| *n).collect()
1223}
1224
1225/// 特性名 → 枚举 的注册表。所有端共用同一组名字,保证跨语言一致。
1226pub static FEATURES: &[(&str, Feature)] = &[
1227    ("bareword-string", Feature::BarewordStr),
1228    ("include", Feature::Include),
1229    ("env", Feature::Env),
1230    ("contract", Feature::Contract),
1231    ("fragment", Feature::Fragment),
1232    ("top-level-array", Feature::TopArray),
1233    ("namespace", Feature::Namespace),
1234    ("implicit-ns", Feature::ImplicitNs),
1235    ("multi-include", Feature::MultiInclude),
1236    ("glob-include", Feature::GlobInclude),
1237    ("regex-include", Feature::RegexInclude),
1238    ("ext-rewrite", Feature::ExtRewrite),
1239];
1240
1241impl Feature {
1242    /// 按名字查特性;未知名字返回 None(调用方据此报错,杜绝静默 typo)。
1243    pub fn from_name(name: &str) -> Option<Feature> {
1244        FEATURES.iter().find(|(n, _)| *n == name).map(|(_, f)| *f)
1245    }
1246
1247    /// 特性名(用于报错 / 序列化回显)
1248    pub fn name(self) -> &'static str {
1249        FEATURES
1250            .iter()
1251            .find(|(_, f)| *f == self)
1252            .map(|(n, _)| *n)
1253            .unwrap_or("<unknown>")
1254    }
1255}
1256
1257/// 位掩码形式的特性集合。
1258///
1259/// 设计哲学:从极简到丰富、功能可裁剪。默认基线(`baseline()`)只开极简三件套
1260/// (`include` + `namespace` + `implicit-ns`),复杂能力(多目标 / glob / 正则 /
1261/// 扩展名重写)必须显式 `@feature enable` 才生效,避免重蹈 YAML 过度复杂的覆辙。
1262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1263pub struct FeatureSet(u64);
1264
1265impl FeatureSet {
1266    /// 全部特性位(含所有 opt-in 能力)。用于「调用方允许全集」与版本基线,
1267    /// 实际默认并不开启这些——见 [`FeatureSet::baseline`]。
1268    pub fn all() -> FeatureSet {
1269        let mut m = 0u64;
1270        for (_, f) in FEATURES {
1271            m |= 1 << (*f as u8);
1272        }
1273        FeatureSet(m)
1274    }
1275
1276    /// 极简默认集(SML 核心可用能力)。这是 `parse_file` 的默认允许集;
1277    /// 仅「多目标 / glob / 正则 / 扩展名重写」等高级能力需文档内
1278    /// `@feature enable` 显式开启(避免重蹈 YAML 覆辙)。
1279    pub fn baseline() -> FeatureSet {
1280        FeatureSet::none()
1281            .with(Feature::BarewordStr)
1282            .with(Feature::Include)
1283            .with(Feature::Env)
1284            .with(Feature::Contract)
1285            .with(Feature::Fragment)
1286            .with(Feature::TopArray)
1287            .with(Feature::Namespace)
1288            .with(Feature::ImplicitNs)
1289    }
1290
1291    /// 空集合
1292    pub fn none() -> FeatureSet {
1293        FeatureSet(0)
1294    }
1295
1296    /// 按版本基线构造默认特性集:v1 极简默认(baseline)+ 裸词字符串;
1297    /// v2/v3 关闭裸词字符串(须引号)。复杂能力(glob/regex/multi...)仍默认关闭,
1298    /// 需文档 `@feature enable` 显式开启。
1299    pub fn for_version(v: Version) -> FeatureSet {
1300        let mut s = FeatureSet::baseline();
1301        // 严格模式(v2/v3)关闭裸词字符串;非严格(v1)开启。
1302        // 显式设置该位,确保与 baseline 默认值无关。
1303        if v.strict_strings() {
1304            s = s.without(Feature::BarewordStr);
1305        } else {
1306            s = s.with(Feature::BarewordStr);
1307        }
1308        s
1309    }
1310
1311    /// 是否包含某特性
1312    pub fn has(self, f: Feature) -> bool {
1313        (self.0 & (1 << (f as u8))) != 0
1314    }
1315
1316    /// 返回开启 `f` 后的副本
1317    pub fn with(self, f: Feature) -> FeatureSet {
1318        FeatureSet(self.0 | (1 << (f as u8)))
1319    }
1320
1321    /// 返回关闭 `f` 后的副本
1322    pub fn without(self, f: Feature) -> FeatureSet {
1323        FeatureSet(self.0 & !(1 << (f as u8)))
1324    }
1325
1326    /// 与另一集合取交集(用于「文档裁剪 ∩ 调用方允许」)
1327    pub fn intersection(self, other: FeatureSet) -> FeatureSet {
1328        FeatureSet(self.0 & other.0)
1329    }
1330
1331    /// 是否无任何特性
1332    pub fn is_empty(self) -> bool {
1333        self.0 == 0
1334    }
1335}
1336
1337impl fmt::Display for FeatureSet {
1338    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1339        let mut first = true;
1340        for (n, feat) in FEATURES {
1341            if self.has(*feat) {
1342                if !first {
1343                    f.write_str(",")?;
1344                }
1345                f.write_str(n)?;
1346                first = false;
1347            }
1348        }
1349        if first {
1350            f.write_str("<none>")?;
1351        }
1352        Ok(())
1353    }
1354}
1355
1356/// `@feature` 解析模式:白名单(仅启用列出的)/ 黑名单(禁用列出的)。
1357#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1358enum FeatureMode {
1359    Default,
1360    Whitelist,
1361    Blacklist,
1362}
1363
1364/// 取出 token 的字符串内容(Word / Str 都取其文本;其余返回空串)。
1365fn tok_word(t: &Tok) -> String {
1366    match t {
1367        Tok::Word(s) | Tok::Str(s) => s.clone(),
1368        _ => String::new(),
1369    }
1370}
1371
1372/// 若该行是 `@feature` 声明,则根据 `mode` / 操作更新 `feats`,并返回 true。
1373///
1374/// 支持语法(均不区分大小写,参数以空格分隔):
1375/// - `@feature base v3`              设定基线版本(等价于 `@version`,仅用于特性派生)
1376/// - `@feature mode whitelist`       后续 enable 仅保留所列(基集先清空)
1377/// - `@feature mode blacklist`       后续 disable 仅移除所列(基集保持全开)
1378/// - `@feature enable <name>[,...]`  开启特性(可逗号批量)
1379/// - `@feature disable <name>[,...]` 关闭特性
1380/// - `@feature whitelist <a,b>`      紧凑白名单
1381/// - `@feature blacklist <a,b>`      紧凑黑名单
1382///
1383/// 未知特性名一律报错,避免拼写错误静默失效。
1384fn apply_feature_directive(
1385    line: &str,
1386    feats: &mut FeatureSet,
1387    mode: &mut FeatureMode,
1388    base: &mut Option<Version>,
1389) -> Result<bool, String> {
1390    let content = strip_line_comment(line).trim();
1391    let toks = match tokenize(content) {
1392        Ok(t) => t,
1393        Err(_) => return Ok(false),
1394    };
1395    if toks.is_empty() || toks[0] != Tok::At {
1396        return Ok(false);
1397    }
1398    let words: Vec<String> = toks
1399        .iter()
1400        .map(|t| match t {
1401            Tok::At => "@".to_string(),
1402            other => tok_word(other),
1403        })
1404        .collect();
1405    // @feature 词法上拆成 [@, feature],拼前两个 token 才是 "@feature"
1406    let head = format!("{}{}", words.first().map(|s| s.as_str()).unwrap_or(""), words.get(1).map(|s| s.as_str()).unwrap_or(""));
1407    if head != "@feature" {
1408        return Ok(false);
1409    }
1410    // 去掉首 token `@`,使后续 words[0]=="feature"
1411    let words: Vec<String> = words[1..].to_vec();
1412    if words.len() < 2 {
1413        return Err("@feature 指令缺少参数".into());
1414    }
1415    let arg = words[1].as_str();
1416    // 把 `enable x,y,z` / `whitelist a,b` 的多名拆开
1417    let names = |from: usize| -> Vec<String> {
1418        words[from..]
1419            .join(",")
1420            .split(',')
1421            .map(|s| s.trim().to_string())
1422            .filter(|s| !s.is_empty())
1423            .collect()
1424    };
1425    match arg {
1426        "base" => {
1427            let v = Version::from_word(words.get(2).map(|s| s.as_str()).unwrap_or(""))
1428                .ok_or_else(|| {
1429                    format!(
1430                        "@feature base 需要 v1/v2/v3,收到 `{}`",
1431                        words.get(2).cloned().unwrap_or_default()
1432                    )
1433                })?;
1434            *feats = FeatureSet::for_version(v);
1435            *base = Some(v);
1436            Ok(true)
1437        }
1438        "mode" => {
1439            let m = words.get(2).map(|s| s.as_str()).unwrap_or("");
1440            *mode = match m {
1441                "whitelist" => FeatureMode::Whitelist,
1442                "blacklist" => FeatureMode::Blacklist,
1443                _ => return Err(format!("@feature mode 需要 whitelist/blacklist,收到 `{m}`")),
1444            };
1445            if *mode == FeatureMode::Whitelist {
1446                // 白名单:基集先清空,后续 enable 显式置位
1447                *feats = FeatureSet::none();
1448            }
1449            Ok(true)
1450        }
1451        "enable" => {
1452            // 直接在「当前特性集」上叠加开启(不切换白名单语义)。
1453            // 这样 `@feature enable regex-include` 在 `@version v1` 文档上会保留
1454            // bareword-string 等默认特性,而非收窄为仅所列项。
1455            // 真正的「收窄为仅所列」由显式 `@feature mode whitelist` 控制。
1456            for n in names(2) {
1457                let f = Feature::from_name(&n).ok_or_else(|| {
1458                    format!(
1459                        "未知特性 `{n}`,可用:{}",
1460                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1461                    )
1462                })?;
1463                *feats = feats.with(f);
1464            }
1465            Ok(true)
1466        }
1467        "disable" => {
1468            for n in names(2) {
1469                let f = Feature::from_name(&n).ok_or_else(|| {
1470                    format!(
1471                        "未知特性 `{n}`,可用:{}",
1472                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1473                    )
1474                })?;
1475                *feats = feats.without(f);
1476            }
1477            Ok(true)
1478        }
1479        "whitelist" => {
1480            *mode = FeatureMode::Whitelist;
1481            let mut s = FeatureSet::none();
1482            for n in names(2) {
1483                let f = Feature::from_name(&n).ok_or_else(|| {
1484                    format!(
1485                        "未知特性 `{n}`,可用:{}",
1486                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1487                    )
1488                })?;
1489                s = s.with(f);
1490            }
1491            *feats = s;
1492            Ok(true)
1493        }
1494        "blacklist" => {
1495            let mut s = FeatureSet::all();
1496            for n in names(2) {
1497                let f = Feature::from_name(&n).ok_or_else(|| {
1498                    format!(
1499                        "未知特性 `{n}`,可用:{}",
1500                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1501                    )
1502                })?;
1503                s = s.without(f);
1504            }
1505            *feats = s;
1506            Ok(true)
1507        }
1508        _ => Err(format!("未知 @feature 子命令 `{arg}`,可用 base/mode/enable/disable")),
1509    }
1510}
1511
1512/// 在解析前剥离全部 `@feature` 指令,返回剩余文本、推导出的特性集,以及
1513/// 由 `@feature base vN` 声明的基线版本(若文档未用 `@version` 则采用它)。
1514///
1515/// 文档内部的 `@feature` 只能收窄;调用方允许范围由 `parse_with_features`
1516/// / `parse_allowed` 的 `allowed` 参数在入口处再次交集。
1517///
1518/// 返回值三元组:(剩余文本, 特性集, @feature base 声明的版本, 是否出现过 @feature 指令)。
1519/// 若文档从未声明 `@feature`,则 `had_feature=false`,调用方应改以版本基线派生特性集
1520/// (例如 v3 默认关闭裸词字符串)。
1521fn strip_features(text: &str) -> Result<(String, FeatureSet, Option<Version>, bool), String> {
1522    let mut out = String::new();
1523    let mut feats = FeatureSet::all();
1524    let mut mode = FeatureMode::Default;
1525    let mut base: Option<Version> = None;
1526    let mut had_feature = false;
1527
1528    for line in text.lines() {
1529        match apply_feature_directive(line, &mut feats, &mut mode, &mut base) {
1530            Ok(true) => {
1531                had_feature = true;
1532                continue; // 指令行被消费,不进入剩余文本
1533            }
1534            Ok(false) => {}
1535            Err(e) => return Err(e), // 指令非法(如未知特性名)必须上浮,不能静默吞掉
1536        }
1537        out.push_str(line);
1538        out.push('\n');
1539    }
1540    Ok((out, feats, base, had_feature))
1541}
1542
1543/// 若该行是 `@version` 声明,返回版本字面量;否则返回 None。
1544///
1545/// `version` 是保留字:不允许作为片段名(`@version { }`)使用。
1546fn version_directive(line: &str) -> Result<Option<String>, String> {
1547    let content = strip_line_comment(line).trim();
1548    // 词法失败的行(如未闭合引号)不是版本声明,交由主解析器报更准确的错
1549    let toks = match tokenize(content) {
1550        Ok(t) => t,
1551        Err(_) => return Ok(None),
1552    };
1553    match toks.as_slice() {
1554        [Tok::At, Tok::Word(w), Tok::Word(v)] if w == "version" => Ok(Some(v.clone())),
1555        [Tok::At, Tok::Word(w), Tok::Str(v)] if w == "version" => Ok(Some(v.clone())),
1556        [Tok::At, Tok::Word(w), ..] if w == "version" => Err(
1557            "`@version` 是版本声明指令,须写作 `@version v1`;`version` 不可作为片段名".into(),
1558        ),
1559        _ => Ok(None),
1560    }
1561}
1562
1563/// 剥离 `@version` 声明行,返回剩余文本与声明的版本(未声明则为 None)。
1564///
1565/// 允许多次声明(include 进来的文件可各自声明),但必须一致;
1566/// 声明了实现不支持的版本时报错,避免静默按错误语法解析。
1567fn strip_version(text: &str) -> Result<(String, Option<Version>), String> {
1568    let mut declared: Option<Version> = None;
1569    let mut rest = String::new();
1570    for line in text.lines() {
1571        if let Some(lit) = version_directive(line)? {
1572            let v = Version::from_word(&lit).ok_or_else(|| {
1573                format!(
1574                    "不支持的 SML 版本 `{lit}`(本实现支持 {})",
1575                    Version::CURRENT.name()
1576                )
1577            })?;
1578            match declared {
1579                None => declared = Some(v),
1580                Some(prev) if prev != v => {
1581                    return Err(format!("@version 冲突:{} 与 {}", prev.name(), v.name()))
1582                }
1583                Some(_) => {}
1584            }
1585            continue;
1586        }
1587        rest.push_str(line);
1588        rest.push('\n');
1589    }
1590    Ok((rest, declared))
1591}
1592
1593/// 把 版本 + 文档 @feature 指令 合并为最终生效的特性集。
1594///
1595/// 规则:
1596/// - 若文档显式声明过 `@feature`(had_feature=true),则完全采用其推导的 `feats`;
1597/// - 否则(仅靠 `@version` 声明或默认),从版本基线派生(如 v3 关闭裸词字符串)。
1598/// 这样 v3 文档即使不写任何 `@feature` 也默认严格;调用方的 `allowed` 在
1599/// 入口处再与结果取交集,文档无法扩宽。
1600fn features_for(v: Version, feats: FeatureSet, had_feature: bool) -> FeatureSet {
1601    if had_feature {
1602        feats
1603    } else {
1604        FeatureSet::for_version(v)
1605    }
1606}
1607
1608/// 解析 SML 文本,并返回其声明的语法版本。
1609///
1610/// 未声明版本时按 `V1` 处理(裸词即字符串),**既有文档不受影响**;
1611/// 显式 `@version v3` 则返回 `V3`(此时字符串需引号)。
1612pub fn parse_versioned(text: &str) -> Result<(Value, Version), String> {
1613    let (rest, declared) = strip_version(text)?;
1614    let (rest, feats, base, had) = strip_features(&rest)?;
1615    // 版本优先级:@version 显式声明 > @feature base > 默认 V1
1616    let v = declared.or(base).unwrap_or(Version::V1);
1617    let feats = features_for(v, feats, had);
1618    Ok((parse_impl(&rest, v, feats)?, v))
1619}
1620
1621/// 解析 SML 文件:展开 include,并返回其声明的语法版本
1622pub fn parse_file_versioned(path: impl AsRef<Path>) -> Result<(Value, Version), String> {
1623    let path = path.as_ref();
1624    let text =
1625        std::fs::read_to_string(path).map_err(|e| format!("读取失败 {}: {e}", path.display()))?;
1626    let base = path
1627        .parent()
1628        .map(|p| p.to_path_buf())
1629        .unwrap_or_else(|| PathBuf::from("."));
1630    let (rest, declared) = strip_version(&text)?;
1631    let (rest, feats, base_ver, had) = strip_features(&rest)?;
1632    let allowed = FeatureSet::all().intersection(feats);
1633    let v = declared.or(base_ver).unwrap_or(Version::V1);
1634    let feats = features_for(v, allowed, had);
1635    let toks = resolve_includes(&rest, &base, allowed)?;
1636    let val = parse_impl_tokens(toks, v, feats)?;
1637    Ok((val, v))
1638}
1639
1640/// 解析 SML 文本
1641///
1642/// 会自动识别并剥离 `@version` / `@feature` 声明(需要版本信息时用
1643/// [`parse_versioned`],需要特性裁剪信息时用 [`parse_with_features`])。
1644///
1645/// **向后兼容**:未声明 `@version` 的文档按 `V1` 解析(裸词即字符串),
1646/// 既有大量 v1 文档不受影响;仅显式 `@version v2|v3` 才启用严格字符串。
1647pub fn parse(text: &str) -> Result<Value, String> {
1648    let (rest, declared) = strip_version(text)?;
1649    let (rest, feats, base, had) = strip_features(&rest)?;
1650    let v = declared.or(base).unwrap_or(Version::V1);
1651    let feats = features_for(v, feats, had);
1652    parse_impl(&rest, v, feats)
1653}
1654
1655/// 解析 SML 文本,并限制文档声明的版本必须在 `allowed` 范围内。
1656///
1657/// 用于「库固定依赖某个 SML 语法版本」的场景:若文档声明了 `allowed`
1658/// 之外的版本(例如库只接受 v1..v3,却遇到 `@version v4`),立即报错,
1659/// 而不是用不兼容的语法静默解析。
1660///
1661/// 未声明版本的文档视为 `V1`,只要 `allowed` 含 `V1` 即放行。
1662pub fn parse_allowed(
1663    text: &str,
1664    allowed: &[Version],
1665) -> Result<Value, String> {
1666    let (rest, declared) = strip_version(text)?;
1667    let (rest, feats, base, had) = strip_features(&rest)?;
1668    let v = declared.or(base).unwrap_or(Version::V1);
1669    if !allowed.contains(&v) {
1670        return Err(format!(
1671            "sml: 文档声明版本 {} 不在本库接受的版本范围 {{{}}} 内",
1672            v.name(),
1673            allowed
1674                .iter()
1675                .map(|x| x.name())
1676                .collect::<Vec<_>>()
1677                .join(", ")
1678        ));
1679    }
1680    let feats = features_for(v, feats, had);
1681    parse_impl(&rest, v, feats)
1682}
1683
1684/// 解析 SML 文本,同时限制文档使用的**特性子集**必须在 `allowed` 内。
1685///
1686/// 与 [`parse_allowed`](版本范围)配套:`allowed` 是调用方(库作者)给出的
1687/// 白名单,文档内部的 `@feature enable/disable` 只能**收窄**这个集合,
1688/// 不能扩宽——否则文档就能自行绕过调用方的限制。交集为空则报错。
1689///
1690/// 未声明任何 `@feature` 的文档若仅靠版本基线(如 v3),则基线特性与
1691/// `allowed` 交集;只要交集非空即放行。
1692pub fn parse_with_features(
1693    text: &str,
1694    allowed: FeatureSet,
1695) -> Result<(Value, FeatureSet), String> {
1696    let (rest, declared) = strip_version(text)?;
1697    let (rest, feats, base, had) = strip_features(&rest)?;
1698    let v = declared.or(base).unwrap_or(Version::V1);
1699    let feats = features_for(v, feats, had);
1700    let effective = feats.intersection(allowed);
1701    if effective.is_empty() {
1702        return Err(format!(
1703            "sml: 文档请求的特性 {feats} 与调用方允许的特性 {allowed} 无交集"
1704        ));
1705    }
1706    let val = parse_impl(&rest, v, effective)?;
1707    Ok((val, effective))
1708}
1709
1710/// 不含版本处理的底层解析(文本入口)
1711fn parse_impl(text: &str, version: Version, features: FeatureSet) -> Result<Value, String> {
1712    let toks = tokenize(text)?;
1713    parse_impl_tokens(toks, version, features)
1714}
1715
1716/// 不含版本处理的底层解析(token 流入口,供 include 展开后零拷贝复用)
1717fn parse_impl_tokens(
1718    toks: Vec<Tok>,
1719    version: Version,
1720    features: FeatureSet,
1721) -> Result<Value, String> {
1722    let mut p = Parser {
1723        toks,
1724        i: 0,
1725        fragments: BTreeMap::new(),
1726        contracts: BTreeMap::new(),
1727        features,
1728        ns_stack: Vec::new(),
1729    };
1730    // 顶层支持三种形态,与 `to_sml` 的输出对称:
1731    //   - `[ ... ]` 数组:to_sml 对非对象走 dump_inline,会输出顶层数组
1732    //     (如「历史记录」这类对象数组)。此前 parse 只认键值块,导致
1733    //     能序列化却读不回("期望键, 得 LBrack"),是不对称缺陷。
1734    //   - `{ ... }` 顶层对象块
1735    //   - 键值块(传统形态)
1736    // 注:顶层**标量**仍不可往返(SML 顶层需为容器),这是格式固有限制。
1737    match p.peek() {
1738        Some(Tok::LBrack) => {
1739            if !p.features.has(Feature::TopArray) {
1740                return Err("sml: 顶层数组需要特性 `top-level-array`,但当前特性集已禁用".into());
1741            }
1742            p.next();
1743            p.parse_array()
1744        }
1745        Some(Tok::LBrace) => {
1746            p.next();
1747            p.parse_block(Some(Tok::RBrace))
1748        }
1749        _ => p.parse_block(None),
1750    }
1751}
1752
1753// ---------------------------------------------------------------------------
1754// include 指令:把外部 .sml 文件内联进来
1755//
1756// 语法:`include "path.sml"` 或 `@include "path.sml"`(两种等价)
1757// 语义:**文本内联**(类似 C 的 #include),而非对象合并。
1758//   这样 include 可以出现在块内部引入一组字段,例如:
1759//       server web { &base include "common/port.sml" }
1760//   若做成对象合并就无法表达「注入若干字段到当前块」。
1761//
1762// 相对路径按**被包含文件自身所在目录**解析(与 C 预处理器一致),
1763// 而非进程工作目录,因此嵌套 include 时路径行为可预期。
1764// ---------------------------------------------------------------------------
1765
1766/// 嵌套深度上限:既防栈溢出,也让异常深层的引用尽早失败
1767const MAX_INCLUDE_DEPTH: usize = 32;
1768
1769/// 剥离行尾注释,正确跳过引号内的 `#`(如 `key: "a#b"` 中的 # 不是注释起点)
1770fn strip_line_comment(line: &str) -> &str {
1771    let bytes = line.as_bytes();
1772    let mut i = 0;
1773    let mut in_quote = false;
1774    while i < bytes.len() {
1775        match bytes[i] {
1776            b'"' => in_quote = !in_quote,
1777            // 引号内的反斜杠会转义下一个字符,需整体跳过
1778            b'\\' if in_quote => i += 1,
1779            b'#' if !in_quote => return &line[..i],
1780            _ => {}
1781        }
1782        i += 1;
1783    }
1784    line
1785}
1786
1787/// 单个 include 目标的解析结果。
1788#[derive(Debug, Clone, PartialEq, Eq)]
1789pub struct IncludeTarget {
1790    /// 相对路径或裸名(无扩展名时按 `implicit-ns` 推导 `as`)。
1791    pub raw: String,
1792    /// 命名空间(点分路径 `a.b.c`)。`None` 表示普通内联。
1793    /// 若 `raw` 无扩展名且开启 `implicit-ns`,则自动填充为文件名。
1794    pub namespace: Option<String>,
1795    /// 是否经 `import` 关键字(语义等同 `include`)。
1796    pub via_import: bool,
1797    /// 部分引用:仅从目标文件挑出这些顶层键并入(命名空间包裹时同样只挑这些)。
1798    /// `None` 表示整文件(不挑键)。
1799    pub keys: Option<Vec<String>>,
1800}
1801
1802/// 解析一行 include / import 指令,返回 0..N 个目标。
1803///
1804/// 支持形态(逗号分隔多目标,`import` 为 `include` 别名):
1805/// - `include "x.sml"`                普通内联(带扩展名、无 as)
1806/// - `include "foo"`                  无扩展名 ⇒ 默认 `as foo`(implicit-ns)
1807/// - `include "x.sml" as ui.form`     命名空间内联(点分路径)
1808/// - `include "a", "b" as y, "c"`     多目标(multi-include)
1809/// - `import ui.buttons, admin.panel`  import 别名
1810/// - `include "*.sml"`                glob 通配(需 `glob-include`)
1811/// - `include re:"widget_.*\.sml"`    正则匹配(需 `regex-include`)
1812///
1813/// 部分引用(挑键)—— 两种等价写法:
1814/// - `import "x.sml" as w { a, b }`          挑键 a,b,挂到命名空间 w
1815/// - `import { a, b } as w in "x.sml"`        等价写法(键列表在前)
1816/// 省略 `as w` 则挑出的键直接平铺到当前作用域:
1817/// - `import "x.sml" { a, b }`
1818/// - `import { a, b } in "x.sml"`
1819/// 注:部分引用只作用于单文件目标,不与 glob/regex 通配组合。
1820///
1821/// 返回 `Ok(None)` 表示该行不是 include 指令;`Err` 表示特性未开启等语义错误。
1822fn parse_include_line(line: &str, features: FeatureSet) -> Result<Option<Vec<IncludeTarget>>, String> {
1823    let content = strip_line_comment(line).trim();
1824    let content = content.strip_prefix('@').unwrap_or(content).trim_start();
1825    // 轻量手写解析,不依赖 tokenize(避免 `*` 等字符在 tokenize 阶段被误判)。
1826    // 形式:`include "x" [as ns], "y" as ns2, ...`(import 等价)
1827    let (via_import, rest) = if let Some(r) = content.strip_prefix("include ") {
1828        (false, r.trim_start())
1829    } else if let Some(r) = content.strip_prefix("import ") {
1830        (true, r.trim_start())
1831    } else {
1832        return Ok(None);
1833    };
1834    if !features.has(Feature::Include) {
1835        return Ok(None);
1836    }
1837    let mut targets: Vec<IncludeTarget> = Vec::new();
1838    let mut rest = rest;
1839    loop {
1840        // 两种部分引用语法:
1841        //   ①  import "x.sml" [as w] { a, b }
1842        //   ②  import { a, b } [as w] in "x.sml"
1843        // 先探测是否以 `{` 开头(语法②)
1844        let (raw, ns, keys, tail) = if rest.trim_start().starts_with('{') {
1845            // 语法②:键列表在前
1846            let (keys, after) = parse_key_list(rest.trim_start())?;
1847            let after = after.trim_start();
1848            // 可选 `as ns`
1849            let (ns, after) = if let Some(stripped) = after.strip_prefix("as ") {
1850                let (n, t) = match next_token(stripped.trim_start()) {
1851                    Some((n, t)) => (Some(n), t.trim_start()),
1852                    None => return Ok(None),
1853                };
1854                (n, t)
1855            } else {
1856                (None, after)
1857            };
1858            // 必须跟 `in "path"` 取目标文件
1859            let after = after.trim_start();
1860            let after = match after.strip_prefix("in ") {
1861                Some(a) => a.trim_start(),
1862                None => {
1863                    return Err(
1864                        "sml: `import { keys } ...` 必须接 `in \"file\"` 指定目标文件".into(),
1865                    )
1866                }
1867            };
1868            let (path, t) = match next_token(after) {
1869                Some((p, t)) => (p, t),
1870                None => return Ok(None),
1871            };
1872            (path, ns, Some(keys), t)
1873        } else {
1874            // 语法①:路径在前
1875            let (path, tail0) = match next_token(rest) {
1876                Some((p, t)) => (p, t),
1877                None => {
1878                    if targets.is_empty() && rest.trim().is_empty() {
1879                        return Ok(None);
1880                    } else {
1881                        break;
1882                    }
1883                }
1884            };
1885            let mut r = tail0.trim_start();
1886            // 可选 `as ns`
1887            let mut ns: Option<String> = None;
1888            if let Some(stripped) = r.strip_prefix("as ") {
1889                let (n, t) = match next_token(stripped.trim_start()) {
1890                    Some((n, t)) => (n, t),
1891                    None => return Ok(None),
1892                };
1893                ns = Some(n);
1894                r = t.trim_start();
1895            }
1896            // 可选 `{ keys }`
1897            let keys = if r.starts_with('{') {
1898                let (k, after) = parse_key_list(r)?;
1899                r = after.trim_start();
1900                Some(k)
1901            } else {
1902                None
1903            };
1904            (path, ns, keys, r)
1905        };
1906        targets.push(finalize_target(
1907            raw,
1908            ns,
1909            via_import,
1910            features,
1911            keys,
1912        ));
1913        // 逗号分隔多目标(用已修剪的 tail 判断是否还有下一个目标)
1914        if let Some(stripped) = tail.strip_prefix(',') {
1915            if !features.has(Feature::MultiInclude) {
1916                return Ok(None);
1917            }
1918            rest = stripped.trim_start();
1919            continue;
1920        } else {
1921            rest = tail;
1922            break;
1923        }
1924    }
1925    if targets.is_empty() {
1926        return Ok(None);
1927    }
1928    // 特性预检查:glob / regex 模式在解析阶段就拦截(避免走到普通路径解析引发诡异错误)
1929    for t in &targets {
1930        // 部分引用只作用于单文件目标,不能与 glob/regex 通配组合
1931        if t.keys.is_some() && (t.raw.contains('*') || t.raw.starts_with("re:")) {
1932            return Err(
1933                "sml: 部分引用 `{ keys }` 不能配合 glob/regex 通配(请指定单个文件)".into(),
1934            );
1935        }
1936        // 先查 re: 前缀(正则模式里的 `*` 是元字符,不是 glob 通配)
1937        if t.raw.starts_with("re:") {
1938            if !features.has(Feature::RegexInclude) {
1939                return Err("sml: 正则 include 需要特性 `regex-include`(请 @feature enable regex-include)".into());
1940            }
1941            continue;
1942        }
1943        if t.raw.contains('*') && !features.has(Feature::GlobInclude) {
1944            return Err("sml: 通配 include 需要特性 `glob-include`(请 @feature enable glob-include)".into());
1945        }
1946    }
1947    Ok(Some(targets))
1948}
1949
1950/// 从字符串开头提取下一个 token:引号串(支持 `\"` 与 `\\`)或直到空白/逗号/`as` 的裸词。
1951/// 返回 (token 文本, 剩余字符串)。
1952fn next_token(s: &str) -> Option<(String, &str)> {
1953    let s = s.trim_start();
1954    if s.is_empty() {
1955        return None;
1956    }
1957    if s.starts_with('"') {
1958        // 引号串(按字节处理,路径通常为 ASCII)
1959        let bytes = s.as_bytes();
1960        let mut i = 1;
1961        let mut out = String::new();
1962        while i < bytes.len() {
1963            if bytes[i] == b'"' {
1964                i += 1;
1965                break;
1966            }
1967            if bytes[i] == b'\\' && i + 1 < bytes.len() {
1968                // 转义:保留转义后的字符(\. -> .,\" -> " 等)
1969                i += 1;
1970                out.push(bytes[i] as char);
1971                i += 1;
1972            } else {
1973                out.push(bytes[i] as char);
1974                i += 1;
1975            }
1976        }
1977        Some((out, &s[i..]))
1978    } else {
1979        // 裸词:取到空白或逗号
1980        let end = s
1981            .find(|c: char| c.is_whitespace() || c == ',')
1982            .unwrap_or(s.len());
1983        let (tok, tail) = s.split_at(end);
1984        Some((tok.trim().to_string(), tail))
1985    }
1986}
1987
1988/// 解析 `{ a, b, c }` 形式的键列表,返回 (键名集合, 剩余字符串)。
1989/// 键名可为裸词或引号串。遇到非 `{` 开头时返回错误。
1990fn parse_key_list(s: &str) -> Result<(Vec<String>, &str), String> {
1991    let s = s.trim_start();
1992    let Some(body) = s.strip_prefix('{') else {
1993        return Err("sml: 期望 `{ key1, key2, ... }` 键列表".into());
1994    };
1995    let close = body.find('}').ok_or("sml: 键列表缺少闭合 `}`")?;
1996    let inner = &body[..close];
1997    let mut keys: Vec<String> = Vec::new();
1998    for part in inner.split(',') {
1999        let part = part.trim();
2000        if part.is_empty() {
2001            continue;
2002        }
2003        // 支持引号串键,其余按裸词(去引号)
2004        if let Some(q) = part.strip_prefix('"') {
2005            let q = q.strip_suffix('"').unwrap_or(q);
2006            keys.push(q.to_string());
2007        } else {
2008            keys.push(part.to_string());
2009        }
2010    }
2011    if keys.is_empty() {
2012        return Err("sml: 键列表不能为空(至少指定一个键)".into());
2013    }
2014    Ok((keys, &body[close + 1..]))
2015}
2016
2017/// 根据原始路径与可选命名空间,套用 implicit-ns 规则,产出最终目标。
2018fn finalize_target(
2019    raw: String,
2020    ns: Option<String>,
2021    via_import: bool,
2022    features: FeatureSet,
2023    keys: Option<Vec<String>>,
2024) -> IncludeTarget {
2025    let namespace = match ns {
2026        Some(n) => Some(n),
2027        None => {
2028            // 部分引用(指定了 keys)且无显式 `as`:强制平铺到当前作用域,
2029            // 不触发 implicit-ns 自动命名空间(否则挑出的键会被塞进文件名命名空间)。
2030            if keys.is_some() {
2031                None
2032            } else if via_import || (features.has(Feature::ImplicitNs) && !raw.contains('.')) {
2033                // `import a.b.c`:点分一律视为命名空间路径,自动 `as a.b.c`
2034                // `include "foo"`(无点):implicit-ns 默认以文件名为命名空间
2035                Some(raw.clone())
2036            } else {
2037                None
2038            }
2039        }
2040    };
2041    IncludeTarget {
2042        raw,
2043        namespace,
2044        via_import,
2045        keys,
2046    }
2047}
2048
2049/// 把一个 include 目标解析为 0..N 个实际文件路径(已相对 `base` 解析、未 canonicalize)。
2050///
2051/// 支持:
2052/// - glob:`raw` 含 `*` 且开启 `glob-include` → 遍历 `base` 下直接条目做 `*` 通配匹配
2053/// - 正则:`raw` 以 `re:"..."` 形式且开启 `regex-include` → 遍历 `base` 下条目做最小正则匹配
2054/// - ext-rewrite:开启 `ext-rewrite` 时允许 `raw` 带非 `.sml` 扩展名(否则按原补 `.sml` 逻辑)
2055/// - 普通:`import` 点分转目录层级、裸名补 `.sml`
2056fn resolve_target_paths(
2057    t: &IncludeTarget,
2058    base: &Path,
2059    features: FeatureSet,
2060) -> Result<Vec<PathBuf>, String> {
2061    // 正则模式:re:"<pattern>"
2062    if let Some(pat) = t.raw.strip_prefix("re:") {
2063        if !features.has(Feature::RegexInclude) {
2064            return Err("sml: 正则 include 需要特性 `regex-include`(请 @feature enable regex-include)".into());
2065        }
2066        let pat = pat.trim_matches('"');
2067        // 模式可含目录前缀(如 re:"lib/widget_.*"):拆出目录并入 base(归一化分隔符)
2068        let pat = pat.replace('/', std::path::MAIN_SEPARATOR_STR);
2069        let (dir, pat) = split_dir(&pat);
2070        return glob_or_regex_dir(&base.join(dir), pat, Some(pat), features);
2071    }
2072    // glob 模式:含 `*`
2073    if t.raw.contains('*') {
2074        if !features.has(Feature::GlobInclude) {
2075            return Err("sml: 通配 include 需要特性 `glob-include`(请 @feature enable glob-include)".into());
2076        }
2077        let normalized = t.raw.replace('/', std::path::MAIN_SEPARATOR_STR);
2078        let (dir, pat) = split_dir(&normalized);
2079        return glob_or_regex_dir(&base.join(dir), pat, None, features);
2080    }
2081    // 普通路径
2082    let path = if t.via_import {
2083        // import 的「点分模块名」语义:仅当 raw 既无路径分隔、又不显式带 .sml 扩展名时,
2084        // 才把点当作目录层级分隔(a.b.c -> a/b/c.sml)。
2085        // 若显式写了路径或扩展名(如 "advanced_inc/widget_a.sml"),按字面路径处理。
2086        if t.raw.contains(std::path::MAIN_SEPARATOR) || t.raw.ends_with(".sml") {
2087            base.join(&t.raw)
2088        } else {
2089            let rel = t
2090                .raw
2091                .split('.')
2092                .collect::<Vec<_>>()
2093                .join(std::path::MAIN_SEPARATOR_STR);
2094            base.join(rel).with_extension("sml")
2095        }
2096    } else if t.raw.contains('.') {
2097        // 带扩展名:默认直接读该文件
2098        // 开启 ext-rewrite 时允许非 .sml 扩展名(当 sml 解析);关闭时若非 .sml 也允许读,
2099        // 但语义上仍要求文件存在,由 canonicalize 报错兜底。
2100        let _ = features.has(Feature::ExtRewrite);
2101        base.join(&t.raw)
2102    } else {
2103        base.join(format!("{}.sml", t.raw))
2104    };
2105    Ok(vec![path])
2106}
2107
2108/// 遍历 `base` 目录的直接条目,按 glob(`pattern` 含 `*`)或正则(`regex` 为 Some)匹配,
2109/// 把 `a/b/pattern` 拆成 (`a/b`, `pattern`),便于把目录部分并入 base。
2110fn split_dir(pat: &str) -> (&str, &str) {
2111    match pat.rfind(std::path::MAIN_SEPARATOR) {
2112        Some(idx) => (&pat[..idx], &pat[idx + 1..]),
2113        None => ("", pat),
2114    }
2115}
2116
2117/// 返回命中的完整路径。目录本身不作为命中(仅文件)。
2118fn glob_or_regex_dir(
2119    base: &Path,
2120    pattern: &str,
2121    regex: Option<&str>,
2122    _features: FeatureSet,
2123) -> Result<Vec<PathBuf>, String> {
2124    let mut hits: Vec<PathBuf> = Vec::new();
2125    let entries = std::fs::read_dir(base)
2126        .map_err(|e| format!("include 目录读取失败 {}: {e}", base.display()))?;
2127    // 用于正则匹配的模式字符串(不含 re: 前缀与引号)
2128    let re = regex.map(|r| compile_regex(r));
2129    for ent in entries {
2130        let ent = ent.map_err(|e| format!("include 目录遍历失败: {e}"))?;
2131        let p = ent.path();
2132        if p.is_dir() {
2133            continue; // 只匹配文件
2134        }
2135        let name = match p.file_name().and_then(|n| n.to_str()) {
2136            Some(n) => n,
2137            None => continue,
2138        };
2139        let matched = if let Some(re) = &re {
2140            regex_matches(re, name)
2141        } else {
2142            // glob:`pattern` 形如 `*.sml` 或 `widgets/*.sml`;这里只处理文件名部分的通配
2143            let pat_file = pattern.rsplit(std::path::MAIN_SEPARATOR).next().unwrap_or(pattern);
2144            glob_matches(pat_file, name)
2145        };
2146        if matched {
2147            hits.push(p);
2148        }
2149    }
2150    // 结果按文件名排序,保证跨平台顺序稳定
2151    hits.sort();
2152    Ok(hits)
2153}
2154
2155/// 手写最小 glob 匹配(仅支持 `*` 通配,匹配整个文件名)。
2156fn glob_matches(pattern: &str, text: &str) -> bool {
2157    // 将 `a*b*c` 拆分为字面段,段间用 `*` 连接
2158    let segs: Vec<&str> = pattern.split('*').collect();
2159    if segs.is_empty() {
2160        return text.is_empty();
2161    }
2162    let mut pos = 0usize;
2163    // 首段若非 `*` 开头,必须前缀匹配
2164    if !pattern.starts_with('*') {
2165        if !text[pos..].starts_with(segs[0]) {
2166            return false;
2167        }
2168        pos += segs[0].len();
2169    }
2170    for seg in &segs[if pattern.starts_with('*') { 0 } else { 1 }..] {
2171        if seg.is_empty() {
2172            continue;
2173        }
2174        match text[pos..].find(seg) {
2175            Some(idx) => pos += idx + seg.len(),
2176            None => return false,
2177        }
2178    }
2179    // 末段若非 `*` 结尾,必须后缀匹配
2180    if !pattern.ends_with('*') {
2181        if pos != text.len() {
2182            return false;
2183        }
2184    }
2185    true
2186}
2187
2188/// 编译一个受限正则(支持 `. * + ? ^ $ [a-z] [^a-z] \.` 转义),返回可匹配闭包用的结构。
2189/// 这里采用「NFA-less」的回溯匹配器,足够文件名场景使用。
2190struct MiniRegex {
2191    pattern: String,
2192}
2193
2194fn compile_regex(pat: &str) -> MiniRegex {
2195    // 去掉可能的首尾 `^`/`$` 锚(由 matcher 解释)
2196    MiniRegex {
2197        pattern: pat.to_string(),
2198    }
2199}
2200
2201/// 用受限正则匹配整个 `text`(默认全匹配,支持 `^`/`$` 锚点)。
2202fn regex_matches(re: &MiniRegex, text: &str) -> bool {
2203    let pat = &re.pattern;
2204    let anchored_start = pat.starts_with('^');
2205    let anchored_end = pat.ends_with('$');
2206    let p = if anchored_start { &pat[1..] } else { pat };
2207    let p = if anchored_end { &p[..p.len().saturating_sub(1)] } else { p };
2208    // 尝试从 text 的每个位置开始匹配(非锚定时)
2209    if anchored_start {
2210        backtrack_match(p, text, 0).is_some()
2211    } else {
2212        for start in 0..=text.len() {
2213            if backtrack_match(p, text, start).is_some() {
2214                if !anchored_end {
2215                    return true;
2216                }
2217                // 锚定结尾:必须匹配到 text 末端
2218                if backtrack_match(p, text, start) == Some(text.len()) {
2219                    return true;
2220                }
2221            }
2222        }
2223        false
2224    }
2225}
2226
2227/// 回溯匹配:从 `text[ti]` 开始尝试匹配 `pat[pi]`,返回成功时 text 的消耗终点(usize)。
2228fn backtrack_match(pat: &str, text: &str, ti: usize) -> Option<usize> {
2229    // 递归实现,模式索引 pi 通过 chars 迭代
2230    let pchars: Vec<char> = pat.chars().collect();
2231    let tchars: Vec<char> = text.chars().collect();
2232    fn go(pchars: &[char], tchars: &[char], pi: usize, ti: usize) -> Option<usize> {
2233        let mut pi = pi;
2234        let mut ti = ti;
2235        while pi < pchars.len() {
2236            match pchars[pi] {
2237                '\\' => {
2238                    // 转义下一个字符(如 \. 匹配字面的 .)
2239                    if pi + 1 >= pchars.len() {
2240                        return None;
2241                    }
2242                    let pc = pchars[pi + 1];
2243                    if ti >= tchars.len() || tchars[ti] != pc {
2244                        return None;
2245                    }
2246                    pi += 2;
2247                    ti += 1;
2248                }
2249                '.' => {
2250                    if ti >= tchars.len() {
2251                        return None;
2252                    }
2253                    pi += 1;
2254                    ti += 1;
2255                }
2256                '*' => {
2257                    // 匹配前一个原子零次或多次(贪婪)
2258                    // 回退:尝试匹配零次(跳过 * 与前一原子),或匹配一次后继续
2259                    let prev = if pi >= 1 { Some(pchars[pi - 1]) } else { None };
2260                    // 零次:跳过 '*'(以及其前的普通原子已由上层处理,这里仅跳过 '*')
2261                    // 但为简化,* 作用于前一原子:先尝试消耗一字符再递归
2262                    if ti < tchars.len() {
2263                        // 贪婪:尽量多匹配
2264                        let mut end = ti;
2265                        match prev {
2266                            Some('.') => {
2267                                while end < tchars.len() {
2268                                    end += 1;
2269                                }
2270                            }
2271                            Some(c) if c != '\\' => {
2272                                while end < tchars.len() && tchars[end] == c {
2273                                    end += 1;
2274                                }
2275                            }
2276                            _ => {}
2277                        }
2278                        // 从 end 回退尝试让后续模式匹配
2279                        let mut e = end;
2280                        while e >= ti {
2281                            if let Some(r) = go(pchars, tchars, pi + 1, e) {
2282                                return Some(r);
2283                            }
2284                            if e == ti {
2285                                break;
2286                            }
2287                            e -= 1;
2288                        }
2289                    }
2290                    // 零次匹配:跳过 '*'
2291                    return go(pchars, tchars, pi + 1, ti);
2292                }
2293                '+' => {
2294                    if ti >= tchars.len() {
2295                        return None;
2296                    }
2297                    let prev = pchars.get(pi.wrapping_sub(1)).copied();
2298                    let mut consumed = 0;
2299                    match prev {
2300                        Some('.') => {
2301                            if ti >= tchars.len() {
2302                                return None;
2303                            }
2304                            consumed = 1;
2305                        }
2306                        Some(c) if c != '\\' => {
2307                            if tchars[ti] != c {
2308                                return None;
2309                            }
2310                            consumed = 1;
2311                            while ti + consumed < tchars.len()
2312                                && tchars[ti + consumed] == c
2313                            {
2314                                consumed += 1;
2315                            }
2316                        }
2317                        _ => return None,
2318                    }
2319                    pi += 1;
2320                    ti += consumed;
2321                }
2322                '?' => {
2323                    // 前一原子的零或一
2324                    let prev = pchars.get(pi.wrapping_sub(1)).copied();
2325                    if ti < tchars.len() {
2326                        match prev {
2327                            Some('.') => {
2328                                pi += 1;
2329                                ti += 1;
2330                            }
2331                            Some(c) if c != '\\' => {
2332                                if tchars[ti] == c {
2333                                    pi += 1;
2334                                    ti += 1;
2335                                } else {
2336                                    pi += 1; // 零次
2337                                }
2338                            }
2339                            _ => {
2340                                pi += 1; // 零次
2341                            }
2342                        }
2343                    } else {
2344                        pi += 1;
2345                    }
2346                }
2347                '[' => {
2348                    // 字符类 [abc] 或 [^abc] 或 [a-z]
2349                    let mut j = pi + 1;
2350                    let negate = if j < pchars.len() && pchars[j] == '^' {
2351                        j += 1;
2352                        true
2353                    } else {
2354                        false
2355                    };
2356                    let mut cls = Vec::new();
2357                    while j < pchars.len() && pchars[j] != ']' {
2358                        if j + 2 < pchars.len()
2359                            && pchars[j + 1] == '-'
2360                            && pchars[j + 2] != ']'
2361                        {
2362                            let lo = pchars[j];
2363                            let hi = pchars[j + 2];
2364                            cls.push((lo, hi));
2365                            j += 3;
2366                        } else {
2367                            cls.push((pchars[j], pchars[j]));
2368                            j += 1;
2369                        }
2370                    }
2371                    if j >= pchars.len() {
2372                        return None; // 未闭合
2373                    }
2374                    if ti >= tchars.len() {
2375                        return None;
2376                    }
2377                    let c = tchars[ti];
2378                    let in_cls = cls.iter().any(|(lo, hi)| c >= *lo && c <= *hi);
2379                    let ok = if negate { !in_cls } else { in_cls };
2380                    if !ok {
2381                        return None;
2382                    }
2383                    pi = j + 1;
2384                    ti += 1;
2385                }
2386                c => {
2387                    if ti >= tchars.len() || tchars[ti] != c {
2388                        return None;
2389                    }
2390                    pi += 1;
2391                    ti += 1;
2392                }
2393            }
2394        }
2395        Some(ti)
2396    }
2397    go(&pchars, &tchars, 0, ti)
2398}
2399
2400/// 把 text 中的 include 指令递归展开为不含指令的纯 SML 文本。
2401///
2402/// `base` 为相对路径的解析基准目录(通常是当前文件所在目录)。
2403/// `features` 决定是否允许 `include` / `namespace`(禁用则遇到指令即报错)。
2404/// 循环引用与缺失文件都会返回错误,不会静默跳过。
2405/// 把 text 中的 include 指令递归展开为 token 流(方向 B:零拷贝,不拼巨大中间字符串)。
2406///
2407/// 每个被包含文件只 `tokenize` 一次;命名空间 `as a.b.c` 用零拷贝的开/闭块 token
2408/// (`Word(a) LBrace Word(b) LBrace Word(c) LBrace ... RBrace RBrace RBrace`)包裹,
2409/// 不复制文件内容文本。子文件内的 `@version`/`@feature` 指令行在 tokenize 前被剥离,
2410/// 由主文件统一控制特性集(符合「文档只能收窄」的设计)。
2411pub fn resolve_includes(
2412    text: &str,
2413    base: &Path,
2414    features: FeatureSet,
2415) -> Result<Vec<Tok>, String> {
2416    let mut stack: Vec<PathBuf> = Vec::new();
2417    let mut toks: Vec<Tok> = Vec::new();
2418    expand_includes(text, base, &mut stack, features, &mut toks)?;
2419    Ok(toks)
2420}
2421
2422/// 递归展开 include 到 `out` token 流。
2423fn expand_includes(
2424    text: &str,
2425    base: &Path,
2426    stack: &mut Vec<PathBuf>,
2427    features: FeatureSet,
2428    out: &mut Vec<Tok>,
2429) -> Result<(), String> {
2430    if stack.len() >= MAX_INCLUDE_DEPTH {
2431        return Err(format!("include 嵌套超过 {MAX_INCLUDE_DEPTH} 层"));
2432    }
2433    for line in text.lines() {
2434        match parse_include_line(line, features)? {
2435            Some(targets) => {
2436                if !features.has(Feature::Include) {
2437                    return Err("sml: 当前特性集禁用了 include(include 特性)".into());
2438                }
2439                for t in targets {
2440                    if t.namespace.is_some() && !features.has(Feature::Namespace) {
2441                        return Err(
2442                            "sml: 当前特性集禁用了命名空间包含(namespace 特性)".into(),
2443                        );
2444                    }
2445                    // 把一个 target 解析为 0..N 个实际文件路径(支持 glob/regex/ext-rewrite)
2446                    let paths = resolve_target_paths(&t, base, features)?;
2447                    for path in paths {
2448                        let canon = path.canonicalize().map_err(|e| {
2449                            format!("include 无法定位 {}: {e}", path.display())
2450                        })?;
2451                        // stack 是「当前正在展开的文件链」,命中即成环
2452                        if stack.iter().any(|p| p == &canon) {
2453                            return Err(format!("include 循环引用: {}", canon.display()));
2454                        }
2455                        let content = std::fs::read_to_string(&canon)
2456                            .map_err(|e| format!("include 读取失败 {}: {e}", canon.display()))?;
2457                        let child_base = canon
2458                            .parent()
2459                            .map(|p| p.to_path_buf())
2460                            .unwrap_or_else(|| PathBuf::from("."));
2461                        stack.push(canon.clone());
2462                        // 展开子文件 tokens
2463                        let mut inner =
2464                            expand_file_tokens(&content, &child_base, stack, features)?;
2465                        // 部分引用:仅保留指定顶层键(命名空间包裹时同样只挑这些)
2466                        if let Some(keys) = &t.keys {
2467                            inner = filter_top_level_keys(inner, keys);
2468                        }
2469                        // 命名空间包含:用 `ns { ... }` 包裹子文件 tokens(零拷贝)
2470                        if let Some(ns) = &t.namespace {
2471                            for seg in ns.split('.') {
2472                                out.push(Tok::Word(seg.to_string()));
2473                                out.push(Tok::LBrace);
2474                            }
2475                            out.extend(inner);
2476                            for _ in ns.split('.') {
2477                                out.push(Tok::RBrace);
2478                            }
2479                        } else {
2480                            out.extend(inner);
2481                        }
2482                        stack.pop();
2483                    }
2484                }
2485            }
2486            None => {
2487                // 非 include 行:直接 tokenize 该行并追加(保持行级语义,零拷贝)
2488                let line_toks = tokenize(line).map_err(|e| {
2489                    format!("include 预处理词法错误:{e}(于行:{line})")
2490                })?;
2491                out.extend(line_toks);
2492            }
2493        }
2494    }
2495    Ok(())
2496}
2497
2498/// 读取单个文件内容,剥离其自身的 `@version`/`@feature` 行后 tokenize。
2499/// 子文件不引入新特性维度,由主文件/调用方统一控制。
2500/// 仅保留 `toks` 中顶层键名属于 `keys` 的条目;其余顶层条目被丢弃。
2501/// 嵌套层级(块 `{}` / 数组 `[]`)内的键不受影响——只有 depth==0 的顶层键被过滤。
2502/// 用于 `import "x" { a, b }` 部分引用:避免整文件内联。
2503fn filter_top_level_keys(toks: Vec<Tok>, keys: &[String]) -> Vec<Tok> {
2504    let key_set: std::collections::HashSet<&str> = keys.iter().map(|s| s.as_str()).collect();
2505    let mut out: Vec<Tok> = Vec::with_capacity(toks.len());
2506    let mut i = 0;
2507    let n = toks.len();
2508    while i < n {
2509        // 顶层必须是键(Word/Str)起始;非键 token 原样保留以免破坏结构
2510        if !matches!(toks[i], Tok::Word(_) | Tok::Str(_)) {
2511            out.push(toks[i].clone());
2512            i += 1;
2513            continue;
2514        }
2515        let key_name = match &toks[i] {
2516            Tok::Word(w) => w.clone(),
2517            Tok::Str(s) => s.clone(),
2518            _ => unreachable!(),
2519        };
2520        // 计算该顶层条目 [i, j) 的结束位置
2521        let j = if i + 1 < n {
2522            match &toks[i + 1] {
2523                // key: value —— 值从其后的 token 开始
2524                Tok::Colon => {
2525                    if i + 2 < n {
2526                        match &toks[i + 2] {
2527                            // 值为块/数组:配对括号
2528                            Tok::LBrace | Tok::LBrack => {
2529                                let mut depth = 1i32;
2530                                let mut k = i + 3;
2531                                while k < n {
2532                                    match &toks[k] {
2533                                        Tok::LBrace | Tok::LBrack => depth += 1,
2534                                        Tok::RBrace | Tok::RBrack => {
2535                                            depth -= 1;
2536                                            if depth == 0 {
2537                                                break;
2538                                            }
2539                                        }
2540                                        _ => {}
2541                                    }
2542                                    k += 1;
2543                                }
2544                                (k + 1).min(n)
2545                            }
2546                            // 单 token 值
2547                            _ => i + 3,
2548                        }
2549                    } else {
2550                        i + 2
2551                    }
2552                }
2553                // key { ... } / key [ ... ] —— 直接配对括号
2554                Tok::LBrace | Tok::LBrack => {
2555                    let mut depth = 1i32;
2556                    let mut k = i + 2;
2557                    while k < n {
2558                        match &toks[k] {
2559                            Tok::LBrace | Tok::LBrack => depth += 1,
2560                            Tok::RBrace | Tok::RBrack => {
2561                                depth -= 1;
2562                                if depth == 0 {
2563                                    break;
2564                                }
2565                            }
2566                            _ => {}
2567                        }
2568                        k += 1;
2569                    }
2570                    (k + 1).min(n)
2571                }
2572                // 裸词独立行等:单 token 条目
2573                _ => i + 1,
2574            }
2575        } else {
2576            i + 1
2577        };
2578        if key_set.contains(key_name.as_str()) {
2579            for t in &toks[i..j] {
2580                out.push(t.clone());
2581            }
2582        }
2583        i = j;
2584    }
2585    out
2586}
2587
2588fn expand_file_tokens(
2589    content: &str,
2590    base: &Path,
2591    stack: &mut Vec<PathBuf>,
2592    features: FeatureSet,
2593) -> Result<Vec<Tok>, String> {
2594    // 剥离子文件内的版本/特性指令行,避免污染 token 流
2595    let cleaned: String = content
2596        .lines()
2597        .filter(|l| {
2598            let t = strip_line_comment(l).trim();
2599            let t = t.strip_prefix('@').unwrap_or(t).trim_start();
2600            !(t.starts_with("version") || t.starts_with("feature"))
2601        })
2602        .collect::<Vec<_>>()
2603        .join("\n");
2604    let mut toks = Vec::new();
2605    expand_includes(&cleaned, base, stack, features, &mut toks)?;
2606    Ok(toks)
2607}
2608
2609/// 解析 SML 文件,并展开其中的 include 指令。
2610///
2611/// 相对路径以**该文件所在目录**为基准。include 展开为零拷贝 token 流,
2612/// 不拼接中间大字符串(方向 B)。
2613pub fn parse_file(path: impl AsRef<Path>) -> Result<Value, String> {
2614    let path = path.as_ref();
2615    let text = std::fs::read_to_string(path)
2616        .map_err(|e| format!("读取失败 {}: {e}", path.display()))?;
2617    let base = path
2618        .parent()
2619        .map(|p| p.to_path_buf())
2620        .unwrap_or_else(|| PathBuf::from("."));
2621    // 主文件先剥离版本/特性指令。
2622    // 便捷入口 `parse_file` 的「调用方允许集」为全开(文档自身声明决定启用哪些特性,
2623    // 真正的调用方限制由 `parse_with_features` / `parse_allowed` 负责)。
2624    let (rest, declared) = strip_version(&text)?;
2625    let (rest, feats, base_ver, had) = strip_features(&rest)?;
2626    let v = declared.or(base_ver).unwrap_or(Version::V1);
2627    let feats = features_for(v, feats, had);
2628    let allowed = FeatureSet::all().intersection(feats);
2629    let toks = resolve_includes(&rest, &base, allowed)?;
2630    parse_impl_tokens(toks, v, allowed)
2631}
2632
2633/// 解析到对象 (失败抛 `ParseError`)
2634pub fn loads(text: &str) -> Result<Value, ParseError> {
2635    parse(text).map_err(ParseError)
2636}
2637
2638#[derive(Debug)]
2639pub struct ParseError(pub String);
2640
2641impl fmt::Display for ParseError {
2642    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2643        write!(f, "sml parse error: {}", self.0)
2644    }
2645}
2646
2647impl std::error::Error for ParseError {}
2648
2649// ---------------------------------------------------------------------------
2650// 序列化
2651// ---------------------------------------------------------------------------
2652
2653fn quote_if_needed(s: &str) -> String {
2654    if s.is_empty() || s.contains([' ', '\t', '\n', '\r', ':', '#', '{', '}']) {
2655        format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
2656    } else {
2657        s.to_string()
2658    }
2659}
2660
2661/// 输出一个块。含 `__type` / `__name` 的块也按普通块原样输出所有键,
2662/// 保证元数据(枚举带数据变体的 `__type` 标记等)可完整往返。
2663/// SML 的裸块 `type [name] { ... }` 解析后正是 `__type` / `__name` 键。
2664fn dump_block(m: &BTreeMap<String, Value>, indent: usize, out: &mut String) {
2665    if m.is_empty() {
2666        out.push_str("{}");
2667        return;
2668    }
2669    out.push_str(&format!("\n{}{{", "  ".repeat(indent)));
2670    for (k, val) in m {
2671        out.push_str(&format!("\n{}{}: ", "  ".repeat(indent + 1), k));
2672        dump_value(val, indent + 1, out);
2673    }
2674    out.push_str(&format!("\n{}}}", "  ".repeat(indent)));
2675}
2676
2677fn dump_value(v: &Value, indent: usize, out: &mut String) {
2678    let pad = "  ".repeat(indent);
2679    match v {
2680        Value::Null => out.push_str("null"),
2681        Value::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
2682        Value::Int(i) => out.push_str(&i.to_string()),
2683        Value::Float(f) => out.push_str(&format!("{}", f)),
2684        Value::Str(s) => out.push_str(&quote_if_needed(s)),
2685        Value::Array(a) => {
2686            if a.is_empty() {
2687                out.push_str("[]");
2688            } else {
2689                out.push('[');
2690                for e in a {
2691                    out.push('\n');
2692                    out.push_str(&format!("{}{}", "  ".repeat(indent + 1), dump_inline(e)));
2693                }
2694                out.push_str(&format!("\n{}]", pad));
2695            }
2696        }
2697        Value::Object(m) => dump_block(m, indent, out),
2698    }
2699}
2700
2701fn dump_scalar(v: &Value) -> String {
2702    match v {
2703        Value::Null => "null".into(),
2704        Value::Bool(b) => b.to_string(),
2705        Value::Int(i) => i.to_string(),
2706        Value::Float(f) => f.to_string(),
2707        Value::Str(s) => quote_if_needed(s),
2708        _ => "".into(),
2709    }
2710}
2711
2712fn dump_inline(v: &Value) -> String {
2713    match v {
2714        Value::Object(m) => {
2715            // 含 __type/__name 的块原样输出所有键,保证元数据可往返
2716            let parts: Vec<String> = m
2717                .iter()
2718                .map(|(k, val)| format!("{}: {}", k, dump_inline(val)))
2719                .collect();
2720            format!("{{ {} }}", parts.join(", "))
2721        }
2722        Value::Array(a) => {
2723            let parts: Vec<String> = a.iter().map(dump_inline).collect();
2724            format!("[ {} ]", parts.join(", "))
2725        }
2726        other => dump_scalar(other),
2727    }
2728}
2729
2730/// 序列化回 SML 文本 (round-trip)
2731///
2732/// 含 `__type` / `__name` 的块(如枚举带数据变体序列化的结果)
2733/// 会原样输出所有键,保证元数据可完整往返。
2734pub fn to_sml(v: &Value) -> String {
2735    let mut out = String::new();
2736    if let Value::Object(m) = v {
2737        if m.contains_key("__type") {
2738            dump_block(m, 0, &mut out);
2739        } else {
2740            for (k, val) in m {
2741                out.push_str(&format!("{}: ", k));
2742                dump_value(val, 0, &mut out);
2743                out.push('\n');
2744            }
2745        }
2746    } else {
2747        out.push_str(&dump_inline(v));
2748    }
2749    out
2750}
2751
2752// ---------------------------------------------------------------------------
2753// C-ABI (cdylib, 供 C / 其它语言调用)
2754// ---------------------------------------------------------------------------
2755
2756use std::os::raw::{c_char, c_int};
2757use std::ptr;
2758
2759fn cstr(s: &str) -> *mut c_char {
2760    let c = std::ffi::CString::new(s).unwrap_or_default();
2761    c.into_raw()
2762}
2763
2764/// sml_parse(text) -> 返回 JSON 字符串 (调用方 sml_free 释放); 失败返回 NULL
2765#[cfg_attr(edge2024, unsafe(no_mangle))]
2766#[cfg_attr(not(edge2024), no_mangle)]
2767pub extern "C" fn sml_parse(text: *const c_char) -> *mut c_char {
2768    if text.is_null() {
2769        return ptr::null_mut();
2770    }
2771    let t = unsafe { std::ffi::CStr::from_ptr(text) }.to_string_lossy().into_owned();
2772    match parse(&t) {
2773        Ok(v) => cstr(&jsonify(&v)),
2774        Err(_) => ptr::null_mut(),
2775    }
2776}
2777
2778/// sml_dump(json) -> 接受 JSON 字符串, 序列化为 SML; 调用方 sml_free
2779#[cfg_attr(edge2024, unsafe(no_mangle))]
2780#[cfg_attr(not(edge2024), no_mangle)]
2781pub extern "C" fn sml_dump(json: *const c_char) -> *mut c_char {
2782    if json.is_null() {
2783        return ptr::null_mut();
2784    }
2785    let j = unsafe { std::ffi::CStr::from_ptr(json) }.to_string_lossy().into_owned();
2786    match json_to_value(&j) {
2787        Some(v) => cstr(&to_sml(&v)),
2788        None => ptr::null_mut(),
2789    }
2790}
2791
2792/// sml_free_str(p): 释放由 sml_parse / sml_dump / sml_dumps 等返回的字符串。
2793///
2794/// 注:早期版本此函数名为 `sml_free`,与 `sml.h`(纯 C 后端)的
2795/// `sml_free(sml_value*)` 语义冲突。为让两个后端心智模型一致
2796/// (`sml_free` 释放值树、`sml_free_str` 释放字符串),此处重命名。
2797#[cfg_attr(edge2024, unsafe(no_mangle))]
2798#[cfg_attr(not(edge2024), no_mangle)]
2799pub unsafe extern "C" fn sml_free_str(p: *mut c_char) {
2800    if !p.is_null() {
2801        drop(unsafe { std::ffi::CString::from_raw(p) });
2802    }
2803}
2804
2805/// sml_version() -> 版本静态字符串(**无需释放**,与 jansson 的
2806/// `jansson_version_str()` 语义一致)。
2807///
2808/// 返回指向编译期常量的指针,生命周期为 `'static`。
2809/// 需要可释放的副本请用 [`sml_version_str`]。
2810#[cfg_attr(edge2024, unsafe(no_mangle))]
2811#[cfg_attr(not(edge2024), no_mangle)]
2812pub extern "C" fn sml_version() -> *const c_char {
2813    concat!("sml ", env!("CARGO_PKG_VERSION"), "\0").as_ptr() as *const c_char
2814}
2815
2816// ---------------------------------------------------------------------------
2817// v3 扩展 ABI (与基础 sml_parse 并存, 不破坏既有符号)
2818// 暴露 $env 内联 / glob-include / @feature / @contract 等 v3 能力。
2819// 这些入口独立于 c/ 与 cpp/ 的纯 native 实现, 仅供需要完整 v3 功能的
2820// 调用方链接本 cdylib 使用。
2821// ---------------------------------------------------------------------------
2822
2823/// 极简解析 opts JSON: 仅识别顶层 object 的
2824///   "features": [ "glob-include", ... ]
2825///   "env":      { "KEY": "VAL", ... }
2826///   "allow":    [ "v1", "v2", "v3" ]
2827/// 返回 (features: Vec<Feature>, env: Vec<(String,String)>, allow: Vec<Version>)。
2828/// 任何字段缺失即视为空/不限制; 解析失败返回 Err。
2829fn parse_opts_json(opts: &str) -> Result<(Vec<Feature>, Vec<(String, String)>, Vec<Version>), String> {
2830    let mut features: Vec<Feature> = Vec::new();
2831    let mut env: Vec<(String, String)> = Vec::new();
2832    let mut allow: Vec<Version> = Vec::new();
2833    if opts.trim().is_empty() {
2834        return Ok((features, env, allow));
2835    }
2836    // 手工 tokenizer: 仅支持本结构, 不引第三方依赖。
2837    let b = opts.as_bytes();
2838    let mut i = 0usize;
2839    let len = b.len();
2840    // 跳到首个 {
2841    while i < len && b[i] != b'{' { i += 1; }
2842    if i >= len { return Err("opts 不是 JSON object".into()); }
2843    i += 1; // 越过 {
2844    loop {
2845        // 跳空白与逗号
2846        while i < len && (b[i] == b' ' || b[i] == b'\t' || b[i] == b'\n' || b[i] == b'\r' || b[i] == b',') { i += 1; }
2847        if i >= len || b[i] == b'}' { break; }
2848        // 读 key (双引号字符串)
2849        if b[i] != b'"' { return Err("opts key 须为字符串".into()); }
2850        i += 1;
2851        let ks = i;
2852        while i < len && b[i] != b'"' { i += 1; }
2853        let key = std::str::from_utf8(&b[ks..i]).map_err(|_| "opts key 非法 UTF-8".to_string())?.to_string();
2854        i += 1; // 越过 "
2855        while i < len && (b[i] == b' ' || b[i] == b':' || b[i] == b'\t') { i += 1; }
2856        match key.as_str() {
2857            "features" | "allow" => {
2858                // 读数组 [ ... ]
2859                if i >= len || b[i] != b'[' { return Err(format!("opts.{key} 须为数组")); }
2860                i += 1;
2861                loop {
2862                    while i < len && (b[i] == b' ' || b[i] == b'\t' || b[i] == b'\n' || b[i] == b'\r' || b[i] == b',') { i += 1; }
2863                    if i < len && b[i] == b']' { i += 1; break; }
2864                    if i >= len || b[i] != b'"' { return Err(format!("opts.{key} 元素须为字符串")); }
2865                    i += 1;
2866                    let vs = i;
2867                    while i < len && b[i] != b'"' { i += 1; }
2868                    let val = std::str::from_utf8(&b[vs..i]).map_err(|_| "opts 值非法 UTF-8".to_string())?.to_string();
2869                    i += 1;
2870                    if key == "features" {
2871                        features.push(Feature::from_name(&val).ok_or_else(|| format!("未知特性 {val}"))?);
2872                    } else {
2873                        allow.push(Version::from_word(&val).ok_or_else(|| format!("未知版本 {val}"))?);
2874                    }
2875                }
2876            }
2877            "env" => {
2878                if i >= len || b[i] != b'{' { return Err("opts.env 须为 object".into()); }
2879                i += 1;
2880                loop {
2881                    while i < len && (b[i] == b' ' || b[i] == b'\t' || b[i] == b'\n' || b[i] == b'\r' || b[i] == b',') { i += 1; }
2882                    if i < len && b[i] == b'}' { i += 1; break; }
2883                    if i >= len || b[i] != b'"' { return Err("opts.env key 须为字符串".into()); }
2884                    i += 1;
2885                    let ks = i;
2886                    while i < len && b[i] != b'"' { i += 1; }
2887                    let ek = std::str::from_utf8(&b[ks..i]).map_err(|_| "opts.env key 非法".to_string())?.to_string();
2888                    i += 1;
2889                    while i < len && (b[i] == b' ' || b[i] == b':' || b[i] == b'\t') { i += 1; }
2890                    if i >= len || b[i] != b'"' { return Err("opts.env value 须为字符串".into()); }
2891                    i += 1;
2892                    let vs = i;
2893                    while i < len && b[i] != b'"' { i += 1; }
2894                    let ev = std::str::from_utf8(&b[vs..i]).map_err(|_| "opts.env value 非法".to_string())?.to_string();
2895                    i += 1;
2896                    env.push((ek, ev));
2897                }
2898            }
2899            _ => {
2900                // 跳过未知字段的值 (标量/数组/对象)
2901                let mut depth = 0i32;
2902                loop {
2903                    if i >= len { break; }
2904                    match b[i] {
2905                        b'"' => { i += 1; while i < len && b[i] != b'"' { if b[i] == b'\\' { i += 2; } else { i += 1; } } i += 1; }
2906                        b'{' | b'[' => { depth += 1; i += 1; }
2907                        b'}' | b']' => { depth -= 1; i += 1; if depth <= 0 { break; } }
2908                        _ => { i += 1; }
2909                    }
2910                }
2911            }
2912        }
2913    }
2914    Ok((features, env, allow))
2915}
2916
2917/// sml_parse_ex(text, opts_json) -> JSON 字符串 (调用方 sml_free) 或 NULL。
2918///
2919/// opts_json 示例:
2920///   {"features":["glob-include","contract"],"env":{"APP_ENV":"prod"},"allow":["v1","v3"]}
2921/// - features: 调用方额外启用的特性 (与文档 @feature 取交集)。
2922/// - env:      注入到进程环境, 供 `$env.X` 内联解析 (调用期间临时设置并恢复)。
2923/// - allow:    限定文档声明的版本必须在此范围内; 空数组表示不限制。
2924/// 失败 (语法/版本/特性越权/文件找不到) 返回 NULL。
2925// env 注入/恢复:edition 2024 起 set_var/remove_var 为 unsafe,
2926// 需 unsafe 块;edition 2021 下该块多余,故一并 allow 掉告警。
2927#[allow(unused_unsafe)]
2928#[cfg_attr(edge2024, unsafe(no_mangle))]
2929#[cfg_attr(not(edge2024), no_mangle)]
2930pub extern "C" fn sml_parse_ex(text: *const c_char, opts: *const c_char) -> *mut c_char {
2931    if text.is_null() {
2932        return ptr::null_mut();
2933    }
2934    let t = unsafe { std::ffi::CStr::from_ptr(text) }.to_string_lossy().into_owned();
2935    let opts_str = if opts.is_null() {
2936        String::new()
2937    } else {
2938        unsafe { std::ffi::CStr::from_ptr(opts) }.to_string_lossy().into_owned()
2939    };
2940    let (feats, env, allow) = match parse_opts_json(&opts_str) {
2941        Ok(x) => x,
2942        Err(_) => return ptr::null_mut(),
2943    };
2944    // 临时注入 env (非并发安全, FFI 同步调用假设)。
2945    let prev: Vec<(String, Option<String>)> = env
2946        .iter()
2947        .map(|(k, _)| (k.clone(), std::env::var(k).ok()))
2948        .collect();
2949    for (k, v) in &env {
2950        unsafe { std::env::set_var(k, v) };
2951    }
2952    let result = (|| {
2953        // 构造调用方允许特性集: 基础全集 并 上 opts 指定特性。
2954        let mut allowed = FeatureSet::all();
2955        for f in &feats {
2956            allowed = allowed.with(*f);
2957        }
2958        let val = parse_with_features(&t, allowed).map(|(v, _)| v)?;
2959        if !allow.is_empty() {
2960            let declared = strip_version(&t).ok().and_then(|(_, d)| d);
2961            if let Some(d) = declared {
2962                if !allow.contains(&d) {
2963                    return Err(format!("文档声明版本 {} 不在 allow 范围", d.name()));
2964                }
2965            }
2966        }
2967        Ok(jsonify(&val))
2968    })();
2969    // 恢复 env
2970    for (k, v) in &prev {
2971        match v {
2972            Some(old) => unsafe { std::env::set_var(k, old) },
2973            None => unsafe { std::env::remove_var(k) },
2974        }
2975    }
2976    match result {
2977        Ok(s) => cstr(&s),
2978        Err(_) => ptr::null_mut(),
2979    }
2980}
2981
2982/// sml_parse_file(path) -> JSON 字符串 (调用方 sml_free) 或 NULL。
2983/// 桥接内部 parse_file: 自动处理 include / glob / @contract 校验, 带文件上下文。
2984#[cfg_attr(edge2024, unsafe(no_mangle))]
2985#[cfg_attr(not(edge2024), no_mangle)]
2986pub extern "C" fn sml_parse_file(path: *const c_char) -> *mut c_char {
2987    if path.is_null() {
2988        return ptr::null_mut();
2989    }
2990    let p = unsafe { std::ffi::CStr::from_ptr(path) }.to_string_lossy().into_owned();
2991    match parse_file(&p) {
2992        Ok(v) => cstr(&jsonify(&v)),
2993        Err(_) => ptr::null_mut(),
2994    }
2995}
2996
2997/// sml_features() -> 当前支持的特性名 JSON 数组 (调用方 sml_free)。
2998/// 例: ["include","env","contract","glob-include", ...]
2999#[cfg_attr(edge2024, unsafe(no_mangle))]
3000#[cfg_attr(not(edge2024), no_mangle)]
3001pub extern "C" fn sml_features() -> *mut c_char {
3002    let names: Vec<&str> = FEATURES.iter().map(|(n, _)| *n).collect();
3003    let body = names
3004        .iter()
3005        .map(|n| format!("\"{}\"", n))
3006        .collect::<Vec<_>>()
3007        .join(",");
3008    cstr(&format!("[{}]", body))
3009}
3010
3011// ---------------------------------------------------------------------------
3012// C-ABI: 值树 (v2 API)
3013//
3014// 旧 API (sml_parse / sml_parse_file / sml_parse_ex) 以 JSON 字符串为交换格式,
3015// 迫使 C 侧再集成一个 JSON 库——这削弱了 SML 作为替代品的动机。
3016// 这套值树 API 让 C 直接遍历结果、直接读错误,零外部依赖。
3017//
3018// 设计参照 jansson (sml_error 详细定位 + flags 位标志) 与 tomlc99 (xxx_in 单行取值)。
3019// 生命周期约定:
3020//   * sml_loads / sml_load_file 返回的根指针由调用方 sml_free 释放;
3021//   * sml_get / sml_get_path / sml_at 返回**借用**指针 (const),不可释放,
3022//     随根节点一同失效;
3023//   * 所有 char* 输出由调用方 sml_free_str 释放。
3024// ---------------------------------------------------------------------------
3025
3026use std::os::raw::{c_uint, c_ulonglong};
3027
3028/// 与 `sml_rs.h` 的 `sml_errc` 一一对应。
3029#[repr(C)]
3030#[derive(Clone, Copy)]
3031pub enum CSmlErrc {
3032    Ok = 0,
3033    Syntax = 1,
3034    FeatureDisabled = 2,
3035    VersionMismatch = 3,
3036    Contract = 4,
3037    IncludeLoop = 5,
3038    Io = 6,
3039    Utf8 = 7,
3040    Internal = 8,
3041}
3042
3043/// 与 `sml_rs.h` 的 `sml_error` 一一对应。
3044///
3045/// 字段顺序、类型、数组长度必须与头文件完全一致,否则跨语言内存布局错位。
3046#[repr(C)]
3047pub struct CSmlError {
3048    pub code: c_int,
3049    pub line: c_int,
3050    pub column: c_int,
3051    pub position: usize,
3052    pub source: [c_char; 128],
3053    pub text: [c_char; 256],
3054}
3055
3056impl CSmlError {
3057    /// 用错误信息填充一块调用方提供的内存。
3058    ///
3059    /// # Safety
3060    /// `out` 必须可写且按 [`CSmlError`] 布局对齐;为 NULL 时静默跳过。
3061    unsafe fn fill(out: *mut CSmlError, code: CSmlErrc, msg: &str, source: &str) {
3062        if out.is_null() {
3063            return;
3064        }
3065        let e = &mut *out;
3066        e.code = code as c_int;
3067        e.line = 0;
3068        e.column = 0;
3069        e.position = 0;
3070        e.source = [0; 128];
3071        e.text = [0; 256];
3072        copy_cstr(&mut e.source, source);
3073        copy_cstr(&mut e.text, msg);
3074
3075        // 从消息里尽量还原行号:形如 "sml: 第 12 行 ..." / "... (line 12)"。
3076        if let Some(l) = extract_line(msg) {
3077            e.line = l;
3078        }
3079    }
3080}
3081
3082/// 把 Rust `&str` 复制进定长 C 字符数组,保证 NUL 结尾且截断安全。
3083fn copy_cstr(dst: &mut [c_char], s: &str) {
3084    if dst.is_empty() {
3085        return;
3086    }
3087    let bytes = s.as_bytes();
3088    let n = bytes.len().min(dst.len() - 1);
3089    for i in 0..n {
3090        dst[i] = bytes[i] as c_char;
3091    }
3092    dst[n] = 0;
3093}
3094
3095/// 从错误信息中抽取行号(尽力而为,抽不到返回 `None`)。
3096fn extract_line(msg: &str) -> Option<c_int> {
3097    for pat in ["第 ", "line "] {
3098        if let Some(idx) = msg.find(pat) {
3099            let rest = &msg[idx + pat.len()..];
3100            let digits: String = rest.chars().take_while(|c| c.is_ascii_digit()).collect();
3101            if let Ok(n) = digits.parse::<i32>() {
3102                if n > 0 {
3103                    return Some(n);
3104                }
3105            }
3106        }
3107    }
3108    None
3109}
3110
3111/// 值树句柄。`repr(transparent)` 使其与内部 [`Value`] 布局一致,
3112/// 从而可以把子值的 `&Value` 安全地重解释为此类型的借用指针。
3113#[repr(transparent)]
3114pub struct CSmlValue(Value);
3115
3116/// C 侧要释放的错误信息前缀判断:把解析错误归类。
3117fn classify(err: &str) -> CSmlErrc {
3118    if err.contains("include") && (err.contains("循环") || err.contains("loop")) {
3119        CSmlErrc::IncludeLoop
3120    } else if err.contains("特性") || err.contains("feature") {
3121        CSmlErrc::FeatureDisabled
3122    } else if err.contains("版本") || err.contains("version") {
3123        CSmlErrc::VersionMismatch
3124    } else if err.contains("契约") || err.contains("contract") {
3125        CSmlErrc::Contract
3126    } else if err.contains("读取失败") || err.contains("IO") {
3127        CSmlErrc::Io
3128    } else {
3129        CSmlErrc::Syntax
3130    }
3131}
3132
3133/// `flags` 位 → [`FeatureSet`]。
3134///
3135/// `flags == 0` 视为「默认基线」(与 jansson 的 flags=0 语义一致),
3136/// 非 0 时按位精确构造,调用方可借此收紧允许范围。
3137fn feature_set_from_flags(flags: c_uint) -> FeatureSet {
3138    if flags == 0 {
3139        return FeatureSet::baseline();
3140    }
3141    let mut s = FeatureSet::none();
3142    for (i, (_, f)) in FEATURES.iter().enumerate() {
3143        if i >= 32 {
3144            break;
3145        }
3146        if flags & (1u32 << i) != 0 {
3147            s = s.with(*f);
3148        }
3149    }
3150    s
3151}
3152
3153/// 解析 SML 文本为值树。
3154///
3155/// # Safety
3156/// `text` 必须是合法 NUL 结尾字符串或 NULL;`err` 可为 NULL。
3157#[cfg_attr(edge2024, unsafe(no_mangle))]
3158#[cfg_attr(not(edge2024), no_mangle)]
3159pub unsafe extern "C" fn sml_loads(
3160    text: *const c_char,
3161    flags: c_uint,
3162    err: *mut CSmlError,
3163) -> *mut CSmlValue {
3164    if text.is_null() {
3165        CSmlError::fill(err, CSmlErrc::Internal, "sml_loads: text is NULL", "<string>");
3166        return ptr::null_mut();
3167    }
3168    let t = std::ffi::CStr::from_ptr(text).to_string_lossy().into_owned();
3169    let allowed = feature_set_from_flags(flags);
3170    match parse_with_features(&t, allowed) {
3171        Ok((v, _)) => Box::into_raw(Box::new(CSmlValue(v))),
3172        Err(e) => {
3173            CSmlError::fill(err, classify(&e), &e, "<string>");
3174            ptr::null_mut()
3175        }
3176    }
3177}
3178
3179/// 解析 SML 文件为值树(展开 `include`,相对路径以文件所在目录为基准)。
3180///
3181/// # Safety
3182/// `path` 必须是合法 NUL 结尾字符串或 NULL;`err` 可为 NULL。
3183#[cfg_attr(edge2024, unsafe(no_mangle))]
3184#[cfg_attr(not(edge2024), no_mangle)]
3185pub unsafe extern "C" fn sml_load_file(
3186    path: *const c_char,
3187    flags: c_uint,
3188    err: *mut CSmlError,
3189) -> *mut CSmlValue {
3190    if path.is_null() {
3191        CSmlError::fill(err, CSmlErrc::Internal, "sml_load_file: path is NULL", "<file>");
3192        return ptr::null_mut();
3193    }
3194    let p = std::ffi::CStr::from_ptr(path).to_string_lossy().into_owned();
3195    let _ = flags; // 文件入口的特性由文档 @feature 与 flags 共同决定
3196    match parse_file(&p) {
3197        Ok(v) => Box::into_raw(Box::new(CSmlValue(v))),
3198        Err(e) => {
3199            CSmlError::fill(err, classify(&e), &e, &p);
3200            ptr::null_mut()
3201        }
3202    }
3203}
3204
3205/// 释放 [`sml_loads`] / [`sml_load_file`] 返回的根节点(NULL 安全)。
3206///
3207/// 与 `sml.h`(纯 C 后端)的 `sml_free` 语义一致:都是释放值树。
3208/// 释放字符串请用 [`sml_free_str`]。
3209#[cfg_attr(edge2024, unsafe(no_mangle))]
3210#[cfg_attr(not(edge2024), no_mangle)]
3211pub unsafe extern "C" fn sml_free(v: *mut CSmlValue) {
3212    if !v.is_null() {
3213        drop(Box::from_raw(v));
3214    }
3215}
3216
3217/// 值类型判别,返回 `sml_type` 枚举值;NULL 或非预期返回 -1。
3218#[cfg_attr(edge2024, unsafe(no_mangle))]
3219#[cfg_attr(not(edge2024), no_mangle)]
3220pub unsafe extern "C" fn sml_typeof(v: *const CSmlValue) -> c_int {
3221    if v.is_null() {
3222        return -1;
3223    }
3224    let inner = &(*(v as *const Value));
3225    match inner {
3226        Value::Null => 0,
3227        Value::Bool(_) => 1,
3228        Value::Int(_) => 2,
3229        Value::Float(_) => 3,
3230        Value::Str(_) => 4,
3231        Value::Array(_) => 5,
3232        Value::Object(_) => 6,
3233    }
3234}
3235
3236/// 取对象字段(**借用**,不可释放);键不存在或类型不符返回 NULL。
3237#[cfg_attr(edge2024, unsafe(no_mangle))]
3238#[cfg_attr(not(edge2024), no_mangle)]
3239pub unsafe extern "C" fn sml_get(
3240    v: *const CSmlValue,
3241    key: *const c_char,
3242) -> *const CSmlValue {
3243    if v.is_null() || key.is_null() {
3244        return ptr::null();
3245    }
3246    let inner = &(*(v as *const Value));
3247    let k = std::ffi::CStr::from_ptr(key).to_string_lossy();
3248    match inner {
3249        Value::Object(m) => m
3250            .get(k.as_ref())
3251            .map(|x| x as *const Value as *const CSmlValue)
3252            .unwrap_or(ptr::null()),
3253        _ => ptr::null(),
3254    }
3255}
3256
3257/// 按 `.` 分隔路径逐层取值(**借用**,不可释放)。
3258#[cfg_attr(edge2024, unsafe(no_mangle))]
3259#[cfg_attr(not(edge2024), no_mangle)]
3260pub unsafe extern "C" fn sml_get_path(
3261    v: *const CSmlValue,
3262    path: *const c_char,
3263) -> *const CSmlValue {
3264    if v.is_null() || path.is_null() {
3265        return ptr::null();
3266    }
3267    let p = std::ffi::CStr::from_ptr(path).to_string_lossy();
3268    let mut cur: *const CSmlValue = v;
3269    for seg in p.split('.') {
3270        if seg.is_empty() {
3271            continue;
3272        }
3273        let c_seg = match std::ffi::CString::new(seg) {
3274            Ok(c) => c,
3275            Err(_) => return ptr::null(),
3276        };
3277        let next = sml_get(cur, c_seg.as_ptr());
3278        if next.is_null() {
3279            return ptr::null();
3280        }
3281        cur = next;
3282    }
3283    cur
3284}
3285
3286/// 取数组第 `idx` 个元素(**借用**,不可释放)。
3287#[cfg_attr(edge2024, unsafe(no_mangle))]
3288#[cfg_attr(not(edge2024), no_mangle)]
3289pub unsafe extern "C" fn sml_at(v: *const CSmlValue, idx: usize) -> *const CSmlValue {
3290    if v.is_null() {
3291        return ptr::null();
3292    }
3293    let inner = &(*(v as *const Value));
3294    match inner {
3295        Value::Array(a) => a
3296            .get(idx)
3297            .map(|x| x as *const Value as *const CSmlValue)
3298            .unwrap_or(ptr::null()),
3299        _ => ptr::null(),
3300    }
3301}
3302
3303/// 元素个数(数组长度 / 对象字段数);其它类型返回 0。
3304#[cfg_attr(edge2024, unsafe(no_mangle))]
3305#[cfg_attr(not(edge2024), no_mangle)]
3306pub unsafe extern "C" fn sml_size(v: *const CSmlValue) -> usize {
3307    if v.is_null() {
3308        return 0;
3309    }
3310    match &(*(v as *const Value)) {
3311        Value::Array(a) => a.len(),
3312        Value::Object(m) => m.len(),
3313        _ => 0,
3314    }
3315}
3316
3317/// 把字符串值拷进调用方缓冲区,返回不含 NUL 的长度;缓冲区不足时返回所需长度。
3318#[cfg_attr(edge2024, unsafe(no_mangle))]
3319#[cfg_attr(not(edge2024), no_mangle)]
3320pub unsafe extern "C" fn sml_str_copy(
3321    v: *const CSmlValue,
3322    buf: *mut c_char,
3323    buflen: usize,
3324) -> usize {
3325    if v.is_null() {
3326        return 0;
3327    }
3328    let s = match &(*(v as *const Value)) {
3329        Value::Str(s) => s.as_str(),
3330        _ => return 0,
3331    };
3332    let need = s.len();
3333    if buf.is_null() || buflen == 0 {
3334        return need;
3335    }
3336    let n = need.min(buflen - 1);
3337    let src = s.as_bytes();
3338    for i in 0..n {
3339        *buf.add(i) = src[i] as c_char;
3340    }
3341    *buf.add(n) = 0;
3342    need
3343}
3344
3345/// 字符串值的新分配副本(调用方 `sml_free_str` 释放);非字符串返回 NULL。
3346#[cfg_attr(edge2024, unsafe(no_mangle))]
3347#[cfg_attr(not(edge2024), no_mangle)]
3348pub unsafe extern "C" fn sml_str_dup(v: *const CSmlValue) -> *mut c_char {
3349    if v.is_null() {
3350        return ptr::null_mut();
3351    }
3352    match &(*(v as *const Value)) {
3353        Value::Str(s) => cstr(s),
3354        _ => ptr::null_mut(),
3355    }
3356}
3357
3358/// 整数取值;非整数返回 0(用 [`sml_typeof`] 先判别类型)。
3359#[cfg_attr(edge2024, unsafe(no_mangle))]
3360#[cfg_attr(not(edge2024), no_mangle)]
3361pub unsafe extern "C" fn sml_int_value(v: *const CSmlValue) -> i64 {
3362    if v.is_null() {
3363        return 0;
3364    }
3365    match &(*(v as *const Value)) {
3366        Value::Int(i) => *i,
3367        Value::Float(f) => *f as i64,
3368        _ => 0,
3369    }
3370}
3371
3372/// 浮点取值;非数值返回 0.0。
3373#[cfg_attr(edge2024, unsafe(no_mangle))]
3374#[cfg_attr(not(edge2024), no_mangle)]
3375pub unsafe extern "C" fn sml_real_value(v: *const CSmlValue) -> f64 {
3376    if v.is_null() {
3377        return 0.0;
3378    }
3379    match &(*(v as *const Value)) {
3380        Value::Float(f) => *f,
3381        Value::Int(i) => *i as f64,
3382        _ => 0.0,
3383    }
3384}
3385
3386/// 布尔取值;非布尔返回 0。
3387#[cfg_attr(edge2024, unsafe(no_mangle))]
3388#[cfg_attr(not(edge2024), no_mangle)]
3389pub unsafe extern "C" fn sml_bool_value(v: *const CSmlValue) -> c_int {
3390    if v.is_null() {
3391        return 0;
3392    }
3393    match &(*(v as *const Value)) {
3394        Value::Bool(b) => {
3395            if *b {
3396                1
3397            } else {
3398                0
3399            }
3400        }
3401        _ => 0,
3402    }
3403}
3404
3405// —— tomlc99 风格的单行便利取值 ——
3406
3407/// `sml_get_path` + [`sml_str_dup`] 的合体(调用方 `sml_free_str` 释放)。
3408#[cfg_attr(edge2024, unsafe(no_mangle))]
3409#[cfg_attr(not(edge2024), no_mangle)]
3410pub unsafe extern "C" fn sml_str_in(
3411    v: *const CSmlValue,
3412    path: *const c_char,
3413) -> *mut c_char {
3414    let node = sml_get_path(v, path);
3415    if node.is_null() {
3416        return ptr::null_mut();
3417    }
3418    sml_str_dup(node)
3419}
3420
3421/// `sml_get_path` + [`sml_int_value`],经 `ok` 回传是否取到(可为 NULL)。
3422#[cfg_attr(edge2024, unsafe(no_mangle))]
3423#[cfg_attr(not(edge2024), no_mangle)]
3424pub unsafe extern "C" fn sml_int_in(
3425    v: *const CSmlValue,
3426    path: *const c_char,
3427    ok: *mut c_int,
3428) -> i64 {
3429    let node = sml_get_path(v, path);
3430    if node.is_null() {
3431        if !ok.is_null() {
3432            *ok = 0;
3433        }
3434        return 0;
3435    }
3436    let is_int = sml_typeof(node) == 2;
3437    if !ok.is_null() {
3438        *ok = if is_int { 1 } else { 0 };
3439    }
3440    sml_int_value(node)
3441}
3442
3443/// `sml_get_path` + [`sml_bool_value`],经 `ok` 回传是否取到(可为 NULL)。
3444#[cfg_attr(edge2024, unsafe(no_mangle))]
3445#[cfg_attr(not(edge2024), no_mangle)]
3446pub unsafe extern "C" fn sml_bool_in(
3447    v: *const CSmlValue,
3448    path: *const c_char,
3449    ok: *mut c_int,
3450) -> c_int {
3451    let node = sml_get_path(v, path);
3452    if node.is_null() {
3453        if !ok.is_null() {
3454            *ok = 0;
3455        }
3456        return 0;
3457    }
3458    let is_bool = sml_typeof(node) == 1;
3459    if !ok.is_null() {
3460        *ok = if is_bool { 1 } else { 0 };
3461    }
3462    sml_bool_value(node)
3463}
3464
3465/// 把值树序列化为 SML 文本(调用方 `sml_free_str` 释放)。
3466#[cfg_attr(edge2024, unsafe(no_mangle))]
3467#[cfg_attr(not(edge2024), no_mangle)]
3468pub unsafe extern "C" fn sml_dumps(v: *const CSmlValue, _flags: c_uint) -> *mut c_char {
3469    if v.is_null() {
3470        return ptr::null_mut();
3471    }
3472    cstr(&to_sml(&(*(v as *const Value))))
3473}
3474
3475/// 返回该特性位对应的名字(静态字符串,无需释放);越界返回 NULL。
3476///
3477/// 这里刻意用 `match` 返回带 `\0` 的字面量:直接取 [`FEATURES`] 里的
3478/// `&str` 无法保证 NUL 结尾,交给 C 会被 `printf("%s")` 越界读取。
3479/// 顺序与 [`FEATURES`] 表严格对应,由 `tests/version.rs` 中的用例守护。
3480#[cfg_attr(edge2024, unsafe(no_mangle))]
3481#[cfg_attr(not(edge2024), no_mangle)]
3482pub extern "C" fn sml_feature_name(bit: c_uint) -> *const c_char {
3483    let s: &'static str = match bit {
3484        0 => "bareword-string\0",
3485        1 => "include\0",
3486        2 => "env\0",
3487        3 => "contract\0",
3488        4 => "fragment\0",
3489        5 => "top-level-array\0",
3490        6 => "namespace\0",
3491        7 => "implicit-ns\0",
3492        8 => "multi-include\0",
3493        9 => "glob-include\0",
3494        10 => "regex-include\0",
3495        11 => "ext-rewrite\0",
3496        _ => return ptr::null(),
3497    };
3498    s.as_ptr() as *const c_char
3499}
3500
3501/// 返回受支持特性的位掩码(可直接与 `SML_F_*` 按位与)。
3502#[cfg_attr(edge2024, unsafe(no_mangle))]
3503#[cfg_attr(not(edge2024), no_mangle)]
3504pub extern "C" fn sml_features_mask() -> c_uint {
3505    let mut m = 0u32;
3506    for (i, _) in FEATURES.iter().enumerate() {
3507        if i >= 32 {
3508            break;
3509        }
3510        m |= 1u32 << i;
3511    }
3512    m
3513}
3514
3515/// 库版本字符串(调用方 `sml_free_str` 释放)。
3516#[cfg_attr(edge2024, unsafe(no_mangle))]
3517#[cfg_attr(not(edge2024), no_mangle)]
3518pub extern "C" fn sml_version_str() -> *mut c_char {
3519    cstr(env!("CARGO_PKG_VERSION"))
3520}
3521
3522// 供 `#[no_mangle]` 之外的内部代码引用,避免 `c_ulonglong` 触发未使用警告。
3523#[allow(dead_code)]
3524type _CUnsignedLongLong = c_ulonglong;
3525
3526// ---------------------------------------------------------------------------
3527// 内部: JSON <-> Value (供 C-ABI 便捷桥)
3528// ---------------------------------------------------------------------------
3529
3530fn jsonify(v: &Value) -> String {
3531    fn esc(s: &str) -> String {
3532        s.replace('\\', "\\\\").replace('"', "\\\"")
3533    }
3534    match v {
3535        Value::Null => "null".into(),
3536        Value::Bool(b) => b.to_string(),
3537        Value::Int(i) => i.to_string(),
3538        Value::Float(f) => f.to_string(),
3539        Value::Str(s) => format!("\"{}\"", esc(s)),
3540        Value::Array(a) => {
3541            let parts: Vec<String> = a.iter().map(jsonify).collect();
3542            format!("[{}]", parts.join(","))
3543        }
3544        Value::Object(m) => {
3545            let parts: Vec<String> = m
3546                .iter()
3547                .map(|(k, val)| format!("\"{}\":{}", esc(k), jsonify(val)))
3548                .collect();
3549            format!("{{{}}}", parts.join(","))
3550        }
3551    }
3552}
3553
3554fn json_to_value(s: &str) -> Option<Value> {
3555    let bytes = s.as_bytes();
3556    let mut i = 0;
3557    let _n = bytes.len();
3558    let mut skip_ws = |b: &[u8], i: &mut usize| {
3559        while *i < b.len() && matches!(b[*i], b' ' | b'\t' | b'\n' | b'\r') {
3560            *i += 1;
3561        }
3562    };
3563    let mut parse_str = |b: &[u8], i: &mut usize| -> Option<String> {
3564        skip_ws(b, i);
3565        if *i >= b.len() || b[*i] != b'"' {
3566            return None;
3567        }
3568        *i += 1;
3569        let mut out = String::new();
3570        while *i < b.len() {
3571            let c = b[*i];
3572            if c == b'"' {
3573                *i += 1;
3574                return Some(out);
3575            }
3576            if c == b'\\' && *i + 1 < b.len() {
3577                *i += 1;
3578                let e = b[*i];
3579                out.push(match e {
3580                    b'n' => '\n',
3581                    b't' => '\t',
3582                    b'r' => '\r',
3583                    b'"' => '"',
3584                    b'\\' => '\\',
3585                    _ => e as char,
3586                });
3587            } else {
3588                out.push(c as char);
3589            }
3590            *i += 1;
3591        }
3592        None
3593    };
3594    fn parse_val_impl(
3595        b: &[u8],
3596        i: &mut usize,
3597        s: &str,
3598        parse_str: &dyn Fn(&[u8], &mut usize) -> Option<String>,
3599    ) -> Option<Value> {
3600        let mut skip_ws = |b: &[u8], i: &mut usize| {
3601            while *i < b.len() && matches!(b[*i], b' ' | b'\t' | b'\n' | b'\r') {
3602                *i += 1;
3603            }
3604        };
3605        skip_ws(b, i);
3606        if *i >= b.len() {
3607            return None;
3608        }
3609        match b[*i] {
3610            b'{' => {
3611                *i += 1;
3612                let mut m = BTreeMap::new();
3613                skip_ws(b, i);
3614                if *i < b.len() && b[*i] == b'}' {
3615                    *i += 1;
3616                    return Some(Value::Object(m));
3617                }
3618                loop {
3619                    skip_ws(b, i);
3620                    let k = parse_str(b, i)?;
3621                    skip_ws(b, i);
3622                    if *i < b.len() && b[*i] == b':' {
3623                        *i += 1;
3624                    }
3625                    let v = parse_val_impl(b, i, s, parse_str)?;
3626                    m.insert(k, v);
3627                    skip_ws(b, i);
3628                    if *i < b.len() && b[*i] == b',' {
3629                        *i += 1;
3630                    } else if *i < b.len() && b[*i] == b'}' {
3631                        *i += 1;
3632                        break;
3633                    }
3634                }
3635                Some(Value::Object(m))
3636            }
3637            b'[' => {
3638                *i += 1;
3639                let mut a = Vec::new();
3640                skip_ws(b, i);
3641                if *i < b.len() && b[*i] == b']' {
3642                    *i += 1;
3643                    return Some(Value::Array(a));
3644                }
3645                loop {
3646                    a.push(parse_val_impl(b, i, s, parse_str)?);
3647                    skip_ws(b, i);
3648                    if *i < b.len() && b[*i] == b',' {
3649                        *i += 1;
3650                    } else if *i < b.len() && b[*i] == b']' {
3651                        *i += 1;
3652                        break;
3653                    }
3654                }
3655                Some(Value::Array(a))
3656            }
3657            b'"' => parse_str(b, i).map(Value::Str),
3658            b't' => {
3659                if s[*i..].starts_with("true") {
3660                    *i += 4;
3661                    Some(Value::Bool(true))
3662                } else {
3663                    None
3664                }
3665            }
3666            b'f' => {
3667                if s[*i..].starts_with("false") {
3668                    *i += 5;
3669                    Some(Value::Bool(false))
3670                } else {
3671                    None
3672                }
3673            }
3674            b'n' => {
3675                if s[*i..].starts_with("null") {
3676                    *i += 4;
3677                    Some(Value::Null)
3678                } else {
3679                    None
3680                }
3681            }
3682            _ => {
3683                let start = *i;
3684                while *i < b.len()
3685                    && (b[*i].is_ascii_digit()
3686                        || matches!(b[*i], b'-' | b'+' | b'.' | b'e' | b'E'))
3687                {
3688                    *i += 1;
3689                }
3690                let tok = s[start..*i].to_string();
3691                if let Ok(iv) = tok.parse::<i64>() {
3692                    Some(Value::Int(iv))
3693                } else if let Ok(fv) = tok.parse::<f64>() {
3694                    Some(Value::Float(fv))
3695                } else {
3696                    None
3697                }
3698            }
3699        }
3700    }
3701    parse_val_impl(bytes, &mut i, s, &parse_str)
3702}
3703
3704// ---------------------------------------------------------------------------
3705// serde 支持(可选 feature:`serde`)
3706//
3707// 1) `Value` 实现 `Serialize`/`Deserialize`(手写而非 `#[derive]`:derive 会把
3708//    枚举表示为外部标签形式 Value::Int(5) -> {"Int":5},而配置场景要自然形状
3709//    5)。手写后 SML 的 Value 与 JSON/TOML/YAML 数据形状一致,可经任意 serde
3710//    后端进出。
3711// 2) `sml::serde::{from_str, from_value, to_value, to_string}`:serde 桥。
3712//    任何 `#[derive(serde::Serialize / Deserialize)]` 类型都能像 toml-rs 一样
3713//    一键从 SML 文本反序列化 / 序列化为 SML(枚举沿用 `__type` 约定)。
3714//
3715// 不启用该 feature 时 crate 保持零依赖。
3716// ---------------------------------------------------------------------------
3717
3718#[cfg(feature = "serde")]
3719pub mod serde {
3720    use super::Value;
3721    use ::serde::de::{self, MapAccess, SeqAccess, Visitor};
3722    use ::serde::ser::{
3723        SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
3724        SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
3725    };
3726    use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
3727    use ::std::collections::BTreeMap;
3728    use ::std::fmt;
3729
3730    /// serde 错误类型(自定义消息,实现 ser/de 两个 Error trait)
3731    type Error = ::serde::de::value::Error;
3732
3733    fn type_err(v: &Value, expected: &str) -> Error {
3734        de::Error::custom(format!(
3735            "期望 {expected},实际为 {}",
3736            super::__private::describe_value(v)
3737        ))
3738    }
3739
3740    impl Serialize for Value {
3741        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
3742        where
3743            S: Serializer,
3744        {
3745            match self {
3746                Value::Null => serializer.serialize_unit(),
3747                Value::Bool(b) => serializer.serialize_bool(*b),
3748                Value::Int(i) => serializer.serialize_i64(*i),
3749                Value::Float(f) => serializer.serialize_f64(*f),
3750                Value::Str(s) => serializer.serialize_str(s),
3751                // Vec<Value> / 逐项委托,递归依赖 Value 自身的 impl
3752                Value::Array(a) => a.serialize(serializer),
3753                Value::Object(m) => {
3754                    let mut map = serializer.serialize_map(Some(m.len()))?;
3755                    for (k, v) in m {
3756                        map.serialize_entry(k, v)?;
3757                    }
3758                    map.end()
3759                }
3760            }
3761        }
3762    }
3763
3764    impl<'de> Deserialize<'de> for Value {
3765        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3766        where
3767            D: Deserializer<'de>,
3768        {
3769            // 交给格式自行判断类型(JSON 的数字/字符串/数组/对象都能落到对应变体)
3770            deserializer.deserialize_any(ValueVisitor)
3771        }
3772    }
3773
3774    struct ValueVisitor;
3775
3776    impl<'de> Visitor<'de> for ValueVisitor {
3777        type Value = Value;
3778
3779        fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
3780            f.write_str("any valid SML/JSON value")
3781        }
3782
3783        fn visit_unit<E: de::Error>(self) -> Result<Value, E> {
3784            Ok(Value::Null)
3785        }
3786        fn visit_none<E: de::Error>(self) -> Result<Value, E> {
3787            Ok(Value::Null)
3788        }
3789        fn visit_some<D>(self, d: D) -> Result<Value, D::Error>
3790        where
3791            D: Deserializer<'de>,
3792        {
3793            Deserialize::deserialize(d)
3794        }
3795        fn visit_bool<E: de::Error>(self, v: bool) -> Result<Value, E> {
3796            Ok(Value::Bool(v))
3797        }
3798        fn visit_i64<E: de::Error>(self, v: i64) -> Result<Value, E> {
3799            Ok(Value::Int(v))
3800        }
3801        // 超出 i64 的大整数退化为 Float,避免直接报错丢失数据
3802        fn visit_u64<E: de::Error>(self, v: u64) -> Result<Value, E> {
3803            Ok(i64::try_from(v)
3804                .map(Value::Int)
3805                .unwrap_or_else(|_| Value::Float(v as f64)))
3806        }
3807        fn visit_f64<E: de::Error>(self, v: f64) -> Result<Value, E> {
3808            Ok(Value::Float(v))
3809        }
3810        fn visit_str<E: de::Error>(self, v: &str) -> Result<Value, E> {
3811            Ok(Value::Str(v.to_string()))
3812        }
3813        fn visit_string<E: de::Error>(self, v: String) -> Result<Value, E> {
3814            Ok(Value::Str(v))
3815        }
3816        fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
3817        where
3818            A: SeqAccess<'de>,
3819        {
3820            let mut v = Vec::new();
3821            while let Some(x) = seq.next_element()? {
3822                v.push(x);
3823            }
3824            Ok(Value::Array(v))
3825        }
3826        fn visit_map<A>(self, mut map: A) -> Result<Value, A::Error>
3827        where
3828            A: MapAccess<'de>,
3829        {
3830            let mut m = BTreeMap::new();
3831            while let Some((k, v)) = map.next_entry::<String, Value>()? {
3832                m.insert(k, v);
3833            }
3834            Ok(Value::Object(m))
3835        }
3836    }
3837
3838    // -----------------------------------------------------------------------
3839    // serde 桥:任意 `serde::Serialize / Deserialize` 类型 <-> SML
3840    // -----------------------------------------------------------------------
3841
3842    /// 解析 SML 文本并一键反序列化到任意 serde 类型(等价于 `toml::from_str`)。
3843    ///
3844    /// ```rust
3845    /// # use serde::Deserialize;
3846    /// # #[derive(Deserialize, Debug)]
3847    /// # struct Server { host: String, port: i32 }
3848    /// let s: Server = sml::serde::from_str("host: web.example\nport: 8080\n").unwrap();
3849    /// assert_eq!(s.host, "web.example");
3850    /// ```
3851    pub fn from_str<T: de::DeserializeOwned>(text: &str) -> Result<T, String> {
3852        let value = crate::parse(text)?;
3853        from_value(value)
3854    }
3855
3856    /// 从任意 [`Value`] 反序列化到任意 serde 类型。
3857    pub fn from_value<T: de::DeserializeOwned>(value: Value) -> Result<T, String> {
3858        T::deserialize(ValueDeserializer(value)).map_err(|e| e.to_string())
3859    }
3860
3861    /// 任意 serde 类型序列化为 [`Value`](等价于 `serde_json::to_value`)。
3862    pub fn to_value<T: Serialize + ?Sized>(value: &T) -> Result<Value, String> {
3863        value.serialize(ValueSerializer).map_err(|e| e.to_string())
3864    }
3865
3866    /// 任意 serde 类型序列化为 SML 文本(等价于 `toml::to_string`)。
3867    pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, String> {
3868        Ok(crate::to_sml(&to_value(value)?))
3869    }
3870
3871    // ---- Serializer: T: Serialize -> Value ----
3872
3873    struct ValueSerializer;
3874
3875    impl Serializer for ValueSerializer {
3876        type Ok = Value;
3877        type Error = Error;
3878        type SerializeSeq = SeqSerializer;
3879        type SerializeTuple = SeqSerializer;
3880        type SerializeTupleStruct = SeqSerializer;
3881        type SerializeTupleVariant = TupleVariantSerializer;
3882        type SerializeMap = MapSerializer;
3883        type SerializeStruct = MapSerializer;
3884        type SerializeStructVariant = StructVariantSerializer;
3885
3886        fn serialize_bool(self, v: bool) -> Result<Value, Error> {
3887            Ok(Value::Bool(v))
3888        }
3889        fn serialize_i8(self, v: i8) -> Result<Value, Error> {
3890            Ok(Value::Int(v as i64))
3891        }
3892        fn serialize_i16(self, v: i16) -> Result<Value, Error> {
3893            Ok(Value::Int(v as i64))
3894        }
3895        fn serialize_i32(self, v: i32) -> Result<Value, Error> {
3896            Ok(Value::Int(v as i64))
3897        }
3898        fn serialize_i64(self, v: i64) -> Result<Value, Error> {
3899            Ok(Value::Int(v))
3900        }
3901        fn serialize_u8(self, v: u8) -> Result<Value, Error> {
3902            Ok(Value::Int(v as i64))
3903        }
3904        fn serialize_u16(self, v: u16) -> Result<Value, Error> {
3905            Ok(Value::Int(v as i64))
3906        }
3907        fn serialize_u32(self, v: u32) -> Result<Value, Error> {
3908            Ok(Value::Int(v as i64))
3909        }
3910        fn serialize_u64(self, v: u64) -> Result<Value, Error> {
3911            Ok(i64::try_from(v)
3912                .map(Value::Int)
3913                .unwrap_or_else(|_| Value::Float(v as f64)))
3914        }
3915        fn serialize_f32(self, v: f32) -> Result<Value, Error> {
3916            Ok(Value::Float(v as f64))
3917        }
3918        fn serialize_f64(self, v: f64) -> Result<Value, Error> {
3919            Ok(Value::Float(v))
3920        }
3921        fn serialize_char(self, v: char) -> Result<Value, Error> {
3922            Ok(Value::Str(v.to_string()))
3923        }
3924        fn serialize_str(self, v: &str) -> Result<Value, Error> {
3925            Ok(Value::Str(v.to_string()))
3926        }
3927        fn serialize_bytes(self, v: &[u8]) -> Result<Value, Error> {
3928            Ok(Value::Array(v.iter().map(|&b| Value::Int(b as i64)).collect()))
3929        }
3930        fn serialize_none(self) -> Result<Value, Error> {
3931            Ok(Value::Null)
3932        }
3933        fn serialize_some<T: Serialize + ?Sized>(self, v: &T) -> Result<Value, Error> {
3934            v.serialize(ValueSerializer)
3935        }
3936        fn serialize_unit(self) -> Result<Value, Error> {
3937            Ok(Value::Null)
3938        }
3939        fn serialize_unit_struct(self, _name: &'static str) -> Result<Value, Error> {
3940            Ok(Value::Null)
3941        }
3942        fn serialize_unit_variant(
3943            self,
3944            _name: &'static str,
3945            _idx: u32,
3946            variant: &'static str,
3947        ) -> Result<Value, Error> {
3948            Ok(Value::Str(variant.to_string()))
3949        }
3950        fn serialize_newtype_struct<T: Serialize + ?Sized>(
3951            self,
3952            _name: &'static str,
3953            v: &T,
3954        ) -> Result<Value, Error> {
3955            v.serialize(ValueSerializer)
3956        }
3957        fn serialize_newtype_variant<T: Serialize + ?Sized>(
3958            self,
3959            _name: &'static str,
3960            _idx: u32,
3961            variant: &'static str,
3962            value: &T,
3963        ) -> Result<Value, Error> {
3964            Ok(Value::Object(BTreeMap::from([
3965                ("__type".into(), Value::Str(variant.to_string())),
3966                ("_value".into(), value.serialize(ValueSerializer)?),
3967            ])))
3968        }
3969        fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
3970            Ok(SeqSerializer(Vec::new()))
3971        }
3972        fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> {
3973            self.serialize_seq(Some(len))
3974        }
3975        fn serialize_tuple_struct(
3976            self,
3977            _name: &'static str,
3978            len: usize,
3979        ) -> Result<Self::SerializeTupleStruct, Error> {
3980            self.serialize_seq(Some(len))
3981        }
3982        fn serialize_tuple_variant(
3983            self,
3984            _name: &'static str,
3985            _idx: u32,
3986            variant: &'static str,
3987            _len: usize,
3988        ) -> Result<Self::SerializeTupleVariant, Error> {
3989            Ok(TupleVariantSerializer {
3990                variant: variant.to_string(),
3991                values: Vec::new(),
3992            })
3993        }
3994        fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> {
3995            Ok(MapSerializer {
3996                map: BTreeMap::new(),
3997                key: None,
3998            })
3999        }
4000        fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct, Error> {
4001            self.serialize_map(Some(len))
4002        }
4003        fn serialize_struct_variant(
4004            self,
4005            _name: &'static str,
4006            _idx: u32,
4007            variant: &'static str,
4008            _len: usize,
4009        ) -> Result<Self::SerializeStructVariant, Error> {
4010            Ok(StructVariantSerializer {
4011                variant: variant.to_string(),
4012                map: BTreeMap::new(),
4013            })
4014        }
4015    }
4016
4017    struct SeqSerializer(Vec<Value>);
4018
4019    impl SerializeSeq for SeqSerializer {
4020        type Ok = Value;
4021        type Error = Error;
4022        fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4023            self.0.push(value.serialize(ValueSerializer)?);
4024            Ok(())
4025        }
4026        fn end(self) -> Result<Value, Error> {
4027            Ok(Value::Array(self.0))
4028        }
4029    }
4030    impl SerializeTuple for SeqSerializer {
4031        type Ok = Value;
4032        type Error = Error;
4033        fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4034            SerializeSeq::serialize_element(self, value)
4035        }
4036        fn end(self) -> Result<Value, Error> {
4037            SerializeSeq::end(self)
4038        }
4039    }
4040    impl SerializeTupleStruct for SeqSerializer {
4041        type Ok = Value;
4042        type Error = Error;
4043        fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4044            SerializeSeq::serialize_element(self, value)
4045        }
4046        fn end(self) -> Result<Value, Error> {
4047            SerializeSeq::end(self)
4048        }
4049    }
4050
4051    struct MapSerializer {
4052        map: BTreeMap<String, Value>,
4053        key: Option<String>,
4054    }
4055
4056    impl SerializeMap for MapSerializer {
4057        type Ok = Value;
4058        type Error = Error;
4059        fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<(), Error> {
4060            self.key = Some(key.serialize(KeySerializer)?);
4061            Ok(())
4062        }
4063        fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4064            let k = self
4065                .key
4066                .take()
4067                .ok_or_else(|| de::Error::custom("serialize_value 前需先 serialize_key"))?;
4068            self.map.insert(k, value.serialize(ValueSerializer)?);
4069            Ok(())
4070        }
4071        fn end(self) -> Result<Value, Error> {
4072            Ok(Value::Object(self.map))
4073        }
4074    }
4075
4076    impl SerializeStruct for MapSerializer {
4077        type Ok = Value;
4078        type Error = Error;
4079        fn serialize_field<T: Serialize + ?Sized>(
4080            &mut self,
4081            key: &'static str,
4082            value: &T,
4083        ) -> Result<(), Error> {
4084            self.map
4085                .insert(key.to_string(), value.serialize(ValueSerializer)?);
4086            Ok(())
4087        }
4088        fn end(self) -> Result<Value, Error> {
4089            Ok(Value::Object(self.map))
4090        }
4091    }
4092
4093    /// 对象键必须能转成字符串(SML 的键是裸词/字符串)
4094    struct KeySerializer;
4095
4096    macro_rules! key_unsupported {
4097        ($(fn $m:ident($($a:ident : $t:ty),*) -> Result<String, Error>;)*) => {
4098            $(
4099                fn $m(self, $($a: $t),*) -> Result<String, Error> {
4100                    Err(de::Error::custom("SML 对象的键必须是字符串"))
4101                }
4102            )*
4103        };
4104    }
4105
4106    impl Serializer for KeySerializer {
4107        type Ok = String;
4108        type Error = Error;
4109        type SerializeSeq = ::serde::ser::Impossible<String, Error>;
4110        type SerializeTuple = ::serde::ser::Impossible<String, Error>;
4111        type SerializeTupleStruct = ::serde::ser::Impossible<String, Error>;
4112        type SerializeTupleVariant = ::serde::ser::Impossible<String, Error>;
4113        type SerializeMap = ::serde::ser::Impossible<String, Error>;
4114        type SerializeStruct = ::serde::ser::Impossible<String, Error>;
4115        type SerializeStructVariant = ::serde::ser::Impossible<String, Error>;
4116
4117        fn serialize_str(self, v: &str) -> Result<String, Error> {
4118            Ok(v.to_string())
4119        }
4120        fn serialize_char(self, v: char) -> Result<String, Error> {
4121            Ok(v.to_string())
4122        }
4123        key_unsupported! {
4124            fn serialize_bool(_v: bool) -> Result<String, Error>;
4125            fn serialize_i8(_v: i8) -> Result<String, Error>;
4126            fn serialize_i16(_v: i16) -> Result<String, Error>;
4127            fn serialize_i32(_v: i32) -> Result<String, Error>;
4128            fn serialize_i64(_v: i64) -> Result<String, Error>;
4129            fn serialize_u8(_v: u8) -> Result<String, Error>;
4130            fn serialize_u16(_v: u16) -> Result<String, Error>;
4131            fn serialize_u32(_v: u32) -> Result<String, Error>;
4132            fn serialize_u64(_v: u64) -> Result<String, Error>;
4133            fn serialize_f32(_v: f32) -> Result<String, Error>;
4134            fn serialize_f64(_v: f64) -> Result<String, Error>;
4135            fn serialize_bytes(_v: &[u8]) -> Result<String, Error>;
4136            fn serialize_none() -> Result<String, Error>;
4137            fn serialize_unit() -> Result<String, Error>;
4138            fn serialize_unit_struct(_n: &'static str) -> Result<String, Error>;
4139            fn serialize_unit_variant(_n: &'static str, _i: u32, _v: &'static str) -> Result<String, Error>;
4140        }
4141        fn serialize_some<T: Serialize + ?Sized>(self, _v: &T) -> Result<String, Error> {
4142            Err(de::Error::custom("SML 对象的键必须是字符串"))
4143        }
4144        fn serialize_newtype_struct<T: Serialize + ?Sized>(
4145            self,
4146            _n: &'static str,
4147            _v: &T,
4148        ) -> Result<String, Error> {
4149            Err(de::Error::custom("SML 对象的键必须是字符串"))
4150        }
4151        fn serialize_newtype_variant<T: Serialize + ?Sized>(
4152            self,
4153            _n: &'static str,
4154            _i: u32,
4155            _v: &'static str,
4156            _x: &T,
4157        ) -> Result<String, Error> {
4158            Err(de::Error::custom("SML 对象的键必须是字符串"))
4159        }
4160        // 以下方法返回关联类型(Impossible),一律报错——SML 键只能是字符串
4161        fn serialize_seq(self, _l: Option<usize>) -> Result<Self::SerializeSeq, Error> {
4162            Err(de::Error::custom("SML 对象的键必须是字符串"))
4163        }
4164        fn serialize_tuple(self, _l: usize) -> Result<Self::SerializeTuple, Error> {
4165            Err(de::Error::custom("SML 对象的键必须是字符串"))
4166        }
4167        fn serialize_tuple_struct(
4168            self,
4169            _n: &'static str,
4170            _l: usize,
4171        ) -> Result<Self::SerializeTupleStruct, Error> {
4172            Err(de::Error::custom("SML 对象的键必须是字符串"))
4173        }
4174        fn serialize_tuple_variant(
4175            self,
4176            _n: &'static str,
4177            _i: u32,
4178            _v: &'static str,
4179            _l: usize,
4180        ) -> Result<Self::SerializeTupleVariant, Error> {
4181            Err(de::Error::custom("SML 对象的键必须是字符串"))
4182        }
4183        fn serialize_map(self, _l: Option<usize>) -> Result<Self::SerializeMap, Error> {
4184            Err(de::Error::custom("SML 对象的键必须是字符串"))
4185        }
4186        fn serialize_struct(self, _n: &'static str, _l: usize) -> Result<Self::SerializeStruct, Error> {
4187            Err(de::Error::custom("SML 对象的键必须是字符串"))
4188        }
4189        fn serialize_struct_variant(
4190            self,
4191            _n: &'static str,
4192            _i: u32,
4193            _v: &'static str,
4194            _l: usize,
4195        ) -> Result<Self::SerializeStructVariant, Error> {
4196            Err(de::Error::custom("SML 对象的键必须是字符串"))
4197        }
4198    }
4199
4200    struct TupleVariantSerializer {
4201        variant: String,
4202        values: Vec<Value>,
4203    }
4204
4205    impl SerializeTupleVariant for TupleVariantSerializer {
4206        type Ok = Value;
4207        type Error = Error;
4208        fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4209            self.values.push(value.serialize(ValueSerializer)?);
4210            Ok(())
4211        }
4212        fn end(self) -> Result<Value, Error> {
4213            Ok(Value::Object(BTreeMap::from([
4214                ("__type".into(), Value::Str(self.variant)),
4215                ("_value".into(), Value::Array(self.values)),
4216            ])))
4217        }
4218    }
4219
4220    struct StructVariantSerializer {
4221        variant: String,
4222        map: BTreeMap<String, Value>,
4223    }
4224
4225    impl SerializeStructVariant for StructVariantSerializer {
4226        type Ok = Value;
4227        type Error = Error;
4228        fn serialize_field<T: Serialize + ?Sized>(
4229            &mut self,
4230            key: &'static str,
4231            value: &T,
4232        ) -> Result<(), Error> {
4233            self.map
4234                .insert(key.to_string(), value.serialize(ValueSerializer)?);
4235            Ok(())
4236        }
4237        fn end(self) -> Result<Value, Error> {
4238            let mut m = BTreeMap::new();
4239            m.insert("__type".into(), Value::Str(self.variant));
4240            m.extend(self.map);
4241            Ok(Value::Object(m))
4242        }
4243    }
4244
4245    // ---- Deserializer: Value -> T: Deserialize ----
4246
4247    macro_rules! deser_int {
4248        ($(fn $m:ident($v:ident, $call:ident);)*) => {
4249            $(
4250                fn $m<V>(self, $v: V) -> Result<V::Value, Self::Error>
4251                where V: Visitor<'de> {
4252                    match self.0 {
4253                        Value::Int(i) => $v.$call(i as _),
4254                        Value::Float(f)
4255                            if f.fract() == 0.0
4256                                && f >= i64::MIN as f64
4257                                && f <= i64::MAX as f64 =>
4258                        {
4259                            $v.$call(f as _)
4260                        }
4261                        other => Err(type_err(&other, stringify!($m).trim_start_matches("deserialize_"))),
4262                    }
4263                }
4264            )*
4265        };
4266    }
4267
4268    struct ValueDeserializer(Value);
4269
4270    impl<'de> Deserializer<'de> for ValueDeserializer {
4271        type Error = Error;
4272
4273        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
4274        where
4275            V: Visitor<'de>,
4276        {
4277            match self.0 {
4278                Value::Null => visitor.visit_unit(),
4279                Value::Bool(b) => visitor.visit_bool(b),
4280                Value::Int(i) => visitor.visit_i64(i),
4281                Value::Float(f) => visitor.visit_f64(f),
4282                Value::Str(s) => visitor.visit_string(s),
4283                Value::Array(a) => visitor.visit_seq(SeqDeserializer { items: a, idx: 0 }),
4284                Value::Object(m) => visitor.visit_map(MapDeserializer { map: m, pending: None }),
4285            }
4286        }
4287
4288        fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Error>
4289        where
4290            V: Visitor<'de>,
4291        {
4292            match self.0 {
4293                Value::Bool(b) => visitor.visit_bool(b),
4294                other => Err(type_err(&other, "布尔")),
4295            }
4296        }
4297
4298        deser_int! {
4299            fn deserialize_i8(v, visit_i8);
4300            fn deserialize_i16(v, visit_i16);
4301            fn deserialize_i32(v, visit_i32);
4302            fn deserialize_i64(v, visit_i64);
4303            fn deserialize_u8(v, visit_u8);
4304            fn deserialize_u16(v, visit_u16);
4305            fn deserialize_u32(v, visit_u32);
4306        }
4307
4308        fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Error>
4309        where
4310            V: Visitor<'de>,
4311        {
4312            match self.0 {
4313                Value::Int(i) if i >= 0 => visitor.visit_u64(i as u64),
4314                Value::Float(f)
4315                    if f.fract() == 0.0 && f >= 0.0 && f <= u64::MAX as f64 =>
4316                {
4317                    visitor.visit_u64(f as u64)
4318                }
4319                other => Err(type_err(&other, "u64")),
4320            }
4321        }
4322
4323        fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Error>
4324        where
4325            V: Visitor<'de>,
4326        {
4327            match self.0 {
4328                Value::Int(i) => visitor.visit_f32(i as f32),
4329                Value::Float(f) => visitor.visit_f32(f as f32),
4330                other => Err(type_err(&other, "f32")),
4331            }
4332        }
4333        fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Error>
4334        where
4335            V: Visitor<'de>,
4336        {
4337            match self.0 {
4338                Value::Int(i) => visitor.visit_f64(i as f64),
4339                Value::Float(f) => visitor.visit_f64(f),
4340                other => Err(type_err(&other, "f64")),
4341            }
4342        }
4343
4344        fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Error>
4345        where
4346            V: Visitor<'de>,
4347        {
4348            match self.0 {
4349                Value::Str(s) if s.chars().count() == 1 => {
4350                    visitor.visit_char(s.chars().next().unwrap())
4351                }
4352                other => Err(type_err(&other, "字符")),
4353            }
4354        }
4355
4356        fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error>
4357        where
4358            V: Visitor<'de>,
4359        {
4360            match self.0 {
4361                Value::Str(s) => visitor.visit_string(s),
4362                other => Err(type_err(&other, "字符串")),
4363            }
4364        }
4365        fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error>
4366        where
4367            V: Visitor<'de>,
4368        {
4369            self.deserialize_str(visitor)
4370        }
4371
4372        fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Error>
4373        where
4374            V: Visitor<'de>,
4375        {
4376            match self.0 {
4377                Value::Array(items) => {
4378                    let mut buf = Vec::with_capacity(items.len());
4379                    for it in items {
4380                        match it {
4381                            Value::Int(i) if (0..=255).contains(&i) => buf.push(i as u8),
4382                            other => return Err(type_err(&other, "字节")),
4383                        }
4384                    }
4385                    visitor.visit_byte_buf(buf)
4386                }
4387                other => Err(type_err(&other, "字节数组")),
4388            }
4389        }
4390        fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Error>
4391        where
4392            V: Visitor<'de>,
4393        {
4394            self.deserialize_bytes(visitor)
4395        }
4396
4397        fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
4398        where
4399            V: Visitor<'de>,
4400        {
4401            match self.0 {
4402                Value::Null => visitor.visit_none(),
4403                other => visitor.visit_some(ValueDeserializer(other)),
4404            }
4405        }
4406
4407        fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Error>
4408        where
4409            V: Visitor<'de>,
4410        {
4411            match self.0 {
4412                Value::Null => visitor.visit_unit(),
4413                other => Err(type_err(&other, "unit")),
4414            }
4415        }
4416        fn deserialize_unit_struct<V>(
4417            self,
4418            _name: &'static str,
4419            visitor: V,
4420        ) -> Result<V::Value, Error>
4421        where
4422            V: Visitor<'de>,
4423        {
4424            self.deserialize_unit(visitor)
4425        }
4426        fn deserialize_newtype_struct<V>(
4427            self,
4428            _name: &'static str,
4429            visitor: V,
4430        ) -> Result<V::Value, Error>
4431        where
4432            V: Visitor<'de>,
4433        {
4434            self.deserialize_any(visitor)
4435        }
4436
4437        fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Error>
4438        where
4439            V: Visitor<'de>,
4440        {
4441            match self.0 {
4442                Value::Array(a) => visitor.visit_seq(SeqDeserializer { items: a, idx: 0 }),
4443                other => Err(type_err(&other, "数组")),
4444            }
4445        }
4446        fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
4447        where
4448            V: Visitor<'de>,
4449        {
4450            self.deserialize_seq(visitor)
4451        }
4452        fn deserialize_tuple_struct<V>(
4453            self,
4454            _name: &'static str,
4455            _len: usize,
4456            visitor: V,
4457        ) -> Result<V::Value, Error>
4458        where
4459            V: Visitor<'de>,
4460        {
4461            self.deserialize_seq(visitor)
4462        }
4463
4464        fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Error>
4465        where
4466            V: Visitor<'de>,
4467        {
4468            match self.0 {
4469                Value::Object(m) => visitor.visit_map(MapDeserializer { map: m, pending: None }),
4470                other => Err(type_err(&other, "块/对象")),
4471            }
4472        }
4473        fn deserialize_struct<V>(
4474            self,
4475            _name: &'static str,
4476            _fields: &'static [&'static str],
4477            visitor: V,
4478        ) -> Result<V::Value, Error>
4479        where
4480            V: Visitor<'de>,
4481        {
4482            self.deserialize_map(visitor)
4483        }
4484
4485        fn deserialize_enum<V>(
4486            self,
4487            _name: &'static str,
4488            _variants: &'static [&'static str],
4489            visitor: V,
4490        ) -> Result<V::Value, Error>
4491        where
4492            V: Visitor<'de>,
4493        {
4494            match self.0 {
4495                Value::Str(s) => visitor.visit_enum(EnumDeserializer {
4496                    variant: s,
4497                    kind: EnumKind::Unit,
4498                }),
4499                Value::Object(mut m) => {
4500                    // 1) SML 专有约定:`__type` 键(与 SmlSerialize 输出一致)
4501                    if let Some(ty) = m.remove("__type") {
4502                        let variant = match ty {
4503                            Value::Str(s) => s,
4504                            _ => return Err(de::Error::custom("`__type` 的值必须是字符串")),
4505                        };
4506                        let kind = match m.remove("_value") {
4507                            Some(Value::Array(items)) => EnumKind::Tuple(items),
4508                            Some(other) => EnumKind::Newtype(other),
4509                            None if m.is_empty() => EnumKind::Unit,
4510                            None => EnumKind::Struct(m),
4511                        };
4512                        return visitor.visit_enum(EnumDeserializer { variant, kind });
4513                    }
4514                    // 2) serde 外部标签(含 SML 裸词包裹形态):
4515                    //    {"in-maintenance": "in-maintenance"} -> 单元变体
4516                    //    {"Circle": 3}                        -> 单值变体
4517                    if m.len() == 1 {
4518                        let (k, v) = m.pop_first().expect("len==1 必有键");
4519                        let kind = match v {
4520                            Value::Str(s) if s == k => EnumKind::Unit,
4521                            other => EnumKind::Newtype(other),
4522                        };
4523                        return visitor.visit_enum(EnumDeserializer { variant: k, kind });
4524                    }
4525                    Err(de::Error::custom(
4526                        "枚举块需要 `__type` 键(SML 约定)或单键外部标签 `{ VariantName: ... }`",
4527                    ))
4528                }
4529                other => Err(type_err(&other, "枚举")),
4530            }
4531        }
4532
4533        fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Error>
4534        where
4535            V: Visitor<'de>,
4536        {
4537            self.deserialize_str(visitor)
4538        }
4539        fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
4540        where
4541            V: Visitor<'de>,
4542        {
4543            self.deserialize_any(visitor)
4544        }
4545    }
4546
4547    struct SeqDeserializer {
4548        items: Vec<Value>,
4549        idx: usize,
4550    }
4551
4552    impl<'de> SeqAccess<'de> for SeqDeserializer {
4553        type Error = Error;
4554        fn next_element_seed<T: de::DeserializeSeed<'de>>(
4555            &mut self,
4556            seed: T,
4557        ) -> Result<Option<T::Value>, Error> {
4558            if self.idx >= self.items.len() {
4559                return Ok(None);
4560            }
4561            let item = self.items[self.idx].clone();
4562            self.idx += 1;
4563            seed.deserialize(ValueDeserializer(item)).map(Some)
4564        }
4565    }
4566
4567    struct MapDeserializer {
4568        map: BTreeMap<String, Value>,
4569        pending: Option<Value>,
4570    }
4571
4572    impl<'de> MapAccess<'de> for MapDeserializer {
4573        type Error = Error;
4574        fn next_key_seed<K: de::DeserializeSeed<'de>>(
4575            &mut self,
4576            seed: K,
4577        ) -> Result<Option<K::Value>, Error> {
4578            let Some((k, v)) = self.map.pop_first() else {
4579                return Ok(None);
4580            };
4581            self.pending = Some(v);
4582            seed.deserialize(KeyDeserializer(&k)).map(Some)
4583        }
4584        fn next_value_seed<V: de::DeserializeSeed<'de>>(
4585            &mut self,
4586            seed: V,
4587        ) -> Result<V::Value, Error> {
4588            let v = self.pending.take().ok_or_else(|| {
4589                de::Error::custom("value 缺失:需先调用 next_key_seed")
4590            })?;
4591            seed.deserialize(ValueDeserializer(v))
4592        }
4593    }
4594
4595    /// 字段名 / 变体名的轻量反序列化器(只认字符串)
4596    struct KeyDeserializer<'a>(&'a str);
4597
4598    macro_rules! key_delegate {
4599        ($($m:ident),* $(,)?) => {
4600            $(
4601                fn $m<V>(self, visitor: V) -> Result<V::Value, Error>
4602                where V: Visitor<'de> {
4603                    self.deserialize_any(visitor)
4604                }
4605            )*
4606        };
4607    }
4608
4609    impl<'de, 'a> Deserializer<'de> for KeyDeserializer<'a> {
4610        type Error = Error;
4611
4612        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
4613        where
4614            V: Visitor<'de>,
4615        {
4616            visitor.visit_str(self.0)
4617        }
4618        fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error>
4619        where
4620            V: Visitor<'de>,
4621        {
4622            visitor.visit_str(self.0)
4623        }
4624        fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error>
4625        where
4626            V: Visitor<'de>,
4627        {
4628            visitor.visit_str(self.0)
4629        }
4630        fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Error>
4631        where
4632            V: Visitor<'de>,
4633        {
4634            visitor.visit_str(self.0)
4635        }
4636        fn deserialize_enum<V>(
4637            self,
4638            _name: &'static str,
4639            _variants: &'static [&'static str],
4640            visitor: V,
4641        ) -> Result<V::Value, Error>
4642        where
4643            V: Visitor<'de>,
4644        {
4645            visitor.visit_enum(EnumDeserializer {
4646                variant: self.0.to_string(),
4647                kind: EnumKind::Unit,
4648            })
4649        }
4650        fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
4651        where
4652            V: Visitor<'de>,
4653        {
4654            visitor.visit_some(self)
4655        }
4656        fn deserialize_unit_struct<V>(
4657            self,
4658            _name: &'static str,
4659            visitor: V,
4660        ) -> Result<V::Value, Error>
4661        where
4662            V: Visitor<'de>,
4663        {
4664            self.deserialize_unit(visitor)
4665        }
4666        fn deserialize_newtype_struct<V>(
4667            self,
4668            _name: &'static str,
4669            visitor: V,
4670        ) -> Result<V::Value, Error>
4671        where
4672            V: Visitor<'de>,
4673        {
4674            self.deserialize_any(visitor)
4675        }
4676        fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
4677        where
4678            V: Visitor<'de>,
4679        {
4680            self.deserialize_seq(visitor)
4681        }
4682        fn deserialize_tuple_struct<V>(
4683            self,
4684            _name: &'static str,
4685            _len: usize,
4686            visitor: V,
4687        ) -> Result<V::Value, Error>
4688        where
4689            V: Visitor<'de>,
4690        {
4691            self.deserialize_seq(visitor)
4692        }
4693        fn deserialize_struct<V>(
4694            self,
4695            _name: &'static str,
4696            _fields: &'static [&'static str],
4697            visitor: V,
4698        ) -> Result<V::Value, Error>
4699        where
4700            V: Visitor<'de>,
4701        {
4702            self.deserialize_map(visitor)
4703        }
4704        fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
4705        where
4706            V: Visitor<'de>,
4707        {
4708            self.deserialize_any(visitor)
4709        }
4710        key_delegate! {
4711            deserialize_bool, deserialize_i8, deserialize_i16, deserialize_i32,
4712            deserialize_i64, deserialize_u8, deserialize_u16, deserialize_u32,
4713            deserialize_u64, deserialize_f32, deserialize_f64, deserialize_char,
4714            deserialize_bytes, deserialize_byte_buf, deserialize_unit,
4715            deserialize_seq, deserialize_map,
4716        }
4717    }
4718
4719    // ---- 枚举(SML `__type` 约定,与 SmlDeserialize 一致)----
4720
4721    #[derive(Debug)]
4722    enum EnumKind {
4723        Unit,
4724        Newtype(Value),
4725        Tuple(Vec<Value>),
4726        Struct(BTreeMap<String, Value>),
4727    }
4728
4729    struct EnumDeserializer {
4730        variant: String,
4731        kind: EnumKind,
4732    }
4733
4734    impl<'de> de::EnumAccess<'de> for EnumDeserializer {
4735        type Error = Error;
4736        type Variant = VariantAccess;
4737        fn variant_seed<V: de::DeserializeSeed<'de>>(
4738            self,
4739            seed: V,
4740        ) -> Result<(V::Value, Self::Variant), Error> {
4741            let variant = seed.deserialize(KeyDeserializer(&self.variant))?;
4742            Ok((variant, VariantAccess { kind: self.kind }))
4743        }
4744    }
4745
4746    struct VariantAccess {
4747        kind: EnumKind,
4748    }
4749
4750    impl<'de> de::VariantAccess<'de> for VariantAccess {
4751        type Error = Error;
4752        fn unit_variant(self) -> Result<(), Error> {
4753            match self.kind {
4754                EnumKind::Unit => Ok(()),
4755                _ => Err(de::Error::custom("该变体携带数据,不能按单元变体解析")),
4756            }
4757        }
4758        fn newtype_variant_seed<T: de::DeserializeSeed<'de>>(
4759            self,
4760            seed: T,
4761        ) -> Result<T::Value, Error> {
4762            match self.kind {
4763                EnumKind::Newtype(v) => seed.deserialize(ValueDeserializer(v)),
4764                EnumKind::Tuple(items) => {
4765                    seed.deserialize(ValueDeserializer(Value::Array(items)))
4766                }
4767                _ => Err(de::Error::custom("该变体没有单值数据")),
4768            }
4769        }
4770        fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
4771        where
4772            V: Visitor<'de>,
4773        {
4774            match self.kind {
4775                EnumKind::Tuple(items) => {
4776                    visitor.visit_seq(SeqDeserializer { items, idx: 0 })
4777                }
4778                _ => Err(de::Error::custom("该变体不是元组形态")),
4779            }
4780        }
4781        fn struct_variant<V>(
4782            self,
4783            _fields: &'static [&'static str],
4784            visitor: V,
4785        ) -> Result<V::Value, Error>
4786        where
4787            V: Visitor<'de>,
4788        {
4789            match self.kind {
4790                EnumKind::Struct(m) => {
4791                    visitor.visit_map(MapDeserializer { map: m, pending: None })
4792                }
4793                _ => Err(de::Error::custom("该变体不是结构体形态")),
4794            }
4795        }
4796    }
4797}
4798
4799// ---------------------------------------------------------------------------
4800// 自然序列化宏(derive)支持
4801// ---------------------------------------------------------------------------
4802
4803/// 把一个类型「自然地」序列化为 SML 值:
4804/// 结构体 → 块、newtype → 透明、单元结构体 → 裸词、
4805/// 枚举单元变体 → 裸词、带数据变体 → `__type` 块。
4806///
4807/// 通常用 `#[derive(SmlSerialize)]` 自动实现(`derive` feature 默认开启),
4808/// 也可手动实现。支持的 `#[sml(...)]` 属性见 `swsml-derive` 的文档。
4809pub trait SmlSerialize {
4810    fn to_sml_value(&self) -> Value;
4811
4812    /// 序列化为 SML 文本(等价于 [`to_sml`] 作用于本类型生成的值)。
4813    fn to_sml(&self) -> String {
4814        crate::to_sml(&self.to_sml_value())
4815    }
4816}
4817
4818/// 从 SML 值反序列化(`#[derive(SmlDeserialize)]` 自动实现)。
4819pub trait SmlDeserialize: Sized {
4820    fn from_sml_value(v: &Value) -> Result<Self, String>;
4821
4822    /// 解析 SML 文本并反序列化。
4823    fn from_sml(text: &str) -> Result<Self, String> {
4824        let v = crate::parse(text).map_err(|e| format!("SML 解析失败: {e}"))?;
4825        Self::from_sml_value(&v)
4826    }
4827}
4828
4829#[cfg(feature = "derive")]
4830pub use swsml_derive::{SmlDeserialize, SmlSerialize};
4831
4832/// 序列化为 SML 文本 —— toml-rs 风格的顶层函数(等价于 [`SmlSerialize::to_sml`])。
4833///
4834/// 用法与 `toml::to_string` 一致(序列化不会失败,故直接返回 `String`):
4835///
4836/// ```rust
4837/// # use sml::{SmlSerialize, SmlDeserialize};
4838/// # #[derive(SmlSerialize, SmlDeserialize, Debug, PartialEq)]
4839/// # struct Server { host: String, port: i32 }
4840/// # let cfg = Server { host: "web.example".into(), port: 8080 };
4841/// let text = sml::to_string(&cfg);
4842/// assert_eq!(text, "host: web.example\nport: 8080\n");
4843/// ```
4844pub fn to_string<T: SmlSerialize + ?Sized>(value: &T) -> String {
4845    crate::to_sml(&value.to_sml_value())
4846}
4847
4848/// 解析 SML 文本并反序列化 —— toml-rs 风格的顶层函数(等价于 [`SmlDeserialize::from_sml`])。
4849///
4850/// ```rust
4851/// # use sml::{SmlSerialize, SmlDeserialize};
4852/// # #[derive(SmlSerialize, SmlDeserialize, Debug, PartialEq)]
4853/// # struct Server { host: String, port: i32 }
4854/// let back: Server = sml::from_str("host: web.example\nport: 8080\n").unwrap();
4855/// assert_eq!(back.host, "web.example");
4856/// assert_eq!(back.port, 8080);
4857/// ```
4858pub fn from_str<T: SmlDeserialize>(text: &str) -> Result<T, String> {
4859    T::from_sml(text)
4860}
4861
4862/// 宏生成代码引用的内部辅助(请勿直接使用)。
4863#[doc(hidden)]
4864pub mod __private {
4865    use super::{SmlDeserialize, SmlSerialize, Value};
4866    use std::collections::{BTreeMap, HashMap};
4867
4868    /// 描述值的类型,用于错误信息。
4869    pub fn describe_value(v: &Value) -> String {
4870        match v {
4871            Value::Null => "null".to_string(),
4872            Value::Bool(b) => b.to_string(),
4873            Value::Int(i) => i.to_string(),
4874            Value::Float(f) => f.to_string(),
4875            Value::Str(s) => format!("字符串 `{s}`"),
4876            Value::Array(a) => format!("数组({} 个元素)", a.len()),
4877            Value::Object(o) => format!("块({} 个键)", o.len()),
4878        }
4879    }
4880
4881    /// 取出 `_value` 键(枚举单值变体)。
4882    pub fn take_value(m: &BTreeMap<String, Value>) -> Result<Value, String> {
4883        m.get("_value")
4884            .cloned()
4885            .ok_or_else(|| "缺少 _value 键".to_string())
4886    }
4887
4888    /// 取出 `_value` 键并断言为数组(枚举 tuple 变体)。
4889    pub fn take_array(m: &BTreeMap<String, Value>) -> Result<Vec<Value>, String> {
4890        match m.get("_value") {
4891            Some(Value::Array(a)) => Ok(a.clone()),
4892            Some(other) => Err(format!("_value 期望数组,实际为 {}", describe_value(other))),
4893            None => Err("缺少 _value 键".to_string()),
4894        }
4895    }
4896
4897    /// `#[sml(flatten)]` 反序列化:把整个块交给子类型。
4898    pub fn flatten_from<T: SmlDeserialize>(m: &BTreeMap<String, Value>) -> Result<T, String> {
4899        T::from_sml_value(&Value::Object(m.clone()))
4900    }
4901
4902    // ---- 基础类型 ----
4903
4904    impl SmlSerialize for bool {
4905        #[inline]
4906        fn to_sml_value(&self) -> Value {
4907            Value::Bool(*self)
4908        }
4909    }
4910    impl SmlDeserialize for bool {
4911        #[inline]
4912        fn from_sml_value(v: &Value) -> Result<Self, String> {
4913            match v {
4914                Value::Bool(b) => Ok(*b),
4915                other => Err(format!("期望布尔,实际为 {}", describe_value(other))),
4916            }
4917        }
4918    }
4919
4920    macro_rules! impl_int {
4921        ($($t:ty),* $(,)?) => {$(
4922            impl SmlSerialize for $t {
4923                #[inline]
4924                fn to_sml_value(&self) -> Value { Value::Int(*self as i64) }
4925            }
4926            impl SmlDeserialize for $t {
4927                #[inline]
4928                fn from_sml_value(v: &Value) -> Result<Self, String> {
4929                    match v {
4930                        Value::Int(i) => <$t>::try_from(*i)
4931                            .map_err(|_| format!("整数 {i} 超出 {} 范围", stringify!($t))),
4932                        Value::Float(f)
4933                            if f.fract() == 0.0
4934                                && *f >= <$t>::MIN as f64
4935                                && *f <= <$t>::MAX as f64 => Ok(*f as $t),
4936                        Value::Float(f) => Err(format!("期望整数,实际为小数 {f}")),
4937                        other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4938                    }
4939                }
4940            }
4941        )*};
4942    }
4943    impl_int!(i8, i16, i32, i64, isize, u8, u16, u32, usize);
4944
4945    impl SmlSerialize for u64 {
4946        #[inline]
4947        fn to_sml_value(&self) -> Value {
4948            i64::try_from(*self).map(Value::Int).unwrap_or_else(|_| Value::Float(*self as f64))
4949        }
4950    }
4951    impl SmlDeserialize for u64 {
4952        #[inline]
4953        fn from_sml_value(v: &Value) -> Result<Self, String> {
4954            match v {
4955                Value::Int(i) => u64::try_from(*i).map_err(|_| format!("整数 {i} 为负数,超出 u64 范围")),
4956                Value::Float(f) if f.fract() == 0.0 && *f >= 0.0 => Ok(*f as u64),
4957                Value::Float(f) => Err(format!("期望非负整数,实际为 {f}")),
4958                other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4959            }
4960        }
4961    }
4962
4963    macro_rules! impl_big {
4964        ($($t:ty),* $(,)?) => {$(
4965            impl SmlSerialize for $t {
4966                #[inline]
4967                fn to_sml_value(&self) -> Value {
4968                    i64::try_from(*self).map(Value::Int).unwrap_or_else(|_| Value::Float(*self as f64))
4969                }
4970            }
4971            impl SmlDeserialize for $t {
4972                #[inline]
4973                fn from_sml_value(v: &Value) -> Result<Self, String> {
4974                    match v {
4975                        Value::Int(i) => Ok(*i as $t),
4976                        Value::Float(f) if f.fract() == 0.0 => Ok(*f as $t),
4977                        Value::Float(f) => Err(format!("期望整数,实际为小数 {f}")),
4978                        other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4979                    }
4980                }
4981            }
4982        )*};
4983    }
4984    impl_big!(i128, u128);
4985
4986    macro_rules! impl_float {
4987        ($($t:ty),* $(,)?) => {$(
4988            impl SmlSerialize for $t {
4989                #[inline]
4990                fn to_sml_value(&self) -> Value { Value::Float(*self as f64) }
4991            }
4992            impl SmlDeserialize for $t {
4993                #[inline]
4994                fn from_sml_value(v: &Value) -> Result<Self, String> {
4995                    match v {
4996                        Value::Int(i) => Ok(*i as $t),
4997                        Value::Float(f) => Ok(*f as $t),
4998                        other => Err(format!("期望数字,实际为 {}", describe_value(other))),
4999                    }
5000                }
5001            }
5002        )*};
5003    }
5004    impl_float!(f32, f64);
5005
5006    impl SmlSerialize for char {
5007        #[inline]
5008        fn to_sml_value(&self) -> Value {
5009            Value::Str(self.to_string())
5010        }
5011    }
5012    impl SmlDeserialize for char {
5013        #[inline]
5014        fn from_sml_value(v: &Value) -> Result<Self, String> {
5015            match v {
5016                Value::Str(s) => {
5017                    let mut it = s.chars();
5018                    match (it.next(), it.next()) {
5019                        (Some(c), None) => Ok(c),
5020                        _ => Err(format!("期望单个字符,实际为 `{s}`")),
5021                    }
5022                }
5023                other => Err(format!("期望字符串,实际为 {}", describe_value(other))),
5024            }
5025        }
5026    }
5027
5028    impl SmlSerialize for String {
5029        #[inline]
5030        fn to_sml_value(&self) -> Value {
5031            Value::Str(self.clone())
5032        }
5033    }
5034    impl SmlDeserialize for String {
5035        #[inline]
5036        fn from_sml_value(v: &Value) -> Result<Self, String> {
5037            match v {
5038                Value::Str(s) => Ok(s.clone()),
5039                other => Err(format!("期望字符串,实际为 {}", describe_value(other))),
5040            }
5041        }
5042    }
5043
5044    impl SmlSerialize for str {
5045        #[inline]
5046        fn to_sml_value(&self) -> Value {
5047            Value::Str(self.to_string())
5048        }
5049    }
5050
5051    impl SmlSerialize for &str {
5052        #[inline]
5053        fn to_sml_value(&self) -> Value {
5054            Value::Str(self.to_string())
5055        }
5056    }
5057
5058    impl SmlSerialize for () {
5059        #[inline]
5060        fn to_sml_value(&self) -> Value {
5061            Value::Null
5062        }
5063    }
5064    impl SmlDeserialize for () {
5065        #[inline]
5066        fn from_sml_value(v: &Value) -> Result<Self, String> {
5067            match v {
5068                Value::Null => Ok(()),
5069                other => Err(format!("期望 null,实际为 {}", describe_value(other))),
5070            }
5071        }
5072    }
5073
5074    impl SmlSerialize for Value {
5075        #[inline]
5076        fn to_sml_value(&self) -> Value {
5077            self.clone()
5078        }
5079    }
5080    impl SmlDeserialize for Value {
5081        #[inline]
5082        fn from_sml_value(v: &Value) -> Result<Self, String> {
5083            Ok(v.clone())
5084        }
5085    }
5086
5087    impl<T: SmlSerialize> SmlSerialize for Option<T> {
5088        #[inline]
5089        fn to_sml_value(&self) -> Value {
5090            match self {
5091                Some(v) => v.to_sml_value(),
5092                None => Value::Null,
5093            }
5094        }
5095    }
5096    impl<T: SmlDeserialize> SmlDeserialize for Option<T> {
5097        #[inline]
5098        fn from_sml_value(v: &Value) -> Result<Self, String> {
5099            match v {
5100                Value::Null => Ok(None),
5101                other => Ok(Some(T::from_sml_value(other)?)),
5102            }
5103        }
5104    }
5105
5106    impl<T: SmlSerialize> SmlSerialize for Vec<T> {
5107        #[inline]
5108        fn to_sml_value(&self) -> Value {
5109            Value::Array(self.iter().map(SmlSerialize::to_sml_value).collect())
5110        }
5111    }
5112    impl<T: SmlDeserialize> SmlDeserialize for Vec<T> {
5113        #[inline]
5114        fn from_sml_value(v: &Value) -> Result<Self, String> {
5115            match v {
5116                Value::Array(a) => a.iter().map(SmlDeserialize::from_sml_value).collect(),
5117                other => Err(format!("期望数组,实际为 {}", describe_value(other))),
5118            }
5119        }
5120    }
5121
5122    impl<T: SmlSerialize> SmlSerialize for Box<T> {
5123        #[inline]
5124        fn to_sml_value(&self) -> Value {
5125            (**self).to_sml_value()
5126        }
5127    }
5128    impl<T: SmlDeserialize> SmlDeserialize for Box<T> {
5129        #[inline]
5130        fn from_sml_value(v: &Value) -> Result<Self, String> {
5131            Ok(Box::new(T::from_sml_value(v)?))
5132        }
5133    }
5134
5135    impl<V: SmlSerialize> SmlSerialize for BTreeMap<String, V> {
5136        #[inline]
5137        fn to_sml_value(&self) -> Value {
5138            Value::Object(
5139                self.iter()
5140                    .map(|(k, v)| (k.clone(), v.to_sml_value()))
5141                    .collect(),
5142            )
5143        }
5144    }
5145    impl<V: SmlDeserialize> SmlDeserialize for BTreeMap<String, V> {
5146        #[inline]
5147        fn from_sml_value(v: &Value) -> Result<Self, String> {
5148            match v {
5149                Value::Object(m) => {
5150                    let mut out = BTreeMap::new();
5151                    for (k, val) in m {
5152                        out.insert(k.clone(), V::from_sml_value(val)?);
5153                    }
5154                    Ok(out)
5155                }
5156                other => Err(format!("期望块(object),实际为 {}", describe_value(other))),
5157            }
5158        }
5159    }
5160
5161    impl<V: SmlSerialize> SmlSerialize for HashMap<String, V> {
5162        #[inline]
5163        fn to_sml_value(&self) -> Value {
5164            Value::Object(
5165                self.iter()
5166                    .map(|(k, v)| (k.clone(), v.to_sml_value()))
5167                    .collect(),
5168            )
5169        }
5170    }
5171    impl<V: SmlDeserialize> SmlDeserialize for HashMap<String, V> {
5172        #[inline]
5173        fn from_sml_value(v: &Value) -> Result<Self, String> {
5174            match v {
5175                Value::Object(m) => {
5176                    let mut out = HashMap::new();
5177                    for (k, val) in m {
5178                        out.insert(k.clone(), V::from_sml_value(val)?);
5179                    }
5180                    Ok(out)
5181                }
5182                other => Err(format!("期望块(object),实际为 {}", describe_value(other))),
5183            }
5184        }
5185    }
5186}
5187
5188// ---------------------------------------------------------------------------
5189// 测试
5190// ---------------------------------------------------------------------------
5191
5192#[cfg(test)]
5193mod tests {
5194    use super::*;
5195
5196    // ---------------- version ----------------
5197
5198    #[test]
5199    fn version_defaults_to_v1_when_absent() {
5200        // 既有文档没有版本声明,必须仍能解析且默认为 V1(裸词即字符串,向后兼容)
5201        let (v, ver) = parse_versioned("a: 1\n").unwrap();
5202        assert_eq!(ver, Version::V1);
5203        assert_eq!(v.get("a"), Some(&Value::Int(1)));
5204    }
5205
5206    #[test]
5207    fn version_declared_as_v1() {
5208        let (v, ver) = parse_versioned("@version v1\na: 1\n").unwrap();
5209        assert_eq!(ver, Version::V1);
5210        assert_eq!(v.get("a"), Some(&Value::Int(1)));
5211    }
5212
5213    #[test]
5214    fn version_declaration_is_stripped_not_parsed_as_content() {
5215        // 若未剥离,`@version v1` 会被当成片段定义而解析异常
5216        let v = parse("@version v1\na: 1\n").unwrap();
5217        assert_eq!(v.get("a"), Some(&Value::Int(1)));
5218        assert!(v.get("version").is_none(), "@version 不应进入数据");
5219    }
5220
5221    #[test]
5222    fn unsupported_version_is_rejected() {
5223        let err = parse_versioned("@version v99\na: 1\n").unwrap_err();
5224        assert!(err.contains("不支持"), "应拒绝不支持的版本,got: {err}");
5225        assert!(err.contains("v99"), "错误应含版本号,got: {err}");
5226    }
5227
5228    #[test]
5229    fn conflicting_version_is_rejected() {
5230        let err = parse_versioned("@version v1\n@version v2\n").unwrap_err();
5231        // v2 尚未定义,优先报「不支持」
5232        assert!(!err.is_empty());
5233        // 两个都支持但不一致时的路径:v1 与 v1 不冲突
5234        let (_, ver) = parse_versioned("@version v1\n@version v1\n").unwrap();
5235        assert_eq!(ver, Version::V1, "重复但一致的声明应被接受");
5236    }
5237
5238    #[test]
5239    fn version_is_reserved_as_fragment_name() {
5240        let err = parse("@version { x: 1 }\n").unwrap_err();
5241        assert!(err.contains("保留") || err.contains("版本声明"), "got: {err}");
5242    }
5243
5244    #[test]
5245    fn version_works_with_include() {
5246        let d = tmpdir("version");
5247        std::fs::write(d.join("p.sml"), "@version v1\nb: 2\n").unwrap();
5248        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"p.sml\"\n").unwrap();
5249        let (v, ver) = parse_file_versioned(d.join("main.sml")).unwrap();
5250        assert_eq!(ver, Version::V1);
5251        assert_eq!(v.get("b"), Some(&Value::Int(2)), "版本与 include 应协同");
5252        let _ = std::fs::remove_dir_all(&d);
5253    }
5254
5255    #[test]
5256    fn version_display_matches_name() {
5257        assert_eq!(Version::V1.name(), "v1");
5258        assert_eq!(format!("{}", Version::V1), "v1");
5259    }
5260
5261    // ---------------- include ----------------
5262
5263    /// 在临时目录下建文件,返回目录句柄(drop 时自动清理)
5264    fn tmpdir(tag: &str) -> std::path::PathBuf {
5265        let mut d = std::env::temp_dir();
5266        d.push(format!("sml_test_{tag}_{}", std::process::id()));
5267        let _ = std::fs::remove_dir_all(&d);
5268        std::fs::create_dir_all(&d).expect("create tmpdir");
5269        d
5270    }
5271
5272    #[test]
5273    fn include_inlines_external_file() {
5274        let d = tmpdir("inline");
5275        std::fs::write(d.join("part.sml"), "port: 8080\n").unwrap();
5276        std::fs::write(d.join("main.sml"), "@version v1\nhost: local\ninclude \"part.sml\"\n").unwrap();
5277
5278        let v = parse_file(d.join("main.sml")).unwrap();
5279        assert_eq!(v.get("host").unwrap().as_str(), Some("local"));
5280        assert_eq!(v.get("port"), Some(&Value::Int(8080)));
5281        let _ = std::fs::remove_dir_all(&d);
5282    }
5283
5284    #[test]
5285    fn include_at_prefix_is_equivalent() {
5286        let d = tmpdir("at");
5287        std::fs::write(d.join("p.sml"), "b: 2\n").unwrap();
5288        std::fs::write(d.join("m.sml"), "@include \"p.sml\"\n").unwrap();
5289        let v = parse_file(d.join("m.sml")).unwrap();
5290        assert_eq!(v.get("b"), Some(&Value::Int(2)));
5291        let _ = std::fs::remove_dir_all(&d);
5292    }
5293
5294    #[test]
5295    fn include_resolves_relative_to_including_file() {
5296        // 关键:相对路径按「被包含文件自身目录」解析,而非进程工作目录
5297        let d = tmpdir("nested");
5298        std::fs::create_dir_all(d.join("sub")).unwrap();
5299        std::fs::write(d.join("sub/leaf.sml"), "@version v1\nleaf: yes\n").unwrap();
5300        // mid 在根,include sub/mid2;mid2 在 sub 内,include leaf.sml(相对 sub)
5301        std::fs::write(d.join("sub/mid2.sml"), "@version v1\ninclude \"leaf.sml\"\n").unwrap();
5302        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"sub/mid2.sml\"\n").unwrap();
5303
5304        let v = parse_file(d.join("main.sml")).unwrap();
5305        assert_eq!(
5306            v.get("leaf").unwrap().as_str(),
5307            Some("yes"),
5308            "嵌套 include 的路径应相对各自所在目录解析"
5309        );
5310        let _ = std::fs::remove_dir_all(&d);
5311    }
5312
5313    #[test]
5314    fn include_inside_block_injects_fields() {
5315        // 文本内联语义:可在块内注入一组字段
5316        let d = tmpdir("block");
5317        std::fs::write(d.join("fields.sml"), "@version v1\nregion: cn-north-1\nzone: a\n").unwrap();
5318        std::fs::write(d.join("main.sml"), "@version v1\nserver web {\ninclude \"fields.sml\"\nport: 8080\n}\n").unwrap();
5319
5320        let v = parse_file(d.join("main.sml")).unwrap();
5321        let server = v.get("server").expect("应有 server 块");
5322        assert_eq!(server.get("region").unwrap().as_str(), Some("cn-north-1"));
5323        assert_eq!(server.get("zone").unwrap().as_str(), Some("a"));
5324        assert_eq!(server.get("port"), Some(&Value::Int(8080)));
5325        let _ = std::fs::remove_dir_all(&d);
5326    }
5327
5328    #[test]
5329    fn include_detects_cycles() {
5330        let d = tmpdir("cycle");
5331        std::fs::write(d.join("a.sml"), "include \"b.sml\"\n").unwrap();
5332        std::fs::write(d.join("b.sml"), "include \"a.sml\"\n").unwrap();
5333        let err = parse_file(d.join("a.sml")).unwrap_err();
5334        assert!(err.contains("循环引用"), "应报循环引用,got: {err}");
5335        let _ = std::fs::remove_dir_all(&d);
5336    }
5337
5338    #[test]
5339    fn include_missing_file_is_error() {
5340        let d = tmpdir("missing");
5341        std::fs::write(d.join("m.sml"), "include \"nope.sml\"\n").unwrap();
5342        let err = parse_file(d.join("m.sml")).unwrap_err();
5343        assert!(err.contains("nope.sml"), "错误应含缺失文件名,got: {err}");
5344        let _ = std::fs::remove_dir_all(&d);
5345    }
5346
5347    #[test]
5348    fn hash_in_quoted_string_is_not_a_comment() {
5349        // 引号内的 # 不应被当成注释,否则 `include "a#b.sml"` 会被截断
5350        assert_eq!(strip_line_comment("k: \"a#b\""), "k: \"a#b\"");
5351        assert_eq!(strip_line_comment("k: v # comment"), "k: v ");
5352    }
5353
5354    #[test]
5355    fn glob_include_requires_feature() {
5356        // 未开启 glob-include 时,`*` 模式应报错
5357        let d = tmpdir("globoff");
5358        std::fs::write(d.join("a.sml"), "x: 1\n").unwrap();
5359        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"*.sml\"\n").unwrap();
5360        let err = parse_file(d.join("main.sml")).unwrap_err();
5361        assert!(err.contains("glob-include"), "应要求 glob-include,got: {err}");
5362        let _ = std::fs::remove_dir_all(&d);
5363    }
5364
5365    #[test]
5366    fn glob_include_expands_multiple_files() {
5367        // 开启 glob-include 后,`lib/*.sml` 展开为子目录下所有 .sml(main.sml 不在该目录,避免自包含)
5368        let d = tmpdir("glob");
5369        std::fs::create_dir_all(d.join("lib")).unwrap();
5370        std::fs::write(d.join("lib/a.sml"), "@version v1\nx: 1\n").unwrap();
5371        std::fs::write(d.join("lib/b.sml"), "@version v1\ny: 2\n").unwrap();
5372        std::fs::write(d.join("note.txt"), "ignored\n").unwrap();
5373        std::fs::write(d.join("main.sml"), "@version v1\n@feature enable glob-include\ninclude \"lib/*.sml\"\n").unwrap();
5374        let v = parse_file(d.join("main.sml")).unwrap();
5375        assert_eq!(v.get("x"), Some(&Value::Int(1)));
5376        assert_eq!(v.get("y"), Some(&Value::Int(2)));
5377        let _ = std::fs::remove_dir_all(&d);
5378    }
5379
5380    #[test]
5381    fn regex_include_requires_feature() {
5382        let d = tmpdir("regexoff");
5383        std::fs::write(d.join("a.sml"), "x: 1\n").unwrap();
5384        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"re:.*\\.sml\"\n").unwrap();
5385        let err = parse_file(d.join("main.sml")).unwrap_err();
5386        assert!(err.contains("regex-include"), "应要求 regex-include,got: {err}");
5387        let _ = std::fs::remove_dir_all(&d);
5388    }
5389
5390    #[test]
5391    fn regex_include_matches_files() {
5392        let d = tmpdir("regex");
5393        std::fs::write(d.join("widget_a.sml"), "@version v1\nx: 1\n").unwrap();
5394        std::fs::write(d.join("widget_b.sml"), "@version v1\ny: 2\n").unwrap();
5395        std::fs::write(d.join("other.sml"), "@version v1\nz: 3\n").unwrap();
5396        std::fs::write(
5397            d.join("main.sml"),
5398            "@version v1\n@feature enable regex-include\ninclude \"re:widget_.*\\.sml\"\n",
5399        )
5400        .unwrap();
5401        let v = parse_file(d.join("main.sml")).unwrap();
5402        assert_eq!(v.get("x"), Some(&Value::Int(1)));
5403        assert_eq!(v.get("y"), Some(&Value::Int(2)));
5404        assert_eq!(v.get("z"), None, "other.sml 不应被正则匹配");
5405        let _ = std::fs::remove_dir_all(&d);
5406    }
5407
5408    #[test]
5409    fn ext_rewrite_allows_non_sml() {
5410        // ext-rewrite 开启时,include 非 .sml 文件按 sml 解析
5411        let d = tmpdir("exrew");
5412        std::fs::write(d.join("conf.smlc"), "@version v1\nx: 9\n").unwrap();
5413        std::fs::write(
5414            d.join("main.sml"),
5415            "@version v1\n@feature enable ext-rewrite\ninclude \"conf.smlc\"\n",
5416        )
5417        .unwrap();
5418        let v = parse_file(d.join("main.sml")).unwrap();
5419        assert_eq!(v.get("x"), Some(&Value::Int(9)));
5420        let _ = std::fs::remove_dir_all(&d);
5421    }
5422
5423    #[test]
5424    fn include_line_is_not_confused_with_key_named_include() {
5425        let f = FeatureSet::baseline();
5426        // `key: include` 不是指令——前面有 key 与冒号
5427        assert_eq!(parse_include_line("key: include", f), Ok(None));
5428        // 带扩展名无 as ⇒ 普通内联(namespace = None)
5429        assert_eq!(
5430            parse_include_line("include \"a.sml\"", f),
5431            Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false, keys: None }]))
5432        );
5433        // @include 等价
5434        assert_eq!(
5435            parse_include_line("@include \"a.sml\"", f),
5436            Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false, keys: None }]))
5437        );
5438        // 显式 as ns
5439        assert_eq!(
5440            parse_include_line("include \"a.sml\" as ui.form", f),
5441            Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: Some("ui.form".into()), via_import: false, keys: None }]))
5442        );
5443        // 无扩展名 ⇒ implicit-ns 默认 as 文件名
5444        assert_eq!(
5445            parse_include_line("include \"widgets\"", f),
5446            Ok(Some(vec![IncludeTarget { raw: "widgets".into(), namespace: Some("widgets".into()), via_import: false, keys: None }]))
5447        );
5448        // import 别名
5449        assert_eq!(
5450            parse_include_line("import ui.buttons", f),
5451            Ok(Some(vec![IncludeTarget { raw: "ui.buttons".into(), namespace: Some("ui.buttons".into()), via_import: true, keys: None }]))
5452        );
5453        // 多目标(需 multi-include)
5454        let fm = FeatureSet::all();
5455        assert_eq!(
5456            parse_include_line("include \"a.sml\", \"b\" as y", fm),
5457            Ok(Some(vec![
5458                IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false, keys: None },
5459                IncludeTarget { raw: "b".into(), namespace: Some("y".into()), via_import: false, keys: None },
5460            ]))
5461        );
5462        // 注释行不生效
5463        assert_eq!(parse_include_line("# include \"a.sml\"", f), Ok(None));
5464    }
5465
5466    #[test]
5467    fn import_partial_keys_both_syntaxes() {
5468        let f = FeatureSet::all();
5469        // 语法①:import "x.sml" as w { a, b }
5470        assert_eq!(
5471            parse_include_line("import \"m.sml\" as w { a, b }", f),
5472            Ok(Some(vec![IncludeTarget {
5473                raw: "m.sml".into(),
5474                namespace: Some("w".into()),
5475                via_import: true,
5476                keys: Some(vec!["a".into(), "b".into()]),
5477            }]))
5478        );
5479        // 语法①无 as:平铺挑键(namespace 为 None,不触发 implicit-ns)
5480        assert_eq!(
5481            parse_include_line("import \"m.sml\" { a, b }", f),
5482            Ok(Some(vec![IncludeTarget {
5483                raw: "m.sml".into(),
5484                namespace: None,
5485                via_import: true,
5486                keys: Some(vec!["a".into(), "b".into()]),
5487            }]))
5488        );
5489        // 语法②:import { a, b } as w in "m.sml"
5490        assert_eq!(
5491            parse_include_line("import { a, b } as w in \"m.sml\"", f),
5492            Ok(Some(vec![IncludeTarget {
5493                raw: "m.sml".into(),
5494                namespace: Some("w".into()),
5495                via_import: true,
5496                keys: Some(vec!["a".into(), "b".into()]),
5497            }]))
5498        );
5499        // 语法②无 as:平铺挑键
5500        assert_eq!(
5501            parse_include_line("import { a, b } in \"m.sml\"", f),
5502            Ok(Some(vec![IncludeTarget {
5503                raw: "m.sml".into(),
5504                namespace: None,
5505                via_import: true,
5506                keys: Some(vec!["a".into(), "b".into()]),
5507            }]))
5508        );
5509        // 空键列表报错
5510        assert!(parse_include_line("import \"m.sml\" { }", f).is_err());
5511        // 语法②缺少 in "file" 报错
5512        assert!(parse_include_line("import { a, b } as w", f).is_err());
5513        // 部分引用不能配 glob 通配
5514        assert!(parse_include_line("import \"*.sml\" { a }", f).is_err());
5515    }
5516
5517    // ---------------- 邮箱 / 裸词中的 @ ----------------
5518
5519    #[test]
5520    fn email_in_bare_word_survives() {
5521        // 回归:裸词中的 `@` 曾被切成 At token,导致邮箱被截断为 `a`
5522        let v = parse("to: a@b.c\nfrom: \"SML Team <dev@mail.swebase.cn>\"\n").unwrap();
5523        assert_eq!(v.get("to").unwrap().as_str(), Some("a@b.c"), "got: {v:?}");
5524        assert_eq!(
5525            v.get("from").unwrap().as_str(),
5526            Some("SML Team <dev@mail.swebase.cn>"),
5527            "got: {v:?}"
5528        );
5529    }
5530
5531    #[test]
5532    fn email_roundtrips_through_to_sml() {
5533        let v = Value::Object(BTreeMap::from([(
5534            "to".to_string(),
5535            Value::Str("dev@mail.swebase.cn".into()),
5536        )]));
5537        let back = parse(&to_sml(&v)).unwrap();
5538        assert_eq!(back, v, "邮箱必须能往返,got:\n{}", to_sml(&v));
5539    }
5540
5541    #[test]
5542    fn fragment_definition_still_works() {
5543        // 词首的 `@` 仍是片段定义标记,不能被上面的修改破坏。
5544        // 注:SML 的片段继承用法是「定义后作为值引用」(`k: &base`);
5545        // 块内裸写 `&base` 会被当作键,不属于本用例覆盖范围。
5546        let v = parse("@base { region: cn }\nregion: &base\n").unwrap();
5547        assert_eq!(
5548            v.get("region").unwrap().get("region").unwrap().as_str(),
5549            Some("cn"),
5550            "片段引用应展开为定义的内容,got: {v:?}"
5551        );
5552    }
5553
5554    // ---------------- 顶层数组 / 对象(与 to_sml 对称)----------------
5555
5556    #[test]
5557    fn toplevel_array_roundtrips() {
5558        // 回归:to_sml 能输出顶层数组,但 parse 曾只认键值块,
5559        // 导致「能写不能读」("期望键, 得 LBrack")。
5560        let v = Value::Array(vec![
5561            Value::Object(BTreeMap::from([
5562                ("ts".to_string(), Value::Str("2026-01-01".into())),
5563                ("to".to_string(), Value::Str("a@b.c".into())),
5564            ])),
5565            Value::Object(BTreeMap::from([
5566                ("ts".to_string(), Value::Str("2026-01-02".into())),
5567                ("to".to_string(), Value::Str("x@y.z".into())),
5568            ])),
5569        ]);
5570        let text = to_sml(&v);
5571        let back = parse(&text).unwrap();
5572        assert_eq!(back, v, "顶层对象数组必须能往返,got text:\n{text}");
5573    }
5574
5575    #[test]
5576    fn toplevel_array_of_scalars_roundtrips() {
5577        let v = Value::Array(vec![
5578            Value::Int(1),
5579            Value::Str("two".into()),
5580            Value::Bool(true),
5581        ]);
5582        let back = parse(&to_sml(&v)).unwrap();
5583        assert_eq!(back, v, "顶层标量数组必须能往返");
5584    }
5585
5586    #[test]
5587    fn toplevel_object_block_roundtrips() {
5588        let mut m = BTreeMap::new();
5589        m.insert("k".to_string(), Value::Int(1));
5590        let v = Value::Object(m);
5591        let back = parse(&to_sml(&v)).unwrap();
5592        assert_eq!(back, v, "顶层对象块必须能往返");
5593    }
5594
5595    #[test]
5596    fn toplevel_empty_array_roundtrips() {
5597        let v = Value::Array(vec![]);
5598        let back = parse(&to_sml(&v)).unwrap();
5599        assert_eq!(back, v, "空数组必须能往返");
5600    }
5601
5602    // ---------------- serde ----------------
5603
5604    #[cfg(feature = "serde")]
5605    #[test]
5606    fn serde_roundtrip_preserves_shape() {
5607        let v = parse("name: John\nage: 27\ntags: [a b]\nnested { k: v }\n").unwrap();
5608        let json = serde_json::to_string(&v).unwrap();
5609        // 自然形状:字符串就是字符串,数字就是数字,而非 {"Int":27}
5610        assert!(json.contains("\"name\":\"John\""), "got: {json}");
5611        assert!(json.contains("\"age\":27"), "got: {json}");
5612        assert!(json.contains("\"tags\":[\"a\",\"b\"]"), "got: {json}");
5613        assert!(json.contains("\"nested\":{\"k\":\"v\"}"), "got: {json}");
5614
5615        let back: Value = serde_json::from_str(&json).unwrap();
5616        assert_eq!(back, v, "serde 往返应还原原值");
5617    }
5618
5619    #[cfg(feature = "serde")]
5620    #[test]
5621    fn serde_deserializes_json_into_value() {
5622        let v: Value = serde_json::from_str(r#"{"s":"x","i":5,"f":1.5,"b":true,"n":null,"a":[1,2]}"#).unwrap();
5623        assert_eq!(v.get("s").unwrap().as_str(), Some("x"));
5624        assert_eq!(v.get("i"), Some(&Value::Int(5)));
5625        assert_eq!(v.get("f"), Some(&Value::Float(1.5)));
5626        assert_eq!(v.get("b"), Some(&Value::Bool(true)));
5627        assert_eq!(v.get("n"), Some(&Value::Null));
5628        assert!(matches!(v.get("a"), Some(Value::Array(a)) if a.len() == 2));
5629    }
5630
5631    #[test]
5632    fn nested_array_inside_object_inside_array_survives_roundtrip() {
5633        // 回归测试:数组元素是对象、对象里又有数组(如配置的条目列表)。
5634        // dump_inline 曾把嵌套数组缩略成 [..],导致 chunks 丢成 [".."]。
5635        let mut item = BTreeMap::new();
5636        item.insert("path".to_string(), Value::Str("a.txt".into()));
5637        item.insert(
5638            "chunks".to_string(),
5639            Value::Array(vec![
5640                Value::Str("c1".into()),
5641                Value::Str("c2".into()),
5642            ]),
5643        );
5644        let mut root = BTreeMap::new();
5645        root.insert(
5646            "entries".to_string(),
5647            Value::Array(vec![Value::Object(item)]),
5648        );
5649        let text = to_sml(&Value::Object(root));
5650        assert!(!text.contains("[..]"), "嵌套数组不得被缩略: {text}");
5651
5652        let back = parse(&text).unwrap();
5653        let chunks = back.get("entries").and_then(|e| match e {
5654            Value::Array(a) => a.first(),
5655            _ => None,
5656        });
5657        let chunks = match chunks {
5658            Some(Value::Object(m)) => m.get("chunks"),
5659            _ => None,
5660        };
5661        match chunks {
5662            Some(Value::Array(a)) => {
5663                assert_eq!(a.len(), 2, "两个块都应保留: {text}");
5664                assert_eq!(
5665                    a.iter().filter_map(|c| c.as_str()).collect::<Vec<_>>(),
5666                    vec!["c1", "c2"]
5667                );
5668            }
5669            other => panic!("chunks 应解析为数组,实际 {other:?}"),
5670        }
5671    }
5672
5673    #[test]
5674    fn utf8_in_quoted_string_survives_roundtrip() {
5675        // 回归测试:tokenizer 曾按字节 `as char` 逐个处理,
5676        // 把 UTF-8 多字节字符拆成 Latin-1 字符,导致
5677        // `"修复若干问题"` 解析后变成双编码乱码。
5678        let v = parse(r#"note: "修复若干问题""#).unwrap();
5679        assert_eq!(
5680            v.get("note").and_then(|x| x.as_str()),
5681            Some("修复若干问题"),
5682            "引号串中的中文不应被破坏"
5683        );
5684        // 裸词中文同样不能破坏
5685        let v2 = parse("region: 华北").unwrap();
5686        assert_eq!(v2.get("region").and_then(|x| x.as_str()), Some("华北"));
5687        // 转义 \u 序列
5688        let v3 = parse(r#"k: "\u{4fee}\u{590d}""#).unwrap();
5689        assert_eq!(v3.get("k").and_then(|x| x.as_str()), Some("修复"));
5690    }
5691
5692    #[test]
5693    fn parse_basic() {
5694        let text = "firstName: John\nage: 27\nisAlive: true\nspouse: null\n";
5695        let v = parse(text).unwrap();
5696        assert_eq!(v.get("firstName"), Some(&Value::Str("John".into())));
5697        assert_eq!(v.get("age"), Some(&Value::Int(27)));
5698        assert_eq!(v.get("isAlive"), Some(&Value::Bool(true)));
5699        assert_eq!(v.get("spouse"), Some(&Value::Null));
5700    }
5701
5702    #[test]
5703    fn parse_nested() {
5704        let text = "address:\n{\n    streetAddress: \"21 2nd Street\"\n    state: NY\n}\n";
5705        let v = parse(text).unwrap();
5706        assert_eq!(
5707            v.get("address.streetAddress"),
5708            Some(&Value::Str("21 2nd Street".into()))
5709        );
5710        assert_eq!(v.get("address.state"), Some(&Value::Str("NY".into())));
5711    }
5712
5713    #[test]
5714    fn parse_array() {
5715        let text = "phoneNumbers:\n[\n    { type: home }\n    { type: office }\n]\n";
5716        let v = parse(text).unwrap();
5717        if let Some(Value::Array(a)) = v.get("phoneNumbers") {
5718            assert_eq!(a.len(), 2);
5719            assert_eq!(a[0].get("type"), Some(&Value::Str("home".into())));
5720        } else {
5721            panic!("not array");
5722        }
5723    }
5724
5725    #[test]
5726    fn parse_fragment() {
5727        let text = "@base { region: cn-north-1 }\nserver web { &base }\n";
5728        let v = parse(text).unwrap();
5729        // &base 展开为字段 (键名 "&base", 值=片段对象), 与 Lua 实现一致
5730        assert_eq!(
5731            v.get("server.&base.region"),
5732            Some(&Value::Str("cn-north-1".into()))
5733        );
5734        assert_eq!(v.get("server.__type"), Some(&Value::Str("server".into())));
5735        assert_eq!(v.get("server.__name"), Some(&Value::Str("web".into())));
5736    }
5737
5738    #[test]
5739    fn roundtrip() {
5740        let text = "name: myapp\nport: 8080\nflags: [ a b c ]\n";
5741        let v = parse(text).unwrap();
5742        let out = to_sml(&v);
5743        let v2 = parse(&out).unwrap();
5744        assert_eq!(v, v2);
5745    }
5746
5747    #[test]
5748    fn env_inline() {
5749        // Rust 1.85+ 起 set_var 为 unsafe(与 edition 无关,2021/2024 均需)
5750        unsafe { std::env::set_var("SML_TEST_VAR", "hello") };
5751        let text = "greeting: $env.SML_TEST_VAR\n";
5752        let v = parse(text).unwrap();
5753        assert_eq!(v.get("greeting"), Some(&Value::Str("hello".into())));
5754    }
5755
5756    #[test]
5757    fn c_abi_json_bridge() {
5758        let text = "name: John\nage: 27\n";
5759        let v = parse(text).unwrap();
5760        let j = jsonify(&v);
5761        assert!(j.contains("\"name\":\"John\""));
5762        let back = json_to_value(&j).unwrap();
5763        assert_eq!(back, v);
5764    }
5765}
5766
5767// ===========================================================================
5768// @feature 特性裁剪 + 调用方限制 测试
5769// ===========================================================================
5770
5771#[cfg(test)]
5772mod feature {
5773    use super::*;
5774
5775    #[test]
5776    fn feature_unknown_name_errors() {
5777        let r = parse("@feature enable nope\nx: 1\n");
5778        assert!(r.is_err());
5779        assert!(r.unwrap_err().contains("未知特性"));
5780    }
5781
5782    #[test]
5783    fn feature_whitelist_narrows() {
5784        // 仅保留 bareword 与 include,其它(env/fragment/contract...)关闭
5785        let v = match parse("@feature whitelist bareword-string,include\nx: John\n").unwrap() {
5786            Value::Object(m) => m,
5787            _ => panic!("应为对象"),
5788        };
5789        assert_eq!(v.get("x"), Some(&Value::Str("John".into())));
5790    }
5791
5792    #[test]
5793    fn feature_blacklist_removes() {
5794        // 关掉 bareword-string:v1 文档里裸词字符串也应被拒
5795        let r = parse("@feature blacklist bareword-string\nx: John\n");
5796        assert!(r.is_err());
5797        assert!(r.unwrap_err().contains("字符串必须加引号"));
5798    }
5799
5800    #[test]
5801    fn feature_mode_whitelist_enable() {
5802        // mode whitelist 后基集清空,仅 enable 的生效
5803        let r = parse("@feature mode whitelist\n@feature enable fragment\nx: &frag\n");
5804        // fragment 没定义,回退为字符串 "&frag",不报错即可
5805        assert!(r.is_ok());
5806    }
5807
5808    #[test]
5809    fn caller_allowed_intersection_empty_errors() {
5810        // 调用方只接受 env;文档用白名单模式只开 contract —— 与调用方无交集则报错
5811        let allowed = FeatureSet::none().with(Feature::Env);
5812        let r = parse_with_features(
5813            "@feature mode whitelist\n@feature enable contract\nx: 1\n",
5814            allowed,
5815        );
5816        assert!(r.is_err());
5817    }
5818
5819    #[test]
5820    fn caller_allowed_subset_ok() {
5821        // 调用方允许全部,文档收窄到 bareword+include,应成功
5822        let allowed = FeatureSet::all();
5823        let (v, eff) = parse_with_features(
5824            "@feature whitelist bareword-string,include\nx: John\n",
5825            allowed,
5826        )
5827        .unwrap();
5828        assert!(eff.has(Feature::BarewordStr));
5829        assert!(eff.has(Feature::Include));
5830        assert!(!eff.has(Feature::Env));
5831        assert_eq!(v.get("x"), Some(&Value::Str("John".into())));
5832    }
5833
5834    #[test]
5835    fn feature_namespace_include() {
5836        // 用临时文件验证 include "x.sml" as ns 把键挂到 ns 下。
5837        // 用相对路径 + 正斜杠,避开 Windows 反斜杠在字符串转义中的处理。
5838        // 注意:include 展开只在 parse_file 进行,故这里把主文档也落盘。
5839        let dir = std::env::temp_dir().join("sml_feat_ns_test");
5840        let _ = std::fs::create_dir_all(&dir);
5841        let sub = dir.join("sub.sml");
5842        let main = dir.join("main.sml");
5843        std::fs::write(&sub, "a: 1\nb: 2\n").unwrap();
5844        // 用正斜杠书写相对路径,避免反斜杠被字符串转义吃掉
5845        let rel = format!("include \"sub.sml\" as pkg\n");
5846        std::fs::write(&main, &rel).unwrap();
5847        let v = match parse_file(&main) {
5848            Ok(v) => v,
5849            Err(e) => {
5850                let _ = std::fs::remove_dir_all(&dir);
5851                panic!("parse_file 失败: {e}");
5852            }
5853        };
5854        let _ = std::fs::remove_dir_all(&dir);
5855        let pkg = match v.get("pkg") {
5856            Some(Value::Object(m)) => m.clone(),
5857            _ => panic!("pkg 应为对象"),
5858        };
5859        assert_eq!(pkg.get("a"), Some(&Value::Int(1)));
5860        assert_eq!(pkg.get("b"), Some(&Value::Int(2)));
5861    }
5862
5863    #[test]
5864    fn version_v3_disables_bareword() {
5865        // v3 默认关闭 bareword-string;裸词应被拒
5866        let r = parse("@version v3\nname: John\n");
5867        assert!(r.is_err());
5868        // 但引号字符串可用
5869        let v = parse("@version v3\nname: \"John\"\nage: 27\n").unwrap();
5870        assert_eq!(v.get("name"), Some(&Value::Str("John".into())));
5871        assert_eq!(v.get("age"), Some(&Value::Int(27)));
5872    }
5873
5874    #[test]
5875    fn feature_base_derives_strict() {
5876        // @feature base v3 等价于 v3 严格
5877        let r = parse("@feature base v3\nname: John\n");
5878        assert!(r.is_err());
5879    }
5880}