1use std::collections::BTreeMap;
56use std::fmt;
57use std::path::{Path, PathBuf};
58
59#[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 Object(BTreeMap<String, Value>),
73}
74
75impl Value {
76 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 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#[derive(Debug, Clone, PartialEq)]
136pub enum TypeSpec {
137 Any,
139 ContractRef(String),
145 Str,
146 Int,
147 Num,
149 Bool,
150 Array(Box<TypeSpec>),
152 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#[derive(Debug, Clone)]
173pub struct FieldSpec {
174 pub ty: TypeSpec,
175 pub required: bool,
177 pub default: Option<Value>,
179 pub min: Option<f64>,
181 pub max: Option<f64>,
183}
184
185#[derive(Debug, Clone)]
187pub struct Contract {
188 pub name: String,
189 pub fields: BTreeMap<String, FieldSpec>,
190 pub allow_extra: bool,
194}
195
196fn check_type(
199 contract: &str,
200 field: &str,
201 spec: &FieldSpec,
202 v: &Value,
203 contracts: &BTreeMap<String, Contract>,
204) -> Result<(), String> {
205 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 (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 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
303fn apply_contract(
308 c: &Contract,
309 node: &mut BTreeMap<String, Value>,
310 contracts: &BTreeMap<String, Contract>,
311) -> Result<(), String> {
312 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 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 if matches!(spec.ty, TypeSpec::ContractRef(_)) {
340 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
358fn 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 check_type(contract, field, spec, &Value::Object(sub.clone()), contracts)?;
378 apply_contract(target, sub, contracts)
379}
380
381#[derive(Debug, Clone, PartialEq)]
386enum Tok {
387 LBrace, RBrace, LBrack, RBrack, Comma, Colon, At, Str(String), Word(String), }
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 for c2 in chars.by_ref() {
412 if c2 == '\n' {
413 break;
414 }
415 }
416 }
417 '-' => {
418 if chars.peek() == Some(&'-') {
420 chars.next(); 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 Some('/') => {
434 chars.next(); for c2 in chars.by_ref() {
436 if c2 == '\n' {
437 break;
438 }
439 }
440 }
441 Some('*') => {
443 chars.next(); 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 _ => buf.push(c),
459 }
460 }
461 '_' => {
462 if chars.peek() == Some(&'*') {
464 chars.next(); 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 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 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 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
577fn 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 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 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 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 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 contracts: BTreeMap<String, Contract>,
647 features: FeatureSet,
649 ns_stack: Vec<String>,
653}
654
655impl Parser {
656 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 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 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 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 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 let mut required = true;
784 let mut default = None;
785 let mut min = None;
786 let mut max = None;
787 loop {
788 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 fn parse_block(&mut self, closing: Option<Tok>) -> Result<Value, String> {
841 let mut node: BTreeMap<String, Value> = BTreeMap::new();
842 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 break;
859 }
860 Tok::Comma => {
861 self.next();
862 }
863 Tok::At => {
864 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 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 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 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 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 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 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 self.fragments.insert(self.qualify(&fname), Value::Object(sub));
968 }
969 }
970 _ => {
971 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 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 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 fn parse_value(&mut self, key: &str, colon: bool) -> Result<Value, String> {
1010 if !colon && matches!(self.peek(), Some(Tok::Word(_))) {
1012 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 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 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 Some(Tok::RBrace) | Some(Tok::RBrack) | Some(Tok::Comma) | None => {
1084 if colon {
1085 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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
1132pub enum Version {
1133 V1,
1135 V2,
1137 V3,
1140}
1141
1142impl Version {
1143 pub const CURRENT: Version = Version::V3;
1145
1146 pub fn strict_strings(self) -> bool {
1148 self >= Version::V2
1149 }
1150
1151 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1191pub enum Feature {
1192 BarewordStr,
1194 Include,
1196 Env,
1198 Contract,
1200 Fragment,
1202 TopArray,
1204 Namespace,
1206 ImplicitNs,
1208 MultiInclude,
1210 GlobInclude,
1212 RegexInclude,
1214 ExtRewrite,
1216}
1217
1218pub 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 pub fn from_name(name: &str) -> Option<Feature> {
1237 FEATURES.iter().find(|(n, _)| *n == name).map(|(_, f)| *f)
1238 }
1239
1240 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1256pub struct FeatureSet(u64);
1257
1258impl FeatureSet {
1259 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 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 pub fn none() -> FeatureSet {
1286 FeatureSet(0)
1287 }
1288
1289 pub fn for_version(v: Version) -> FeatureSet {
1293 let mut s = FeatureSet::baseline();
1294 if v.strict_strings() {
1297 s = s.without(Feature::BarewordStr);
1298 } else {
1299 s = s.with(Feature::BarewordStr);
1300 }
1301 s
1302 }
1303
1304 pub fn has(self, f: Feature) -> bool {
1306 (self.0 & (1 << (f as u8))) != 0
1307 }
1308
1309 pub fn with(self, f: Feature) -> FeatureSet {
1311 FeatureSet(self.0 | (1 << (f as u8)))
1312 }
1313
1314 pub fn without(self, f: Feature) -> FeatureSet {
1316 FeatureSet(self.0 & !(1 << (f as u8)))
1317 }
1318
1319 pub fn intersection(self, other: FeatureSet) -> FeatureSet {
1321 FeatureSet(self.0 & other.0)
1322 }
1323
1324 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1351enum FeatureMode {
1352 Default,
1353 Whitelist,
1354 Blacklist,
1355}
1356
1357fn tok_word(t: &Tok) -> String {
1359 match t {
1360 Tok::Word(s) | Tok::Str(s) => s.clone(),
1361 _ => String::new(),
1362 }
1363}
1364
1365fn 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 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 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 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 *feats = FeatureSet::none();
1441 }
1442 Ok(true)
1443 }
1444 "enable" => {
1445 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
1505fn 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; }
1527 Ok(false) => {}
1528 Err(e) => return Err(e), }
1530 out.push_str(line);
1531 out.push('\n');
1532 }
1533 Ok((out, feats, base, had_feature))
1534}
1535
1536fn version_directive(line: &str) -> Result<Option<String>, String> {
1540 let content = strip_line_comment(line).trim();
1541 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
1556fn 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
1586fn 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
1601pub 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 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
1614pub 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
1633pub 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
1648pub 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
1677pub 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
1703fn 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
1709fn 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 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
1746const MAX_INCLUDE_DEPTH: usize = 32;
1761
1762fn 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 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#[derive(Debug, Clone, PartialEq, Eq)]
1782pub struct IncludeTarget {
1783 pub raw: String,
1785 pub namespace: Option<String>,
1788 pub via_import: bool,
1790}
1791
1792fn 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 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 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 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 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 for t in &targets {
1864 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
1878fn 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 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 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 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
1916fn 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 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
1942fn resolve_target_paths(
1950 t: &IncludeTarget,
1951 base: &Path,
1952 features: FeatureSet,
1953) -> Result<Vec<PathBuf>, String> {
1954 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 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 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 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 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
1994fn 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
2003fn 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 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; }
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 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 hits.sort();
2038 Ok(hits)
2039}
2040
2041fn glob_matches(pattern: &str, text: &str) -> bool {
2043 let segs: Vec<&str> = pattern.split('*').collect();
2045 if segs.is_empty() {
2046 return text.is_empty();
2047 }
2048 let mut pos = 0usize;
2049 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 if !pattern.ends_with('*') {
2067 if pos != text.len() {
2068 return false;
2069 }
2070 }
2071 true
2072}
2073
2074struct MiniRegex {
2077 pattern: String,
2078}
2079
2080fn compile_regex(pat: &str) -> MiniRegex {
2081 MiniRegex {
2083 pattern: pat.to_string(),
2084 }
2085}
2086
2087fn 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 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 if backtrack_match(p, text, start) == Some(text.len()) {
2105 return true;
2106 }
2107 }
2108 }
2109 false
2110 }
2111}
2112
2113fn backtrack_match(pat: &str, text: &str, ti: usize) -> Option<usize> {
2115 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 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 let prev = if pi >= 1 { Some(pchars[pi - 1]) } else { None };
2146 if ti < tchars.len() {
2149 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 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 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 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; }
2224 }
2225 _ => {
2226 pi += 1; }
2228 }
2229 } else {
2230 pi += 1;
2231 }
2232 }
2233 '[' => {
2234 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; }
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
2286pub 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
2308fn 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 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 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 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 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
2381fn expand_file_tokens(
2384 content: &str,
2385 base: &Path,
2386 stack: &mut Vec<PathBuf>,
2387 features: FeatureSet,
2388) -> Result<Vec<Tok>, String> {
2389 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
2404pub 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 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
2428pub 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
2444fn 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
2456fn 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("e_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 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
2525pub 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
2547use 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#[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#[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#[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#[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
2603fn 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#[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 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 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 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 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 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 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 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 pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, String> {
2945 Ok(crate::to_sml(&to_value(value)?))
2946 }
2947
2948 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 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 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 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 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 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 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 #[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
3876pub trait SmlSerialize {
3887 fn to_sml_value(&self) -> Value;
3888
3889 fn to_sml(&self) -> String {
3891 crate::to_sml(&self.to_sml_value())
3892 }
3893}
3894
3895pub trait SmlDeserialize: Sized {
3897 fn from_sml_value(v: &Value) -> Result<Self, String>;
3898
3899 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
3909pub fn to_string<T: SmlSerialize + ?Sized>(value: &T) -> String {
3922 crate::to_sml(&value.to_sml_value())
3923}
3924
3925pub fn from_str<T: SmlDeserialize>(text: &str) -> Result<T, String> {
3936 T::from_sml(text)
3937}
3938
3939#[doc(hidden)]
3941pub mod __private {
3942 use super::{SmlDeserialize, SmlSerialize, Value};
3943 use std::collections::{BTreeMap, HashMap};
3944
3945 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 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 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 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 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#[cfg(test)]
4270mod tests {
4271 use super::*;
4272
4273 #[test]
4276 fn version_defaults_to_v1_when_absent() {
4277 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 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 assert!(!err.is_empty());
4310 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 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 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 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 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 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 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 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 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 assert_eq!(parse_include_line("key: include", f), Ok(None));
4505 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 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 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 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 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 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 assert_eq!(parse_include_line("# include \"a.sml\"", f), Ok(None));
4541 }
4542
4543 #[test]
4546 fn email_in_bare_word_survives() {
4547 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 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 #[test]
4583 fn toplevel_array_roundtrips() {
4584 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 #[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 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 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 let v = parse(r#"note: "修复若干问题""#).unwrap();
4705 assert_eq!(
4706 v.get("note").and_then(|x| x.as_str()),
4707 Some("修复若干问题"),
4708 "引号串中的中文不应被破坏"
4709 );
4710 let v2 = parse("region: 华北").unwrap();
4712 assert_eq!(v2.get("region").and_then(|x| x.as_str()), Some("华北"));
4713 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 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 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#[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 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 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 let r = parse("@feature mode whitelist\n@feature enable fragment\nx: &frag\n");
4830 assert!(r.is_ok());
4832 }
4833
4834 #[test]
4835 fn caller_allowed_intersection_empty_errors() {
4836 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 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 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 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 let r = parse("@version v3\nname: John\n");
4893 assert!(r.is_err());
4894 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 let r = parse("@feature base v3\nname: John\n");
4904 assert!(r.is_err());
4905 }
4906}