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/// 特性名 → 枚举 的注册表。所有端共用同一组名字,保证跨语言一致。
1219pub static FEATURES: &[(&str, Feature)] = &[
1220    ("bareword-string", Feature::BarewordStr),
1221    ("include", Feature::Include),
1222    ("env", Feature::Env),
1223    ("contract", Feature::Contract),
1224    ("fragment", Feature::Fragment),
1225    ("top-level-array", Feature::TopArray),
1226    ("namespace", Feature::Namespace),
1227    ("implicit-ns", Feature::ImplicitNs),
1228    ("multi-include", Feature::MultiInclude),
1229    ("glob-include", Feature::GlobInclude),
1230    ("regex-include", Feature::RegexInclude),
1231    ("ext-rewrite", Feature::ExtRewrite),
1232];
1233
1234impl Feature {
1235    /// 按名字查特性;未知名字返回 None(调用方据此报错,杜绝静默 typo)。
1236    pub fn from_name(name: &str) -> Option<Feature> {
1237        FEATURES.iter().find(|(n, _)| *n == name).map(|(_, f)| *f)
1238    }
1239
1240    /// 特性名(用于报错 / 序列化回显)
1241    pub fn name(self) -> &'static str {
1242        FEATURES
1243            .iter()
1244            .find(|(_, f)| *f == self)
1245            .map(|(n, _)| *n)
1246            .unwrap_or("<unknown>")
1247    }
1248}
1249
1250/// 位掩码形式的特性集合。
1251///
1252/// 设计哲学:从极简到丰富、功能可裁剪。默认基线(`baseline()`)只开极简三件套
1253/// (`include` + `namespace` + `implicit-ns`),复杂能力(多目标 / glob / 正则 /
1254/// 扩展名重写)必须显式 `@feature enable` 才生效,避免重蹈 YAML 过度复杂的覆辙。
1255#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1256pub struct FeatureSet(u64);
1257
1258impl FeatureSet {
1259    /// 全部特性位(含所有 opt-in 能力)。用于「调用方允许全集」与版本基线,
1260    /// 实际默认并不开启这些——见 [`FeatureSet::baseline`]。
1261    pub fn all() -> FeatureSet {
1262        let mut m = 0u64;
1263        for (_, f) in FEATURES {
1264            m |= 1 << (*f as u8);
1265        }
1266        FeatureSet(m)
1267    }
1268
1269    /// 极简默认集(SML 核心可用能力)。这是 `parse_file` 的默认允许集;
1270    /// 仅「多目标 / glob / 正则 / 扩展名重写」等高级能力需文档内
1271    /// `@feature enable` 显式开启(避免重蹈 YAML 覆辙)。
1272    pub fn baseline() -> FeatureSet {
1273        FeatureSet::none()
1274            .with(Feature::BarewordStr)
1275            .with(Feature::Include)
1276            .with(Feature::Env)
1277            .with(Feature::Contract)
1278            .with(Feature::Fragment)
1279            .with(Feature::TopArray)
1280            .with(Feature::Namespace)
1281            .with(Feature::ImplicitNs)
1282    }
1283
1284    /// 空集合
1285    pub fn none() -> FeatureSet {
1286        FeatureSet(0)
1287    }
1288
1289    /// 按版本基线构造默认特性集:v1 极简默认(baseline)+ 裸词字符串;
1290    /// v2/v3 关闭裸词字符串(须引号)。复杂能力(glob/regex/multi...)仍默认关闭,
1291    /// 需文档 `@feature enable` 显式开启。
1292    pub fn for_version(v: Version) -> FeatureSet {
1293        let mut s = FeatureSet::baseline();
1294        // 严格模式(v2/v3)关闭裸词字符串;非严格(v1)开启。
1295        // 显式设置该位,确保与 baseline 默认值无关。
1296        if v.strict_strings() {
1297            s = s.without(Feature::BarewordStr);
1298        } else {
1299            s = s.with(Feature::BarewordStr);
1300        }
1301        s
1302    }
1303
1304    /// 是否包含某特性
1305    pub fn has(self, f: Feature) -> bool {
1306        (self.0 & (1 << (f as u8))) != 0
1307    }
1308
1309    /// 返回开启 `f` 后的副本
1310    pub fn with(self, f: Feature) -> FeatureSet {
1311        FeatureSet(self.0 | (1 << (f as u8)))
1312    }
1313
1314    /// 返回关闭 `f` 后的副本
1315    pub fn without(self, f: Feature) -> FeatureSet {
1316        FeatureSet(self.0 & !(1 << (f as u8)))
1317    }
1318
1319    /// 与另一集合取交集(用于「文档裁剪 ∩ 调用方允许」)
1320    pub fn intersection(self, other: FeatureSet) -> FeatureSet {
1321        FeatureSet(self.0 & other.0)
1322    }
1323
1324    /// 是否无任何特性
1325    pub fn is_empty(self) -> bool {
1326        self.0 == 0
1327    }
1328}
1329
1330impl fmt::Display for FeatureSet {
1331    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1332        let mut first = true;
1333        for (n, feat) in FEATURES {
1334            if self.has(*feat) {
1335                if !first {
1336                    f.write_str(",")?;
1337                }
1338                f.write_str(n)?;
1339                first = false;
1340            }
1341        }
1342        if first {
1343            f.write_str("<none>")?;
1344        }
1345        Ok(())
1346    }
1347}
1348
1349/// `@feature` 解析模式:白名单(仅启用列出的)/ 黑名单(禁用列出的)。
1350#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1351enum FeatureMode {
1352    Default,
1353    Whitelist,
1354    Blacklist,
1355}
1356
1357/// 取出 token 的字符串内容(Word / Str 都取其文本;其余返回空串)。
1358fn tok_word(t: &Tok) -> String {
1359    match t {
1360        Tok::Word(s) | Tok::Str(s) => s.clone(),
1361        _ => String::new(),
1362    }
1363}
1364
1365/// 若该行是 `@feature` 声明,则根据 `mode` / 操作更新 `feats`,并返回 true。
1366///
1367/// 支持语法(均不区分大小写,参数以空格分隔):
1368/// - `@feature base v3`              设定基线版本(等价于 `@version`,仅用于特性派生)
1369/// - `@feature mode whitelist`       后续 enable 仅保留所列(基集先清空)
1370/// - `@feature mode blacklist`       后续 disable 仅移除所列(基集保持全开)
1371/// - `@feature enable <name>[,...]`  开启特性(可逗号批量)
1372/// - `@feature disable <name>[,...]` 关闭特性
1373/// - `@feature whitelist <a,b>`      紧凑白名单
1374/// - `@feature blacklist <a,b>`      紧凑黑名单
1375///
1376/// 未知特性名一律报错,避免拼写错误静默失效。
1377fn apply_feature_directive(
1378    line: &str,
1379    feats: &mut FeatureSet,
1380    mode: &mut FeatureMode,
1381    base: &mut Option<Version>,
1382) -> Result<bool, String> {
1383    let content = strip_line_comment(line).trim();
1384    let toks = match tokenize(content) {
1385        Ok(t) => t,
1386        Err(_) => return Ok(false),
1387    };
1388    if toks.is_empty() || toks[0] != Tok::At {
1389        return Ok(false);
1390    }
1391    let words: Vec<String> = toks
1392        .iter()
1393        .map(|t| match t {
1394            Tok::At => "@".to_string(),
1395            other => tok_word(other),
1396        })
1397        .collect();
1398    // @feature 词法上拆成 [@, feature],拼前两个 token 才是 "@feature"
1399    let head = format!("{}{}", words.first().map(|s| s.as_str()).unwrap_or(""), words.get(1).map(|s| s.as_str()).unwrap_or(""));
1400    if head != "@feature" {
1401        return Ok(false);
1402    }
1403    // 去掉首 token `@`,使后续 words[0]=="feature"
1404    let words: Vec<String> = words[1..].to_vec();
1405    if words.len() < 2 {
1406        return Err("@feature 指令缺少参数".into());
1407    }
1408    let arg = words[1].as_str();
1409    // 把 `enable x,y,z` / `whitelist a,b` 的多名拆开
1410    let names = |from: usize| -> Vec<String> {
1411        words[from..]
1412            .join(",")
1413            .split(',')
1414            .map(|s| s.trim().to_string())
1415            .filter(|s| !s.is_empty())
1416            .collect()
1417    };
1418    match arg {
1419        "base" => {
1420            let v = Version::from_word(words.get(2).map(|s| s.as_str()).unwrap_or(""))
1421                .ok_or_else(|| {
1422                    format!(
1423                        "@feature base 需要 v1/v2/v3,收到 `{}`",
1424                        words.get(2).cloned().unwrap_or_default()
1425                    )
1426                })?;
1427            *feats = FeatureSet::for_version(v);
1428            *base = Some(v);
1429            Ok(true)
1430        }
1431        "mode" => {
1432            let m = words.get(2).map(|s| s.as_str()).unwrap_or("");
1433            *mode = match m {
1434                "whitelist" => FeatureMode::Whitelist,
1435                "blacklist" => FeatureMode::Blacklist,
1436                _ => return Err(format!("@feature mode 需要 whitelist/blacklist,收到 `{m}`")),
1437            };
1438            if *mode == FeatureMode::Whitelist {
1439                // 白名单:基集先清空,后续 enable 显式置位
1440                *feats = FeatureSet::none();
1441            }
1442            Ok(true)
1443        }
1444        "enable" => {
1445            // 直接在「当前特性集」上叠加开启(不切换白名单语义)。
1446            // 这样 `@feature enable regex-include` 在 `@version v1` 文档上会保留
1447            // bareword-string 等默认特性,而非收窄为仅所列项。
1448            // 真正的「收窄为仅所列」由显式 `@feature mode whitelist` 控制。
1449            for n in names(2) {
1450                let f = Feature::from_name(&n).ok_or_else(|| {
1451                    format!(
1452                        "未知特性 `{n}`,可用:{}",
1453                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1454                    )
1455                })?;
1456                *feats = feats.with(f);
1457            }
1458            Ok(true)
1459        }
1460        "disable" => {
1461            for n in names(2) {
1462                let f = Feature::from_name(&n).ok_or_else(|| {
1463                    format!(
1464                        "未知特性 `{n}`,可用:{}",
1465                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1466                    )
1467                })?;
1468                *feats = feats.without(f);
1469            }
1470            Ok(true)
1471        }
1472        "whitelist" => {
1473            *mode = FeatureMode::Whitelist;
1474            let mut s = FeatureSet::none();
1475            for n in names(2) {
1476                let f = Feature::from_name(&n).ok_or_else(|| {
1477                    format!(
1478                        "未知特性 `{n}`,可用:{}",
1479                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1480                    )
1481                })?;
1482                s = s.with(f);
1483            }
1484            *feats = s;
1485            Ok(true)
1486        }
1487        "blacklist" => {
1488            let mut s = FeatureSet::all();
1489            for n in names(2) {
1490                let f = Feature::from_name(&n).ok_or_else(|| {
1491                    format!(
1492                        "未知特性 `{n}`,可用:{}",
1493                        FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1494                    )
1495                })?;
1496                s = s.without(f);
1497            }
1498            *feats = s;
1499            Ok(true)
1500        }
1501        _ => Err(format!("未知 @feature 子命令 `{arg}`,可用 base/mode/enable/disable")),
1502    }
1503}
1504
1505/// 在解析前剥离全部 `@feature` 指令,返回剩余文本、推导出的特性集,以及
1506/// 由 `@feature base vN` 声明的基线版本(若文档未用 `@version` 则采用它)。
1507///
1508/// 文档内部的 `@feature` 只能收窄;调用方允许范围由 `parse_with_features`
1509/// / `parse_allowed` 的 `allowed` 参数在入口处再次交集。
1510///
1511/// 返回值三元组:(剩余文本, 特性集, @feature base 声明的版本, 是否出现过 @feature 指令)。
1512/// 若文档从未声明 `@feature`,则 `had_feature=false`,调用方应改以版本基线派生特性集
1513/// (例如 v3 默认关闭裸词字符串)。
1514fn strip_features(text: &str) -> Result<(String, FeatureSet, Option<Version>, bool), String> {
1515    let mut out = String::new();
1516    let mut feats = FeatureSet::all();
1517    let mut mode = FeatureMode::Default;
1518    let mut base: Option<Version> = None;
1519    let mut had_feature = false;
1520
1521    for line in text.lines() {
1522        match apply_feature_directive(line, &mut feats, &mut mode, &mut base) {
1523            Ok(true) => {
1524                had_feature = true;
1525                continue; // 指令行被消费,不进入剩余文本
1526            }
1527            Ok(false) => {}
1528            Err(e) => return Err(e), // 指令非法(如未知特性名)必须上浮,不能静默吞掉
1529        }
1530        out.push_str(line);
1531        out.push('\n');
1532    }
1533    Ok((out, feats, base, had_feature))
1534}
1535
1536/// 若该行是 `@version` 声明,返回版本字面量;否则返回 None。
1537///
1538/// `version` 是保留字:不允许作为片段名(`@version { }`)使用。
1539fn version_directive(line: &str) -> Result<Option<String>, String> {
1540    let content = strip_line_comment(line).trim();
1541    // 词法失败的行(如未闭合引号)不是版本声明,交由主解析器报更准确的错
1542    let toks = match tokenize(content) {
1543        Ok(t) => t,
1544        Err(_) => return Ok(None),
1545    };
1546    match toks.as_slice() {
1547        [Tok::At, Tok::Word(w), Tok::Word(v)] if w == "version" => Ok(Some(v.clone())),
1548        [Tok::At, Tok::Word(w), Tok::Str(v)] if w == "version" => Ok(Some(v.clone())),
1549        [Tok::At, Tok::Word(w), ..] if w == "version" => Err(
1550            "`@version` 是版本声明指令,须写作 `@version v1`;`version` 不可作为片段名".into(),
1551        ),
1552        _ => Ok(None),
1553    }
1554}
1555
1556/// 剥离 `@version` 声明行,返回剩余文本与声明的版本(未声明则为 None)。
1557///
1558/// 允许多次声明(include 进来的文件可各自声明),但必须一致;
1559/// 声明了实现不支持的版本时报错,避免静默按错误语法解析。
1560fn strip_version(text: &str) -> Result<(String, Option<Version>), String> {
1561    let mut declared: Option<Version> = None;
1562    let mut rest = String::new();
1563    for line in text.lines() {
1564        if let Some(lit) = version_directive(line)? {
1565            let v = Version::from_word(&lit).ok_or_else(|| {
1566                format!(
1567                    "不支持的 SML 版本 `{lit}`(本实现支持 {})",
1568                    Version::CURRENT.name()
1569                )
1570            })?;
1571            match declared {
1572                None => declared = Some(v),
1573                Some(prev) if prev != v => {
1574                    return Err(format!("@version 冲突:{} 与 {}", prev.name(), v.name()))
1575                }
1576                Some(_) => {}
1577            }
1578            continue;
1579        }
1580        rest.push_str(line);
1581        rest.push('\n');
1582    }
1583    Ok((rest, declared))
1584}
1585
1586/// 把 版本 + 文档 @feature 指令 合并为最终生效的特性集。
1587///
1588/// 规则:
1589/// - 若文档显式声明过 `@feature`(had_feature=true),则完全采用其推导的 `feats`;
1590/// - 否则(仅靠 `@version` 声明或默认),从版本基线派生(如 v3 关闭裸词字符串)。
1591/// 这样 v3 文档即使不写任何 `@feature` 也默认严格;调用方的 `allowed` 在
1592/// 入口处再与结果取交集,文档无法扩宽。
1593fn features_for(v: Version, feats: FeatureSet, had_feature: bool) -> FeatureSet {
1594    if had_feature {
1595        feats
1596    } else {
1597        FeatureSet::for_version(v)
1598    }
1599}
1600
1601/// 解析 SML 文本,并返回其声明的语法版本。
1602///
1603/// 未声明版本时按 `V1` 处理(裸词即字符串),**既有文档不受影响**;
1604/// 显式 `@version v3` 则返回 `V3`(此时字符串需引号)。
1605pub fn parse_versioned(text: &str) -> Result<(Value, Version), String> {
1606    let (rest, declared) = strip_version(text)?;
1607    let (rest, feats, base, had) = strip_features(&rest)?;
1608    // 版本优先级:@version 显式声明 > @feature base > 默认 V1
1609    let v = declared.or(base).unwrap_or(Version::V1);
1610    let feats = features_for(v, feats, had);
1611    Ok((parse_impl(&rest, v, feats)?, v))
1612}
1613
1614/// 解析 SML 文件:展开 include,并返回其声明的语法版本
1615pub fn parse_file_versioned(path: impl AsRef<Path>) -> Result<(Value, Version), String> {
1616    let path = path.as_ref();
1617    let text =
1618        std::fs::read_to_string(path).map_err(|e| format!("读取失败 {}: {e}", path.display()))?;
1619    let base = path
1620        .parent()
1621        .map(|p| p.to_path_buf())
1622        .unwrap_or_else(|| PathBuf::from("."));
1623    let (rest, declared) = strip_version(&text)?;
1624    let (rest, feats, base_ver, had) = strip_features(&rest)?;
1625    let allowed = FeatureSet::all().intersection(feats);
1626    let v = declared.or(base_ver).unwrap_or(Version::V1);
1627    let feats = features_for(v, allowed, had);
1628    let toks = resolve_includes(&rest, &base, allowed)?;
1629    let val = parse_impl_tokens(toks, v, feats)?;
1630    Ok((val, v))
1631}
1632
1633/// 解析 SML 文本
1634///
1635/// 会自动识别并剥离 `@version` / `@feature` 声明(需要版本信息时用
1636/// [`parse_versioned`],需要特性裁剪信息时用 [`parse_with_features`])。
1637///
1638/// **向后兼容**:未声明 `@version` 的文档按 `V1` 解析(裸词即字符串),
1639/// 既有大量 v1 文档不受影响;仅显式 `@version v2|v3` 才启用严格字符串。
1640pub fn parse(text: &str) -> Result<Value, String> {
1641    let (rest, declared) = strip_version(text)?;
1642    let (rest, feats, base, had) = strip_features(&rest)?;
1643    let v = declared.or(base).unwrap_or(Version::V1);
1644    let feats = features_for(v, feats, had);
1645    parse_impl(&rest, v, feats)
1646}
1647
1648/// 解析 SML 文本,并限制文档声明的版本必须在 `allowed` 范围内。
1649///
1650/// 用于「库固定依赖某个 SML 语法版本」的场景:若文档声明了 `allowed`
1651/// 之外的版本(例如库只接受 v1..v3,却遇到 `@version v4`),立即报错,
1652/// 而不是用不兼容的语法静默解析。
1653///
1654/// 未声明版本的文档视为 `V1`,只要 `allowed` 含 `V1` 即放行。
1655pub fn parse_allowed(
1656    text: &str,
1657    allowed: &[Version],
1658) -> Result<Value, String> {
1659    let (rest, declared) = strip_version(text)?;
1660    let (rest, feats, base, had) = strip_features(&rest)?;
1661    let v = declared.or(base).unwrap_or(Version::V1);
1662    if !allowed.contains(&v) {
1663        return Err(format!(
1664            "sml: 文档声明版本 {} 不在本库接受的版本范围 {{{}}} 内",
1665            v.name(),
1666            allowed
1667                .iter()
1668                .map(|x| x.name())
1669                .collect::<Vec<_>>()
1670                .join(", ")
1671        ));
1672    }
1673    let feats = features_for(v, feats, had);
1674    parse_impl(&rest, v, feats)
1675}
1676
1677/// 解析 SML 文本,同时限制文档使用的**特性子集**必须在 `allowed` 内。
1678///
1679/// 与 [`parse_allowed`](版本范围)配套:`allowed` 是调用方(库作者)给出的
1680/// 白名单,文档内部的 `@feature enable/disable` 只能**收窄**这个集合,
1681/// 不能扩宽——否则文档就能自行绕过调用方的限制。交集为空则报错。
1682///
1683/// 未声明任何 `@feature` 的文档若仅靠版本基线(如 v3),则基线特性与
1684/// `allowed` 交集;只要交集非空即放行。
1685pub fn parse_with_features(
1686    text: &str,
1687    allowed: FeatureSet,
1688) -> Result<(Value, FeatureSet), String> {
1689    let (rest, declared) = strip_version(text)?;
1690    let (rest, feats, base, had) = strip_features(&rest)?;
1691    let v = declared.or(base).unwrap_or(Version::V1);
1692    let feats = features_for(v, feats, had);
1693    let effective = feats.intersection(allowed);
1694    if effective.is_empty() {
1695        return Err(format!(
1696            "sml: 文档请求的特性 {feats} 与调用方允许的特性 {allowed} 无交集"
1697        ));
1698    }
1699    let val = parse_impl(&rest, v, effective)?;
1700    Ok((val, effective))
1701}
1702
1703/// 不含版本处理的底层解析(文本入口)
1704fn parse_impl(text: &str, version: Version, features: FeatureSet) -> Result<Value, String> {
1705    let toks = tokenize(text)?;
1706    parse_impl_tokens(toks, version, features)
1707}
1708
1709/// 不含版本处理的底层解析(token 流入口,供 include 展开后零拷贝复用)
1710fn parse_impl_tokens(
1711    toks: Vec<Tok>,
1712    version: Version,
1713    features: FeatureSet,
1714) -> Result<Value, String> {
1715    let mut p = Parser {
1716        toks,
1717        i: 0,
1718        fragments: BTreeMap::new(),
1719        contracts: BTreeMap::new(),
1720        features,
1721        ns_stack: Vec::new(),
1722    };
1723    // 顶层支持三种形态,与 `to_sml` 的输出对称:
1724    //   - `[ ... ]` 数组:to_sml 对非对象走 dump_inline,会输出顶层数组
1725    //     (如「历史记录」这类对象数组)。此前 parse 只认键值块,导致
1726    //     能序列化却读不回("期望键, 得 LBrack"),是不对称缺陷。
1727    //   - `{ ... }` 顶层对象块
1728    //   - 键值块(传统形态)
1729    // 注:顶层**标量**仍不可往返(SML 顶层需为容器),这是格式固有限制。
1730    match p.peek() {
1731        Some(Tok::LBrack) => {
1732            if !p.features.has(Feature::TopArray) {
1733                return Err("sml: 顶层数组需要特性 `top-level-array`,但当前特性集已禁用".into());
1734            }
1735            p.next();
1736            p.parse_array()
1737        }
1738        Some(Tok::LBrace) => {
1739            p.next();
1740            p.parse_block(Some(Tok::RBrace))
1741        }
1742        _ => p.parse_block(None),
1743    }
1744}
1745
1746// ---------------------------------------------------------------------------
1747// include 指令:把外部 .sml 文件内联进来
1748//
1749// 语法:`include "path.sml"` 或 `@include "path.sml"`(两种等价)
1750// 语义:**文本内联**(类似 C 的 #include),而非对象合并。
1751//   这样 include 可以出现在块内部引入一组字段,例如:
1752//       server web { &base include "common/port.sml" }
1753//   若做成对象合并就无法表达「注入若干字段到当前块」。
1754//
1755// 相对路径按**被包含文件自身所在目录**解析(与 C 预处理器一致),
1756// 而非进程工作目录,因此嵌套 include 时路径行为可预期。
1757// ---------------------------------------------------------------------------
1758
1759/// 嵌套深度上限:既防栈溢出,也让异常深层的引用尽早失败
1760const MAX_INCLUDE_DEPTH: usize = 32;
1761
1762/// 剥离行尾注释,正确跳过引号内的 `#`(如 `key: "a#b"` 中的 # 不是注释起点)
1763fn strip_line_comment(line: &str) -> &str {
1764    let bytes = line.as_bytes();
1765    let mut i = 0;
1766    let mut in_quote = false;
1767    while i < bytes.len() {
1768        match bytes[i] {
1769            b'"' => in_quote = !in_quote,
1770            // 引号内的反斜杠会转义下一个字符,需整体跳过
1771            b'\\' if in_quote => i += 1,
1772            b'#' if !in_quote => return &line[..i],
1773            _ => {}
1774        }
1775        i += 1;
1776    }
1777    line
1778}
1779
1780/// 单个 include 目标的解析结果。
1781#[derive(Debug, Clone, PartialEq, Eq)]
1782pub struct IncludeTarget {
1783    /// 相对路径或裸名(无扩展名时按 `implicit-ns` 推导 `as`)。
1784    pub raw: String,
1785    /// 命名空间(点分路径 `a.b.c`)。`None` 表示普通内联。
1786    /// 若 `raw` 无扩展名且开启 `implicit-ns`,则自动填充为文件名。
1787    pub namespace: Option<String>,
1788    /// 是否经 `import` 关键字(语义等同 `include`)。
1789    pub via_import: bool,
1790}
1791
1792/// 解析一行 include / import 指令,返回 0..N 个目标。
1793///
1794/// 支持形态(逗号分隔多目标,`import` 为 `include` 别名):
1795/// - `include "x.sml"`                普通内联(带扩展名、无 as)
1796/// - `include "foo"`                  无扩展名 ⇒ 默认 `as foo`(implicit-ns)
1797/// - `include "x.sml" as ui.form`     命名空间内联(点分路径)
1798/// - `include "a", "b" as y, "c"`     多目标(multi-include)
1799/// - `import ui.buttons, admin.panel`  import 别名
1800/// - `include "*.sml"`                glob 通配(需 `glob-include`)
1801/// - `include re:"widget_.*\.sml"`    正则匹配(需 `regex-include`)
1802///
1803/// 返回 `Ok(None)` 表示该行不是 include 指令;`Err` 表示特性未开启等语义错误。
1804fn parse_include_line(line: &str, features: FeatureSet) -> Result<Option<Vec<IncludeTarget>>, String> {
1805    let content = strip_line_comment(line).trim();
1806    let content = content.strip_prefix('@').unwrap_or(content).trim_start();
1807    // 轻量手写解析,不依赖 tokenize(避免 `*` 等字符在 tokenize 阶段被误判)。
1808    // 形式:`include "x" [as ns], "y" as ns2, ...`(import 等价)
1809    let (via_import, rest) = if let Some(r) = content.strip_prefix("include ") {
1810        (false, r.trim_start())
1811    } else if let Some(r) = content.strip_prefix("import ") {
1812        (true, r.trim_start())
1813    } else {
1814        return Ok(None);
1815    };
1816    if !features.has(Feature::Include) {
1817        return Ok(None);
1818    }
1819    let mut targets: Vec<IncludeTarget> = Vec::new();
1820    let mut rest = rest;
1821    loop {
1822        // 提取一个路径(引号串或裸词,直到逗号 / as / 行尾)
1823        let (path, tail) = match next_token(rest) {
1824            Some((p, t)) => (p, t),
1825            None => {
1826                if targets.is_empty() && rest.trim().is_empty() {
1827                    return Ok(None);
1828                } else {
1829                    break;
1830                }
1831            }
1832        };
1833        rest = tail.trim_start();
1834        // 可选 `as ns`
1835        let mut ns: Option<String> = None;
1836        let rest_after = if let Some(stripped) = rest.strip_prefix("as ") {
1837            let (n, t) = match next_token(stripped.trim_start()) {
1838                Some((n, t)) => (n, t),
1839                None => return Ok(None),
1840            };
1841            ns = Some(n);
1842            t.trim_start()
1843        } else {
1844            rest
1845        };
1846        targets.push(finalize_target(path, ns, via_import, features));
1847        // 逗号分隔多目标
1848        if let Some(stripped) = rest_after.strip_prefix(',') {
1849            if !features.has(Feature::MultiInclude) {
1850                return Ok(None);
1851            }
1852            rest = stripped.trim_start();
1853            continue;
1854        } else {
1855            rest = rest_after;
1856            break;
1857        }
1858    }
1859    if targets.is_empty() {
1860        return Ok(None);
1861    }
1862    // 特性预检查:glob / regex 模式在解析阶段就拦截(避免走到普通路径解析引发诡异错误)
1863    for t in &targets {
1864        // 先查 re: 前缀(正则模式里的 `*` 是元字符,不是 glob 通配)
1865        if t.raw.starts_with("re:") {
1866            if !features.has(Feature::RegexInclude) {
1867                return Err("sml: 正则 include 需要特性 `regex-include`(请 @feature enable regex-include)".into());
1868            }
1869            continue;
1870        }
1871        if t.raw.contains('*') && !features.has(Feature::GlobInclude) {
1872            return Err("sml: 通配 include 需要特性 `glob-include`(请 @feature enable glob-include)".into());
1873        }
1874    }
1875    Ok(Some(targets))
1876}
1877
1878/// 从字符串开头提取下一个 token:引号串(支持 `\"` 与 `\\`)或直到空白/逗号/`as` 的裸词。
1879/// 返回 (token 文本, 剩余字符串)。
1880fn next_token(s: &str) -> Option<(String, &str)> {
1881    let s = s.trim_start();
1882    if s.is_empty() {
1883        return None;
1884    }
1885    if s.starts_with('"') {
1886        // 引号串(按字节处理,路径通常为 ASCII)
1887        let bytes = s.as_bytes();
1888        let mut i = 1;
1889        let mut out = String::new();
1890        while i < bytes.len() {
1891            if bytes[i] == b'"' {
1892                i += 1;
1893                break;
1894            }
1895            if bytes[i] == b'\\' && i + 1 < bytes.len() {
1896                // 转义:保留转义后的字符(\. -> .,\" -> " 等)
1897                i += 1;
1898                out.push(bytes[i] as char);
1899                i += 1;
1900            } else {
1901                out.push(bytes[i] as char);
1902                i += 1;
1903            }
1904        }
1905        Some((out, &s[i..]))
1906    } else {
1907        // 裸词:取到空白或逗号
1908        let end = s
1909            .find(|c: char| c.is_whitespace() || c == ',')
1910            .unwrap_or(s.len());
1911        let (tok, tail) = s.split_at(end);
1912        Some((tok.trim().to_string(), tail))
1913    }
1914}
1915
1916/// 根据原始路径与可选命名空间,套用 implicit-ns 规则,产出最终目标。
1917fn finalize_target(
1918    raw: String,
1919    ns: Option<String>,
1920    via_import: bool,
1921    features: FeatureSet,
1922) -> IncludeTarget {
1923    let namespace = match ns {
1924        Some(n) => Some(n),
1925        None => {
1926            // `import a.b.c`:点分一律视为命名空间路径,自动 `as a.b.c`
1927            // `include "foo"`(无点):implicit-ns 默认以文件名为命名空间
1928            if via_import || (features.has(Feature::ImplicitNs) && !raw.contains('.')) {
1929                Some(raw.clone())
1930            } else {
1931                None
1932            }
1933        }
1934    };
1935    IncludeTarget {
1936        raw,
1937        namespace,
1938        via_import,
1939    }
1940}
1941
1942/// 把一个 include 目标解析为 0..N 个实际文件路径(已相对 `base` 解析、未 canonicalize)。
1943///
1944/// 支持:
1945/// - glob:`raw` 含 `*` 且开启 `glob-include` → 遍历 `base` 下直接条目做 `*` 通配匹配
1946/// - 正则:`raw` 以 `re:"..."` 形式且开启 `regex-include` → 遍历 `base` 下条目做最小正则匹配
1947/// - ext-rewrite:开启 `ext-rewrite` 时允许 `raw` 带非 `.sml` 扩展名(否则按原补 `.sml` 逻辑)
1948/// - 普通:`import` 点分转目录层级、裸名补 `.sml`
1949fn resolve_target_paths(
1950    t: &IncludeTarget,
1951    base: &Path,
1952    features: FeatureSet,
1953) -> Result<Vec<PathBuf>, String> {
1954    // 正则模式:re:"<pattern>"
1955    if let Some(pat) = t.raw.strip_prefix("re:") {
1956        if !features.has(Feature::RegexInclude) {
1957            return Err("sml: 正则 include 需要特性 `regex-include`(请 @feature enable regex-include)".into());
1958        }
1959        let pat = pat.trim_matches('"');
1960        // 模式可含目录前缀(如 re:"lib/widget_.*"):拆出目录并入 base(归一化分隔符)
1961        let pat = pat.replace('/', std::path::MAIN_SEPARATOR_STR);
1962        let (dir, pat) = split_dir(&pat);
1963        return glob_or_regex_dir(&base.join(dir), pat, Some(pat), features);
1964    }
1965    // glob 模式:含 `*`
1966    if t.raw.contains('*') {
1967        if !features.has(Feature::GlobInclude) {
1968            return Err("sml: 通配 include 需要特性 `glob-include`(请 @feature enable glob-include)".into());
1969        }
1970        let normalized = t.raw.replace('/', std::path::MAIN_SEPARATOR_STR);
1971        let (dir, pat) = split_dir(&normalized);
1972        return glob_or_regex_dir(&base.join(dir), pat, None, features);
1973    }
1974    // 普通路径
1975    let path = if t.via_import {
1976        let rel = t
1977            .raw
1978            .split('.')
1979            .collect::<Vec<_>>()
1980            .join(std::path::MAIN_SEPARATOR_STR);
1981        base.join(rel).with_extension("sml")
1982    } else if t.raw.contains('.') {
1983        // 带扩展名:默认直接读该文件
1984        // 开启 ext-rewrite 时允许非 .sml 扩展名(当 sml 解析);关闭时若非 .sml 也允许读,
1985        // 但语义上仍要求文件存在,由 canonicalize 报错兜底。
1986        let _ = features.has(Feature::ExtRewrite);
1987        base.join(&t.raw)
1988    } else {
1989        base.join(format!("{}.sml", t.raw))
1990    };
1991    Ok(vec![path])
1992}
1993
1994/// 遍历 `base` 目录的直接条目,按 glob(`pattern` 含 `*`)或正则(`regex` 为 Some)匹配,
1995/// 把 `a/b/pattern` 拆成 (`a/b`, `pattern`),便于把目录部分并入 base。
1996fn split_dir(pat: &str) -> (&str, &str) {
1997    match pat.rfind(std::path::MAIN_SEPARATOR) {
1998        Some(idx) => (&pat[..idx], &pat[idx + 1..]),
1999        None => ("", pat),
2000    }
2001}
2002
2003/// 返回命中的完整路径。目录本身不作为命中(仅文件)。
2004fn glob_or_regex_dir(
2005    base: &Path,
2006    pattern: &str,
2007    regex: Option<&str>,
2008    _features: FeatureSet,
2009) -> Result<Vec<PathBuf>, String> {
2010    let mut hits: Vec<PathBuf> = Vec::new();
2011    let entries = std::fs::read_dir(base)
2012        .map_err(|e| format!("include 目录读取失败 {}: {e}", base.display()))?;
2013    // 用于正则匹配的模式字符串(不含 re: 前缀与引号)
2014    let re = regex.map(|r| compile_regex(r));
2015    for ent in entries {
2016        let ent = ent.map_err(|e| format!("include 目录遍历失败: {e}"))?;
2017        let p = ent.path();
2018        if p.is_dir() {
2019            continue; // 只匹配文件
2020        }
2021        let name = match p.file_name().and_then(|n| n.to_str()) {
2022            Some(n) => n,
2023            None => continue,
2024        };
2025        let matched = if let Some(re) = &re {
2026            regex_matches(re, name)
2027        } else {
2028            // glob:`pattern` 形如 `*.sml` 或 `widgets/*.sml`;这里只处理文件名部分的通配
2029            let pat_file = pattern.rsplit(std::path::MAIN_SEPARATOR).next().unwrap_or(pattern);
2030            glob_matches(pat_file, name)
2031        };
2032        if matched {
2033            hits.push(p);
2034        }
2035    }
2036    // 结果按文件名排序,保证跨平台顺序稳定
2037    hits.sort();
2038    Ok(hits)
2039}
2040
2041/// 手写最小 glob 匹配(仅支持 `*` 通配,匹配整个文件名)。
2042fn glob_matches(pattern: &str, text: &str) -> bool {
2043    // 将 `a*b*c` 拆分为字面段,段间用 `*` 连接
2044    let segs: Vec<&str> = pattern.split('*').collect();
2045    if segs.is_empty() {
2046        return text.is_empty();
2047    }
2048    let mut pos = 0usize;
2049    // 首段若非 `*` 开头,必须前缀匹配
2050    if !pattern.starts_with('*') {
2051        if !text[pos..].starts_with(segs[0]) {
2052            return false;
2053        }
2054        pos += segs[0].len();
2055    }
2056    for seg in &segs[if pattern.starts_with('*') { 0 } else { 1 }..] {
2057        if seg.is_empty() {
2058            continue;
2059        }
2060        match text[pos..].find(seg) {
2061            Some(idx) => pos += idx + seg.len(),
2062            None => return false,
2063        }
2064    }
2065    // 末段若非 `*` 结尾,必须后缀匹配
2066    if !pattern.ends_with('*') {
2067        if pos != text.len() {
2068            return false;
2069        }
2070    }
2071    true
2072}
2073
2074/// 编译一个受限正则(支持 `. * + ? ^ $ [a-z] [^a-z] \.` 转义),返回可匹配闭包用的结构。
2075/// 这里采用「NFA-less」的回溯匹配器,足够文件名场景使用。
2076struct MiniRegex {
2077    pattern: String,
2078}
2079
2080fn compile_regex(pat: &str) -> MiniRegex {
2081    // 去掉可能的首尾 `^`/`$` 锚(由 matcher 解释)
2082    MiniRegex {
2083        pattern: pat.to_string(),
2084    }
2085}
2086
2087/// 用受限正则匹配整个 `text`(默认全匹配,支持 `^`/`$` 锚点)。
2088fn regex_matches(re: &MiniRegex, text: &str) -> bool {
2089    let pat = &re.pattern;
2090    let anchored_start = pat.starts_with('^');
2091    let anchored_end = pat.ends_with('$');
2092    let p = if anchored_start { &pat[1..] } else { pat };
2093    let p = if anchored_end { &p[..p.len().saturating_sub(1)] } else { p };
2094    // 尝试从 text 的每个位置开始匹配(非锚定时)
2095    if anchored_start {
2096        backtrack_match(p, text, 0).is_some()
2097    } else {
2098        for start in 0..=text.len() {
2099            if backtrack_match(p, text, start).is_some() {
2100                if !anchored_end {
2101                    return true;
2102                }
2103                // 锚定结尾:必须匹配到 text 末端
2104                if backtrack_match(p, text, start) == Some(text.len()) {
2105                    return true;
2106                }
2107            }
2108        }
2109        false
2110    }
2111}
2112
2113/// 回溯匹配:从 `text[ti]` 开始尝试匹配 `pat[pi]`,返回成功时 text 的消耗终点(usize)。
2114fn backtrack_match(pat: &str, text: &str, ti: usize) -> Option<usize> {
2115    // 递归实现,模式索引 pi 通过 chars 迭代
2116    let pchars: Vec<char> = pat.chars().collect();
2117    let tchars: Vec<char> = text.chars().collect();
2118    fn go(pchars: &[char], tchars: &[char], pi: usize, ti: usize) -> Option<usize> {
2119        let mut pi = pi;
2120        let mut ti = ti;
2121        while pi < pchars.len() {
2122            match pchars[pi] {
2123                '\\' => {
2124                    // 转义下一个字符(如 \. 匹配字面的 .)
2125                    if pi + 1 >= pchars.len() {
2126                        return None;
2127                    }
2128                    let pc = pchars[pi + 1];
2129                    if ti >= tchars.len() || tchars[ti] != pc {
2130                        return None;
2131                    }
2132                    pi += 2;
2133                    ti += 1;
2134                }
2135                '.' => {
2136                    if ti >= tchars.len() {
2137                        return None;
2138                    }
2139                    pi += 1;
2140                    ti += 1;
2141                }
2142                '*' => {
2143                    // 匹配前一个原子零次或多次(贪婪)
2144                    // 回退:尝试匹配零次(跳过 * 与前一原子),或匹配一次后继续
2145                    let prev = if pi >= 1 { Some(pchars[pi - 1]) } else { None };
2146                    // 零次:跳过 '*'(以及其前的普通原子已由上层处理,这里仅跳过 '*')
2147                    // 但为简化,* 作用于前一原子:先尝试消耗一字符再递归
2148                    if ti < tchars.len() {
2149                        // 贪婪:尽量多匹配
2150                        let mut end = ti;
2151                        match prev {
2152                            Some('.') => {
2153                                while end < tchars.len() {
2154                                    end += 1;
2155                                }
2156                            }
2157                            Some(c) if c != '\\' => {
2158                                while end < tchars.len() && tchars[end] == c {
2159                                    end += 1;
2160                                }
2161                            }
2162                            _ => {}
2163                        }
2164                        // 从 end 回退尝试让后续模式匹配
2165                        let mut e = end;
2166                        while e >= ti {
2167                            if let Some(r) = go(pchars, tchars, pi + 1, e) {
2168                                return Some(r);
2169                            }
2170                            if e == ti {
2171                                break;
2172                            }
2173                            e -= 1;
2174                        }
2175                    }
2176                    // 零次匹配:跳过 '*'
2177                    return go(pchars, tchars, pi + 1, ti);
2178                }
2179                '+' => {
2180                    if ti >= tchars.len() {
2181                        return None;
2182                    }
2183                    let prev = pchars.get(pi.wrapping_sub(1)).copied();
2184                    let mut consumed = 0;
2185                    match prev {
2186                        Some('.') => {
2187                            if ti >= tchars.len() {
2188                                return None;
2189                            }
2190                            consumed = 1;
2191                        }
2192                        Some(c) if c != '\\' => {
2193                            if tchars[ti] != c {
2194                                return None;
2195                            }
2196                            consumed = 1;
2197                            while ti + consumed < tchars.len()
2198                                && tchars[ti + consumed] == c
2199                            {
2200                                consumed += 1;
2201                            }
2202                        }
2203                        _ => return None,
2204                    }
2205                    pi += 1;
2206                    ti += consumed;
2207                }
2208                '?' => {
2209                    // 前一原子的零或一
2210                    let prev = pchars.get(pi.wrapping_sub(1)).copied();
2211                    if ti < tchars.len() {
2212                        match prev {
2213                            Some('.') => {
2214                                pi += 1;
2215                                ti += 1;
2216                            }
2217                            Some(c) if c != '\\' => {
2218                                if tchars[ti] == c {
2219                                    pi += 1;
2220                                    ti += 1;
2221                                } else {
2222                                    pi += 1; // 零次
2223                                }
2224                            }
2225                            _ => {
2226                                pi += 1; // 零次
2227                            }
2228                        }
2229                    } else {
2230                        pi += 1;
2231                    }
2232                }
2233                '[' => {
2234                    // 字符类 [abc] 或 [^abc] 或 [a-z]
2235                    let mut j = pi + 1;
2236                    let negate = if j < pchars.len() && pchars[j] == '^' {
2237                        j += 1;
2238                        true
2239                    } else {
2240                        false
2241                    };
2242                    let mut cls = Vec::new();
2243                    while j < pchars.len() && pchars[j] != ']' {
2244                        if j + 2 < pchars.len()
2245                            && pchars[j + 1] == '-'
2246                            && pchars[j + 2] != ']'
2247                        {
2248                            let lo = pchars[j];
2249                            let hi = pchars[j + 2];
2250                            cls.push((lo, hi));
2251                            j += 3;
2252                        } else {
2253                            cls.push((pchars[j], pchars[j]));
2254                            j += 1;
2255                        }
2256                    }
2257                    if j >= pchars.len() {
2258                        return None; // 未闭合
2259                    }
2260                    if ti >= tchars.len() {
2261                        return None;
2262                    }
2263                    let c = tchars[ti];
2264                    let in_cls = cls.iter().any(|(lo, hi)| c >= *lo && c <= *hi);
2265                    let ok = if negate { !in_cls } else { in_cls };
2266                    if !ok {
2267                        return None;
2268                    }
2269                    pi = j + 1;
2270                    ti += 1;
2271                }
2272                c => {
2273                    if ti >= tchars.len() || tchars[ti] != c {
2274                        return None;
2275                    }
2276                    pi += 1;
2277                    ti += 1;
2278                }
2279            }
2280        }
2281        Some(ti)
2282    }
2283    go(&pchars, &tchars, 0, ti)
2284}
2285
2286/// 把 text 中的 include 指令递归展开为不含指令的纯 SML 文本。
2287///
2288/// `base` 为相对路径的解析基准目录(通常是当前文件所在目录)。
2289/// `features` 决定是否允许 `include` / `namespace`(禁用则遇到指令即报错)。
2290/// 循环引用与缺失文件都会返回错误,不会静默跳过。
2291/// 把 text 中的 include 指令递归展开为 token 流(方向 B:零拷贝,不拼巨大中间字符串)。
2292///
2293/// 每个被包含文件只 `tokenize` 一次;命名空间 `as a.b.c` 用零拷贝的开/闭块 token
2294/// (`Word(a) LBrace Word(b) LBrace Word(c) LBrace ... RBrace RBrace RBrace`)包裹,
2295/// 不复制文件内容文本。子文件内的 `@version`/`@feature` 指令行在 tokenize 前被剥离,
2296/// 由主文件统一控制特性集(符合「文档只能收窄」的设计)。
2297pub fn resolve_includes(
2298    text: &str,
2299    base: &Path,
2300    features: FeatureSet,
2301) -> Result<Vec<Tok>, String> {
2302    let mut stack: Vec<PathBuf> = Vec::new();
2303    let mut toks: Vec<Tok> = Vec::new();
2304    expand_includes(text, base, &mut stack, features, &mut toks)?;
2305    Ok(toks)
2306}
2307
2308/// 递归展开 include 到 `out` token 流。
2309fn expand_includes(
2310    text: &str,
2311    base: &Path,
2312    stack: &mut Vec<PathBuf>,
2313    features: FeatureSet,
2314    out: &mut Vec<Tok>,
2315) -> Result<(), String> {
2316    if stack.len() >= MAX_INCLUDE_DEPTH {
2317        return Err(format!("include 嵌套超过 {MAX_INCLUDE_DEPTH} 层"));
2318    }
2319    for line in text.lines() {
2320        match parse_include_line(line, features)? {
2321            Some(targets) => {
2322                if !features.has(Feature::Include) {
2323                    return Err("sml: 当前特性集禁用了 include(include 特性)".into());
2324                }
2325                for t in targets {
2326                    if t.namespace.is_some() && !features.has(Feature::Namespace) {
2327                        return Err(
2328                            "sml: 当前特性集禁用了命名空间包含(namespace 特性)".into(),
2329                        );
2330                    }
2331                    // 把一个 target 解析为 0..N 个实际文件路径(支持 glob/regex/ext-rewrite)
2332                    let paths = resolve_target_paths(&t, base, features)?;
2333                    for path in paths {
2334                        let canon = path.canonicalize().map_err(|e| {
2335                            format!("include 无法定位 {}: {e}", path.display())
2336                        })?;
2337                        // stack 是「当前正在展开的文件链」,命中即成环
2338                        if stack.iter().any(|p| p == &canon) {
2339                            return Err(format!("include 循环引用: {}", canon.display()));
2340                        }
2341                        let content = std::fs::read_to_string(&canon)
2342                            .map_err(|e| format!("include 读取失败 {}: {e}", canon.display()))?;
2343                        let child_base = canon
2344                            .parent()
2345                            .map(|p| p.to_path_buf())
2346                            .unwrap_or_else(|| PathBuf::from("."));
2347                        stack.push(canon.clone());
2348                        // 命名空间包含:用 `ns { ... }` 包裹子文件 tokens(零拷贝)
2349                        if let Some(ns) = &t.namespace {
2350                            for seg in ns.split('.') {
2351                                out.push(Tok::Word(seg.to_string()));
2352                                out.push(Tok::LBrace);
2353                            }
2354                            let inner =
2355                                expand_file_tokens(&content, &child_base, stack, features)?;
2356                            out.extend(inner);
2357                            for _ in ns.split('.') {
2358                                out.push(Tok::RBrace);
2359                            }
2360                        } else {
2361                            let inner =
2362                                expand_file_tokens(&content, &child_base, stack, features)?;
2363                            out.extend(inner);
2364                        }
2365                        stack.pop();
2366                    }
2367                }
2368            }
2369            None => {
2370                // 非 include 行:直接 tokenize 该行并追加(保持行级语义,零拷贝)
2371                let line_toks = tokenize(line).map_err(|e| {
2372                    format!("include 预处理词法错误:{e}(于行:{line})")
2373                })?;
2374                out.extend(line_toks);
2375            }
2376        }
2377    }
2378    Ok(())
2379}
2380
2381/// 读取单个文件内容,剥离其自身的 `@version`/`@feature` 行后 tokenize。
2382/// 子文件不引入新特性维度,由主文件/调用方统一控制。
2383fn expand_file_tokens(
2384    content: &str,
2385    base: &Path,
2386    stack: &mut Vec<PathBuf>,
2387    features: FeatureSet,
2388) -> Result<Vec<Tok>, String> {
2389    // 剥离子文件内的版本/特性指令行,避免污染 token 流
2390    let cleaned: String = content
2391        .lines()
2392        .filter(|l| {
2393            let t = strip_line_comment(l).trim();
2394            let t = t.strip_prefix('@').unwrap_or(t).trim_start();
2395            !(t.starts_with("version") || t.starts_with("feature"))
2396        })
2397        .collect::<Vec<_>>()
2398        .join("\n");
2399    let mut toks = Vec::new();
2400    expand_includes(&cleaned, base, stack, features, &mut toks)?;
2401    Ok(toks)
2402}
2403
2404/// 解析 SML 文件,并展开其中的 include 指令。
2405///
2406/// 相对路径以**该文件所在目录**为基准。include 展开为零拷贝 token 流,
2407/// 不拼接中间大字符串(方向 B)。
2408pub fn parse_file(path: impl AsRef<Path>) -> Result<Value, String> {
2409    let path = path.as_ref();
2410    let text = std::fs::read_to_string(path)
2411        .map_err(|e| format!("读取失败 {}: {e}", path.display()))?;
2412    let base = path
2413        .parent()
2414        .map(|p| p.to_path_buf())
2415        .unwrap_or_else(|| PathBuf::from("."));
2416    // 主文件先剥离版本/特性指令。
2417    // 便捷入口 `parse_file` 的「调用方允许集」为全开(文档自身声明决定启用哪些特性,
2418    // 真正的调用方限制由 `parse_with_features` / `parse_allowed` 负责)。
2419    let (rest, declared) = strip_version(&text)?;
2420    let (rest, feats, base_ver, had) = strip_features(&rest)?;
2421    let v = declared.or(base_ver).unwrap_or(Version::V1);
2422    let feats = features_for(v, feats, had);
2423    let allowed = FeatureSet::all().intersection(feats);
2424    let toks = resolve_includes(&rest, &base, allowed)?;
2425    parse_impl_tokens(toks, v, allowed)
2426}
2427
2428/// 解析到对象 (失败抛 `ParseError`)
2429pub fn loads(text: &str) -> Result<Value, ParseError> {
2430    parse(text).map_err(ParseError)
2431}
2432
2433#[derive(Debug)]
2434pub struct ParseError(pub String);
2435
2436impl fmt::Display for ParseError {
2437    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2438        write!(f, "sml parse error: {}", self.0)
2439    }
2440}
2441
2442impl std::error::Error for ParseError {}
2443
2444// ---------------------------------------------------------------------------
2445// 序列化
2446// ---------------------------------------------------------------------------
2447
2448fn quote_if_needed(s: &str) -> String {
2449    if s.is_empty() || s.contains([' ', '\t', '\n', '\r', ':', '#', '{', '}']) {
2450        format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
2451    } else {
2452        s.to_string()
2453    }
2454}
2455
2456/// 输出一个块。含 `__type` / `__name` 的块也按普通块原样输出所有键,
2457/// 保证元数据(枚举带数据变体的 `__type` 标记等)可完整往返。
2458/// SML 的裸块 `type [name] { ... }` 解析后正是 `__type` / `__name` 键。
2459fn dump_block(m: &BTreeMap<String, Value>, indent: usize, out: &mut String) {
2460    if m.is_empty() {
2461        out.push_str("{}");
2462        return;
2463    }
2464    out.push_str(&format!("\n{}{{", "  ".repeat(indent)));
2465    for (k, val) in m {
2466        out.push_str(&format!("\n{}{}: ", "  ".repeat(indent + 1), k));
2467        dump_value(val, indent + 1, out);
2468    }
2469    out.push_str(&format!("\n{}}}", "  ".repeat(indent)));
2470}
2471
2472fn dump_value(v: &Value, indent: usize, out: &mut String) {
2473    let pad = "  ".repeat(indent);
2474    match v {
2475        Value::Null => out.push_str("null"),
2476        Value::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
2477        Value::Int(i) => out.push_str(&i.to_string()),
2478        Value::Float(f) => out.push_str(&format!("{}", f)),
2479        Value::Str(s) => out.push_str(&quote_if_needed(s)),
2480        Value::Array(a) => {
2481            if a.is_empty() {
2482                out.push_str("[]");
2483            } else {
2484                out.push('[');
2485                for e in a {
2486                    out.push('\n');
2487                    out.push_str(&format!("{}{}", "  ".repeat(indent + 1), dump_inline(e)));
2488                }
2489                out.push_str(&format!("\n{}]", pad));
2490            }
2491        }
2492        Value::Object(m) => dump_block(m, indent, out),
2493    }
2494}
2495
2496fn dump_scalar(v: &Value) -> String {
2497    match v {
2498        Value::Null => "null".into(),
2499        Value::Bool(b) => b.to_string(),
2500        Value::Int(i) => i.to_string(),
2501        Value::Float(f) => f.to_string(),
2502        Value::Str(s) => quote_if_needed(s),
2503        _ => "".into(),
2504    }
2505}
2506
2507fn dump_inline(v: &Value) -> String {
2508    match v {
2509        Value::Object(m) => {
2510            // 含 __type/__name 的块原样输出所有键,保证元数据可往返
2511            let parts: Vec<String> = m
2512                .iter()
2513                .map(|(k, val)| format!("{}: {}", k, dump_inline(val)))
2514                .collect();
2515            format!("{{ {} }}", parts.join(", "))
2516        }
2517        Value::Array(a) => {
2518            let parts: Vec<String> = a.iter().map(dump_inline).collect();
2519            format!("[ {} ]", parts.join(", "))
2520        }
2521        other => dump_scalar(other),
2522    }
2523}
2524
2525/// 序列化回 SML 文本 (round-trip)
2526///
2527/// 含 `__type` / `__name` 的块(如枚举带数据变体序列化的结果)
2528/// 会原样输出所有键,保证元数据可完整往返。
2529pub fn to_sml(v: &Value) -> String {
2530    let mut out = String::new();
2531    if let Value::Object(m) = v {
2532        if m.contains_key("__type") {
2533            dump_block(m, 0, &mut out);
2534        } else {
2535            for (k, val) in m {
2536                out.push_str(&format!("{}: ", k));
2537                dump_value(val, 0, &mut out);
2538                out.push('\n');
2539            }
2540        }
2541    } else {
2542        out.push_str(&dump_inline(v));
2543    }
2544    out
2545}
2546
2547// ---------------------------------------------------------------------------
2548// C-ABI (cdylib, 供 C / 其它语言调用)
2549// ---------------------------------------------------------------------------
2550
2551use std::os::raw::{c_char, c_int};
2552use std::ptr;
2553
2554fn cstr(s: &str) -> *mut c_char {
2555    let c = std::ffi::CString::new(s).unwrap_or_default();
2556    c.into_raw()
2557}
2558
2559/// sml_parse(text) -> 返回 JSON 字符串 (调用方 sml_free 释放); 失败返回 NULL
2560#[cfg_attr(edge2024, unsafe(no_mangle))]
2561#[cfg_attr(not(edge2024), no_mangle)]
2562pub extern "C" fn sml_parse(text: *const c_char) -> *mut c_char {
2563    if text.is_null() {
2564        return ptr::null_mut();
2565    }
2566    let t = unsafe { std::ffi::CStr::from_ptr(text) }.to_string_lossy().into_owned();
2567    match parse(&t) {
2568        Ok(v) => cstr(&jsonify(&v)),
2569        Err(_) => ptr::null_mut(),
2570    }
2571}
2572
2573/// sml_dump(json) -> 接受 JSON 字符串, 序列化为 SML; 调用方 sml_free
2574#[cfg_attr(edge2024, unsafe(no_mangle))]
2575#[cfg_attr(not(edge2024), no_mangle)]
2576pub extern "C" fn sml_dump(json: *const c_char) -> *mut c_char {
2577    if json.is_null() {
2578        return ptr::null_mut();
2579    }
2580    let j = unsafe { std::ffi::CStr::from_ptr(json) }.to_string_lossy().into_owned();
2581    match json_to_value(&j) {
2582        Some(v) => cstr(&to_sml(&v)),
2583        None => ptr::null_mut(),
2584    }
2585}
2586
2587/// sml_free(p): 释放由 sml_parse / sml_dump 返回的字符串
2588#[cfg_attr(edge2024, unsafe(no_mangle))]
2589#[cfg_attr(not(edge2024), no_mangle)]
2590pub unsafe extern "C" fn sml_free(p: *mut c_char) {
2591    if !p.is_null() {
2592        drop(unsafe { std::ffi::CString::from_raw(p) });
2593    }
2594}
2595
2596/// sml_version() -> 版本字符串 (调用方 sml_free)
2597#[cfg_attr(edge2024, unsafe(no_mangle))]
2598#[cfg_attr(not(edge2024), no_mangle)]
2599pub extern "C" fn sml_version() -> *mut c_char {
2600    cstr(concat!("sml ", env!("CARGO_PKG_VERSION")))
2601}
2602
2603// ---------------------------------------------------------------------------
2604// 内部: JSON <-> Value (供 C-ABI 便捷桥)
2605// ---------------------------------------------------------------------------
2606
2607fn jsonify(v: &Value) -> String {
2608    fn esc(s: &str) -> String {
2609        s.replace('\\', "\\\\").replace('"', "\\\"")
2610    }
2611    match v {
2612        Value::Null => "null".into(),
2613        Value::Bool(b) => b.to_string(),
2614        Value::Int(i) => i.to_string(),
2615        Value::Float(f) => f.to_string(),
2616        Value::Str(s) => format!("\"{}\"", esc(s)),
2617        Value::Array(a) => {
2618            let parts: Vec<String> = a.iter().map(jsonify).collect();
2619            format!("[{}]", parts.join(","))
2620        }
2621        Value::Object(m) => {
2622            let parts: Vec<String> = m
2623                .iter()
2624                .map(|(k, val)| format!("\"{}\":{}", esc(k), jsonify(val)))
2625                .collect();
2626            format!("{{{}}}", parts.join(","))
2627        }
2628    }
2629}
2630
2631fn json_to_value(s: &str) -> Option<Value> {
2632    let bytes = s.as_bytes();
2633    let mut i = 0;
2634    let _n = bytes.len();
2635    let mut skip_ws = |b: &[u8], i: &mut usize| {
2636        while *i < b.len() && matches!(b[*i], b' ' | b'\t' | b'\n' | b'\r') {
2637            *i += 1;
2638        }
2639    };
2640    let mut parse_str = |b: &[u8], i: &mut usize| -> Option<String> {
2641        skip_ws(b, i);
2642        if *i >= b.len() || b[*i] != b'"' {
2643            return None;
2644        }
2645        *i += 1;
2646        let mut out = String::new();
2647        while *i < b.len() {
2648            let c = b[*i];
2649            if c == b'"' {
2650                *i += 1;
2651                return Some(out);
2652            }
2653            if c == b'\\' && *i + 1 < b.len() {
2654                *i += 1;
2655                let e = b[*i];
2656                out.push(match e {
2657                    b'n' => '\n',
2658                    b't' => '\t',
2659                    b'r' => '\r',
2660                    b'"' => '"',
2661                    b'\\' => '\\',
2662                    _ => e as char,
2663                });
2664            } else {
2665                out.push(c as char);
2666            }
2667            *i += 1;
2668        }
2669        None
2670    };
2671    fn parse_val_impl(
2672        b: &[u8],
2673        i: &mut usize,
2674        s: &str,
2675        parse_str: &dyn Fn(&[u8], &mut usize) -> Option<String>,
2676    ) -> Option<Value> {
2677        let mut skip_ws = |b: &[u8], i: &mut usize| {
2678            while *i < b.len() && matches!(b[*i], b' ' | b'\t' | b'\n' | b'\r') {
2679                *i += 1;
2680            }
2681        };
2682        skip_ws(b, i);
2683        if *i >= b.len() {
2684            return None;
2685        }
2686        match b[*i] {
2687            b'{' => {
2688                *i += 1;
2689                let mut m = BTreeMap::new();
2690                skip_ws(b, i);
2691                if *i < b.len() && b[*i] == b'}' {
2692                    *i += 1;
2693                    return Some(Value::Object(m));
2694                }
2695                loop {
2696                    skip_ws(b, i);
2697                    let k = parse_str(b, i)?;
2698                    skip_ws(b, i);
2699                    if *i < b.len() && b[*i] == b':' {
2700                        *i += 1;
2701                    }
2702                    let v = parse_val_impl(b, i, s, parse_str)?;
2703                    m.insert(k, v);
2704                    skip_ws(b, i);
2705                    if *i < b.len() && b[*i] == b',' {
2706                        *i += 1;
2707                    } else if *i < b.len() && b[*i] == b'}' {
2708                        *i += 1;
2709                        break;
2710                    }
2711                }
2712                Some(Value::Object(m))
2713            }
2714            b'[' => {
2715                *i += 1;
2716                let mut a = Vec::new();
2717                skip_ws(b, i);
2718                if *i < b.len() && b[*i] == b']' {
2719                    *i += 1;
2720                    return Some(Value::Array(a));
2721                }
2722                loop {
2723                    a.push(parse_val_impl(b, i, s, parse_str)?);
2724                    skip_ws(b, i);
2725                    if *i < b.len() && b[*i] == b',' {
2726                        *i += 1;
2727                    } else if *i < b.len() && b[*i] == b']' {
2728                        *i += 1;
2729                        break;
2730                    }
2731                }
2732                Some(Value::Array(a))
2733            }
2734            b'"' => parse_str(b, i).map(Value::Str),
2735            b't' => {
2736                if s[*i..].starts_with("true") {
2737                    *i += 4;
2738                    Some(Value::Bool(true))
2739                } else {
2740                    None
2741                }
2742            }
2743            b'f' => {
2744                if s[*i..].starts_with("false") {
2745                    *i += 5;
2746                    Some(Value::Bool(false))
2747                } else {
2748                    None
2749                }
2750            }
2751            b'n' => {
2752                if s[*i..].starts_with("null") {
2753                    *i += 4;
2754                    Some(Value::Null)
2755                } else {
2756                    None
2757                }
2758            }
2759            _ => {
2760                let start = *i;
2761                while *i < b.len()
2762                    && (b[*i].is_ascii_digit()
2763                        || matches!(b[*i], b'-' | b'+' | b'.' | b'e' | b'E'))
2764                {
2765                    *i += 1;
2766                }
2767                let tok = s[start..*i].to_string();
2768                if let Ok(iv) = tok.parse::<i64>() {
2769                    Some(Value::Int(iv))
2770                } else if let Ok(fv) = tok.parse::<f64>() {
2771                    Some(Value::Float(fv))
2772                } else {
2773                    None
2774                }
2775            }
2776        }
2777    }
2778    parse_val_impl(bytes, &mut i, s, &parse_str)
2779}
2780
2781// ---------------------------------------------------------------------------
2782// serde 支持(可选 feature:`serde`)
2783//
2784// 1) `Value` 实现 `Serialize`/`Deserialize`(手写而非 `#[derive]`:derive 会把
2785//    枚举表示为外部标签形式 Value::Int(5) -> {"Int":5},而配置场景要自然形状
2786//    5)。手写后 SML 的 Value 与 JSON/TOML/YAML 数据形状一致,可经任意 serde
2787//    后端进出。
2788// 2) `sml::serde::{from_str, from_value, to_value, to_string}`:serde 桥。
2789//    任何 `#[derive(serde::Serialize / Deserialize)]` 类型都能像 toml-rs 一样
2790//    一键从 SML 文本反序列化 / 序列化为 SML(枚举沿用 `__type` 约定)。
2791//
2792// 不启用该 feature 时 crate 保持零依赖。
2793// ---------------------------------------------------------------------------
2794
2795#[cfg(feature = "serde")]
2796pub mod serde {
2797    use super::Value;
2798    use ::serde::de::{self, MapAccess, SeqAccess, Visitor};
2799    use ::serde::ser::{
2800        SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
2801        SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
2802    };
2803    use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
2804    use ::std::collections::BTreeMap;
2805    use ::std::fmt;
2806
2807    /// serde 错误类型(自定义消息,实现 ser/de 两个 Error trait)
2808    type Error = ::serde::de::value::Error;
2809
2810    fn type_err(v: &Value, expected: &str) -> Error {
2811        de::Error::custom(format!(
2812            "期望 {expected},实际为 {}",
2813            super::__private::describe_value(v)
2814        ))
2815    }
2816
2817    impl Serialize for Value {
2818        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2819        where
2820            S: Serializer,
2821        {
2822            match self {
2823                Value::Null => serializer.serialize_unit(),
2824                Value::Bool(b) => serializer.serialize_bool(*b),
2825                Value::Int(i) => serializer.serialize_i64(*i),
2826                Value::Float(f) => serializer.serialize_f64(*f),
2827                Value::Str(s) => serializer.serialize_str(s),
2828                // Vec<Value> / 逐项委托,递归依赖 Value 自身的 impl
2829                Value::Array(a) => a.serialize(serializer),
2830                Value::Object(m) => {
2831                    let mut map = serializer.serialize_map(Some(m.len()))?;
2832                    for (k, v) in m {
2833                        map.serialize_entry(k, v)?;
2834                    }
2835                    map.end()
2836                }
2837            }
2838        }
2839    }
2840
2841    impl<'de> Deserialize<'de> for Value {
2842        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2843        where
2844            D: Deserializer<'de>,
2845        {
2846            // 交给格式自行判断类型(JSON 的数字/字符串/数组/对象都能落到对应变体)
2847            deserializer.deserialize_any(ValueVisitor)
2848        }
2849    }
2850
2851    struct ValueVisitor;
2852
2853    impl<'de> Visitor<'de> for ValueVisitor {
2854        type Value = Value;
2855
2856        fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
2857            f.write_str("any valid SML/JSON value")
2858        }
2859
2860        fn visit_unit<E: de::Error>(self) -> Result<Value, E> {
2861            Ok(Value::Null)
2862        }
2863        fn visit_none<E: de::Error>(self) -> Result<Value, E> {
2864            Ok(Value::Null)
2865        }
2866        fn visit_some<D>(self, d: D) -> Result<Value, D::Error>
2867        where
2868            D: Deserializer<'de>,
2869        {
2870            Deserialize::deserialize(d)
2871        }
2872        fn visit_bool<E: de::Error>(self, v: bool) -> Result<Value, E> {
2873            Ok(Value::Bool(v))
2874        }
2875        fn visit_i64<E: de::Error>(self, v: i64) -> Result<Value, E> {
2876            Ok(Value::Int(v))
2877        }
2878        // 超出 i64 的大整数退化为 Float,避免直接报错丢失数据
2879        fn visit_u64<E: de::Error>(self, v: u64) -> Result<Value, E> {
2880            Ok(i64::try_from(v)
2881                .map(Value::Int)
2882                .unwrap_or_else(|_| Value::Float(v as f64)))
2883        }
2884        fn visit_f64<E: de::Error>(self, v: f64) -> Result<Value, E> {
2885            Ok(Value::Float(v))
2886        }
2887        fn visit_str<E: de::Error>(self, v: &str) -> Result<Value, E> {
2888            Ok(Value::Str(v.to_string()))
2889        }
2890        fn visit_string<E: de::Error>(self, v: String) -> Result<Value, E> {
2891            Ok(Value::Str(v))
2892        }
2893        fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
2894        where
2895            A: SeqAccess<'de>,
2896        {
2897            let mut v = Vec::new();
2898            while let Some(x) = seq.next_element()? {
2899                v.push(x);
2900            }
2901            Ok(Value::Array(v))
2902        }
2903        fn visit_map<A>(self, mut map: A) -> Result<Value, A::Error>
2904        where
2905            A: MapAccess<'de>,
2906        {
2907            let mut m = BTreeMap::new();
2908            while let Some((k, v)) = map.next_entry::<String, Value>()? {
2909                m.insert(k, v);
2910            }
2911            Ok(Value::Object(m))
2912        }
2913    }
2914
2915    // -----------------------------------------------------------------------
2916    // serde 桥:任意 `serde::Serialize / Deserialize` 类型 <-> SML
2917    // -----------------------------------------------------------------------
2918
2919    /// 解析 SML 文本并一键反序列化到任意 serde 类型(等价于 `toml::from_str`)。
2920    ///
2921    /// ```rust
2922    /// # use serde::Deserialize;
2923    /// # #[derive(Deserialize, Debug)]
2924    /// # struct Server { host: String, port: i32 }
2925    /// let s: Server = sml::serde::from_str("host: web.example\nport: 8080\n").unwrap();
2926    /// assert_eq!(s.host, "web.example");
2927    /// ```
2928    pub fn from_str<T: de::DeserializeOwned>(text: &str) -> Result<T, String> {
2929        let value = crate::parse(text)?;
2930        from_value(value)
2931    }
2932
2933    /// 从任意 [`Value`] 反序列化到任意 serde 类型。
2934    pub fn from_value<T: de::DeserializeOwned>(value: Value) -> Result<T, String> {
2935        T::deserialize(ValueDeserializer(value)).map_err(|e| e.to_string())
2936    }
2937
2938    /// 任意 serde 类型序列化为 [`Value`](等价于 `serde_json::to_value`)。
2939    pub fn to_value<T: Serialize + ?Sized>(value: &T) -> Result<Value, String> {
2940        value.serialize(ValueSerializer).map_err(|e| e.to_string())
2941    }
2942
2943    /// 任意 serde 类型序列化为 SML 文本(等价于 `toml::to_string`)。
2944    pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, String> {
2945        Ok(crate::to_sml(&to_value(value)?))
2946    }
2947
2948    // ---- Serializer: T: Serialize -> Value ----
2949
2950    struct ValueSerializer;
2951
2952    impl Serializer for ValueSerializer {
2953        type Ok = Value;
2954        type Error = Error;
2955        type SerializeSeq = SeqSerializer;
2956        type SerializeTuple = SeqSerializer;
2957        type SerializeTupleStruct = SeqSerializer;
2958        type SerializeTupleVariant = TupleVariantSerializer;
2959        type SerializeMap = MapSerializer;
2960        type SerializeStruct = MapSerializer;
2961        type SerializeStructVariant = StructVariantSerializer;
2962
2963        fn serialize_bool(self, v: bool) -> Result<Value, Error> {
2964            Ok(Value::Bool(v))
2965        }
2966        fn serialize_i8(self, v: i8) -> Result<Value, Error> {
2967            Ok(Value::Int(v as i64))
2968        }
2969        fn serialize_i16(self, v: i16) -> Result<Value, Error> {
2970            Ok(Value::Int(v as i64))
2971        }
2972        fn serialize_i32(self, v: i32) -> Result<Value, Error> {
2973            Ok(Value::Int(v as i64))
2974        }
2975        fn serialize_i64(self, v: i64) -> Result<Value, Error> {
2976            Ok(Value::Int(v))
2977        }
2978        fn serialize_u8(self, v: u8) -> Result<Value, Error> {
2979            Ok(Value::Int(v as i64))
2980        }
2981        fn serialize_u16(self, v: u16) -> Result<Value, Error> {
2982            Ok(Value::Int(v as i64))
2983        }
2984        fn serialize_u32(self, v: u32) -> Result<Value, Error> {
2985            Ok(Value::Int(v as i64))
2986        }
2987        fn serialize_u64(self, v: u64) -> Result<Value, Error> {
2988            Ok(i64::try_from(v)
2989                .map(Value::Int)
2990                .unwrap_or_else(|_| Value::Float(v as f64)))
2991        }
2992        fn serialize_f32(self, v: f32) -> Result<Value, Error> {
2993            Ok(Value::Float(v as f64))
2994        }
2995        fn serialize_f64(self, v: f64) -> Result<Value, Error> {
2996            Ok(Value::Float(v))
2997        }
2998        fn serialize_char(self, v: char) -> Result<Value, Error> {
2999            Ok(Value::Str(v.to_string()))
3000        }
3001        fn serialize_str(self, v: &str) -> Result<Value, Error> {
3002            Ok(Value::Str(v.to_string()))
3003        }
3004        fn serialize_bytes(self, v: &[u8]) -> Result<Value, Error> {
3005            Ok(Value::Array(v.iter().map(|&b| Value::Int(b as i64)).collect()))
3006        }
3007        fn serialize_none(self) -> Result<Value, Error> {
3008            Ok(Value::Null)
3009        }
3010        fn serialize_some<T: Serialize + ?Sized>(self, v: &T) -> Result<Value, Error> {
3011            v.serialize(ValueSerializer)
3012        }
3013        fn serialize_unit(self) -> Result<Value, Error> {
3014            Ok(Value::Null)
3015        }
3016        fn serialize_unit_struct(self, _name: &'static str) -> Result<Value, Error> {
3017            Ok(Value::Null)
3018        }
3019        fn serialize_unit_variant(
3020            self,
3021            _name: &'static str,
3022            _idx: u32,
3023            variant: &'static str,
3024        ) -> Result<Value, Error> {
3025            Ok(Value::Str(variant.to_string()))
3026        }
3027        fn serialize_newtype_struct<T: Serialize + ?Sized>(
3028            self,
3029            _name: &'static str,
3030            v: &T,
3031        ) -> Result<Value, Error> {
3032            v.serialize(ValueSerializer)
3033        }
3034        fn serialize_newtype_variant<T: Serialize + ?Sized>(
3035            self,
3036            _name: &'static str,
3037            _idx: u32,
3038            variant: &'static str,
3039            value: &T,
3040        ) -> Result<Value, Error> {
3041            Ok(Value::Object(BTreeMap::from([
3042                ("__type".into(), Value::Str(variant.to_string())),
3043                ("_value".into(), value.serialize(ValueSerializer)?),
3044            ])))
3045        }
3046        fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
3047            Ok(SeqSerializer(Vec::new()))
3048        }
3049        fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> {
3050            self.serialize_seq(Some(len))
3051        }
3052        fn serialize_tuple_struct(
3053            self,
3054            _name: &'static str,
3055            len: usize,
3056        ) -> Result<Self::SerializeTupleStruct, Error> {
3057            self.serialize_seq(Some(len))
3058        }
3059        fn serialize_tuple_variant(
3060            self,
3061            _name: &'static str,
3062            _idx: u32,
3063            variant: &'static str,
3064            _len: usize,
3065        ) -> Result<Self::SerializeTupleVariant, Error> {
3066            Ok(TupleVariantSerializer {
3067                variant: variant.to_string(),
3068                values: Vec::new(),
3069            })
3070        }
3071        fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> {
3072            Ok(MapSerializer {
3073                map: BTreeMap::new(),
3074                key: None,
3075            })
3076        }
3077        fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct, Error> {
3078            self.serialize_map(Some(len))
3079        }
3080        fn serialize_struct_variant(
3081            self,
3082            _name: &'static str,
3083            _idx: u32,
3084            variant: &'static str,
3085            _len: usize,
3086        ) -> Result<Self::SerializeStructVariant, Error> {
3087            Ok(StructVariantSerializer {
3088                variant: variant.to_string(),
3089                map: BTreeMap::new(),
3090            })
3091        }
3092    }
3093
3094    struct SeqSerializer(Vec<Value>);
3095
3096    impl SerializeSeq for SeqSerializer {
3097        type Ok = Value;
3098        type Error = Error;
3099        fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
3100            self.0.push(value.serialize(ValueSerializer)?);
3101            Ok(())
3102        }
3103        fn end(self) -> Result<Value, Error> {
3104            Ok(Value::Array(self.0))
3105        }
3106    }
3107    impl SerializeTuple for SeqSerializer {
3108        type Ok = Value;
3109        type Error = Error;
3110        fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
3111            SerializeSeq::serialize_element(self, value)
3112        }
3113        fn end(self) -> Result<Value, Error> {
3114            SerializeSeq::end(self)
3115        }
3116    }
3117    impl SerializeTupleStruct for SeqSerializer {
3118        type Ok = Value;
3119        type Error = Error;
3120        fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
3121            SerializeSeq::serialize_element(self, value)
3122        }
3123        fn end(self) -> Result<Value, Error> {
3124            SerializeSeq::end(self)
3125        }
3126    }
3127
3128    struct MapSerializer {
3129        map: BTreeMap<String, Value>,
3130        key: Option<String>,
3131    }
3132
3133    impl SerializeMap for MapSerializer {
3134        type Ok = Value;
3135        type Error = Error;
3136        fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<(), Error> {
3137            self.key = Some(key.serialize(KeySerializer)?);
3138            Ok(())
3139        }
3140        fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
3141            let k = self
3142                .key
3143                .take()
3144                .ok_or_else(|| de::Error::custom("serialize_value 前需先 serialize_key"))?;
3145            self.map.insert(k, value.serialize(ValueSerializer)?);
3146            Ok(())
3147        }
3148        fn end(self) -> Result<Value, Error> {
3149            Ok(Value::Object(self.map))
3150        }
3151    }
3152
3153    impl SerializeStruct for MapSerializer {
3154        type Ok = Value;
3155        type Error = Error;
3156        fn serialize_field<T: Serialize + ?Sized>(
3157            &mut self,
3158            key: &'static str,
3159            value: &T,
3160        ) -> Result<(), Error> {
3161            self.map
3162                .insert(key.to_string(), value.serialize(ValueSerializer)?);
3163            Ok(())
3164        }
3165        fn end(self) -> Result<Value, Error> {
3166            Ok(Value::Object(self.map))
3167        }
3168    }
3169
3170    /// 对象键必须能转成字符串(SML 的键是裸词/字符串)
3171    struct KeySerializer;
3172
3173    macro_rules! key_unsupported {
3174        ($(fn $m:ident($($a:ident : $t:ty),*) -> Result<String, Error>;)*) => {
3175            $(
3176                fn $m(self, $($a: $t),*) -> Result<String, Error> {
3177                    Err(de::Error::custom("SML 对象的键必须是字符串"))
3178                }
3179            )*
3180        };
3181    }
3182
3183    impl Serializer for KeySerializer {
3184        type Ok = String;
3185        type Error = Error;
3186        type SerializeSeq = ::serde::ser::Impossible<String, Error>;
3187        type SerializeTuple = ::serde::ser::Impossible<String, Error>;
3188        type SerializeTupleStruct = ::serde::ser::Impossible<String, Error>;
3189        type SerializeTupleVariant = ::serde::ser::Impossible<String, Error>;
3190        type SerializeMap = ::serde::ser::Impossible<String, Error>;
3191        type SerializeStruct = ::serde::ser::Impossible<String, Error>;
3192        type SerializeStructVariant = ::serde::ser::Impossible<String, Error>;
3193
3194        fn serialize_str(self, v: &str) -> Result<String, Error> {
3195            Ok(v.to_string())
3196        }
3197        fn serialize_char(self, v: char) -> Result<String, Error> {
3198            Ok(v.to_string())
3199        }
3200        key_unsupported! {
3201            fn serialize_bool(_v: bool) -> Result<String, Error>;
3202            fn serialize_i8(_v: i8) -> Result<String, Error>;
3203            fn serialize_i16(_v: i16) -> Result<String, Error>;
3204            fn serialize_i32(_v: i32) -> Result<String, Error>;
3205            fn serialize_i64(_v: i64) -> Result<String, Error>;
3206            fn serialize_u8(_v: u8) -> Result<String, Error>;
3207            fn serialize_u16(_v: u16) -> Result<String, Error>;
3208            fn serialize_u32(_v: u32) -> Result<String, Error>;
3209            fn serialize_u64(_v: u64) -> Result<String, Error>;
3210            fn serialize_f32(_v: f32) -> Result<String, Error>;
3211            fn serialize_f64(_v: f64) -> Result<String, Error>;
3212            fn serialize_bytes(_v: &[u8]) -> Result<String, Error>;
3213            fn serialize_none() -> Result<String, Error>;
3214            fn serialize_unit() -> Result<String, Error>;
3215            fn serialize_unit_struct(_n: &'static str) -> Result<String, Error>;
3216            fn serialize_unit_variant(_n: &'static str, _i: u32, _v: &'static str) -> Result<String, Error>;
3217        }
3218        fn serialize_some<T: Serialize + ?Sized>(self, _v: &T) -> Result<String, Error> {
3219            Err(de::Error::custom("SML 对象的键必须是字符串"))
3220        }
3221        fn serialize_newtype_struct<T: Serialize + ?Sized>(
3222            self,
3223            _n: &'static str,
3224            _v: &T,
3225        ) -> Result<String, Error> {
3226            Err(de::Error::custom("SML 对象的键必须是字符串"))
3227        }
3228        fn serialize_newtype_variant<T: Serialize + ?Sized>(
3229            self,
3230            _n: &'static str,
3231            _i: u32,
3232            _v: &'static str,
3233            _x: &T,
3234        ) -> Result<String, Error> {
3235            Err(de::Error::custom("SML 对象的键必须是字符串"))
3236        }
3237        // 以下方法返回关联类型(Impossible),一律报错——SML 键只能是字符串
3238        fn serialize_seq(self, _l: Option<usize>) -> Result<Self::SerializeSeq, Error> {
3239            Err(de::Error::custom("SML 对象的键必须是字符串"))
3240        }
3241        fn serialize_tuple(self, _l: usize) -> Result<Self::SerializeTuple, Error> {
3242            Err(de::Error::custom("SML 对象的键必须是字符串"))
3243        }
3244        fn serialize_tuple_struct(
3245            self,
3246            _n: &'static str,
3247            _l: usize,
3248        ) -> Result<Self::SerializeTupleStruct, Error> {
3249            Err(de::Error::custom("SML 对象的键必须是字符串"))
3250        }
3251        fn serialize_tuple_variant(
3252            self,
3253            _n: &'static str,
3254            _i: u32,
3255            _v: &'static str,
3256            _l: usize,
3257        ) -> Result<Self::SerializeTupleVariant, Error> {
3258            Err(de::Error::custom("SML 对象的键必须是字符串"))
3259        }
3260        fn serialize_map(self, _l: Option<usize>) -> Result<Self::SerializeMap, Error> {
3261            Err(de::Error::custom("SML 对象的键必须是字符串"))
3262        }
3263        fn serialize_struct(self, _n: &'static str, _l: usize) -> Result<Self::SerializeStruct, Error> {
3264            Err(de::Error::custom("SML 对象的键必须是字符串"))
3265        }
3266        fn serialize_struct_variant(
3267            self,
3268            _n: &'static str,
3269            _i: u32,
3270            _v: &'static str,
3271            _l: usize,
3272        ) -> Result<Self::SerializeStructVariant, Error> {
3273            Err(de::Error::custom("SML 对象的键必须是字符串"))
3274        }
3275    }
3276
3277    struct TupleVariantSerializer {
3278        variant: String,
3279        values: Vec<Value>,
3280    }
3281
3282    impl SerializeTupleVariant for TupleVariantSerializer {
3283        type Ok = Value;
3284        type Error = Error;
3285        fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
3286            self.values.push(value.serialize(ValueSerializer)?);
3287            Ok(())
3288        }
3289        fn end(self) -> Result<Value, Error> {
3290            Ok(Value::Object(BTreeMap::from([
3291                ("__type".into(), Value::Str(self.variant)),
3292                ("_value".into(), Value::Array(self.values)),
3293            ])))
3294        }
3295    }
3296
3297    struct StructVariantSerializer {
3298        variant: String,
3299        map: BTreeMap<String, Value>,
3300    }
3301
3302    impl SerializeStructVariant for StructVariantSerializer {
3303        type Ok = Value;
3304        type Error = Error;
3305        fn serialize_field<T: Serialize + ?Sized>(
3306            &mut self,
3307            key: &'static str,
3308            value: &T,
3309        ) -> Result<(), Error> {
3310            self.map
3311                .insert(key.to_string(), value.serialize(ValueSerializer)?);
3312            Ok(())
3313        }
3314        fn end(self) -> Result<Value, Error> {
3315            let mut m = BTreeMap::new();
3316            m.insert("__type".into(), Value::Str(self.variant));
3317            m.extend(self.map);
3318            Ok(Value::Object(m))
3319        }
3320    }
3321
3322    // ---- Deserializer: Value -> T: Deserialize ----
3323
3324    macro_rules! deser_int {
3325        ($(fn $m:ident($v:ident, $call:ident);)*) => {
3326            $(
3327                fn $m<V>(self, $v: V) -> Result<V::Value, Self::Error>
3328                where V: Visitor<'de> {
3329                    match self.0 {
3330                        Value::Int(i) => $v.$call(i as _),
3331                        Value::Float(f)
3332                            if f.fract() == 0.0
3333                                && f >= i64::MIN as f64
3334                                && f <= i64::MAX as f64 =>
3335                        {
3336                            $v.$call(f as _)
3337                        }
3338                        other => Err(type_err(&other, stringify!($m).trim_start_matches("deserialize_"))),
3339                    }
3340                }
3341            )*
3342        };
3343    }
3344
3345    struct ValueDeserializer(Value);
3346
3347    impl<'de> Deserializer<'de> for ValueDeserializer {
3348        type Error = Error;
3349
3350        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
3351        where
3352            V: Visitor<'de>,
3353        {
3354            match self.0 {
3355                Value::Null => visitor.visit_unit(),
3356                Value::Bool(b) => visitor.visit_bool(b),
3357                Value::Int(i) => visitor.visit_i64(i),
3358                Value::Float(f) => visitor.visit_f64(f),
3359                Value::Str(s) => visitor.visit_string(s),
3360                Value::Array(a) => visitor.visit_seq(SeqDeserializer { items: a, idx: 0 }),
3361                Value::Object(m) => visitor.visit_map(MapDeserializer { map: m, pending: None }),
3362            }
3363        }
3364
3365        fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Error>
3366        where
3367            V: Visitor<'de>,
3368        {
3369            match self.0 {
3370                Value::Bool(b) => visitor.visit_bool(b),
3371                other => Err(type_err(&other, "布尔")),
3372            }
3373        }
3374
3375        deser_int! {
3376            fn deserialize_i8(v, visit_i8);
3377            fn deserialize_i16(v, visit_i16);
3378            fn deserialize_i32(v, visit_i32);
3379            fn deserialize_i64(v, visit_i64);
3380            fn deserialize_u8(v, visit_u8);
3381            fn deserialize_u16(v, visit_u16);
3382            fn deserialize_u32(v, visit_u32);
3383        }
3384
3385        fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Error>
3386        where
3387            V: Visitor<'de>,
3388        {
3389            match self.0 {
3390                Value::Int(i) if i >= 0 => visitor.visit_u64(i as u64),
3391                Value::Float(f)
3392                    if f.fract() == 0.0 && f >= 0.0 && f <= u64::MAX as f64 =>
3393                {
3394                    visitor.visit_u64(f as u64)
3395                }
3396                other => Err(type_err(&other, "u64")),
3397            }
3398        }
3399
3400        fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Error>
3401        where
3402            V: Visitor<'de>,
3403        {
3404            match self.0 {
3405                Value::Int(i) => visitor.visit_f32(i as f32),
3406                Value::Float(f) => visitor.visit_f32(f as f32),
3407                other => Err(type_err(&other, "f32")),
3408            }
3409        }
3410        fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Error>
3411        where
3412            V: Visitor<'de>,
3413        {
3414            match self.0 {
3415                Value::Int(i) => visitor.visit_f64(i as f64),
3416                Value::Float(f) => visitor.visit_f64(f),
3417                other => Err(type_err(&other, "f64")),
3418            }
3419        }
3420
3421        fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Error>
3422        where
3423            V: Visitor<'de>,
3424        {
3425            match self.0 {
3426                Value::Str(s) if s.chars().count() == 1 => {
3427                    visitor.visit_char(s.chars().next().unwrap())
3428                }
3429                other => Err(type_err(&other, "字符")),
3430            }
3431        }
3432
3433        fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error>
3434        where
3435            V: Visitor<'de>,
3436        {
3437            match self.0 {
3438                Value::Str(s) => visitor.visit_string(s),
3439                other => Err(type_err(&other, "字符串")),
3440            }
3441        }
3442        fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error>
3443        where
3444            V: Visitor<'de>,
3445        {
3446            self.deserialize_str(visitor)
3447        }
3448
3449        fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Error>
3450        where
3451            V: Visitor<'de>,
3452        {
3453            match self.0 {
3454                Value::Array(items) => {
3455                    let mut buf = Vec::with_capacity(items.len());
3456                    for it in items {
3457                        match it {
3458                            Value::Int(i) if (0..=255).contains(&i) => buf.push(i as u8),
3459                            other => return Err(type_err(&other, "字节")),
3460                        }
3461                    }
3462                    visitor.visit_byte_buf(buf)
3463                }
3464                other => Err(type_err(&other, "字节数组")),
3465            }
3466        }
3467        fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Error>
3468        where
3469            V: Visitor<'de>,
3470        {
3471            self.deserialize_bytes(visitor)
3472        }
3473
3474        fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
3475        where
3476            V: Visitor<'de>,
3477        {
3478            match self.0 {
3479                Value::Null => visitor.visit_none(),
3480                other => visitor.visit_some(ValueDeserializer(other)),
3481            }
3482        }
3483
3484        fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Error>
3485        where
3486            V: Visitor<'de>,
3487        {
3488            match self.0 {
3489                Value::Null => visitor.visit_unit(),
3490                other => Err(type_err(&other, "unit")),
3491            }
3492        }
3493        fn deserialize_unit_struct<V>(
3494            self,
3495            _name: &'static str,
3496            visitor: V,
3497        ) -> Result<V::Value, Error>
3498        where
3499            V: Visitor<'de>,
3500        {
3501            self.deserialize_unit(visitor)
3502        }
3503        fn deserialize_newtype_struct<V>(
3504            self,
3505            _name: &'static str,
3506            visitor: V,
3507        ) -> Result<V::Value, Error>
3508        where
3509            V: Visitor<'de>,
3510        {
3511            self.deserialize_any(visitor)
3512        }
3513
3514        fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Error>
3515        where
3516            V: Visitor<'de>,
3517        {
3518            match self.0 {
3519                Value::Array(a) => visitor.visit_seq(SeqDeserializer { items: a, idx: 0 }),
3520                other => Err(type_err(&other, "数组")),
3521            }
3522        }
3523        fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
3524        where
3525            V: Visitor<'de>,
3526        {
3527            self.deserialize_seq(visitor)
3528        }
3529        fn deserialize_tuple_struct<V>(
3530            self,
3531            _name: &'static str,
3532            _len: usize,
3533            visitor: V,
3534        ) -> Result<V::Value, Error>
3535        where
3536            V: Visitor<'de>,
3537        {
3538            self.deserialize_seq(visitor)
3539        }
3540
3541        fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Error>
3542        where
3543            V: Visitor<'de>,
3544        {
3545            match self.0 {
3546                Value::Object(m) => visitor.visit_map(MapDeserializer { map: m, pending: None }),
3547                other => Err(type_err(&other, "块/对象")),
3548            }
3549        }
3550        fn deserialize_struct<V>(
3551            self,
3552            _name: &'static str,
3553            _fields: &'static [&'static str],
3554            visitor: V,
3555        ) -> Result<V::Value, Error>
3556        where
3557            V: Visitor<'de>,
3558        {
3559            self.deserialize_map(visitor)
3560        }
3561
3562        fn deserialize_enum<V>(
3563            self,
3564            _name: &'static str,
3565            _variants: &'static [&'static str],
3566            visitor: V,
3567        ) -> Result<V::Value, Error>
3568        where
3569            V: Visitor<'de>,
3570        {
3571            match self.0 {
3572                Value::Str(s) => visitor.visit_enum(EnumDeserializer {
3573                    variant: s,
3574                    kind: EnumKind::Unit,
3575                }),
3576                Value::Object(mut m) => {
3577                    // 1) SML 专有约定:`__type` 键(与 SmlSerialize 输出一致)
3578                    if let Some(ty) = m.remove("__type") {
3579                        let variant = match ty {
3580                            Value::Str(s) => s,
3581                            _ => return Err(de::Error::custom("`__type` 的值必须是字符串")),
3582                        };
3583                        let kind = match m.remove("_value") {
3584                            Some(Value::Array(items)) => EnumKind::Tuple(items),
3585                            Some(other) => EnumKind::Newtype(other),
3586                            None if m.is_empty() => EnumKind::Unit,
3587                            None => EnumKind::Struct(m),
3588                        };
3589                        return visitor.visit_enum(EnumDeserializer { variant, kind });
3590                    }
3591                    // 2) serde 外部标签(含 SML 裸词包裹形态):
3592                    //    {"in-maintenance": "in-maintenance"} -> 单元变体
3593                    //    {"Circle": 3}                        -> 单值变体
3594                    if m.len() == 1 {
3595                        let (k, v) = m.pop_first().expect("len==1 必有键");
3596                        let kind = match v {
3597                            Value::Str(s) if s == k => EnumKind::Unit,
3598                            other => EnumKind::Newtype(other),
3599                        };
3600                        return visitor.visit_enum(EnumDeserializer { variant: k, kind });
3601                    }
3602                    Err(de::Error::custom(
3603                        "枚举块需要 `__type` 键(SML 约定)或单键外部标签 `{ VariantName: ... }`",
3604                    ))
3605                }
3606                other => Err(type_err(&other, "枚举")),
3607            }
3608        }
3609
3610        fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Error>
3611        where
3612            V: Visitor<'de>,
3613        {
3614            self.deserialize_str(visitor)
3615        }
3616        fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
3617        where
3618            V: Visitor<'de>,
3619        {
3620            self.deserialize_any(visitor)
3621        }
3622    }
3623
3624    struct SeqDeserializer {
3625        items: Vec<Value>,
3626        idx: usize,
3627    }
3628
3629    impl<'de> SeqAccess<'de> for SeqDeserializer {
3630        type Error = Error;
3631        fn next_element_seed<T: de::DeserializeSeed<'de>>(
3632            &mut self,
3633            seed: T,
3634        ) -> Result<Option<T::Value>, Error> {
3635            if self.idx >= self.items.len() {
3636                return Ok(None);
3637            }
3638            let item = self.items[self.idx].clone();
3639            self.idx += 1;
3640            seed.deserialize(ValueDeserializer(item)).map(Some)
3641        }
3642    }
3643
3644    struct MapDeserializer {
3645        map: BTreeMap<String, Value>,
3646        pending: Option<Value>,
3647    }
3648
3649    impl<'de> MapAccess<'de> for MapDeserializer {
3650        type Error = Error;
3651        fn next_key_seed<K: de::DeserializeSeed<'de>>(
3652            &mut self,
3653            seed: K,
3654        ) -> Result<Option<K::Value>, Error> {
3655            let Some((k, v)) = self.map.pop_first() else {
3656                return Ok(None);
3657            };
3658            self.pending = Some(v);
3659            seed.deserialize(KeyDeserializer(&k)).map(Some)
3660        }
3661        fn next_value_seed<V: de::DeserializeSeed<'de>>(
3662            &mut self,
3663            seed: V,
3664        ) -> Result<V::Value, Error> {
3665            let v = self.pending.take().ok_or_else(|| {
3666                de::Error::custom("value 缺失:需先调用 next_key_seed")
3667            })?;
3668            seed.deserialize(ValueDeserializer(v))
3669        }
3670    }
3671
3672    /// 字段名 / 变体名的轻量反序列化器(只认字符串)
3673    struct KeyDeserializer<'a>(&'a str);
3674
3675    macro_rules! key_delegate {
3676        ($($m:ident),* $(,)?) => {
3677            $(
3678                fn $m<V>(self, visitor: V) -> Result<V::Value, Error>
3679                where V: Visitor<'de> {
3680                    self.deserialize_any(visitor)
3681                }
3682            )*
3683        };
3684    }
3685
3686    impl<'de, 'a> Deserializer<'de> for KeyDeserializer<'a> {
3687        type Error = Error;
3688
3689        fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
3690        where
3691            V: Visitor<'de>,
3692        {
3693            visitor.visit_str(self.0)
3694        }
3695        fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error>
3696        where
3697            V: Visitor<'de>,
3698        {
3699            visitor.visit_str(self.0)
3700        }
3701        fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error>
3702        where
3703            V: Visitor<'de>,
3704        {
3705            visitor.visit_str(self.0)
3706        }
3707        fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Error>
3708        where
3709            V: Visitor<'de>,
3710        {
3711            visitor.visit_str(self.0)
3712        }
3713        fn deserialize_enum<V>(
3714            self,
3715            _name: &'static str,
3716            _variants: &'static [&'static str],
3717            visitor: V,
3718        ) -> Result<V::Value, Error>
3719        where
3720            V: Visitor<'de>,
3721        {
3722            visitor.visit_enum(EnumDeserializer {
3723                variant: self.0.to_string(),
3724                kind: EnumKind::Unit,
3725            })
3726        }
3727        fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
3728        where
3729            V: Visitor<'de>,
3730        {
3731            visitor.visit_some(self)
3732        }
3733        fn deserialize_unit_struct<V>(
3734            self,
3735            _name: &'static str,
3736            visitor: V,
3737        ) -> Result<V::Value, Error>
3738        where
3739            V: Visitor<'de>,
3740        {
3741            self.deserialize_unit(visitor)
3742        }
3743        fn deserialize_newtype_struct<V>(
3744            self,
3745            _name: &'static str,
3746            visitor: V,
3747        ) -> Result<V::Value, Error>
3748        where
3749            V: Visitor<'de>,
3750        {
3751            self.deserialize_any(visitor)
3752        }
3753        fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
3754        where
3755            V: Visitor<'de>,
3756        {
3757            self.deserialize_seq(visitor)
3758        }
3759        fn deserialize_tuple_struct<V>(
3760            self,
3761            _name: &'static str,
3762            _len: usize,
3763            visitor: V,
3764        ) -> Result<V::Value, Error>
3765        where
3766            V: Visitor<'de>,
3767        {
3768            self.deserialize_seq(visitor)
3769        }
3770        fn deserialize_struct<V>(
3771            self,
3772            _name: &'static str,
3773            _fields: &'static [&'static str],
3774            visitor: V,
3775        ) -> Result<V::Value, Error>
3776        where
3777            V: Visitor<'de>,
3778        {
3779            self.deserialize_map(visitor)
3780        }
3781        fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
3782        where
3783            V: Visitor<'de>,
3784        {
3785            self.deserialize_any(visitor)
3786        }
3787        key_delegate! {
3788            deserialize_bool, deserialize_i8, deserialize_i16, deserialize_i32,
3789            deserialize_i64, deserialize_u8, deserialize_u16, deserialize_u32,
3790            deserialize_u64, deserialize_f32, deserialize_f64, deserialize_char,
3791            deserialize_bytes, deserialize_byte_buf, deserialize_unit,
3792            deserialize_seq, deserialize_map,
3793        }
3794    }
3795
3796    // ---- 枚举(SML `__type` 约定,与 SmlDeserialize 一致)----
3797
3798    #[derive(Debug)]
3799    enum EnumKind {
3800        Unit,
3801        Newtype(Value),
3802        Tuple(Vec<Value>),
3803        Struct(BTreeMap<String, Value>),
3804    }
3805
3806    struct EnumDeserializer {
3807        variant: String,
3808        kind: EnumKind,
3809    }
3810
3811    impl<'de> de::EnumAccess<'de> for EnumDeserializer {
3812        type Error = Error;
3813        type Variant = VariantAccess;
3814        fn variant_seed<V: de::DeserializeSeed<'de>>(
3815            self,
3816            seed: V,
3817        ) -> Result<(V::Value, Self::Variant), Error> {
3818            let variant = seed.deserialize(KeyDeserializer(&self.variant))?;
3819            Ok((variant, VariantAccess { kind: self.kind }))
3820        }
3821    }
3822
3823    struct VariantAccess {
3824        kind: EnumKind,
3825    }
3826
3827    impl<'de> de::VariantAccess<'de> for VariantAccess {
3828        type Error = Error;
3829        fn unit_variant(self) -> Result<(), Error> {
3830            match self.kind {
3831                EnumKind::Unit => Ok(()),
3832                _ => Err(de::Error::custom("该变体携带数据,不能按单元变体解析")),
3833            }
3834        }
3835        fn newtype_variant_seed<T: de::DeserializeSeed<'de>>(
3836            self,
3837            seed: T,
3838        ) -> Result<T::Value, Error> {
3839            match self.kind {
3840                EnumKind::Newtype(v) => seed.deserialize(ValueDeserializer(v)),
3841                EnumKind::Tuple(items) => {
3842                    seed.deserialize(ValueDeserializer(Value::Array(items)))
3843                }
3844                _ => Err(de::Error::custom("该变体没有单值数据")),
3845            }
3846        }
3847        fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
3848        where
3849            V: Visitor<'de>,
3850        {
3851            match self.kind {
3852                EnumKind::Tuple(items) => {
3853                    visitor.visit_seq(SeqDeserializer { items, idx: 0 })
3854                }
3855                _ => Err(de::Error::custom("该变体不是元组形态")),
3856            }
3857        }
3858        fn struct_variant<V>(
3859            self,
3860            _fields: &'static [&'static str],
3861            visitor: V,
3862        ) -> Result<V::Value, Error>
3863        where
3864            V: Visitor<'de>,
3865        {
3866            match self.kind {
3867                EnumKind::Struct(m) => {
3868                    visitor.visit_map(MapDeserializer { map: m, pending: None })
3869                }
3870                _ => Err(de::Error::custom("该变体不是结构体形态")),
3871            }
3872        }
3873    }
3874}
3875
3876// ---------------------------------------------------------------------------
3877// 自然序列化宏(derive)支持
3878// ---------------------------------------------------------------------------
3879
3880/// 把一个类型「自然地」序列化为 SML 值:
3881/// 结构体 → 块、newtype → 透明、单元结构体 → 裸词、
3882/// 枚举单元变体 → 裸词、带数据变体 → `__type` 块。
3883///
3884/// 通常用 `#[derive(SmlSerialize)]` 自动实现(`derive` feature 默认开启),
3885/// 也可手动实现。支持的 `#[sml(...)]` 属性见 `swsml-derive` 的文档。
3886pub trait SmlSerialize {
3887    fn to_sml_value(&self) -> Value;
3888
3889    /// 序列化为 SML 文本(等价于 [`to_sml`] 作用于本类型生成的值)。
3890    fn to_sml(&self) -> String {
3891        crate::to_sml(&self.to_sml_value())
3892    }
3893}
3894
3895/// 从 SML 值反序列化(`#[derive(SmlDeserialize)]` 自动实现)。
3896pub trait SmlDeserialize: Sized {
3897    fn from_sml_value(v: &Value) -> Result<Self, String>;
3898
3899    /// 解析 SML 文本并反序列化。
3900    fn from_sml(text: &str) -> Result<Self, String> {
3901        let v = crate::parse(text).map_err(|e| format!("SML 解析失败: {e}"))?;
3902        Self::from_sml_value(&v)
3903    }
3904}
3905
3906#[cfg(feature = "derive")]
3907pub use swsml_derive::{SmlDeserialize, SmlSerialize};
3908
3909/// 序列化为 SML 文本 —— toml-rs 风格的顶层函数(等价于 [`SmlSerialize::to_sml`])。
3910///
3911/// 用法与 `toml::to_string` 一致(序列化不会失败,故直接返回 `String`):
3912///
3913/// ```rust
3914/// # use sml::{SmlSerialize, SmlDeserialize};
3915/// # #[derive(SmlSerialize, SmlDeserialize, Debug, PartialEq)]
3916/// # struct Server { host: String, port: i32 }
3917/// # let cfg = Server { host: "web.example".into(), port: 8080 };
3918/// let text = sml::to_string(&cfg);
3919/// assert_eq!(text, "host: web.example\nport: 8080\n");
3920/// ```
3921pub fn to_string<T: SmlSerialize + ?Sized>(value: &T) -> String {
3922    crate::to_sml(&value.to_sml_value())
3923}
3924
3925/// 解析 SML 文本并反序列化 —— toml-rs 风格的顶层函数(等价于 [`SmlDeserialize::from_sml`])。
3926///
3927/// ```rust
3928/// # use sml::{SmlSerialize, SmlDeserialize};
3929/// # #[derive(SmlSerialize, SmlDeserialize, Debug, PartialEq)]
3930/// # struct Server { host: String, port: i32 }
3931/// let back: Server = sml::from_str("host: web.example\nport: 8080\n").unwrap();
3932/// assert_eq!(back.host, "web.example");
3933/// assert_eq!(back.port, 8080);
3934/// ```
3935pub fn from_str<T: SmlDeserialize>(text: &str) -> Result<T, String> {
3936    T::from_sml(text)
3937}
3938
3939/// 宏生成代码引用的内部辅助(请勿直接使用)。
3940#[doc(hidden)]
3941pub mod __private {
3942    use super::{SmlDeserialize, SmlSerialize, Value};
3943    use std::collections::{BTreeMap, HashMap};
3944
3945    /// 描述值的类型,用于错误信息。
3946    pub fn describe_value(v: &Value) -> String {
3947        match v {
3948            Value::Null => "null".to_string(),
3949            Value::Bool(b) => b.to_string(),
3950            Value::Int(i) => i.to_string(),
3951            Value::Float(f) => f.to_string(),
3952            Value::Str(s) => format!("字符串 `{s}`"),
3953            Value::Array(a) => format!("数组({} 个元素)", a.len()),
3954            Value::Object(o) => format!("块({} 个键)", o.len()),
3955        }
3956    }
3957
3958    /// 取出 `_value` 键(枚举单值变体)。
3959    pub fn take_value(m: &BTreeMap<String, Value>) -> Result<Value, String> {
3960        m.get("_value")
3961            .cloned()
3962            .ok_or_else(|| "缺少 _value 键".to_string())
3963    }
3964
3965    /// 取出 `_value` 键并断言为数组(枚举 tuple 变体)。
3966    pub fn take_array(m: &BTreeMap<String, Value>) -> Result<Vec<Value>, String> {
3967        match m.get("_value") {
3968            Some(Value::Array(a)) => Ok(a.clone()),
3969            Some(other) => Err(format!("_value 期望数组,实际为 {}", describe_value(other))),
3970            None => Err("缺少 _value 键".to_string()),
3971        }
3972    }
3973
3974    /// `#[sml(flatten)]` 反序列化:把整个块交给子类型。
3975    pub fn flatten_from<T: SmlDeserialize>(m: &BTreeMap<String, Value>) -> Result<T, String> {
3976        T::from_sml_value(&Value::Object(m.clone()))
3977    }
3978
3979    // ---- 基础类型 ----
3980
3981    impl SmlSerialize for bool {
3982        #[inline]
3983        fn to_sml_value(&self) -> Value {
3984            Value::Bool(*self)
3985        }
3986    }
3987    impl SmlDeserialize for bool {
3988        #[inline]
3989        fn from_sml_value(v: &Value) -> Result<Self, String> {
3990            match v {
3991                Value::Bool(b) => Ok(*b),
3992                other => Err(format!("期望布尔,实际为 {}", describe_value(other))),
3993            }
3994        }
3995    }
3996
3997    macro_rules! impl_int {
3998        ($($t:ty),* $(,)?) => {$(
3999            impl SmlSerialize for $t {
4000                #[inline]
4001                fn to_sml_value(&self) -> Value { Value::Int(*self as i64) }
4002            }
4003            impl SmlDeserialize for $t {
4004                #[inline]
4005                fn from_sml_value(v: &Value) -> Result<Self, String> {
4006                    match v {
4007                        Value::Int(i) => <$t>::try_from(*i)
4008                            .map_err(|_| format!("整数 {i} 超出 {} 范围", stringify!($t))),
4009                        Value::Float(f)
4010                            if f.fract() == 0.0
4011                                && *f >= <$t>::MIN as f64
4012                                && *f <= <$t>::MAX as f64 => Ok(*f as $t),
4013                        Value::Float(f) => Err(format!("期望整数,实际为小数 {f}")),
4014                        other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4015                    }
4016                }
4017            }
4018        )*};
4019    }
4020    impl_int!(i8, i16, i32, i64, isize, u8, u16, u32, usize);
4021
4022    impl SmlSerialize for u64 {
4023        #[inline]
4024        fn to_sml_value(&self) -> Value {
4025            i64::try_from(*self).map(Value::Int).unwrap_or_else(|_| Value::Float(*self as f64))
4026        }
4027    }
4028    impl SmlDeserialize for u64 {
4029        #[inline]
4030        fn from_sml_value(v: &Value) -> Result<Self, String> {
4031            match v {
4032                Value::Int(i) => u64::try_from(*i).map_err(|_| format!("整数 {i} 为负数,超出 u64 范围")),
4033                Value::Float(f) if f.fract() == 0.0 && *f >= 0.0 => Ok(*f as u64),
4034                Value::Float(f) => Err(format!("期望非负整数,实际为 {f}")),
4035                other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4036            }
4037        }
4038    }
4039
4040    macro_rules! impl_big {
4041        ($($t:ty),* $(,)?) => {$(
4042            impl SmlSerialize for $t {
4043                #[inline]
4044                fn to_sml_value(&self) -> Value {
4045                    i64::try_from(*self).map(Value::Int).unwrap_or_else(|_| Value::Float(*self as f64))
4046                }
4047            }
4048            impl SmlDeserialize for $t {
4049                #[inline]
4050                fn from_sml_value(v: &Value) -> Result<Self, String> {
4051                    match v {
4052                        Value::Int(i) => Ok(*i as $t),
4053                        Value::Float(f) if f.fract() == 0.0 => Ok(*f as $t),
4054                        Value::Float(f) => Err(format!("期望整数,实际为小数 {f}")),
4055                        other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4056                    }
4057                }
4058            }
4059        )*};
4060    }
4061    impl_big!(i128, u128);
4062
4063    macro_rules! impl_float {
4064        ($($t:ty),* $(,)?) => {$(
4065            impl SmlSerialize for $t {
4066                #[inline]
4067                fn to_sml_value(&self) -> Value { Value::Float(*self as f64) }
4068            }
4069            impl SmlDeserialize for $t {
4070                #[inline]
4071                fn from_sml_value(v: &Value) -> Result<Self, String> {
4072                    match v {
4073                        Value::Int(i) => Ok(*i as $t),
4074                        Value::Float(f) => Ok(*f as $t),
4075                        other => Err(format!("期望数字,实际为 {}", describe_value(other))),
4076                    }
4077                }
4078            }
4079        )*};
4080    }
4081    impl_float!(f32, f64);
4082
4083    impl SmlSerialize for char {
4084        #[inline]
4085        fn to_sml_value(&self) -> Value {
4086            Value::Str(self.to_string())
4087        }
4088    }
4089    impl SmlDeserialize for char {
4090        #[inline]
4091        fn from_sml_value(v: &Value) -> Result<Self, String> {
4092            match v {
4093                Value::Str(s) => {
4094                    let mut it = s.chars();
4095                    match (it.next(), it.next()) {
4096                        (Some(c), None) => Ok(c),
4097                        _ => Err(format!("期望单个字符,实际为 `{s}`")),
4098                    }
4099                }
4100                other => Err(format!("期望字符串,实际为 {}", describe_value(other))),
4101            }
4102        }
4103    }
4104
4105    impl SmlSerialize for String {
4106        #[inline]
4107        fn to_sml_value(&self) -> Value {
4108            Value::Str(self.clone())
4109        }
4110    }
4111    impl SmlDeserialize for String {
4112        #[inline]
4113        fn from_sml_value(v: &Value) -> Result<Self, String> {
4114            match v {
4115                Value::Str(s) => Ok(s.clone()),
4116                other => Err(format!("期望字符串,实际为 {}", describe_value(other))),
4117            }
4118        }
4119    }
4120
4121    impl SmlSerialize for str {
4122        #[inline]
4123        fn to_sml_value(&self) -> Value {
4124            Value::Str(self.to_string())
4125        }
4126    }
4127
4128    impl SmlSerialize for &str {
4129        #[inline]
4130        fn to_sml_value(&self) -> Value {
4131            Value::Str(self.to_string())
4132        }
4133    }
4134
4135    impl SmlSerialize for () {
4136        #[inline]
4137        fn to_sml_value(&self) -> Value {
4138            Value::Null
4139        }
4140    }
4141    impl SmlDeserialize for () {
4142        #[inline]
4143        fn from_sml_value(v: &Value) -> Result<Self, String> {
4144            match v {
4145                Value::Null => Ok(()),
4146                other => Err(format!("期望 null,实际为 {}", describe_value(other))),
4147            }
4148        }
4149    }
4150
4151    impl SmlSerialize for Value {
4152        #[inline]
4153        fn to_sml_value(&self) -> Value {
4154            self.clone()
4155        }
4156    }
4157    impl SmlDeserialize for Value {
4158        #[inline]
4159        fn from_sml_value(v: &Value) -> Result<Self, String> {
4160            Ok(v.clone())
4161        }
4162    }
4163
4164    impl<T: SmlSerialize> SmlSerialize for Option<T> {
4165        #[inline]
4166        fn to_sml_value(&self) -> Value {
4167            match self {
4168                Some(v) => v.to_sml_value(),
4169                None => Value::Null,
4170            }
4171        }
4172    }
4173    impl<T: SmlDeserialize> SmlDeserialize for Option<T> {
4174        #[inline]
4175        fn from_sml_value(v: &Value) -> Result<Self, String> {
4176            match v {
4177                Value::Null => Ok(None),
4178                other => Ok(Some(T::from_sml_value(other)?)),
4179            }
4180        }
4181    }
4182
4183    impl<T: SmlSerialize> SmlSerialize for Vec<T> {
4184        #[inline]
4185        fn to_sml_value(&self) -> Value {
4186            Value::Array(self.iter().map(SmlSerialize::to_sml_value).collect())
4187        }
4188    }
4189    impl<T: SmlDeserialize> SmlDeserialize for Vec<T> {
4190        #[inline]
4191        fn from_sml_value(v: &Value) -> Result<Self, String> {
4192            match v {
4193                Value::Array(a) => a.iter().map(SmlDeserialize::from_sml_value).collect(),
4194                other => Err(format!("期望数组,实际为 {}", describe_value(other))),
4195            }
4196        }
4197    }
4198
4199    impl<T: SmlSerialize> SmlSerialize for Box<T> {
4200        #[inline]
4201        fn to_sml_value(&self) -> Value {
4202            (**self).to_sml_value()
4203        }
4204    }
4205    impl<T: SmlDeserialize> SmlDeserialize for Box<T> {
4206        #[inline]
4207        fn from_sml_value(v: &Value) -> Result<Self, String> {
4208            Ok(Box::new(T::from_sml_value(v)?))
4209        }
4210    }
4211
4212    impl<V: SmlSerialize> SmlSerialize for BTreeMap<String, V> {
4213        #[inline]
4214        fn to_sml_value(&self) -> Value {
4215            Value::Object(
4216                self.iter()
4217                    .map(|(k, v)| (k.clone(), v.to_sml_value()))
4218                    .collect(),
4219            )
4220        }
4221    }
4222    impl<V: SmlDeserialize> SmlDeserialize for BTreeMap<String, V> {
4223        #[inline]
4224        fn from_sml_value(v: &Value) -> Result<Self, String> {
4225            match v {
4226                Value::Object(m) => {
4227                    let mut out = BTreeMap::new();
4228                    for (k, val) in m {
4229                        out.insert(k.clone(), V::from_sml_value(val)?);
4230                    }
4231                    Ok(out)
4232                }
4233                other => Err(format!("期望块(object),实际为 {}", describe_value(other))),
4234            }
4235        }
4236    }
4237
4238    impl<V: SmlSerialize> SmlSerialize for HashMap<String, V> {
4239        #[inline]
4240        fn to_sml_value(&self) -> Value {
4241            Value::Object(
4242                self.iter()
4243                    .map(|(k, v)| (k.clone(), v.to_sml_value()))
4244                    .collect(),
4245            )
4246        }
4247    }
4248    impl<V: SmlDeserialize> SmlDeserialize for HashMap<String, V> {
4249        #[inline]
4250        fn from_sml_value(v: &Value) -> Result<Self, String> {
4251            match v {
4252                Value::Object(m) => {
4253                    let mut out = HashMap::new();
4254                    for (k, val) in m {
4255                        out.insert(k.clone(), V::from_sml_value(val)?);
4256                    }
4257                    Ok(out)
4258                }
4259                other => Err(format!("期望块(object),实际为 {}", describe_value(other))),
4260            }
4261        }
4262    }
4263}
4264
4265// ---------------------------------------------------------------------------
4266// 测试
4267// ---------------------------------------------------------------------------
4268
4269#[cfg(test)]
4270mod tests {
4271    use super::*;
4272
4273    // ---------------- version ----------------
4274
4275    #[test]
4276    fn version_defaults_to_v1_when_absent() {
4277        // 既有文档没有版本声明,必须仍能解析且默认为 V1(裸词即字符串,向后兼容)
4278        let (v, ver) = parse_versioned("a: 1\n").unwrap();
4279        assert_eq!(ver, Version::V1);
4280        assert_eq!(v.get("a"), Some(&Value::Int(1)));
4281    }
4282
4283    #[test]
4284    fn version_declared_as_v1() {
4285        let (v, ver) = parse_versioned("@version v1\na: 1\n").unwrap();
4286        assert_eq!(ver, Version::V1);
4287        assert_eq!(v.get("a"), Some(&Value::Int(1)));
4288    }
4289
4290    #[test]
4291    fn version_declaration_is_stripped_not_parsed_as_content() {
4292        // 若未剥离,`@version v1` 会被当成片段定义而解析异常
4293        let v = parse("@version v1\na: 1\n").unwrap();
4294        assert_eq!(v.get("a"), Some(&Value::Int(1)));
4295        assert!(v.get("version").is_none(), "@version 不应进入数据");
4296    }
4297
4298    #[test]
4299    fn unsupported_version_is_rejected() {
4300        let err = parse_versioned("@version v99\na: 1\n").unwrap_err();
4301        assert!(err.contains("不支持"), "应拒绝不支持的版本,got: {err}");
4302        assert!(err.contains("v99"), "错误应含版本号,got: {err}");
4303    }
4304
4305    #[test]
4306    fn conflicting_version_is_rejected() {
4307        let err = parse_versioned("@version v1\n@version v2\n").unwrap_err();
4308        // v2 尚未定义,优先报「不支持」
4309        assert!(!err.is_empty());
4310        // 两个都支持但不一致时的路径:v1 与 v1 不冲突
4311        let (_, ver) = parse_versioned("@version v1\n@version v1\n").unwrap();
4312        assert_eq!(ver, Version::V1, "重复但一致的声明应被接受");
4313    }
4314
4315    #[test]
4316    fn version_is_reserved_as_fragment_name() {
4317        let err = parse("@version { x: 1 }\n").unwrap_err();
4318        assert!(err.contains("保留") || err.contains("版本声明"), "got: {err}");
4319    }
4320
4321    #[test]
4322    fn version_works_with_include() {
4323        let d = tmpdir("version");
4324        std::fs::write(d.join("p.sml"), "@version v1\nb: 2\n").unwrap();
4325        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"p.sml\"\n").unwrap();
4326        let (v, ver) = parse_file_versioned(d.join("main.sml")).unwrap();
4327        assert_eq!(ver, Version::V1);
4328        assert_eq!(v.get("b"), Some(&Value::Int(2)), "版本与 include 应协同");
4329        let _ = std::fs::remove_dir_all(&d);
4330    }
4331
4332    #[test]
4333    fn version_display_matches_name() {
4334        assert_eq!(Version::V1.name(), "v1");
4335        assert_eq!(format!("{}", Version::V1), "v1");
4336    }
4337
4338    // ---------------- include ----------------
4339
4340    /// 在临时目录下建文件,返回目录句柄(drop 时自动清理)
4341    fn tmpdir(tag: &str) -> std::path::PathBuf {
4342        let mut d = std::env::temp_dir();
4343        d.push(format!("sml_test_{tag}_{}", std::process::id()));
4344        let _ = std::fs::remove_dir_all(&d);
4345        std::fs::create_dir_all(&d).expect("create tmpdir");
4346        d
4347    }
4348
4349    #[test]
4350    fn include_inlines_external_file() {
4351        let d = tmpdir("inline");
4352        std::fs::write(d.join("part.sml"), "port: 8080\n").unwrap();
4353        std::fs::write(d.join("main.sml"), "@version v1\nhost: local\ninclude \"part.sml\"\n").unwrap();
4354
4355        let v = parse_file(d.join("main.sml")).unwrap();
4356        assert_eq!(v.get("host").unwrap().as_str(), Some("local"));
4357        assert_eq!(v.get("port"), Some(&Value::Int(8080)));
4358        let _ = std::fs::remove_dir_all(&d);
4359    }
4360
4361    #[test]
4362    fn include_at_prefix_is_equivalent() {
4363        let d = tmpdir("at");
4364        std::fs::write(d.join("p.sml"), "b: 2\n").unwrap();
4365        std::fs::write(d.join("m.sml"), "@include \"p.sml\"\n").unwrap();
4366        let v = parse_file(d.join("m.sml")).unwrap();
4367        assert_eq!(v.get("b"), Some(&Value::Int(2)));
4368        let _ = std::fs::remove_dir_all(&d);
4369    }
4370
4371    #[test]
4372    fn include_resolves_relative_to_including_file() {
4373        // 关键:相对路径按「被包含文件自身目录」解析,而非进程工作目录
4374        let d = tmpdir("nested");
4375        std::fs::create_dir_all(d.join("sub")).unwrap();
4376        std::fs::write(d.join("sub/leaf.sml"), "@version v1\nleaf: yes\n").unwrap();
4377        // mid 在根,include sub/mid2;mid2 在 sub 内,include leaf.sml(相对 sub)
4378        std::fs::write(d.join("sub/mid2.sml"), "@version v1\ninclude \"leaf.sml\"\n").unwrap();
4379        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"sub/mid2.sml\"\n").unwrap();
4380
4381        let v = parse_file(d.join("main.sml")).unwrap();
4382        assert_eq!(
4383            v.get("leaf").unwrap().as_str(),
4384            Some("yes"),
4385            "嵌套 include 的路径应相对各自所在目录解析"
4386        );
4387        let _ = std::fs::remove_dir_all(&d);
4388    }
4389
4390    #[test]
4391    fn include_inside_block_injects_fields() {
4392        // 文本内联语义:可在块内注入一组字段
4393        let d = tmpdir("block");
4394        std::fs::write(d.join("fields.sml"), "@version v1\nregion: cn-north-1\nzone: a\n").unwrap();
4395        std::fs::write(d.join("main.sml"), "@version v1\nserver web {\ninclude \"fields.sml\"\nport: 8080\n}\n").unwrap();
4396
4397        let v = parse_file(d.join("main.sml")).unwrap();
4398        let server = v.get("server").expect("应有 server 块");
4399        assert_eq!(server.get("region").unwrap().as_str(), Some("cn-north-1"));
4400        assert_eq!(server.get("zone").unwrap().as_str(), Some("a"));
4401        assert_eq!(server.get("port"), Some(&Value::Int(8080)));
4402        let _ = std::fs::remove_dir_all(&d);
4403    }
4404
4405    #[test]
4406    fn include_detects_cycles() {
4407        let d = tmpdir("cycle");
4408        std::fs::write(d.join("a.sml"), "include \"b.sml\"\n").unwrap();
4409        std::fs::write(d.join("b.sml"), "include \"a.sml\"\n").unwrap();
4410        let err = parse_file(d.join("a.sml")).unwrap_err();
4411        assert!(err.contains("循环引用"), "应报循环引用,got: {err}");
4412        let _ = std::fs::remove_dir_all(&d);
4413    }
4414
4415    #[test]
4416    fn include_missing_file_is_error() {
4417        let d = tmpdir("missing");
4418        std::fs::write(d.join("m.sml"), "include \"nope.sml\"\n").unwrap();
4419        let err = parse_file(d.join("m.sml")).unwrap_err();
4420        assert!(err.contains("nope.sml"), "错误应含缺失文件名,got: {err}");
4421        let _ = std::fs::remove_dir_all(&d);
4422    }
4423
4424    #[test]
4425    fn hash_in_quoted_string_is_not_a_comment() {
4426        // 引号内的 # 不应被当成注释,否则 `include "a#b.sml"` 会被截断
4427        assert_eq!(strip_line_comment("k: \"a#b\""), "k: \"a#b\"");
4428        assert_eq!(strip_line_comment("k: v # comment"), "k: v ");
4429    }
4430
4431    #[test]
4432    fn glob_include_requires_feature() {
4433        // 未开启 glob-include 时,`*` 模式应报错
4434        let d = tmpdir("globoff");
4435        std::fs::write(d.join("a.sml"), "x: 1\n").unwrap();
4436        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"*.sml\"\n").unwrap();
4437        let err = parse_file(d.join("main.sml")).unwrap_err();
4438        assert!(err.contains("glob-include"), "应要求 glob-include,got: {err}");
4439        let _ = std::fs::remove_dir_all(&d);
4440    }
4441
4442    #[test]
4443    fn glob_include_expands_multiple_files() {
4444        // 开启 glob-include 后,`lib/*.sml` 展开为子目录下所有 .sml(main.sml 不在该目录,避免自包含)
4445        let d = tmpdir("glob");
4446        std::fs::create_dir_all(d.join("lib")).unwrap();
4447        std::fs::write(d.join("lib/a.sml"), "@version v1\nx: 1\n").unwrap();
4448        std::fs::write(d.join("lib/b.sml"), "@version v1\ny: 2\n").unwrap();
4449        std::fs::write(d.join("note.txt"), "ignored\n").unwrap();
4450        std::fs::write(d.join("main.sml"), "@version v1\n@feature enable glob-include\ninclude \"lib/*.sml\"\n").unwrap();
4451        let v = parse_file(d.join("main.sml")).unwrap();
4452        assert_eq!(v.get("x"), Some(&Value::Int(1)));
4453        assert_eq!(v.get("y"), Some(&Value::Int(2)));
4454        let _ = std::fs::remove_dir_all(&d);
4455    }
4456
4457    #[test]
4458    fn regex_include_requires_feature() {
4459        let d = tmpdir("regexoff");
4460        std::fs::write(d.join("a.sml"), "x: 1\n").unwrap();
4461        std::fs::write(d.join("main.sml"), "@version v1\ninclude \"re:.*\\.sml\"\n").unwrap();
4462        let err = parse_file(d.join("main.sml")).unwrap_err();
4463        assert!(err.contains("regex-include"), "应要求 regex-include,got: {err}");
4464        let _ = std::fs::remove_dir_all(&d);
4465    }
4466
4467    #[test]
4468    fn regex_include_matches_files() {
4469        let d = tmpdir("regex");
4470        std::fs::write(d.join("widget_a.sml"), "@version v1\nx: 1\n").unwrap();
4471        std::fs::write(d.join("widget_b.sml"), "@version v1\ny: 2\n").unwrap();
4472        std::fs::write(d.join("other.sml"), "@version v1\nz: 3\n").unwrap();
4473        std::fs::write(
4474            d.join("main.sml"),
4475            "@version v1\n@feature enable regex-include\ninclude \"re:widget_.*\\.sml\"\n",
4476        )
4477        .unwrap();
4478        let v = parse_file(d.join("main.sml")).unwrap();
4479        assert_eq!(v.get("x"), Some(&Value::Int(1)));
4480        assert_eq!(v.get("y"), Some(&Value::Int(2)));
4481        assert_eq!(v.get("z"), None, "other.sml 不应被正则匹配");
4482        let _ = std::fs::remove_dir_all(&d);
4483    }
4484
4485    #[test]
4486    fn ext_rewrite_allows_non_sml() {
4487        // ext-rewrite 开启时,include 非 .sml 文件按 sml 解析
4488        let d = tmpdir("exrew");
4489        std::fs::write(d.join("conf.smlc"), "@version v1\nx: 9\n").unwrap();
4490        std::fs::write(
4491            d.join("main.sml"),
4492            "@version v1\n@feature enable ext-rewrite\ninclude \"conf.smlc\"\n",
4493        )
4494        .unwrap();
4495        let v = parse_file(d.join("main.sml")).unwrap();
4496        assert_eq!(v.get("x"), Some(&Value::Int(9)));
4497        let _ = std::fs::remove_dir_all(&d);
4498    }
4499
4500    #[test]
4501    fn include_line_is_not_confused_with_key_named_include() {
4502        let f = FeatureSet::baseline();
4503        // `key: include` 不是指令——前面有 key 与冒号
4504        assert_eq!(parse_include_line("key: include", f), Ok(None));
4505        // 带扩展名无 as ⇒ 普通内联(namespace = None)
4506        assert_eq!(
4507            parse_include_line("include \"a.sml\"", f),
4508            Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false }]))
4509        );
4510        // @include 等价
4511        assert_eq!(
4512            parse_include_line("@include \"a.sml\"", f),
4513            Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false }]))
4514        );
4515        // 显式 as ns
4516        assert_eq!(
4517            parse_include_line("include \"a.sml\" as ui.form", f),
4518            Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: Some("ui.form".into()), via_import: false }]))
4519        );
4520        // 无扩展名 ⇒ implicit-ns 默认 as 文件名
4521        assert_eq!(
4522            parse_include_line("include \"widgets\"", f),
4523            Ok(Some(vec![IncludeTarget { raw: "widgets".into(), namespace: Some("widgets".into()), via_import: false }]))
4524        );
4525        // import 别名
4526        assert_eq!(
4527            parse_include_line("import ui.buttons", f),
4528            Ok(Some(vec![IncludeTarget { raw: "ui.buttons".into(), namespace: Some("ui.buttons".into()), via_import: true }]))
4529        );
4530        // 多目标(需 multi-include)
4531        let fm = FeatureSet::all();
4532        assert_eq!(
4533            parse_include_line("include \"a.sml\", \"b\" as y", fm),
4534            Ok(Some(vec![
4535                IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false },
4536                IncludeTarget { raw: "b".into(), namespace: Some("y".into()), via_import: false },
4537            ]))
4538        );
4539        // 注释行不生效
4540        assert_eq!(parse_include_line("# include \"a.sml\"", f), Ok(None));
4541    }
4542
4543    // ---------------- 邮箱 / 裸词中的 @ ----------------
4544
4545    #[test]
4546    fn email_in_bare_word_survives() {
4547        // 回归:裸词中的 `@` 曾被切成 At token,导致邮箱被截断为 `a`
4548        let v = parse("to: a@b.c\nfrom: \"sal <sal@mail.swebase.cn>\"\n").unwrap();
4549        assert_eq!(v.get("to").unwrap().as_str(), Some("a@b.c"), "got: {v:?}");
4550        assert_eq!(
4551            v.get("from").unwrap().as_str(),
4552            Some("sal <sal@mail.swebase.cn>"),
4553            "got: {v:?}"
4554        );
4555    }
4556
4557    #[test]
4558    fn email_roundtrips_through_to_sml() {
4559        let v = Value::Object(BTreeMap::from([(
4560            "to".to_string(),
4561            Value::Str("SALflake@qq.com".into()),
4562        )]));
4563        let back = parse(&to_sml(&v)).unwrap();
4564        assert_eq!(back, v, "邮箱必须能往返,got:\n{}", to_sml(&v));
4565    }
4566
4567    #[test]
4568    fn fragment_definition_still_works() {
4569        // 词首的 `@` 仍是片段定义标记,不能被上面的修改破坏。
4570        // 注:SML 的片段继承用法是「定义后作为值引用」(`k: &base`);
4571        // 块内裸写 `&base` 会被当作键,不属于本用例覆盖范围。
4572        let v = parse("@base { region: cn }\nregion: &base\n").unwrap();
4573        assert_eq!(
4574            v.get("region").unwrap().get("region").unwrap().as_str(),
4575            Some("cn"),
4576            "片段引用应展开为定义的内容,got: {v:?}"
4577        );
4578    }
4579
4580    // ---------------- 顶层数组 / 对象(与 to_sml 对称)----------------
4581
4582    #[test]
4583    fn toplevel_array_roundtrips() {
4584        // 回归:to_sml 能输出顶层数组,但 parse 曾只认键值块,
4585        // 导致「能写不能读」("期望键, 得 LBrack")。
4586        let v = Value::Array(vec![
4587            Value::Object(BTreeMap::from([
4588                ("ts".to_string(), Value::Str("2026-01-01".into())),
4589                ("to".to_string(), Value::Str("a@b.c".into())),
4590            ])),
4591            Value::Object(BTreeMap::from([
4592                ("ts".to_string(), Value::Str("2026-01-02".into())),
4593                ("to".to_string(), Value::Str("x@y.z".into())),
4594            ])),
4595        ]);
4596        let text = to_sml(&v);
4597        let back = parse(&text).unwrap();
4598        assert_eq!(back, v, "顶层对象数组必须能往返,got text:\n{text}");
4599    }
4600
4601    #[test]
4602    fn toplevel_array_of_scalars_roundtrips() {
4603        let v = Value::Array(vec![
4604            Value::Int(1),
4605            Value::Str("two".into()),
4606            Value::Bool(true),
4607        ]);
4608        let back = parse(&to_sml(&v)).unwrap();
4609        assert_eq!(back, v, "顶层标量数组必须能往返");
4610    }
4611
4612    #[test]
4613    fn toplevel_object_block_roundtrips() {
4614        let mut m = BTreeMap::new();
4615        m.insert("k".to_string(), Value::Int(1));
4616        let v = Value::Object(m);
4617        let back = parse(&to_sml(&v)).unwrap();
4618        assert_eq!(back, v, "顶层对象块必须能往返");
4619    }
4620
4621    #[test]
4622    fn toplevel_empty_array_roundtrips() {
4623        let v = Value::Array(vec![]);
4624        let back = parse(&to_sml(&v)).unwrap();
4625        assert_eq!(back, v, "空数组必须能往返");
4626    }
4627
4628    // ---------------- serde ----------------
4629
4630    #[cfg(feature = "serde")]
4631    #[test]
4632    fn serde_roundtrip_preserves_shape() {
4633        let v = parse("name: John\nage: 27\ntags: [a b]\nnested { k: v }\n").unwrap();
4634        let json = serde_json::to_string(&v).unwrap();
4635        // 自然形状:字符串就是字符串,数字就是数字,而非 {"Int":27}
4636        assert!(json.contains("\"name\":\"John\""), "got: {json}");
4637        assert!(json.contains("\"age\":27"), "got: {json}");
4638        assert!(json.contains("\"tags\":[\"a\",\"b\"]"), "got: {json}");
4639        assert!(json.contains("\"nested\":{\"k\":\"v\"}"), "got: {json}");
4640
4641        let back: Value = serde_json::from_str(&json).unwrap();
4642        assert_eq!(back, v, "serde 往返应还原原值");
4643    }
4644
4645    #[cfg(feature = "serde")]
4646    #[test]
4647    fn serde_deserializes_json_into_value() {
4648        let v: Value = serde_json::from_str(r#"{"s":"x","i":5,"f":1.5,"b":true,"n":null,"a":[1,2]}"#).unwrap();
4649        assert_eq!(v.get("s").unwrap().as_str(), Some("x"));
4650        assert_eq!(v.get("i"), Some(&Value::Int(5)));
4651        assert_eq!(v.get("f"), Some(&Value::Float(1.5)));
4652        assert_eq!(v.get("b"), Some(&Value::Bool(true)));
4653        assert_eq!(v.get("n"), Some(&Value::Null));
4654        assert!(matches!(v.get("a"), Some(Value::Array(a)) if a.len() == 2));
4655    }
4656
4657    #[test]
4658    fn nested_array_inside_object_inside_array_survives_roundtrip() {
4659        // 回归测试:数组元素是对象、对象里又有数组(如配置的条目列表)。
4660        // dump_inline 曾把嵌套数组缩略成 [..],导致 chunks 丢成 [".."]。
4661        let mut item = BTreeMap::new();
4662        item.insert("path".to_string(), Value::Str("a.txt".into()));
4663        item.insert(
4664            "chunks".to_string(),
4665            Value::Array(vec![
4666                Value::Str("c1".into()),
4667                Value::Str("c2".into()),
4668            ]),
4669        );
4670        let mut root = BTreeMap::new();
4671        root.insert(
4672            "entries".to_string(),
4673            Value::Array(vec![Value::Object(item)]),
4674        );
4675        let text = to_sml(&Value::Object(root));
4676        assert!(!text.contains("[..]"), "嵌套数组不得被缩略: {text}");
4677
4678        let back = parse(&text).unwrap();
4679        let chunks = back.get("entries").and_then(|e| match e {
4680            Value::Array(a) => a.first(),
4681            _ => None,
4682        });
4683        let chunks = match chunks {
4684            Some(Value::Object(m)) => m.get("chunks"),
4685            _ => None,
4686        };
4687        match chunks {
4688            Some(Value::Array(a)) => {
4689                assert_eq!(a.len(), 2, "两个块都应保留: {text}");
4690                assert_eq!(
4691                    a.iter().filter_map(|c| c.as_str()).collect::<Vec<_>>(),
4692                    vec!["c1", "c2"]
4693                );
4694            }
4695            other => panic!("chunks 应解析为数组,实际 {other:?}"),
4696        }
4697    }
4698
4699    #[test]
4700    fn utf8_in_quoted_string_survives_roundtrip() {
4701        // 回归测试:tokenizer 曾按字节 `as char` 逐个处理,
4702        // 把 UTF-8 多字节字符拆成 Latin-1 字符,导致
4703        // `"修复若干问题"` 解析后变成双编码乱码。
4704        let v = parse(r#"note: "修复若干问题""#).unwrap();
4705        assert_eq!(
4706            v.get("note").and_then(|x| x.as_str()),
4707            Some("修复若干问题"),
4708            "引号串中的中文不应被破坏"
4709        );
4710        // 裸词中文同样不能破坏
4711        let v2 = parse("region: 华北").unwrap();
4712        assert_eq!(v2.get("region").and_then(|x| x.as_str()), Some("华北"));
4713        // 转义 \u 序列
4714        let v3 = parse(r#"k: "\u{4fee}\u{590d}""#).unwrap();
4715        assert_eq!(v3.get("k").and_then(|x| x.as_str()), Some("修复"));
4716    }
4717
4718    #[test]
4719    fn parse_basic() {
4720        let text = "firstName: John\nage: 27\nisAlive: true\nspouse: null\n";
4721        let v = parse(text).unwrap();
4722        assert_eq!(v.get("firstName"), Some(&Value::Str("John".into())));
4723        assert_eq!(v.get("age"), Some(&Value::Int(27)));
4724        assert_eq!(v.get("isAlive"), Some(&Value::Bool(true)));
4725        assert_eq!(v.get("spouse"), Some(&Value::Null));
4726    }
4727
4728    #[test]
4729    fn parse_nested() {
4730        let text = "address:\n{\n    streetAddress: \"21 2nd Street\"\n    state: NY\n}\n";
4731        let v = parse(text).unwrap();
4732        assert_eq!(
4733            v.get("address.streetAddress"),
4734            Some(&Value::Str("21 2nd Street".into()))
4735        );
4736        assert_eq!(v.get("address.state"), Some(&Value::Str("NY".into())));
4737    }
4738
4739    #[test]
4740    fn parse_array() {
4741        let text = "phoneNumbers:\n[\n    { type: home }\n    { type: office }\n]\n";
4742        let v = parse(text).unwrap();
4743        if let Some(Value::Array(a)) = v.get("phoneNumbers") {
4744            assert_eq!(a.len(), 2);
4745            assert_eq!(a[0].get("type"), Some(&Value::Str("home".into())));
4746        } else {
4747            panic!("not array");
4748        }
4749    }
4750
4751    #[test]
4752    fn parse_fragment() {
4753        let text = "@base { region: cn-north-1 }\nserver web { &base }\n";
4754        let v = parse(text).unwrap();
4755        // &base 展开为字段 (键名 "&base", 值=片段对象), 与 Lua 实现一致
4756        assert_eq!(
4757            v.get("server.&base.region"),
4758            Some(&Value::Str("cn-north-1".into()))
4759        );
4760        assert_eq!(v.get("server.__type"), Some(&Value::Str("server".into())));
4761        assert_eq!(v.get("server.__name"), Some(&Value::Str("web".into())));
4762    }
4763
4764    #[test]
4765    fn roundtrip() {
4766        let text = "name: myapp\nport: 8080\nflags: [ a b c ]\n";
4767        let v = parse(text).unwrap();
4768        let out = to_sml(&v);
4769        let v2 = parse(&out).unwrap();
4770        assert_eq!(v, v2);
4771    }
4772
4773    #[test]
4774    fn env_inline() {
4775        // Rust 1.85+ 起 set_var 为 unsafe(与 edition 无关,2021/2024 均需)
4776        unsafe { std::env::set_var("SML_TEST_VAR", "hello") };
4777        let text = "greeting: $env.SML_TEST_VAR\n";
4778        let v = parse(text).unwrap();
4779        assert_eq!(v.get("greeting"), Some(&Value::Str("hello".into())));
4780    }
4781
4782    #[test]
4783    fn c_abi_json_bridge() {
4784        let text = "name: John\nage: 27\n";
4785        let v = parse(text).unwrap();
4786        let j = jsonify(&v);
4787        assert!(j.contains("\"name\":\"John\""));
4788        let back = json_to_value(&j).unwrap();
4789        assert_eq!(back, v);
4790    }
4791}
4792
4793// ===========================================================================
4794// @feature 特性裁剪 + 调用方限制 测试
4795// ===========================================================================
4796
4797#[cfg(test)]
4798mod feature {
4799    use super::*;
4800
4801    #[test]
4802    fn feature_unknown_name_errors() {
4803        let r = parse("@feature enable nope\nx: 1\n");
4804        assert!(r.is_err());
4805        assert!(r.unwrap_err().contains("未知特性"));
4806    }
4807
4808    #[test]
4809    fn feature_whitelist_narrows() {
4810        // 仅保留 bareword 与 include,其它(env/fragment/contract...)关闭
4811        let v = match parse("@feature whitelist bareword-string,include\nx: John\n").unwrap() {
4812            Value::Object(m) => m,
4813            _ => panic!("应为对象"),
4814        };
4815        assert_eq!(v.get("x"), Some(&Value::Str("John".into())));
4816    }
4817
4818    #[test]
4819    fn feature_blacklist_removes() {
4820        // 关掉 bareword-string:v1 文档里裸词字符串也应被拒
4821        let r = parse("@feature blacklist bareword-string\nx: John\n");
4822        assert!(r.is_err());
4823        assert!(r.unwrap_err().contains("字符串必须加引号"));
4824    }
4825
4826    #[test]
4827    fn feature_mode_whitelist_enable() {
4828        // mode whitelist 后基集清空,仅 enable 的生效
4829        let r = parse("@feature mode whitelist\n@feature enable fragment\nx: &frag\n");
4830        // fragment 没定义,回退为字符串 "&frag",不报错即可
4831        assert!(r.is_ok());
4832    }
4833
4834    #[test]
4835    fn caller_allowed_intersection_empty_errors() {
4836        // 调用方只接受 env;文档用白名单模式只开 contract —— 与调用方无交集则报错
4837        let allowed = FeatureSet::none().with(Feature::Env);
4838        let r = parse_with_features(
4839            "@feature mode whitelist\n@feature enable contract\nx: 1\n",
4840            allowed,
4841        );
4842        assert!(r.is_err());
4843    }
4844
4845    #[test]
4846    fn caller_allowed_subset_ok() {
4847        // 调用方允许全部,文档收窄到 bareword+include,应成功
4848        let allowed = FeatureSet::all();
4849        let (v, eff) = parse_with_features(
4850            "@feature whitelist bareword-string,include\nx: John\n",
4851            allowed,
4852        )
4853        .unwrap();
4854        assert!(eff.has(Feature::BarewordStr));
4855        assert!(eff.has(Feature::Include));
4856        assert!(!eff.has(Feature::Env));
4857        assert_eq!(v.get("x"), Some(&Value::Str("John".into())));
4858    }
4859
4860    #[test]
4861    fn feature_namespace_include() {
4862        // 用临时文件验证 include "x.sml" as ns 把键挂到 ns 下。
4863        // 用相对路径 + 正斜杠,避开 Windows 反斜杠在字符串转义中的处理。
4864        // 注意:include 展开只在 parse_file 进行,故这里把主文档也落盘。
4865        let dir = std::env::temp_dir().join("sml_feat_ns_test");
4866        let _ = std::fs::create_dir_all(&dir);
4867        let sub = dir.join("sub.sml");
4868        let main = dir.join("main.sml");
4869        std::fs::write(&sub, "a: 1\nb: 2\n").unwrap();
4870        // 用正斜杠书写相对路径,避免反斜杠被字符串转义吃掉
4871        let rel = format!("include \"sub.sml\" as pkg\n");
4872        std::fs::write(&main, &rel).unwrap();
4873        let v = match parse_file(&main) {
4874            Ok(v) => v,
4875            Err(e) => {
4876                let _ = std::fs::remove_dir_all(&dir);
4877                panic!("parse_file 失败: {e}");
4878            }
4879        };
4880        let _ = std::fs::remove_dir_all(&dir);
4881        let pkg = match v.get("pkg") {
4882            Some(Value::Object(m)) => m.clone(),
4883            _ => panic!("pkg 应为对象"),
4884        };
4885        assert_eq!(pkg.get("a"), Some(&Value::Int(1)));
4886        assert_eq!(pkg.get("b"), Some(&Value::Int(2)));
4887    }
4888
4889    #[test]
4890    fn version_v3_disables_bareword() {
4891        // v3 默认关闭 bareword-string;裸词应被拒
4892        let r = parse("@version v3\nname: John\n");
4893        assert!(r.is_err());
4894        // 但引号字符串可用
4895        let v = parse("@version v3\nname: \"John\"\nage: 27\n").unwrap();
4896        assert_eq!(v.get("name"), Some(&Value::Str("John".into())));
4897        assert_eq!(v.get("age"), Some(&Value::Int(27)));
4898    }
4899
4900    #[test]
4901    fn feature_base_derives_strict() {
4902        // @feature base v3 等价于 v3 严格
4903        let r = parse("@feature base v3\nname: John\n");
4904        assert!(r.is_err());
4905    }
4906}