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 fn feature_names() -> Vec<&'static str> {
1222 FEATURES.iter().map(|(n, _)| *n).collect()
1223}
1224
1225pub static FEATURES: &[(&str, Feature)] = &[
1227 ("bareword-string", Feature::BarewordStr),
1228 ("include", Feature::Include),
1229 ("env", Feature::Env),
1230 ("contract", Feature::Contract),
1231 ("fragment", Feature::Fragment),
1232 ("top-level-array", Feature::TopArray),
1233 ("namespace", Feature::Namespace),
1234 ("implicit-ns", Feature::ImplicitNs),
1235 ("multi-include", Feature::MultiInclude),
1236 ("glob-include", Feature::GlobInclude),
1237 ("regex-include", Feature::RegexInclude),
1238 ("ext-rewrite", Feature::ExtRewrite),
1239];
1240
1241impl Feature {
1242 pub fn from_name(name: &str) -> Option<Feature> {
1244 FEATURES.iter().find(|(n, _)| *n == name).map(|(_, f)| *f)
1245 }
1246
1247 pub fn name(self) -> &'static str {
1249 FEATURES
1250 .iter()
1251 .find(|(_, f)| *f == self)
1252 .map(|(n, _)| *n)
1253 .unwrap_or("<unknown>")
1254 }
1255}
1256
1257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1263pub struct FeatureSet(u64);
1264
1265impl FeatureSet {
1266 pub fn all() -> FeatureSet {
1269 let mut m = 0u64;
1270 for (_, f) in FEATURES {
1271 m |= 1 << (*f as u8);
1272 }
1273 FeatureSet(m)
1274 }
1275
1276 pub fn baseline() -> FeatureSet {
1280 FeatureSet::none()
1281 .with(Feature::BarewordStr)
1282 .with(Feature::Include)
1283 .with(Feature::Env)
1284 .with(Feature::Contract)
1285 .with(Feature::Fragment)
1286 .with(Feature::TopArray)
1287 .with(Feature::Namespace)
1288 .with(Feature::ImplicitNs)
1289 }
1290
1291 pub fn none() -> FeatureSet {
1293 FeatureSet(0)
1294 }
1295
1296 pub fn for_version(v: Version) -> FeatureSet {
1300 let mut s = FeatureSet::baseline();
1301 if v.strict_strings() {
1304 s = s.without(Feature::BarewordStr);
1305 } else {
1306 s = s.with(Feature::BarewordStr);
1307 }
1308 s
1309 }
1310
1311 pub fn has(self, f: Feature) -> bool {
1313 (self.0 & (1 << (f as u8))) != 0
1314 }
1315
1316 pub fn with(self, f: Feature) -> FeatureSet {
1318 FeatureSet(self.0 | (1 << (f as u8)))
1319 }
1320
1321 pub fn without(self, f: Feature) -> FeatureSet {
1323 FeatureSet(self.0 & !(1 << (f as u8)))
1324 }
1325
1326 pub fn intersection(self, other: FeatureSet) -> FeatureSet {
1328 FeatureSet(self.0 & other.0)
1329 }
1330
1331 pub fn is_empty(self) -> bool {
1333 self.0 == 0
1334 }
1335}
1336
1337impl fmt::Display for FeatureSet {
1338 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1339 let mut first = true;
1340 for (n, feat) in FEATURES {
1341 if self.has(*feat) {
1342 if !first {
1343 f.write_str(",")?;
1344 }
1345 f.write_str(n)?;
1346 first = false;
1347 }
1348 }
1349 if first {
1350 f.write_str("<none>")?;
1351 }
1352 Ok(())
1353 }
1354}
1355
1356#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1358enum FeatureMode {
1359 Default,
1360 Whitelist,
1361 Blacklist,
1362}
1363
1364fn tok_word(t: &Tok) -> String {
1366 match t {
1367 Tok::Word(s) | Tok::Str(s) => s.clone(),
1368 _ => String::new(),
1369 }
1370}
1371
1372fn apply_feature_directive(
1385 line: &str,
1386 feats: &mut FeatureSet,
1387 mode: &mut FeatureMode,
1388 base: &mut Option<Version>,
1389) -> Result<bool, String> {
1390 let content = strip_line_comment(line).trim();
1391 let toks = match tokenize(content) {
1392 Ok(t) => t,
1393 Err(_) => return Ok(false),
1394 };
1395 if toks.is_empty() || toks[0] != Tok::At {
1396 return Ok(false);
1397 }
1398 let words: Vec<String> = toks
1399 .iter()
1400 .map(|t| match t {
1401 Tok::At => "@".to_string(),
1402 other => tok_word(other),
1403 })
1404 .collect();
1405 let head = format!("{}{}", words.first().map(|s| s.as_str()).unwrap_or(""), words.get(1).map(|s| s.as_str()).unwrap_or(""));
1407 if head != "@feature" {
1408 return Ok(false);
1409 }
1410 let words: Vec<String> = words[1..].to_vec();
1412 if words.len() < 2 {
1413 return Err("@feature 指令缺少参数".into());
1414 }
1415 let arg = words[1].as_str();
1416 let names = |from: usize| -> Vec<String> {
1418 words[from..]
1419 .join(",")
1420 .split(',')
1421 .map(|s| s.trim().to_string())
1422 .filter(|s| !s.is_empty())
1423 .collect()
1424 };
1425 match arg {
1426 "base" => {
1427 let v = Version::from_word(words.get(2).map(|s| s.as_str()).unwrap_or(""))
1428 .ok_or_else(|| {
1429 format!(
1430 "@feature base 需要 v1/v2/v3,收到 `{}`",
1431 words.get(2).cloned().unwrap_or_default()
1432 )
1433 })?;
1434 *feats = FeatureSet::for_version(v);
1435 *base = Some(v);
1436 Ok(true)
1437 }
1438 "mode" => {
1439 let m = words.get(2).map(|s| s.as_str()).unwrap_or("");
1440 *mode = match m {
1441 "whitelist" => FeatureMode::Whitelist,
1442 "blacklist" => FeatureMode::Blacklist,
1443 _ => return Err(format!("@feature mode 需要 whitelist/blacklist,收到 `{m}`")),
1444 };
1445 if *mode == FeatureMode::Whitelist {
1446 *feats = FeatureSet::none();
1448 }
1449 Ok(true)
1450 }
1451 "enable" => {
1452 for n in names(2) {
1457 let f = Feature::from_name(&n).ok_or_else(|| {
1458 format!(
1459 "未知特性 `{n}`,可用:{}",
1460 FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1461 )
1462 })?;
1463 *feats = feats.with(f);
1464 }
1465 Ok(true)
1466 }
1467 "disable" => {
1468 for n in names(2) {
1469 let f = Feature::from_name(&n).ok_or_else(|| {
1470 format!(
1471 "未知特性 `{n}`,可用:{}",
1472 FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1473 )
1474 })?;
1475 *feats = feats.without(f);
1476 }
1477 Ok(true)
1478 }
1479 "whitelist" => {
1480 *mode = FeatureMode::Whitelist;
1481 let mut s = FeatureSet::none();
1482 for n in names(2) {
1483 let f = Feature::from_name(&n).ok_or_else(|| {
1484 format!(
1485 "未知特性 `{n}`,可用:{}",
1486 FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1487 )
1488 })?;
1489 s = s.with(f);
1490 }
1491 *feats = s;
1492 Ok(true)
1493 }
1494 "blacklist" => {
1495 let mut s = FeatureSet::all();
1496 for n in names(2) {
1497 let f = Feature::from_name(&n).ok_or_else(|| {
1498 format!(
1499 "未知特性 `{n}`,可用:{}",
1500 FEATURES.iter().map(|(n, _)| *n).collect::<Vec<_>>().join(", ")
1501 )
1502 })?;
1503 s = s.without(f);
1504 }
1505 *feats = s;
1506 Ok(true)
1507 }
1508 _ => Err(format!("未知 @feature 子命令 `{arg}`,可用 base/mode/enable/disable")),
1509 }
1510}
1511
1512fn strip_features(text: &str) -> Result<(String, FeatureSet, Option<Version>, bool), String> {
1522 let mut out = String::new();
1523 let mut feats = FeatureSet::all();
1524 let mut mode = FeatureMode::Default;
1525 let mut base: Option<Version> = None;
1526 let mut had_feature = false;
1527
1528 for line in text.lines() {
1529 match apply_feature_directive(line, &mut feats, &mut mode, &mut base) {
1530 Ok(true) => {
1531 had_feature = true;
1532 continue; }
1534 Ok(false) => {}
1535 Err(e) => return Err(e), }
1537 out.push_str(line);
1538 out.push('\n');
1539 }
1540 Ok((out, feats, base, had_feature))
1541}
1542
1543fn version_directive(line: &str) -> Result<Option<String>, String> {
1547 let content = strip_line_comment(line).trim();
1548 let toks = match tokenize(content) {
1550 Ok(t) => t,
1551 Err(_) => return Ok(None),
1552 };
1553 match toks.as_slice() {
1554 [Tok::At, Tok::Word(w), Tok::Word(v)] if w == "version" => Ok(Some(v.clone())),
1555 [Tok::At, Tok::Word(w), Tok::Str(v)] if w == "version" => Ok(Some(v.clone())),
1556 [Tok::At, Tok::Word(w), ..] if w == "version" => Err(
1557 "`@version` 是版本声明指令,须写作 `@version v1`;`version` 不可作为片段名".into(),
1558 ),
1559 _ => Ok(None),
1560 }
1561}
1562
1563fn strip_version(text: &str) -> Result<(String, Option<Version>), String> {
1568 let mut declared: Option<Version> = None;
1569 let mut rest = String::new();
1570 for line in text.lines() {
1571 if let Some(lit) = version_directive(line)? {
1572 let v = Version::from_word(&lit).ok_or_else(|| {
1573 format!(
1574 "不支持的 SML 版本 `{lit}`(本实现支持 {})",
1575 Version::CURRENT.name()
1576 )
1577 })?;
1578 match declared {
1579 None => declared = Some(v),
1580 Some(prev) if prev != v => {
1581 return Err(format!("@version 冲突:{} 与 {}", prev.name(), v.name()))
1582 }
1583 Some(_) => {}
1584 }
1585 continue;
1586 }
1587 rest.push_str(line);
1588 rest.push('\n');
1589 }
1590 Ok((rest, declared))
1591}
1592
1593fn features_for(v: Version, feats: FeatureSet, had_feature: bool) -> FeatureSet {
1601 if had_feature {
1602 feats
1603 } else {
1604 FeatureSet::for_version(v)
1605 }
1606}
1607
1608pub fn parse_versioned(text: &str) -> Result<(Value, Version), String> {
1613 let (rest, declared) = strip_version(text)?;
1614 let (rest, feats, base, had) = strip_features(&rest)?;
1615 let v = declared.or(base).unwrap_or(Version::V1);
1617 let feats = features_for(v, feats, had);
1618 Ok((parse_impl(&rest, v, feats)?, v))
1619}
1620
1621pub fn parse_file_versioned(path: impl AsRef<Path>) -> Result<(Value, Version), String> {
1623 let path = path.as_ref();
1624 let text =
1625 std::fs::read_to_string(path).map_err(|e| format!("读取失败 {}: {e}", path.display()))?;
1626 let base = path
1627 .parent()
1628 .map(|p| p.to_path_buf())
1629 .unwrap_or_else(|| PathBuf::from("."));
1630 let (rest, declared) = strip_version(&text)?;
1631 let (rest, feats, base_ver, had) = strip_features(&rest)?;
1632 let allowed = FeatureSet::all().intersection(feats);
1633 let v = declared.or(base_ver).unwrap_or(Version::V1);
1634 let feats = features_for(v, allowed, had);
1635 let toks = resolve_includes(&rest, &base, allowed)?;
1636 let val = parse_impl_tokens(toks, v, feats)?;
1637 Ok((val, v))
1638}
1639
1640pub fn parse(text: &str) -> Result<Value, String> {
1648 let (rest, declared) = strip_version(text)?;
1649 let (rest, feats, base, had) = strip_features(&rest)?;
1650 let v = declared.or(base).unwrap_or(Version::V1);
1651 let feats = features_for(v, feats, had);
1652 parse_impl(&rest, v, feats)
1653}
1654
1655pub fn parse_allowed(
1663 text: &str,
1664 allowed: &[Version],
1665) -> Result<Value, String> {
1666 let (rest, declared) = strip_version(text)?;
1667 let (rest, feats, base, had) = strip_features(&rest)?;
1668 let v = declared.or(base).unwrap_or(Version::V1);
1669 if !allowed.contains(&v) {
1670 return Err(format!(
1671 "sml: 文档声明版本 {} 不在本库接受的版本范围 {{{}}} 内",
1672 v.name(),
1673 allowed
1674 .iter()
1675 .map(|x| x.name())
1676 .collect::<Vec<_>>()
1677 .join(", ")
1678 ));
1679 }
1680 let feats = features_for(v, feats, had);
1681 parse_impl(&rest, v, feats)
1682}
1683
1684pub fn parse_with_features(
1693 text: &str,
1694 allowed: FeatureSet,
1695) -> Result<(Value, FeatureSet), String> {
1696 let (rest, declared) = strip_version(text)?;
1697 let (rest, feats, base, had) = strip_features(&rest)?;
1698 let v = declared.or(base).unwrap_or(Version::V1);
1699 let feats = features_for(v, feats, had);
1700 let effective = feats.intersection(allowed);
1701 if effective.is_empty() {
1702 return Err(format!(
1703 "sml: 文档请求的特性 {feats} 与调用方允许的特性 {allowed} 无交集"
1704 ));
1705 }
1706 let val = parse_impl(&rest, v, effective)?;
1707 Ok((val, effective))
1708}
1709
1710fn parse_impl(text: &str, version: Version, features: FeatureSet) -> Result<Value, String> {
1712 let toks = tokenize(text)?;
1713 parse_impl_tokens(toks, version, features)
1714}
1715
1716fn parse_impl_tokens(
1718 toks: Vec<Tok>,
1719 version: Version,
1720 features: FeatureSet,
1721) -> Result<Value, String> {
1722 let mut p = Parser {
1723 toks,
1724 i: 0,
1725 fragments: BTreeMap::new(),
1726 contracts: BTreeMap::new(),
1727 features,
1728 ns_stack: Vec::new(),
1729 };
1730 match p.peek() {
1738 Some(Tok::LBrack) => {
1739 if !p.features.has(Feature::TopArray) {
1740 return Err("sml: 顶层数组需要特性 `top-level-array`,但当前特性集已禁用".into());
1741 }
1742 p.next();
1743 p.parse_array()
1744 }
1745 Some(Tok::LBrace) => {
1746 p.next();
1747 p.parse_block(Some(Tok::RBrace))
1748 }
1749 _ => p.parse_block(None),
1750 }
1751}
1752
1753const MAX_INCLUDE_DEPTH: usize = 32;
1768
1769fn strip_line_comment(line: &str) -> &str {
1771 let bytes = line.as_bytes();
1772 let mut i = 0;
1773 let mut in_quote = false;
1774 while i < bytes.len() {
1775 match bytes[i] {
1776 b'"' => in_quote = !in_quote,
1777 b'\\' if in_quote => i += 1,
1779 b'#' if !in_quote => return &line[..i],
1780 _ => {}
1781 }
1782 i += 1;
1783 }
1784 line
1785}
1786
1787#[derive(Debug, Clone, PartialEq, Eq)]
1789pub struct IncludeTarget {
1790 pub raw: String,
1792 pub namespace: Option<String>,
1795 pub via_import: bool,
1797 pub keys: Option<Vec<String>>,
1800}
1801
1802fn parse_include_line(line: &str, features: FeatureSet) -> Result<Option<Vec<IncludeTarget>>, String> {
1823 let content = strip_line_comment(line).trim();
1824 let content = content.strip_prefix('@').unwrap_or(content).trim_start();
1825 let (via_import, rest) = if let Some(r) = content.strip_prefix("include ") {
1828 (false, r.trim_start())
1829 } else if let Some(r) = content.strip_prefix("import ") {
1830 (true, r.trim_start())
1831 } else {
1832 return Ok(None);
1833 };
1834 if !features.has(Feature::Include) {
1835 return Ok(None);
1836 }
1837 let mut targets: Vec<IncludeTarget> = Vec::new();
1838 let mut rest = rest;
1839 loop {
1840 let (raw, ns, keys, tail) = if rest.trim_start().starts_with('{') {
1845 let (keys, after) = parse_key_list(rest.trim_start())?;
1847 let after = after.trim_start();
1848 let (ns, after) = if let Some(stripped) = after.strip_prefix("as ") {
1850 let (n, t) = match next_token(stripped.trim_start()) {
1851 Some((n, t)) => (Some(n), t.trim_start()),
1852 None => return Ok(None),
1853 };
1854 (n, t)
1855 } else {
1856 (None, after)
1857 };
1858 let after = after.trim_start();
1860 let after = match after.strip_prefix("in ") {
1861 Some(a) => a.trim_start(),
1862 None => {
1863 return Err(
1864 "sml: `import { keys } ...` 必须接 `in \"file\"` 指定目标文件".into(),
1865 )
1866 }
1867 };
1868 let (path, t) = match next_token(after) {
1869 Some((p, t)) => (p, t),
1870 None => return Ok(None),
1871 };
1872 (path, ns, Some(keys), t)
1873 } else {
1874 let (path, tail0) = match next_token(rest) {
1876 Some((p, t)) => (p, t),
1877 None => {
1878 if targets.is_empty() && rest.trim().is_empty() {
1879 return Ok(None);
1880 } else {
1881 break;
1882 }
1883 }
1884 };
1885 let mut r = tail0.trim_start();
1886 let mut ns: Option<String> = None;
1888 if let Some(stripped) = r.strip_prefix("as ") {
1889 let (n, t) = match next_token(stripped.trim_start()) {
1890 Some((n, t)) => (n, t),
1891 None => return Ok(None),
1892 };
1893 ns = Some(n);
1894 r = t.trim_start();
1895 }
1896 let keys = if r.starts_with('{') {
1898 let (k, after) = parse_key_list(r)?;
1899 r = after.trim_start();
1900 Some(k)
1901 } else {
1902 None
1903 };
1904 (path, ns, keys, r)
1905 };
1906 targets.push(finalize_target(
1907 raw,
1908 ns,
1909 via_import,
1910 features,
1911 keys,
1912 ));
1913 if let Some(stripped) = tail.strip_prefix(',') {
1915 if !features.has(Feature::MultiInclude) {
1916 return Ok(None);
1917 }
1918 rest = stripped.trim_start();
1919 continue;
1920 } else {
1921 rest = tail;
1922 break;
1923 }
1924 }
1925 if targets.is_empty() {
1926 return Ok(None);
1927 }
1928 for t in &targets {
1930 if t.keys.is_some() && (t.raw.contains('*') || t.raw.starts_with("re:")) {
1932 return Err(
1933 "sml: 部分引用 `{ keys }` 不能配合 glob/regex 通配(请指定单个文件)".into(),
1934 );
1935 }
1936 if t.raw.starts_with("re:") {
1938 if !features.has(Feature::RegexInclude) {
1939 return Err("sml: 正则 include 需要特性 `regex-include`(请 @feature enable regex-include)".into());
1940 }
1941 continue;
1942 }
1943 if t.raw.contains('*') && !features.has(Feature::GlobInclude) {
1944 return Err("sml: 通配 include 需要特性 `glob-include`(请 @feature enable glob-include)".into());
1945 }
1946 }
1947 Ok(Some(targets))
1948}
1949
1950fn next_token(s: &str) -> Option<(String, &str)> {
1953 let s = s.trim_start();
1954 if s.is_empty() {
1955 return None;
1956 }
1957 if s.starts_with('"') {
1958 let bytes = s.as_bytes();
1960 let mut i = 1;
1961 let mut out = String::new();
1962 while i < bytes.len() {
1963 if bytes[i] == b'"' {
1964 i += 1;
1965 break;
1966 }
1967 if bytes[i] == b'\\' && i + 1 < bytes.len() {
1968 i += 1;
1970 out.push(bytes[i] as char);
1971 i += 1;
1972 } else {
1973 out.push(bytes[i] as char);
1974 i += 1;
1975 }
1976 }
1977 Some((out, &s[i..]))
1978 } else {
1979 let end = s
1981 .find(|c: char| c.is_whitespace() || c == ',')
1982 .unwrap_or(s.len());
1983 let (tok, tail) = s.split_at(end);
1984 Some((tok.trim().to_string(), tail))
1985 }
1986}
1987
1988fn parse_key_list(s: &str) -> Result<(Vec<String>, &str), String> {
1991 let s = s.trim_start();
1992 let Some(body) = s.strip_prefix('{') else {
1993 return Err("sml: 期望 `{ key1, key2, ... }` 键列表".into());
1994 };
1995 let close = body.find('}').ok_or("sml: 键列表缺少闭合 `}`")?;
1996 let inner = &body[..close];
1997 let mut keys: Vec<String> = Vec::new();
1998 for part in inner.split(',') {
1999 let part = part.trim();
2000 if part.is_empty() {
2001 continue;
2002 }
2003 if let Some(q) = part.strip_prefix('"') {
2005 let q = q.strip_suffix('"').unwrap_or(q);
2006 keys.push(q.to_string());
2007 } else {
2008 keys.push(part.to_string());
2009 }
2010 }
2011 if keys.is_empty() {
2012 return Err("sml: 键列表不能为空(至少指定一个键)".into());
2013 }
2014 Ok((keys, &body[close + 1..]))
2015}
2016
2017fn finalize_target(
2019 raw: String,
2020 ns: Option<String>,
2021 via_import: bool,
2022 features: FeatureSet,
2023 keys: Option<Vec<String>>,
2024) -> IncludeTarget {
2025 let namespace = match ns {
2026 Some(n) => Some(n),
2027 None => {
2028 if keys.is_some() {
2031 None
2032 } else if via_import || (features.has(Feature::ImplicitNs) && !raw.contains('.')) {
2033 Some(raw.clone())
2036 } else {
2037 None
2038 }
2039 }
2040 };
2041 IncludeTarget {
2042 raw,
2043 namespace,
2044 via_import,
2045 keys,
2046 }
2047}
2048
2049fn resolve_target_paths(
2057 t: &IncludeTarget,
2058 base: &Path,
2059 features: FeatureSet,
2060) -> Result<Vec<PathBuf>, String> {
2061 if let Some(pat) = t.raw.strip_prefix("re:") {
2063 if !features.has(Feature::RegexInclude) {
2064 return Err("sml: 正则 include 需要特性 `regex-include`(请 @feature enable regex-include)".into());
2065 }
2066 let pat = pat.trim_matches('"');
2067 let pat = pat.replace('/', std::path::MAIN_SEPARATOR_STR);
2069 let (dir, pat) = split_dir(&pat);
2070 return glob_or_regex_dir(&base.join(dir), pat, Some(pat), features);
2071 }
2072 if t.raw.contains('*') {
2074 if !features.has(Feature::GlobInclude) {
2075 return Err("sml: 通配 include 需要特性 `glob-include`(请 @feature enable glob-include)".into());
2076 }
2077 let normalized = t.raw.replace('/', std::path::MAIN_SEPARATOR_STR);
2078 let (dir, pat) = split_dir(&normalized);
2079 return glob_or_regex_dir(&base.join(dir), pat, None, features);
2080 }
2081 let path = if t.via_import {
2083 if t.raw.contains(std::path::MAIN_SEPARATOR) || t.raw.ends_with(".sml") {
2087 base.join(&t.raw)
2088 } else {
2089 let rel = t
2090 .raw
2091 .split('.')
2092 .collect::<Vec<_>>()
2093 .join(std::path::MAIN_SEPARATOR_STR);
2094 base.join(rel).with_extension("sml")
2095 }
2096 } else if t.raw.contains('.') {
2097 let _ = features.has(Feature::ExtRewrite);
2101 base.join(&t.raw)
2102 } else {
2103 base.join(format!("{}.sml", t.raw))
2104 };
2105 Ok(vec![path])
2106}
2107
2108fn split_dir(pat: &str) -> (&str, &str) {
2111 match pat.rfind(std::path::MAIN_SEPARATOR) {
2112 Some(idx) => (&pat[..idx], &pat[idx + 1..]),
2113 None => ("", pat),
2114 }
2115}
2116
2117fn glob_or_regex_dir(
2119 base: &Path,
2120 pattern: &str,
2121 regex: Option<&str>,
2122 _features: FeatureSet,
2123) -> Result<Vec<PathBuf>, String> {
2124 let mut hits: Vec<PathBuf> = Vec::new();
2125 let entries = std::fs::read_dir(base)
2126 .map_err(|e| format!("include 目录读取失败 {}: {e}", base.display()))?;
2127 let re = regex.map(|r| compile_regex(r));
2129 for ent in entries {
2130 let ent = ent.map_err(|e| format!("include 目录遍历失败: {e}"))?;
2131 let p = ent.path();
2132 if p.is_dir() {
2133 continue; }
2135 let name = match p.file_name().and_then(|n| n.to_str()) {
2136 Some(n) => n,
2137 None => continue,
2138 };
2139 let matched = if let Some(re) = &re {
2140 regex_matches(re, name)
2141 } else {
2142 let pat_file = pattern.rsplit(std::path::MAIN_SEPARATOR).next().unwrap_or(pattern);
2144 glob_matches(pat_file, name)
2145 };
2146 if matched {
2147 hits.push(p);
2148 }
2149 }
2150 hits.sort();
2152 Ok(hits)
2153}
2154
2155fn glob_matches(pattern: &str, text: &str) -> bool {
2157 let segs: Vec<&str> = pattern.split('*').collect();
2159 if segs.is_empty() {
2160 return text.is_empty();
2161 }
2162 let mut pos = 0usize;
2163 if !pattern.starts_with('*') {
2165 if !text[pos..].starts_with(segs[0]) {
2166 return false;
2167 }
2168 pos += segs[0].len();
2169 }
2170 for seg in &segs[if pattern.starts_with('*') { 0 } else { 1 }..] {
2171 if seg.is_empty() {
2172 continue;
2173 }
2174 match text[pos..].find(seg) {
2175 Some(idx) => pos += idx + seg.len(),
2176 None => return false,
2177 }
2178 }
2179 if !pattern.ends_with('*') {
2181 if pos != text.len() {
2182 return false;
2183 }
2184 }
2185 true
2186}
2187
2188struct MiniRegex {
2191 pattern: String,
2192}
2193
2194fn compile_regex(pat: &str) -> MiniRegex {
2195 MiniRegex {
2197 pattern: pat.to_string(),
2198 }
2199}
2200
2201fn regex_matches(re: &MiniRegex, text: &str) -> bool {
2203 let pat = &re.pattern;
2204 let anchored_start = pat.starts_with('^');
2205 let anchored_end = pat.ends_with('$');
2206 let p = if anchored_start { &pat[1..] } else { pat };
2207 let p = if anchored_end { &p[..p.len().saturating_sub(1)] } else { p };
2208 if anchored_start {
2210 backtrack_match(p, text, 0).is_some()
2211 } else {
2212 for start in 0..=text.len() {
2213 if backtrack_match(p, text, start).is_some() {
2214 if !anchored_end {
2215 return true;
2216 }
2217 if backtrack_match(p, text, start) == Some(text.len()) {
2219 return true;
2220 }
2221 }
2222 }
2223 false
2224 }
2225}
2226
2227fn backtrack_match(pat: &str, text: &str, ti: usize) -> Option<usize> {
2229 let pchars: Vec<char> = pat.chars().collect();
2231 let tchars: Vec<char> = text.chars().collect();
2232 fn go(pchars: &[char], tchars: &[char], pi: usize, ti: usize) -> Option<usize> {
2233 let mut pi = pi;
2234 let mut ti = ti;
2235 while pi < pchars.len() {
2236 match pchars[pi] {
2237 '\\' => {
2238 if pi + 1 >= pchars.len() {
2240 return None;
2241 }
2242 let pc = pchars[pi + 1];
2243 if ti >= tchars.len() || tchars[ti] != pc {
2244 return None;
2245 }
2246 pi += 2;
2247 ti += 1;
2248 }
2249 '.' => {
2250 if ti >= tchars.len() {
2251 return None;
2252 }
2253 pi += 1;
2254 ti += 1;
2255 }
2256 '*' => {
2257 let prev = if pi >= 1 { Some(pchars[pi - 1]) } else { None };
2260 if ti < tchars.len() {
2263 let mut end = ti;
2265 match prev {
2266 Some('.') => {
2267 while end < tchars.len() {
2268 end += 1;
2269 }
2270 }
2271 Some(c) if c != '\\' => {
2272 while end < tchars.len() && tchars[end] == c {
2273 end += 1;
2274 }
2275 }
2276 _ => {}
2277 }
2278 let mut e = end;
2280 while e >= ti {
2281 if let Some(r) = go(pchars, tchars, pi + 1, e) {
2282 return Some(r);
2283 }
2284 if e == ti {
2285 break;
2286 }
2287 e -= 1;
2288 }
2289 }
2290 return go(pchars, tchars, pi + 1, ti);
2292 }
2293 '+' => {
2294 if ti >= tchars.len() {
2295 return None;
2296 }
2297 let prev = pchars.get(pi.wrapping_sub(1)).copied();
2298 let mut consumed = 0;
2299 match prev {
2300 Some('.') => {
2301 if ti >= tchars.len() {
2302 return None;
2303 }
2304 consumed = 1;
2305 }
2306 Some(c) if c != '\\' => {
2307 if tchars[ti] != c {
2308 return None;
2309 }
2310 consumed = 1;
2311 while ti + consumed < tchars.len()
2312 && tchars[ti + consumed] == c
2313 {
2314 consumed += 1;
2315 }
2316 }
2317 _ => return None,
2318 }
2319 pi += 1;
2320 ti += consumed;
2321 }
2322 '?' => {
2323 let prev = pchars.get(pi.wrapping_sub(1)).copied();
2325 if ti < tchars.len() {
2326 match prev {
2327 Some('.') => {
2328 pi += 1;
2329 ti += 1;
2330 }
2331 Some(c) if c != '\\' => {
2332 if tchars[ti] == c {
2333 pi += 1;
2334 ti += 1;
2335 } else {
2336 pi += 1; }
2338 }
2339 _ => {
2340 pi += 1; }
2342 }
2343 } else {
2344 pi += 1;
2345 }
2346 }
2347 '[' => {
2348 let mut j = pi + 1;
2350 let negate = if j < pchars.len() && pchars[j] == '^' {
2351 j += 1;
2352 true
2353 } else {
2354 false
2355 };
2356 let mut cls = Vec::new();
2357 while j < pchars.len() && pchars[j] != ']' {
2358 if j + 2 < pchars.len()
2359 && pchars[j + 1] == '-'
2360 && pchars[j + 2] != ']'
2361 {
2362 let lo = pchars[j];
2363 let hi = pchars[j + 2];
2364 cls.push((lo, hi));
2365 j += 3;
2366 } else {
2367 cls.push((pchars[j], pchars[j]));
2368 j += 1;
2369 }
2370 }
2371 if j >= pchars.len() {
2372 return None; }
2374 if ti >= tchars.len() {
2375 return None;
2376 }
2377 let c = tchars[ti];
2378 let in_cls = cls.iter().any(|(lo, hi)| c >= *lo && c <= *hi);
2379 let ok = if negate { !in_cls } else { in_cls };
2380 if !ok {
2381 return None;
2382 }
2383 pi = j + 1;
2384 ti += 1;
2385 }
2386 c => {
2387 if ti >= tchars.len() || tchars[ti] != c {
2388 return None;
2389 }
2390 pi += 1;
2391 ti += 1;
2392 }
2393 }
2394 }
2395 Some(ti)
2396 }
2397 go(&pchars, &tchars, 0, ti)
2398}
2399
2400pub fn resolve_includes(
2412 text: &str,
2413 base: &Path,
2414 features: FeatureSet,
2415) -> Result<Vec<Tok>, String> {
2416 let mut stack: Vec<PathBuf> = Vec::new();
2417 let mut toks: Vec<Tok> = Vec::new();
2418 expand_includes(text, base, &mut stack, features, &mut toks)?;
2419 Ok(toks)
2420}
2421
2422fn expand_includes(
2424 text: &str,
2425 base: &Path,
2426 stack: &mut Vec<PathBuf>,
2427 features: FeatureSet,
2428 out: &mut Vec<Tok>,
2429) -> Result<(), String> {
2430 if stack.len() >= MAX_INCLUDE_DEPTH {
2431 return Err(format!("include 嵌套超过 {MAX_INCLUDE_DEPTH} 层"));
2432 }
2433 for line in text.lines() {
2434 match parse_include_line(line, features)? {
2435 Some(targets) => {
2436 if !features.has(Feature::Include) {
2437 return Err("sml: 当前特性集禁用了 include(include 特性)".into());
2438 }
2439 for t in targets {
2440 if t.namespace.is_some() && !features.has(Feature::Namespace) {
2441 return Err(
2442 "sml: 当前特性集禁用了命名空间包含(namespace 特性)".into(),
2443 );
2444 }
2445 let paths = resolve_target_paths(&t, base, features)?;
2447 for path in paths {
2448 let canon = path.canonicalize().map_err(|e| {
2449 format!("include 无法定位 {}: {e}", path.display())
2450 })?;
2451 if stack.iter().any(|p| p == &canon) {
2453 return Err(format!("include 循环引用: {}", canon.display()));
2454 }
2455 let content = std::fs::read_to_string(&canon)
2456 .map_err(|e| format!("include 读取失败 {}: {e}", canon.display()))?;
2457 let child_base = canon
2458 .parent()
2459 .map(|p| p.to_path_buf())
2460 .unwrap_or_else(|| PathBuf::from("."));
2461 stack.push(canon.clone());
2462 let mut inner =
2464 expand_file_tokens(&content, &child_base, stack, features)?;
2465 if let Some(keys) = &t.keys {
2467 inner = filter_top_level_keys(inner, keys);
2468 }
2469 if let Some(ns) = &t.namespace {
2471 for seg in ns.split('.') {
2472 out.push(Tok::Word(seg.to_string()));
2473 out.push(Tok::LBrace);
2474 }
2475 out.extend(inner);
2476 for _ in ns.split('.') {
2477 out.push(Tok::RBrace);
2478 }
2479 } else {
2480 out.extend(inner);
2481 }
2482 stack.pop();
2483 }
2484 }
2485 }
2486 None => {
2487 let line_toks = tokenize(line).map_err(|e| {
2489 format!("include 预处理词法错误:{e}(于行:{line})")
2490 })?;
2491 out.extend(line_toks);
2492 }
2493 }
2494 }
2495 Ok(())
2496}
2497
2498fn filter_top_level_keys(toks: Vec<Tok>, keys: &[String]) -> Vec<Tok> {
2504 let key_set: std::collections::HashSet<&str> = keys.iter().map(|s| s.as_str()).collect();
2505 let mut out: Vec<Tok> = Vec::with_capacity(toks.len());
2506 let mut i = 0;
2507 let n = toks.len();
2508 while i < n {
2509 if !matches!(toks[i], Tok::Word(_) | Tok::Str(_)) {
2511 out.push(toks[i].clone());
2512 i += 1;
2513 continue;
2514 }
2515 let key_name = match &toks[i] {
2516 Tok::Word(w) => w.clone(),
2517 Tok::Str(s) => s.clone(),
2518 _ => unreachable!(),
2519 };
2520 let j = if i + 1 < n {
2522 match &toks[i + 1] {
2523 Tok::Colon => {
2525 if i + 2 < n {
2526 match &toks[i + 2] {
2527 Tok::LBrace | Tok::LBrack => {
2529 let mut depth = 1i32;
2530 let mut k = i + 3;
2531 while k < n {
2532 match &toks[k] {
2533 Tok::LBrace | Tok::LBrack => depth += 1,
2534 Tok::RBrace | Tok::RBrack => {
2535 depth -= 1;
2536 if depth == 0 {
2537 break;
2538 }
2539 }
2540 _ => {}
2541 }
2542 k += 1;
2543 }
2544 (k + 1).min(n)
2545 }
2546 _ => i + 3,
2548 }
2549 } else {
2550 i + 2
2551 }
2552 }
2553 Tok::LBrace | Tok::LBrack => {
2555 let mut depth = 1i32;
2556 let mut k = i + 2;
2557 while k < n {
2558 match &toks[k] {
2559 Tok::LBrace | Tok::LBrack => depth += 1,
2560 Tok::RBrace | Tok::RBrack => {
2561 depth -= 1;
2562 if depth == 0 {
2563 break;
2564 }
2565 }
2566 _ => {}
2567 }
2568 k += 1;
2569 }
2570 (k + 1).min(n)
2571 }
2572 _ => i + 1,
2574 }
2575 } else {
2576 i + 1
2577 };
2578 if key_set.contains(key_name.as_str()) {
2579 for t in &toks[i..j] {
2580 out.push(t.clone());
2581 }
2582 }
2583 i = j;
2584 }
2585 out
2586}
2587
2588fn expand_file_tokens(
2589 content: &str,
2590 base: &Path,
2591 stack: &mut Vec<PathBuf>,
2592 features: FeatureSet,
2593) -> Result<Vec<Tok>, String> {
2594 let cleaned: String = content
2596 .lines()
2597 .filter(|l| {
2598 let t = strip_line_comment(l).trim();
2599 let t = t.strip_prefix('@').unwrap_or(t).trim_start();
2600 !(t.starts_with("version") || t.starts_with("feature"))
2601 })
2602 .collect::<Vec<_>>()
2603 .join("\n");
2604 let mut toks = Vec::new();
2605 expand_includes(&cleaned, base, stack, features, &mut toks)?;
2606 Ok(toks)
2607}
2608
2609pub fn parse_file(path: impl AsRef<Path>) -> Result<Value, String> {
2614 let path = path.as_ref();
2615 let text = std::fs::read_to_string(path)
2616 .map_err(|e| format!("读取失败 {}: {e}", path.display()))?;
2617 let base = path
2618 .parent()
2619 .map(|p| p.to_path_buf())
2620 .unwrap_or_else(|| PathBuf::from("."));
2621 let (rest, declared) = strip_version(&text)?;
2625 let (rest, feats, base_ver, had) = strip_features(&rest)?;
2626 let v = declared.or(base_ver).unwrap_or(Version::V1);
2627 let feats = features_for(v, feats, had);
2628 let allowed = FeatureSet::all().intersection(feats);
2629 let toks = resolve_includes(&rest, &base, allowed)?;
2630 parse_impl_tokens(toks, v, allowed)
2631}
2632
2633pub fn loads(text: &str) -> Result<Value, ParseError> {
2635 parse(text).map_err(ParseError)
2636}
2637
2638#[derive(Debug)]
2639pub struct ParseError(pub String);
2640
2641impl fmt::Display for ParseError {
2642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2643 write!(f, "sml parse error: {}", self.0)
2644 }
2645}
2646
2647impl std::error::Error for ParseError {}
2648
2649fn quote_if_needed(s: &str) -> String {
2654 if s.is_empty() || s.contains([' ', '\t', '\n', '\r', ':', '#', '{', '}']) {
2655 format!("\"{}\"", s.replace('\\', "\\\\").replace('"', "\\\""))
2656 } else {
2657 s.to_string()
2658 }
2659}
2660
2661fn dump_block(m: &BTreeMap<String, Value>, indent: usize, out: &mut String) {
2665 if m.is_empty() {
2666 out.push_str("{}");
2667 return;
2668 }
2669 out.push_str(&format!("\n{}{{", " ".repeat(indent)));
2670 for (k, val) in m {
2671 out.push_str(&format!("\n{}{}: ", " ".repeat(indent + 1), k));
2672 dump_value(val, indent + 1, out);
2673 }
2674 out.push_str(&format!("\n{}}}", " ".repeat(indent)));
2675}
2676
2677fn dump_value(v: &Value, indent: usize, out: &mut String) {
2678 let pad = " ".repeat(indent);
2679 match v {
2680 Value::Null => out.push_str("null"),
2681 Value::Bool(b) => out.push_str(if *b { "true" } else { "false" }),
2682 Value::Int(i) => out.push_str(&i.to_string()),
2683 Value::Float(f) => out.push_str(&format!("{}", f)),
2684 Value::Str(s) => out.push_str("e_if_needed(s)),
2685 Value::Array(a) => {
2686 if a.is_empty() {
2687 out.push_str("[]");
2688 } else {
2689 out.push('[');
2690 for e in a {
2691 out.push('\n');
2692 out.push_str(&format!("{}{}", " ".repeat(indent + 1), dump_inline(e)));
2693 }
2694 out.push_str(&format!("\n{}]", pad));
2695 }
2696 }
2697 Value::Object(m) => dump_block(m, indent, out),
2698 }
2699}
2700
2701fn dump_scalar(v: &Value) -> String {
2702 match v {
2703 Value::Null => "null".into(),
2704 Value::Bool(b) => b.to_string(),
2705 Value::Int(i) => i.to_string(),
2706 Value::Float(f) => f.to_string(),
2707 Value::Str(s) => quote_if_needed(s),
2708 _ => "".into(),
2709 }
2710}
2711
2712fn dump_inline(v: &Value) -> String {
2713 match v {
2714 Value::Object(m) => {
2715 let parts: Vec<String> = m
2717 .iter()
2718 .map(|(k, val)| format!("{}: {}", k, dump_inline(val)))
2719 .collect();
2720 format!("{{ {} }}", parts.join(", "))
2721 }
2722 Value::Array(a) => {
2723 let parts: Vec<String> = a.iter().map(dump_inline).collect();
2724 format!("[ {} ]", parts.join(", "))
2725 }
2726 other => dump_scalar(other),
2727 }
2728}
2729
2730pub fn to_sml(v: &Value) -> String {
2735 let mut out = String::new();
2736 if let Value::Object(m) = v {
2737 if m.contains_key("__type") {
2738 dump_block(m, 0, &mut out);
2739 } else {
2740 for (k, val) in m {
2741 out.push_str(&format!("{}: ", k));
2742 dump_value(val, 0, &mut out);
2743 out.push('\n');
2744 }
2745 }
2746 } else {
2747 out.push_str(&dump_inline(v));
2748 }
2749 out
2750}
2751
2752use std::os::raw::{c_char, c_int};
2757use std::ptr;
2758
2759fn cstr(s: &str) -> *mut c_char {
2760 let c = std::ffi::CString::new(s).unwrap_or_default();
2761 c.into_raw()
2762}
2763
2764#[cfg_attr(edge2024, unsafe(no_mangle))]
2766#[cfg_attr(not(edge2024), no_mangle)]
2767pub extern "C" fn sml_parse(text: *const c_char) -> *mut c_char {
2768 if text.is_null() {
2769 return ptr::null_mut();
2770 }
2771 let t = unsafe { std::ffi::CStr::from_ptr(text) }.to_string_lossy().into_owned();
2772 match parse(&t) {
2773 Ok(v) => cstr(&jsonify(&v)),
2774 Err(_) => ptr::null_mut(),
2775 }
2776}
2777
2778#[cfg_attr(edge2024, unsafe(no_mangle))]
2780#[cfg_attr(not(edge2024), no_mangle)]
2781pub extern "C" fn sml_dump(json: *const c_char) -> *mut c_char {
2782 if json.is_null() {
2783 return ptr::null_mut();
2784 }
2785 let j = unsafe { std::ffi::CStr::from_ptr(json) }.to_string_lossy().into_owned();
2786 match json_to_value(&j) {
2787 Some(v) => cstr(&to_sml(&v)),
2788 None => ptr::null_mut(),
2789 }
2790}
2791
2792#[cfg_attr(edge2024, unsafe(no_mangle))]
2798#[cfg_attr(not(edge2024), no_mangle)]
2799pub unsafe extern "C" fn sml_free_str(p: *mut c_char) {
2800 if !p.is_null() {
2801 drop(unsafe { std::ffi::CString::from_raw(p) });
2802 }
2803}
2804
2805#[cfg_attr(edge2024, unsafe(no_mangle))]
2811#[cfg_attr(not(edge2024), no_mangle)]
2812pub extern "C" fn sml_version() -> *const c_char {
2813 concat!("sml ", env!("CARGO_PKG_VERSION"), "\0").as_ptr() as *const c_char
2814}
2815
2816fn parse_opts_json(opts: &str) -> Result<(Vec<Feature>, Vec<(String, String)>, Vec<Version>), String> {
2830 let mut features: Vec<Feature> = Vec::new();
2831 let mut env: Vec<(String, String)> = Vec::new();
2832 let mut allow: Vec<Version> = Vec::new();
2833 if opts.trim().is_empty() {
2834 return Ok((features, env, allow));
2835 }
2836 let b = opts.as_bytes();
2838 let mut i = 0usize;
2839 let len = b.len();
2840 while i < len && b[i] != b'{' { i += 1; }
2842 if i >= len { return Err("opts 不是 JSON object".into()); }
2843 i += 1; loop {
2845 while i < len && (b[i] == b' ' || b[i] == b'\t' || b[i] == b'\n' || b[i] == b'\r' || b[i] == b',') { i += 1; }
2847 if i >= len || b[i] == b'}' { break; }
2848 if b[i] != b'"' { return Err("opts key 须为字符串".into()); }
2850 i += 1;
2851 let ks = i;
2852 while i < len && b[i] != b'"' { i += 1; }
2853 let key = std::str::from_utf8(&b[ks..i]).map_err(|_| "opts key 非法 UTF-8".to_string())?.to_string();
2854 i += 1; while i < len && (b[i] == b' ' || b[i] == b':' || b[i] == b'\t') { i += 1; }
2856 match key.as_str() {
2857 "features" | "allow" => {
2858 if i >= len || b[i] != b'[' { return Err(format!("opts.{key} 须为数组")); }
2860 i += 1;
2861 loop {
2862 while i < len && (b[i] == b' ' || b[i] == b'\t' || b[i] == b'\n' || b[i] == b'\r' || b[i] == b',') { i += 1; }
2863 if i < len && b[i] == b']' { i += 1; break; }
2864 if i >= len || b[i] != b'"' { return Err(format!("opts.{key} 元素须为字符串")); }
2865 i += 1;
2866 let vs = i;
2867 while i < len && b[i] != b'"' { i += 1; }
2868 let val = std::str::from_utf8(&b[vs..i]).map_err(|_| "opts 值非法 UTF-8".to_string())?.to_string();
2869 i += 1;
2870 if key == "features" {
2871 features.push(Feature::from_name(&val).ok_or_else(|| format!("未知特性 {val}"))?);
2872 } else {
2873 allow.push(Version::from_word(&val).ok_or_else(|| format!("未知版本 {val}"))?);
2874 }
2875 }
2876 }
2877 "env" => {
2878 if i >= len || b[i] != b'{' { return Err("opts.env 须为 object".into()); }
2879 i += 1;
2880 loop {
2881 while i < len && (b[i] == b' ' || b[i] == b'\t' || b[i] == b'\n' || b[i] == b'\r' || b[i] == b',') { i += 1; }
2882 if i < len && b[i] == b'}' { i += 1; break; }
2883 if i >= len || b[i] != b'"' { return Err("opts.env key 须为字符串".into()); }
2884 i += 1;
2885 let ks = i;
2886 while i < len && b[i] != b'"' { i += 1; }
2887 let ek = std::str::from_utf8(&b[ks..i]).map_err(|_| "opts.env key 非法".to_string())?.to_string();
2888 i += 1;
2889 while i < len && (b[i] == b' ' || b[i] == b':' || b[i] == b'\t') { i += 1; }
2890 if i >= len || b[i] != b'"' { return Err("opts.env value 须为字符串".into()); }
2891 i += 1;
2892 let vs = i;
2893 while i < len && b[i] != b'"' { i += 1; }
2894 let ev = std::str::from_utf8(&b[vs..i]).map_err(|_| "opts.env value 非法".to_string())?.to_string();
2895 i += 1;
2896 env.push((ek, ev));
2897 }
2898 }
2899 _ => {
2900 let mut depth = 0i32;
2902 loop {
2903 if i >= len { break; }
2904 match b[i] {
2905 b'"' => { i += 1; while i < len && b[i] != b'"' { if b[i] == b'\\' { i += 2; } else { i += 1; } } i += 1; }
2906 b'{' | b'[' => { depth += 1; i += 1; }
2907 b'}' | b']' => { depth -= 1; i += 1; if depth <= 0 { break; } }
2908 _ => { i += 1; }
2909 }
2910 }
2911 }
2912 }
2913 }
2914 Ok((features, env, allow))
2915}
2916
2917#[allow(unused_unsafe)]
2928#[cfg_attr(edge2024, unsafe(no_mangle))]
2929#[cfg_attr(not(edge2024), no_mangle)]
2930pub extern "C" fn sml_parse_ex(text: *const c_char, opts: *const c_char) -> *mut c_char {
2931 if text.is_null() {
2932 return ptr::null_mut();
2933 }
2934 let t = unsafe { std::ffi::CStr::from_ptr(text) }.to_string_lossy().into_owned();
2935 let opts_str = if opts.is_null() {
2936 String::new()
2937 } else {
2938 unsafe { std::ffi::CStr::from_ptr(opts) }.to_string_lossy().into_owned()
2939 };
2940 let (feats, env, allow) = match parse_opts_json(&opts_str) {
2941 Ok(x) => x,
2942 Err(_) => return ptr::null_mut(),
2943 };
2944 let prev: Vec<(String, Option<String>)> = env
2946 .iter()
2947 .map(|(k, _)| (k.clone(), std::env::var(k).ok()))
2948 .collect();
2949 for (k, v) in &env {
2950 unsafe { std::env::set_var(k, v) };
2951 }
2952 let result = (|| {
2953 let mut allowed = FeatureSet::all();
2955 for f in &feats {
2956 allowed = allowed.with(*f);
2957 }
2958 let val = parse_with_features(&t, allowed).map(|(v, _)| v)?;
2959 if !allow.is_empty() {
2960 let declared = strip_version(&t).ok().and_then(|(_, d)| d);
2961 if let Some(d) = declared {
2962 if !allow.contains(&d) {
2963 return Err(format!("文档声明版本 {} 不在 allow 范围", d.name()));
2964 }
2965 }
2966 }
2967 Ok(jsonify(&val))
2968 })();
2969 for (k, v) in &prev {
2971 match v {
2972 Some(old) => unsafe { std::env::set_var(k, old) },
2973 None => unsafe { std::env::remove_var(k) },
2974 }
2975 }
2976 match result {
2977 Ok(s) => cstr(&s),
2978 Err(_) => ptr::null_mut(),
2979 }
2980}
2981
2982#[cfg_attr(edge2024, unsafe(no_mangle))]
2985#[cfg_attr(not(edge2024), no_mangle)]
2986pub extern "C" fn sml_parse_file(path: *const c_char) -> *mut c_char {
2987 if path.is_null() {
2988 return ptr::null_mut();
2989 }
2990 let p = unsafe { std::ffi::CStr::from_ptr(path) }.to_string_lossy().into_owned();
2991 match parse_file(&p) {
2992 Ok(v) => cstr(&jsonify(&v)),
2993 Err(_) => ptr::null_mut(),
2994 }
2995}
2996
2997#[cfg_attr(edge2024, unsafe(no_mangle))]
3000#[cfg_attr(not(edge2024), no_mangle)]
3001pub extern "C" fn sml_features() -> *mut c_char {
3002 let names: Vec<&str> = FEATURES.iter().map(|(n, _)| *n).collect();
3003 let body = names
3004 .iter()
3005 .map(|n| format!("\"{}\"", n))
3006 .collect::<Vec<_>>()
3007 .join(",");
3008 cstr(&format!("[{}]", body))
3009}
3010
3011use std::os::raw::{c_uint, c_ulonglong};
3027
3028#[repr(C)]
3030#[derive(Clone, Copy)]
3031pub enum CSmlErrc {
3032 Ok = 0,
3033 Syntax = 1,
3034 FeatureDisabled = 2,
3035 VersionMismatch = 3,
3036 Contract = 4,
3037 IncludeLoop = 5,
3038 Io = 6,
3039 Utf8 = 7,
3040 Internal = 8,
3041}
3042
3043#[repr(C)]
3047pub struct CSmlError {
3048 pub code: c_int,
3049 pub line: c_int,
3050 pub column: c_int,
3051 pub position: usize,
3052 pub source: [c_char; 128],
3053 pub text: [c_char; 256],
3054}
3055
3056impl CSmlError {
3057 unsafe fn fill(out: *mut CSmlError, code: CSmlErrc, msg: &str, source: &str) {
3062 if out.is_null() {
3063 return;
3064 }
3065 let e = &mut *out;
3066 e.code = code as c_int;
3067 e.line = 0;
3068 e.column = 0;
3069 e.position = 0;
3070 e.source = [0; 128];
3071 e.text = [0; 256];
3072 copy_cstr(&mut e.source, source);
3073 copy_cstr(&mut e.text, msg);
3074
3075 if let Some(l) = extract_line(msg) {
3077 e.line = l;
3078 }
3079 }
3080}
3081
3082fn copy_cstr(dst: &mut [c_char], s: &str) {
3084 if dst.is_empty() {
3085 return;
3086 }
3087 let bytes = s.as_bytes();
3088 let n = bytes.len().min(dst.len() - 1);
3089 for i in 0..n {
3090 dst[i] = bytes[i] as c_char;
3091 }
3092 dst[n] = 0;
3093}
3094
3095fn extract_line(msg: &str) -> Option<c_int> {
3097 for pat in ["第 ", "line "] {
3098 if let Some(idx) = msg.find(pat) {
3099 let rest = &msg[idx + pat.len()..];
3100 let digits: String = rest.chars().take_while(|c| c.is_ascii_digit()).collect();
3101 if let Ok(n) = digits.parse::<i32>() {
3102 if n > 0 {
3103 return Some(n);
3104 }
3105 }
3106 }
3107 }
3108 None
3109}
3110
3111#[repr(transparent)]
3114pub struct CSmlValue(Value);
3115
3116fn classify(err: &str) -> CSmlErrc {
3118 if err.contains("include") && (err.contains("循环") || err.contains("loop")) {
3119 CSmlErrc::IncludeLoop
3120 } else if err.contains("特性") || err.contains("feature") {
3121 CSmlErrc::FeatureDisabled
3122 } else if err.contains("版本") || err.contains("version") {
3123 CSmlErrc::VersionMismatch
3124 } else if err.contains("契约") || err.contains("contract") {
3125 CSmlErrc::Contract
3126 } else if err.contains("读取失败") || err.contains("IO") {
3127 CSmlErrc::Io
3128 } else {
3129 CSmlErrc::Syntax
3130 }
3131}
3132
3133fn feature_set_from_flags(flags: c_uint) -> FeatureSet {
3138 if flags == 0 {
3139 return FeatureSet::baseline();
3140 }
3141 let mut s = FeatureSet::none();
3142 for (i, (_, f)) in FEATURES.iter().enumerate() {
3143 if i >= 32 {
3144 break;
3145 }
3146 if flags & (1u32 << i) != 0 {
3147 s = s.with(*f);
3148 }
3149 }
3150 s
3151}
3152
3153#[cfg_attr(edge2024, unsafe(no_mangle))]
3158#[cfg_attr(not(edge2024), no_mangle)]
3159pub unsafe extern "C" fn sml_loads(
3160 text: *const c_char,
3161 flags: c_uint,
3162 err: *mut CSmlError,
3163) -> *mut CSmlValue {
3164 if text.is_null() {
3165 CSmlError::fill(err, CSmlErrc::Internal, "sml_loads: text is NULL", "<string>");
3166 return ptr::null_mut();
3167 }
3168 let t = std::ffi::CStr::from_ptr(text).to_string_lossy().into_owned();
3169 let allowed = feature_set_from_flags(flags);
3170 match parse_with_features(&t, allowed) {
3171 Ok((v, _)) => Box::into_raw(Box::new(CSmlValue(v))),
3172 Err(e) => {
3173 CSmlError::fill(err, classify(&e), &e, "<string>");
3174 ptr::null_mut()
3175 }
3176 }
3177}
3178
3179#[cfg_attr(edge2024, unsafe(no_mangle))]
3184#[cfg_attr(not(edge2024), no_mangle)]
3185pub unsafe extern "C" fn sml_load_file(
3186 path: *const c_char,
3187 flags: c_uint,
3188 err: *mut CSmlError,
3189) -> *mut CSmlValue {
3190 if path.is_null() {
3191 CSmlError::fill(err, CSmlErrc::Internal, "sml_load_file: path is NULL", "<file>");
3192 return ptr::null_mut();
3193 }
3194 let p = std::ffi::CStr::from_ptr(path).to_string_lossy().into_owned();
3195 let _ = flags; match parse_file(&p) {
3197 Ok(v) => Box::into_raw(Box::new(CSmlValue(v))),
3198 Err(e) => {
3199 CSmlError::fill(err, classify(&e), &e, &p);
3200 ptr::null_mut()
3201 }
3202 }
3203}
3204
3205#[cfg_attr(edge2024, unsafe(no_mangle))]
3210#[cfg_attr(not(edge2024), no_mangle)]
3211pub unsafe extern "C" fn sml_free(v: *mut CSmlValue) {
3212 if !v.is_null() {
3213 drop(Box::from_raw(v));
3214 }
3215}
3216
3217#[cfg_attr(edge2024, unsafe(no_mangle))]
3219#[cfg_attr(not(edge2024), no_mangle)]
3220pub unsafe extern "C" fn sml_typeof(v: *const CSmlValue) -> c_int {
3221 if v.is_null() {
3222 return -1;
3223 }
3224 let inner = &(*(v as *const Value));
3225 match inner {
3226 Value::Null => 0,
3227 Value::Bool(_) => 1,
3228 Value::Int(_) => 2,
3229 Value::Float(_) => 3,
3230 Value::Str(_) => 4,
3231 Value::Array(_) => 5,
3232 Value::Object(_) => 6,
3233 }
3234}
3235
3236#[cfg_attr(edge2024, unsafe(no_mangle))]
3238#[cfg_attr(not(edge2024), no_mangle)]
3239pub unsafe extern "C" fn sml_get(
3240 v: *const CSmlValue,
3241 key: *const c_char,
3242) -> *const CSmlValue {
3243 if v.is_null() || key.is_null() {
3244 return ptr::null();
3245 }
3246 let inner = &(*(v as *const Value));
3247 let k = std::ffi::CStr::from_ptr(key).to_string_lossy();
3248 match inner {
3249 Value::Object(m) => m
3250 .get(k.as_ref())
3251 .map(|x| x as *const Value as *const CSmlValue)
3252 .unwrap_or(ptr::null()),
3253 _ => ptr::null(),
3254 }
3255}
3256
3257#[cfg_attr(edge2024, unsafe(no_mangle))]
3259#[cfg_attr(not(edge2024), no_mangle)]
3260pub unsafe extern "C" fn sml_get_path(
3261 v: *const CSmlValue,
3262 path: *const c_char,
3263) -> *const CSmlValue {
3264 if v.is_null() || path.is_null() {
3265 return ptr::null();
3266 }
3267 let p = std::ffi::CStr::from_ptr(path).to_string_lossy();
3268 let mut cur: *const CSmlValue = v;
3269 for seg in p.split('.') {
3270 if seg.is_empty() {
3271 continue;
3272 }
3273 let c_seg = match std::ffi::CString::new(seg) {
3274 Ok(c) => c,
3275 Err(_) => return ptr::null(),
3276 };
3277 let next = sml_get(cur, c_seg.as_ptr());
3278 if next.is_null() {
3279 return ptr::null();
3280 }
3281 cur = next;
3282 }
3283 cur
3284}
3285
3286#[cfg_attr(edge2024, unsafe(no_mangle))]
3288#[cfg_attr(not(edge2024), no_mangle)]
3289pub unsafe extern "C" fn sml_at(v: *const CSmlValue, idx: usize) -> *const CSmlValue {
3290 if v.is_null() {
3291 return ptr::null();
3292 }
3293 let inner = &(*(v as *const Value));
3294 match inner {
3295 Value::Array(a) => a
3296 .get(idx)
3297 .map(|x| x as *const Value as *const CSmlValue)
3298 .unwrap_or(ptr::null()),
3299 _ => ptr::null(),
3300 }
3301}
3302
3303#[cfg_attr(edge2024, unsafe(no_mangle))]
3305#[cfg_attr(not(edge2024), no_mangle)]
3306pub unsafe extern "C" fn sml_size(v: *const CSmlValue) -> usize {
3307 if v.is_null() {
3308 return 0;
3309 }
3310 match &(*(v as *const Value)) {
3311 Value::Array(a) => a.len(),
3312 Value::Object(m) => m.len(),
3313 _ => 0,
3314 }
3315}
3316
3317#[cfg_attr(edge2024, unsafe(no_mangle))]
3319#[cfg_attr(not(edge2024), no_mangle)]
3320pub unsafe extern "C" fn sml_str_copy(
3321 v: *const CSmlValue,
3322 buf: *mut c_char,
3323 buflen: usize,
3324) -> usize {
3325 if v.is_null() {
3326 return 0;
3327 }
3328 let s = match &(*(v as *const Value)) {
3329 Value::Str(s) => s.as_str(),
3330 _ => return 0,
3331 };
3332 let need = s.len();
3333 if buf.is_null() || buflen == 0 {
3334 return need;
3335 }
3336 let n = need.min(buflen - 1);
3337 let src = s.as_bytes();
3338 for i in 0..n {
3339 *buf.add(i) = src[i] as c_char;
3340 }
3341 *buf.add(n) = 0;
3342 need
3343}
3344
3345#[cfg_attr(edge2024, unsafe(no_mangle))]
3347#[cfg_attr(not(edge2024), no_mangle)]
3348pub unsafe extern "C" fn sml_str_dup(v: *const CSmlValue) -> *mut c_char {
3349 if v.is_null() {
3350 return ptr::null_mut();
3351 }
3352 match &(*(v as *const Value)) {
3353 Value::Str(s) => cstr(s),
3354 _ => ptr::null_mut(),
3355 }
3356}
3357
3358#[cfg_attr(edge2024, unsafe(no_mangle))]
3360#[cfg_attr(not(edge2024), no_mangle)]
3361pub unsafe extern "C" fn sml_int_value(v: *const CSmlValue) -> i64 {
3362 if v.is_null() {
3363 return 0;
3364 }
3365 match &(*(v as *const Value)) {
3366 Value::Int(i) => *i,
3367 Value::Float(f) => *f as i64,
3368 _ => 0,
3369 }
3370}
3371
3372#[cfg_attr(edge2024, unsafe(no_mangle))]
3374#[cfg_attr(not(edge2024), no_mangle)]
3375pub unsafe extern "C" fn sml_real_value(v: *const CSmlValue) -> f64 {
3376 if v.is_null() {
3377 return 0.0;
3378 }
3379 match &(*(v as *const Value)) {
3380 Value::Float(f) => *f,
3381 Value::Int(i) => *i as f64,
3382 _ => 0.0,
3383 }
3384}
3385
3386#[cfg_attr(edge2024, unsafe(no_mangle))]
3388#[cfg_attr(not(edge2024), no_mangle)]
3389pub unsafe extern "C" fn sml_bool_value(v: *const CSmlValue) -> c_int {
3390 if v.is_null() {
3391 return 0;
3392 }
3393 match &(*(v as *const Value)) {
3394 Value::Bool(b) => {
3395 if *b {
3396 1
3397 } else {
3398 0
3399 }
3400 }
3401 _ => 0,
3402 }
3403}
3404
3405#[cfg_attr(edge2024, unsafe(no_mangle))]
3409#[cfg_attr(not(edge2024), no_mangle)]
3410pub unsafe extern "C" fn sml_str_in(
3411 v: *const CSmlValue,
3412 path: *const c_char,
3413) -> *mut c_char {
3414 let node = sml_get_path(v, path);
3415 if node.is_null() {
3416 return ptr::null_mut();
3417 }
3418 sml_str_dup(node)
3419}
3420
3421#[cfg_attr(edge2024, unsafe(no_mangle))]
3423#[cfg_attr(not(edge2024), no_mangle)]
3424pub unsafe extern "C" fn sml_int_in(
3425 v: *const CSmlValue,
3426 path: *const c_char,
3427 ok: *mut c_int,
3428) -> i64 {
3429 let node = sml_get_path(v, path);
3430 if node.is_null() {
3431 if !ok.is_null() {
3432 *ok = 0;
3433 }
3434 return 0;
3435 }
3436 let is_int = sml_typeof(node) == 2;
3437 if !ok.is_null() {
3438 *ok = if is_int { 1 } else { 0 };
3439 }
3440 sml_int_value(node)
3441}
3442
3443#[cfg_attr(edge2024, unsafe(no_mangle))]
3445#[cfg_attr(not(edge2024), no_mangle)]
3446pub unsafe extern "C" fn sml_bool_in(
3447 v: *const CSmlValue,
3448 path: *const c_char,
3449 ok: *mut c_int,
3450) -> c_int {
3451 let node = sml_get_path(v, path);
3452 if node.is_null() {
3453 if !ok.is_null() {
3454 *ok = 0;
3455 }
3456 return 0;
3457 }
3458 let is_bool = sml_typeof(node) == 1;
3459 if !ok.is_null() {
3460 *ok = if is_bool { 1 } else { 0 };
3461 }
3462 sml_bool_value(node)
3463}
3464
3465#[cfg_attr(edge2024, unsafe(no_mangle))]
3467#[cfg_attr(not(edge2024), no_mangle)]
3468pub unsafe extern "C" fn sml_dumps(v: *const CSmlValue, _flags: c_uint) -> *mut c_char {
3469 if v.is_null() {
3470 return ptr::null_mut();
3471 }
3472 cstr(&to_sml(&(*(v as *const Value))))
3473}
3474
3475#[cfg_attr(edge2024, unsafe(no_mangle))]
3481#[cfg_attr(not(edge2024), no_mangle)]
3482pub extern "C" fn sml_feature_name(bit: c_uint) -> *const c_char {
3483 let s: &'static str = match bit {
3484 0 => "bareword-string\0",
3485 1 => "include\0",
3486 2 => "env\0",
3487 3 => "contract\0",
3488 4 => "fragment\0",
3489 5 => "top-level-array\0",
3490 6 => "namespace\0",
3491 7 => "implicit-ns\0",
3492 8 => "multi-include\0",
3493 9 => "glob-include\0",
3494 10 => "regex-include\0",
3495 11 => "ext-rewrite\0",
3496 _ => return ptr::null(),
3497 };
3498 s.as_ptr() as *const c_char
3499}
3500
3501#[cfg_attr(edge2024, unsafe(no_mangle))]
3503#[cfg_attr(not(edge2024), no_mangle)]
3504pub extern "C" fn sml_features_mask() -> c_uint {
3505 let mut m = 0u32;
3506 for (i, _) in FEATURES.iter().enumerate() {
3507 if i >= 32 {
3508 break;
3509 }
3510 m |= 1u32 << i;
3511 }
3512 m
3513}
3514
3515#[cfg_attr(edge2024, unsafe(no_mangle))]
3517#[cfg_attr(not(edge2024), no_mangle)]
3518pub extern "C" fn sml_version_str() -> *mut c_char {
3519 cstr(env!("CARGO_PKG_VERSION"))
3520}
3521
3522#[allow(dead_code)]
3524type _CUnsignedLongLong = c_ulonglong;
3525
3526fn jsonify(v: &Value) -> String {
3531 fn esc(s: &str) -> String {
3532 s.replace('\\', "\\\\").replace('"', "\\\"")
3533 }
3534 match v {
3535 Value::Null => "null".into(),
3536 Value::Bool(b) => b.to_string(),
3537 Value::Int(i) => i.to_string(),
3538 Value::Float(f) => f.to_string(),
3539 Value::Str(s) => format!("\"{}\"", esc(s)),
3540 Value::Array(a) => {
3541 let parts: Vec<String> = a.iter().map(jsonify).collect();
3542 format!("[{}]", parts.join(","))
3543 }
3544 Value::Object(m) => {
3545 let parts: Vec<String> = m
3546 .iter()
3547 .map(|(k, val)| format!("\"{}\":{}", esc(k), jsonify(val)))
3548 .collect();
3549 format!("{{{}}}", parts.join(","))
3550 }
3551 }
3552}
3553
3554fn json_to_value(s: &str) -> Option<Value> {
3555 let bytes = s.as_bytes();
3556 let mut i = 0;
3557 let _n = bytes.len();
3558 let mut skip_ws = |b: &[u8], i: &mut usize| {
3559 while *i < b.len() && matches!(b[*i], b' ' | b'\t' | b'\n' | b'\r') {
3560 *i += 1;
3561 }
3562 };
3563 let mut parse_str = |b: &[u8], i: &mut usize| -> Option<String> {
3564 skip_ws(b, i);
3565 if *i >= b.len() || b[*i] != b'"' {
3566 return None;
3567 }
3568 *i += 1;
3569 let mut out = String::new();
3570 while *i < b.len() {
3571 let c = b[*i];
3572 if c == b'"' {
3573 *i += 1;
3574 return Some(out);
3575 }
3576 if c == b'\\' && *i + 1 < b.len() {
3577 *i += 1;
3578 let e = b[*i];
3579 out.push(match e {
3580 b'n' => '\n',
3581 b't' => '\t',
3582 b'r' => '\r',
3583 b'"' => '"',
3584 b'\\' => '\\',
3585 _ => e as char,
3586 });
3587 } else {
3588 out.push(c as char);
3589 }
3590 *i += 1;
3591 }
3592 None
3593 };
3594 fn parse_val_impl(
3595 b: &[u8],
3596 i: &mut usize,
3597 s: &str,
3598 parse_str: &dyn Fn(&[u8], &mut usize) -> Option<String>,
3599 ) -> Option<Value> {
3600 let mut skip_ws = |b: &[u8], i: &mut usize| {
3601 while *i < b.len() && matches!(b[*i], b' ' | b'\t' | b'\n' | b'\r') {
3602 *i += 1;
3603 }
3604 };
3605 skip_ws(b, i);
3606 if *i >= b.len() {
3607 return None;
3608 }
3609 match b[*i] {
3610 b'{' => {
3611 *i += 1;
3612 let mut m = BTreeMap::new();
3613 skip_ws(b, i);
3614 if *i < b.len() && b[*i] == b'}' {
3615 *i += 1;
3616 return Some(Value::Object(m));
3617 }
3618 loop {
3619 skip_ws(b, i);
3620 let k = parse_str(b, i)?;
3621 skip_ws(b, i);
3622 if *i < b.len() && b[*i] == b':' {
3623 *i += 1;
3624 }
3625 let v = parse_val_impl(b, i, s, parse_str)?;
3626 m.insert(k, v);
3627 skip_ws(b, i);
3628 if *i < b.len() && b[*i] == b',' {
3629 *i += 1;
3630 } else if *i < b.len() && b[*i] == b'}' {
3631 *i += 1;
3632 break;
3633 }
3634 }
3635 Some(Value::Object(m))
3636 }
3637 b'[' => {
3638 *i += 1;
3639 let mut a = Vec::new();
3640 skip_ws(b, i);
3641 if *i < b.len() && b[*i] == b']' {
3642 *i += 1;
3643 return Some(Value::Array(a));
3644 }
3645 loop {
3646 a.push(parse_val_impl(b, i, s, parse_str)?);
3647 skip_ws(b, i);
3648 if *i < b.len() && b[*i] == b',' {
3649 *i += 1;
3650 } else if *i < b.len() && b[*i] == b']' {
3651 *i += 1;
3652 break;
3653 }
3654 }
3655 Some(Value::Array(a))
3656 }
3657 b'"' => parse_str(b, i).map(Value::Str),
3658 b't' => {
3659 if s[*i..].starts_with("true") {
3660 *i += 4;
3661 Some(Value::Bool(true))
3662 } else {
3663 None
3664 }
3665 }
3666 b'f' => {
3667 if s[*i..].starts_with("false") {
3668 *i += 5;
3669 Some(Value::Bool(false))
3670 } else {
3671 None
3672 }
3673 }
3674 b'n' => {
3675 if s[*i..].starts_with("null") {
3676 *i += 4;
3677 Some(Value::Null)
3678 } else {
3679 None
3680 }
3681 }
3682 _ => {
3683 let start = *i;
3684 while *i < b.len()
3685 && (b[*i].is_ascii_digit()
3686 || matches!(b[*i], b'-' | b'+' | b'.' | b'e' | b'E'))
3687 {
3688 *i += 1;
3689 }
3690 let tok = s[start..*i].to_string();
3691 if let Ok(iv) = tok.parse::<i64>() {
3692 Some(Value::Int(iv))
3693 } else if let Ok(fv) = tok.parse::<f64>() {
3694 Some(Value::Float(fv))
3695 } else {
3696 None
3697 }
3698 }
3699 }
3700 }
3701 parse_val_impl(bytes, &mut i, s, &parse_str)
3702}
3703
3704#[cfg(feature = "serde")]
3719pub mod serde {
3720 use super::Value;
3721 use ::serde::de::{self, MapAccess, SeqAccess, Visitor};
3722 use ::serde::ser::{
3723 SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant,
3724 SerializeTuple, SerializeTupleStruct, SerializeTupleVariant,
3725 };
3726 use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
3727 use ::std::collections::BTreeMap;
3728 use ::std::fmt;
3729
3730 type Error = ::serde::de::value::Error;
3732
3733 fn type_err(v: &Value, expected: &str) -> Error {
3734 de::Error::custom(format!(
3735 "期望 {expected},实际为 {}",
3736 super::__private::describe_value(v)
3737 ))
3738 }
3739
3740 impl Serialize for Value {
3741 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
3742 where
3743 S: Serializer,
3744 {
3745 match self {
3746 Value::Null => serializer.serialize_unit(),
3747 Value::Bool(b) => serializer.serialize_bool(*b),
3748 Value::Int(i) => serializer.serialize_i64(*i),
3749 Value::Float(f) => serializer.serialize_f64(*f),
3750 Value::Str(s) => serializer.serialize_str(s),
3751 Value::Array(a) => a.serialize(serializer),
3753 Value::Object(m) => {
3754 let mut map = serializer.serialize_map(Some(m.len()))?;
3755 for (k, v) in m {
3756 map.serialize_entry(k, v)?;
3757 }
3758 map.end()
3759 }
3760 }
3761 }
3762 }
3763
3764 impl<'de> Deserialize<'de> for Value {
3765 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3766 where
3767 D: Deserializer<'de>,
3768 {
3769 deserializer.deserialize_any(ValueVisitor)
3771 }
3772 }
3773
3774 struct ValueVisitor;
3775
3776 impl<'de> Visitor<'de> for ValueVisitor {
3777 type Value = Value;
3778
3779 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
3780 f.write_str("any valid SML/JSON value")
3781 }
3782
3783 fn visit_unit<E: de::Error>(self) -> Result<Value, E> {
3784 Ok(Value::Null)
3785 }
3786 fn visit_none<E: de::Error>(self) -> Result<Value, E> {
3787 Ok(Value::Null)
3788 }
3789 fn visit_some<D>(self, d: D) -> Result<Value, D::Error>
3790 where
3791 D: Deserializer<'de>,
3792 {
3793 Deserialize::deserialize(d)
3794 }
3795 fn visit_bool<E: de::Error>(self, v: bool) -> Result<Value, E> {
3796 Ok(Value::Bool(v))
3797 }
3798 fn visit_i64<E: de::Error>(self, v: i64) -> Result<Value, E> {
3799 Ok(Value::Int(v))
3800 }
3801 fn visit_u64<E: de::Error>(self, v: u64) -> Result<Value, E> {
3803 Ok(i64::try_from(v)
3804 .map(Value::Int)
3805 .unwrap_or_else(|_| Value::Float(v as f64)))
3806 }
3807 fn visit_f64<E: de::Error>(self, v: f64) -> Result<Value, E> {
3808 Ok(Value::Float(v))
3809 }
3810 fn visit_str<E: de::Error>(self, v: &str) -> Result<Value, E> {
3811 Ok(Value::Str(v.to_string()))
3812 }
3813 fn visit_string<E: de::Error>(self, v: String) -> Result<Value, E> {
3814 Ok(Value::Str(v))
3815 }
3816 fn visit_seq<A>(self, mut seq: A) -> Result<Value, A::Error>
3817 where
3818 A: SeqAccess<'de>,
3819 {
3820 let mut v = Vec::new();
3821 while let Some(x) = seq.next_element()? {
3822 v.push(x);
3823 }
3824 Ok(Value::Array(v))
3825 }
3826 fn visit_map<A>(self, mut map: A) -> Result<Value, A::Error>
3827 where
3828 A: MapAccess<'de>,
3829 {
3830 let mut m = BTreeMap::new();
3831 while let Some((k, v)) = map.next_entry::<String, Value>()? {
3832 m.insert(k, v);
3833 }
3834 Ok(Value::Object(m))
3835 }
3836 }
3837
3838 pub fn from_str<T: de::DeserializeOwned>(text: &str) -> Result<T, String> {
3852 let value = crate::parse(text)?;
3853 from_value(value)
3854 }
3855
3856 pub fn from_value<T: de::DeserializeOwned>(value: Value) -> Result<T, String> {
3858 T::deserialize(ValueDeserializer(value)).map_err(|e| e.to_string())
3859 }
3860
3861 pub fn to_value<T: Serialize + ?Sized>(value: &T) -> Result<Value, String> {
3863 value.serialize(ValueSerializer).map_err(|e| e.to_string())
3864 }
3865
3866 pub fn to_string<T: Serialize + ?Sized>(value: &T) -> Result<String, String> {
3868 Ok(crate::to_sml(&to_value(value)?))
3869 }
3870
3871 struct ValueSerializer;
3874
3875 impl Serializer for ValueSerializer {
3876 type Ok = Value;
3877 type Error = Error;
3878 type SerializeSeq = SeqSerializer;
3879 type SerializeTuple = SeqSerializer;
3880 type SerializeTupleStruct = SeqSerializer;
3881 type SerializeTupleVariant = TupleVariantSerializer;
3882 type SerializeMap = MapSerializer;
3883 type SerializeStruct = MapSerializer;
3884 type SerializeStructVariant = StructVariantSerializer;
3885
3886 fn serialize_bool(self, v: bool) -> Result<Value, Error> {
3887 Ok(Value::Bool(v))
3888 }
3889 fn serialize_i8(self, v: i8) -> Result<Value, Error> {
3890 Ok(Value::Int(v as i64))
3891 }
3892 fn serialize_i16(self, v: i16) -> Result<Value, Error> {
3893 Ok(Value::Int(v as i64))
3894 }
3895 fn serialize_i32(self, v: i32) -> Result<Value, Error> {
3896 Ok(Value::Int(v as i64))
3897 }
3898 fn serialize_i64(self, v: i64) -> Result<Value, Error> {
3899 Ok(Value::Int(v))
3900 }
3901 fn serialize_u8(self, v: u8) -> Result<Value, Error> {
3902 Ok(Value::Int(v as i64))
3903 }
3904 fn serialize_u16(self, v: u16) -> Result<Value, Error> {
3905 Ok(Value::Int(v as i64))
3906 }
3907 fn serialize_u32(self, v: u32) -> Result<Value, Error> {
3908 Ok(Value::Int(v as i64))
3909 }
3910 fn serialize_u64(self, v: u64) -> Result<Value, Error> {
3911 Ok(i64::try_from(v)
3912 .map(Value::Int)
3913 .unwrap_or_else(|_| Value::Float(v as f64)))
3914 }
3915 fn serialize_f32(self, v: f32) -> Result<Value, Error> {
3916 Ok(Value::Float(v as f64))
3917 }
3918 fn serialize_f64(self, v: f64) -> Result<Value, Error> {
3919 Ok(Value::Float(v))
3920 }
3921 fn serialize_char(self, v: char) -> Result<Value, Error> {
3922 Ok(Value::Str(v.to_string()))
3923 }
3924 fn serialize_str(self, v: &str) -> Result<Value, Error> {
3925 Ok(Value::Str(v.to_string()))
3926 }
3927 fn serialize_bytes(self, v: &[u8]) -> Result<Value, Error> {
3928 Ok(Value::Array(v.iter().map(|&b| Value::Int(b as i64)).collect()))
3929 }
3930 fn serialize_none(self) -> Result<Value, Error> {
3931 Ok(Value::Null)
3932 }
3933 fn serialize_some<T: Serialize + ?Sized>(self, v: &T) -> Result<Value, Error> {
3934 v.serialize(ValueSerializer)
3935 }
3936 fn serialize_unit(self) -> Result<Value, Error> {
3937 Ok(Value::Null)
3938 }
3939 fn serialize_unit_struct(self, _name: &'static str) -> Result<Value, Error> {
3940 Ok(Value::Null)
3941 }
3942 fn serialize_unit_variant(
3943 self,
3944 _name: &'static str,
3945 _idx: u32,
3946 variant: &'static str,
3947 ) -> Result<Value, Error> {
3948 Ok(Value::Str(variant.to_string()))
3949 }
3950 fn serialize_newtype_struct<T: Serialize + ?Sized>(
3951 self,
3952 _name: &'static str,
3953 v: &T,
3954 ) -> Result<Value, Error> {
3955 v.serialize(ValueSerializer)
3956 }
3957 fn serialize_newtype_variant<T: Serialize + ?Sized>(
3958 self,
3959 _name: &'static str,
3960 _idx: u32,
3961 variant: &'static str,
3962 value: &T,
3963 ) -> Result<Value, Error> {
3964 Ok(Value::Object(BTreeMap::from([
3965 ("__type".into(), Value::Str(variant.to_string())),
3966 ("_value".into(), value.serialize(ValueSerializer)?),
3967 ])))
3968 }
3969 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Error> {
3970 Ok(SeqSerializer(Vec::new()))
3971 }
3972 fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Error> {
3973 self.serialize_seq(Some(len))
3974 }
3975 fn serialize_tuple_struct(
3976 self,
3977 _name: &'static str,
3978 len: usize,
3979 ) -> Result<Self::SerializeTupleStruct, Error> {
3980 self.serialize_seq(Some(len))
3981 }
3982 fn serialize_tuple_variant(
3983 self,
3984 _name: &'static str,
3985 _idx: u32,
3986 variant: &'static str,
3987 _len: usize,
3988 ) -> Result<Self::SerializeTupleVariant, Error> {
3989 Ok(TupleVariantSerializer {
3990 variant: variant.to_string(),
3991 values: Vec::new(),
3992 })
3993 }
3994 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Error> {
3995 Ok(MapSerializer {
3996 map: BTreeMap::new(),
3997 key: None,
3998 })
3999 }
4000 fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct, Error> {
4001 self.serialize_map(Some(len))
4002 }
4003 fn serialize_struct_variant(
4004 self,
4005 _name: &'static str,
4006 _idx: u32,
4007 variant: &'static str,
4008 _len: usize,
4009 ) -> Result<Self::SerializeStructVariant, Error> {
4010 Ok(StructVariantSerializer {
4011 variant: variant.to_string(),
4012 map: BTreeMap::new(),
4013 })
4014 }
4015 }
4016
4017 struct SeqSerializer(Vec<Value>);
4018
4019 impl SerializeSeq for SeqSerializer {
4020 type Ok = Value;
4021 type Error = Error;
4022 fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4023 self.0.push(value.serialize(ValueSerializer)?);
4024 Ok(())
4025 }
4026 fn end(self) -> Result<Value, Error> {
4027 Ok(Value::Array(self.0))
4028 }
4029 }
4030 impl SerializeTuple for SeqSerializer {
4031 type Ok = Value;
4032 type Error = Error;
4033 fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4034 SerializeSeq::serialize_element(self, value)
4035 }
4036 fn end(self) -> Result<Value, Error> {
4037 SerializeSeq::end(self)
4038 }
4039 }
4040 impl SerializeTupleStruct for SeqSerializer {
4041 type Ok = Value;
4042 type Error = Error;
4043 fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4044 SerializeSeq::serialize_element(self, value)
4045 }
4046 fn end(self) -> Result<Value, Error> {
4047 SerializeSeq::end(self)
4048 }
4049 }
4050
4051 struct MapSerializer {
4052 map: BTreeMap<String, Value>,
4053 key: Option<String>,
4054 }
4055
4056 impl SerializeMap for MapSerializer {
4057 type Ok = Value;
4058 type Error = Error;
4059 fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<(), Error> {
4060 self.key = Some(key.serialize(KeySerializer)?);
4061 Ok(())
4062 }
4063 fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4064 let k = self
4065 .key
4066 .take()
4067 .ok_or_else(|| de::Error::custom("serialize_value 前需先 serialize_key"))?;
4068 self.map.insert(k, value.serialize(ValueSerializer)?);
4069 Ok(())
4070 }
4071 fn end(self) -> Result<Value, Error> {
4072 Ok(Value::Object(self.map))
4073 }
4074 }
4075
4076 impl SerializeStruct for MapSerializer {
4077 type Ok = Value;
4078 type Error = Error;
4079 fn serialize_field<T: Serialize + ?Sized>(
4080 &mut self,
4081 key: &'static str,
4082 value: &T,
4083 ) -> Result<(), Error> {
4084 self.map
4085 .insert(key.to_string(), value.serialize(ValueSerializer)?);
4086 Ok(())
4087 }
4088 fn end(self) -> Result<Value, Error> {
4089 Ok(Value::Object(self.map))
4090 }
4091 }
4092
4093 struct KeySerializer;
4095
4096 macro_rules! key_unsupported {
4097 ($(fn $m:ident($($a:ident : $t:ty),*) -> Result<String, Error>;)*) => {
4098 $(
4099 fn $m(self, $($a: $t),*) -> Result<String, Error> {
4100 Err(de::Error::custom("SML 对象的键必须是字符串"))
4101 }
4102 )*
4103 };
4104 }
4105
4106 impl Serializer for KeySerializer {
4107 type Ok = String;
4108 type Error = Error;
4109 type SerializeSeq = ::serde::ser::Impossible<String, Error>;
4110 type SerializeTuple = ::serde::ser::Impossible<String, Error>;
4111 type SerializeTupleStruct = ::serde::ser::Impossible<String, Error>;
4112 type SerializeTupleVariant = ::serde::ser::Impossible<String, Error>;
4113 type SerializeMap = ::serde::ser::Impossible<String, Error>;
4114 type SerializeStruct = ::serde::ser::Impossible<String, Error>;
4115 type SerializeStructVariant = ::serde::ser::Impossible<String, Error>;
4116
4117 fn serialize_str(self, v: &str) -> Result<String, Error> {
4118 Ok(v.to_string())
4119 }
4120 fn serialize_char(self, v: char) -> Result<String, Error> {
4121 Ok(v.to_string())
4122 }
4123 key_unsupported! {
4124 fn serialize_bool(_v: bool) -> Result<String, Error>;
4125 fn serialize_i8(_v: i8) -> Result<String, Error>;
4126 fn serialize_i16(_v: i16) -> Result<String, Error>;
4127 fn serialize_i32(_v: i32) -> Result<String, Error>;
4128 fn serialize_i64(_v: i64) -> Result<String, Error>;
4129 fn serialize_u8(_v: u8) -> Result<String, Error>;
4130 fn serialize_u16(_v: u16) -> Result<String, Error>;
4131 fn serialize_u32(_v: u32) -> Result<String, Error>;
4132 fn serialize_u64(_v: u64) -> Result<String, Error>;
4133 fn serialize_f32(_v: f32) -> Result<String, Error>;
4134 fn serialize_f64(_v: f64) -> Result<String, Error>;
4135 fn serialize_bytes(_v: &[u8]) -> Result<String, Error>;
4136 fn serialize_none() -> Result<String, Error>;
4137 fn serialize_unit() -> Result<String, Error>;
4138 fn serialize_unit_struct(_n: &'static str) -> Result<String, Error>;
4139 fn serialize_unit_variant(_n: &'static str, _i: u32, _v: &'static str) -> Result<String, Error>;
4140 }
4141 fn serialize_some<T: Serialize + ?Sized>(self, _v: &T) -> Result<String, Error> {
4142 Err(de::Error::custom("SML 对象的键必须是字符串"))
4143 }
4144 fn serialize_newtype_struct<T: Serialize + ?Sized>(
4145 self,
4146 _n: &'static str,
4147 _v: &T,
4148 ) -> Result<String, Error> {
4149 Err(de::Error::custom("SML 对象的键必须是字符串"))
4150 }
4151 fn serialize_newtype_variant<T: Serialize + ?Sized>(
4152 self,
4153 _n: &'static str,
4154 _i: u32,
4155 _v: &'static str,
4156 _x: &T,
4157 ) -> Result<String, Error> {
4158 Err(de::Error::custom("SML 对象的键必须是字符串"))
4159 }
4160 fn serialize_seq(self, _l: Option<usize>) -> Result<Self::SerializeSeq, Error> {
4162 Err(de::Error::custom("SML 对象的键必须是字符串"))
4163 }
4164 fn serialize_tuple(self, _l: usize) -> Result<Self::SerializeTuple, Error> {
4165 Err(de::Error::custom("SML 对象的键必须是字符串"))
4166 }
4167 fn serialize_tuple_struct(
4168 self,
4169 _n: &'static str,
4170 _l: usize,
4171 ) -> Result<Self::SerializeTupleStruct, Error> {
4172 Err(de::Error::custom("SML 对象的键必须是字符串"))
4173 }
4174 fn serialize_tuple_variant(
4175 self,
4176 _n: &'static str,
4177 _i: u32,
4178 _v: &'static str,
4179 _l: usize,
4180 ) -> Result<Self::SerializeTupleVariant, Error> {
4181 Err(de::Error::custom("SML 对象的键必须是字符串"))
4182 }
4183 fn serialize_map(self, _l: Option<usize>) -> Result<Self::SerializeMap, Error> {
4184 Err(de::Error::custom("SML 对象的键必须是字符串"))
4185 }
4186 fn serialize_struct(self, _n: &'static str, _l: usize) -> Result<Self::SerializeStruct, Error> {
4187 Err(de::Error::custom("SML 对象的键必须是字符串"))
4188 }
4189 fn serialize_struct_variant(
4190 self,
4191 _n: &'static str,
4192 _i: u32,
4193 _v: &'static str,
4194 _l: usize,
4195 ) -> Result<Self::SerializeStructVariant, Error> {
4196 Err(de::Error::custom("SML 对象的键必须是字符串"))
4197 }
4198 }
4199
4200 struct TupleVariantSerializer {
4201 variant: String,
4202 values: Vec<Value>,
4203 }
4204
4205 impl SerializeTupleVariant for TupleVariantSerializer {
4206 type Ok = Value;
4207 type Error = Error;
4208 fn serialize_field<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
4209 self.values.push(value.serialize(ValueSerializer)?);
4210 Ok(())
4211 }
4212 fn end(self) -> Result<Value, Error> {
4213 Ok(Value::Object(BTreeMap::from([
4214 ("__type".into(), Value::Str(self.variant)),
4215 ("_value".into(), Value::Array(self.values)),
4216 ])))
4217 }
4218 }
4219
4220 struct StructVariantSerializer {
4221 variant: String,
4222 map: BTreeMap<String, Value>,
4223 }
4224
4225 impl SerializeStructVariant for StructVariantSerializer {
4226 type Ok = Value;
4227 type Error = Error;
4228 fn serialize_field<T: Serialize + ?Sized>(
4229 &mut self,
4230 key: &'static str,
4231 value: &T,
4232 ) -> Result<(), Error> {
4233 self.map
4234 .insert(key.to_string(), value.serialize(ValueSerializer)?);
4235 Ok(())
4236 }
4237 fn end(self) -> Result<Value, Error> {
4238 let mut m = BTreeMap::new();
4239 m.insert("__type".into(), Value::Str(self.variant));
4240 m.extend(self.map);
4241 Ok(Value::Object(m))
4242 }
4243 }
4244
4245 macro_rules! deser_int {
4248 ($(fn $m:ident($v:ident, $call:ident);)*) => {
4249 $(
4250 fn $m<V>(self, $v: V) -> Result<V::Value, Self::Error>
4251 where V: Visitor<'de> {
4252 match self.0 {
4253 Value::Int(i) => $v.$call(i as _),
4254 Value::Float(f)
4255 if f.fract() == 0.0
4256 && f >= i64::MIN as f64
4257 && f <= i64::MAX as f64 =>
4258 {
4259 $v.$call(f as _)
4260 }
4261 other => Err(type_err(&other, stringify!($m).trim_start_matches("deserialize_"))),
4262 }
4263 }
4264 )*
4265 };
4266 }
4267
4268 struct ValueDeserializer(Value);
4269
4270 impl<'de> Deserializer<'de> for ValueDeserializer {
4271 type Error = Error;
4272
4273 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
4274 where
4275 V: Visitor<'de>,
4276 {
4277 match self.0 {
4278 Value::Null => visitor.visit_unit(),
4279 Value::Bool(b) => visitor.visit_bool(b),
4280 Value::Int(i) => visitor.visit_i64(i),
4281 Value::Float(f) => visitor.visit_f64(f),
4282 Value::Str(s) => visitor.visit_string(s),
4283 Value::Array(a) => visitor.visit_seq(SeqDeserializer { items: a, idx: 0 }),
4284 Value::Object(m) => visitor.visit_map(MapDeserializer { map: m, pending: None }),
4285 }
4286 }
4287
4288 fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Error>
4289 where
4290 V: Visitor<'de>,
4291 {
4292 match self.0 {
4293 Value::Bool(b) => visitor.visit_bool(b),
4294 other => Err(type_err(&other, "布尔")),
4295 }
4296 }
4297
4298 deser_int! {
4299 fn deserialize_i8(v, visit_i8);
4300 fn deserialize_i16(v, visit_i16);
4301 fn deserialize_i32(v, visit_i32);
4302 fn deserialize_i64(v, visit_i64);
4303 fn deserialize_u8(v, visit_u8);
4304 fn deserialize_u16(v, visit_u16);
4305 fn deserialize_u32(v, visit_u32);
4306 }
4307
4308 fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Error>
4309 where
4310 V: Visitor<'de>,
4311 {
4312 match self.0 {
4313 Value::Int(i) if i >= 0 => visitor.visit_u64(i as u64),
4314 Value::Float(f)
4315 if f.fract() == 0.0 && f >= 0.0 && f <= u64::MAX as f64 =>
4316 {
4317 visitor.visit_u64(f as u64)
4318 }
4319 other => Err(type_err(&other, "u64")),
4320 }
4321 }
4322
4323 fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Error>
4324 where
4325 V: Visitor<'de>,
4326 {
4327 match self.0 {
4328 Value::Int(i) => visitor.visit_f32(i as f32),
4329 Value::Float(f) => visitor.visit_f32(f as f32),
4330 other => Err(type_err(&other, "f32")),
4331 }
4332 }
4333 fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Error>
4334 where
4335 V: Visitor<'de>,
4336 {
4337 match self.0 {
4338 Value::Int(i) => visitor.visit_f64(i as f64),
4339 Value::Float(f) => visitor.visit_f64(f),
4340 other => Err(type_err(&other, "f64")),
4341 }
4342 }
4343
4344 fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Error>
4345 where
4346 V: Visitor<'de>,
4347 {
4348 match self.0 {
4349 Value::Str(s) if s.chars().count() == 1 => {
4350 visitor.visit_char(s.chars().next().unwrap())
4351 }
4352 other => Err(type_err(&other, "字符")),
4353 }
4354 }
4355
4356 fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error>
4357 where
4358 V: Visitor<'de>,
4359 {
4360 match self.0 {
4361 Value::Str(s) => visitor.visit_string(s),
4362 other => Err(type_err(&other, "字符串")),
4363 }
4364 }
4365 fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error>
4366 where
4367 V: Visitor<'de>,
4368 {
4369 self.deserialize_str(visitor)
4370 }
4371
4372 fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Error>
4373 where
4374 V: Visitor<'de>,
4375 {
4376 match self.0 {
4377 Value::Array(items) => {
4378 let mut buf = Vec::with_capacity(items.len());
4379 for it in items {
4380 match it {
4381 Value::Int(i) if (0..=255).contains(&i) => buf.push(i as u8),
4382 other => return Err(type_err(&other, "字节")),
4383 }
4384 }
4385 visitor.visit_byte_buf(buf)
4386 }
4387 other => Err(type_err(&other, "字节数组")),
4388 }
4389 }
4390 fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Error>
4391 where
4392 V: Visitor<'de>,
4393 {
4394 self.deserialize_bytes(visitor)
4395 }
4396
4397 fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
4398 where
4399 V: Visitor<'de>,
4400 {
4401 match self.0 {
4402 Value::Null => visitor.visit_none(),
4403 other => visitor.visit_some(ValueDeserializer(other)),
4404 }
4405 }
4406
4407 fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Error>
4408 where
4409 V: Visitor<'de>,
4410 {
4411 match self.0 {
4412 Value::Null => visitor.visit_unit(),
4413 other => Err(type_err(&other, "unit")),
4414 }
4415 }
4416 fn deserialize_unit_struct<V>(
4417 self,
4418 _name: &'static str,
4419 visitor: V,
4420 ) -> Result<V::Value, Error>
4421 where
4422 V: Visitor<'de>,
4423 {
4424 self.deserialize_unit(visitor)
4425 }
4426 fn deserialize_newtype_struct<V>(
4427 self,
4428 _name: &'static str,
4429 visitor: V,
4430 ) -> Result<V::Value, Error>
4431 where
4432 V: Visitor<'de>,
4433 {
4434 self.deserialize_any(visitor)
4435 }
4436
4437 fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Error>
4438 where
4439 V: Visitor<'de>,
4440 {
4441 match self.0 {
4442 Value::Array(a) => visitor.visit_seq(SeqDeserializer { items: a, idx: 0 }),
4443 other => Err(type_err(&other, "数组")),
4444 }
4445 }
4446 fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
4447 where
4448 V: Visitor<'de>,
4449 {
4450 self.deserialize_seq(visitor)
4451 }
4452 fn deserialize_tuple_struct<V>(
4453 self,
4454 _name: &'static str,
4455 _len: usize,
4456 visitor: V,
4457 ) -> Result<V::Value, Error>
4458 where
4459 V: Visitor<'de>,
4460 {
4461 self.deserialize_seq(visitor)
4462 }
4463
4464 fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Error>
4465 where
4466 V: Visitor<'de>,
4467 {
4468 match self.0 {
4469 Value::Object(m) => visitor.visit_map(MapDeserializer { map: m, pending: None }),
4470 other => Err(type_err(&other, "块/对象")),
4471 }
4472 }
4473 fn deserialize_struct<V>(
4474 self,
4475 _name: &'static str,
4476 _fields: &'static [&'static str],
4477 visitor: V,
4478 ) -> Result<V::Value, Error>
4479 where
4480 V: Visitor<'de>,
4481 {
4482 self.deserialize_map(visitor)
4483 }
4484
4485 fn deserialize_enum<V>(
4486 self,
4487 _name: &'static str,
4488 _variants: &'static [&'static str],
4489 visitor: V,
4490 ) -> Result<V::Value, Error>
4491 where
4492 V: Visitor<'de>,
4493 {
4494 match self.0 {
4495 Value::Str(s) => visitor.visit_enum(EnumDeserializer {
4496 variant: s,
4497 kind: EnumKind::Unit,
4498 }),
4499 Value::Object(mut m) => {
4500 if let Some(ty) = m.remove("__type") {
4502 let variant = match ty {
4503 Value::Str(s) => s,
4504 _ => return Err(de::Error::custom("`__type` 的值必须是字符串")),
4505 };
4506 let kind = match m.remove("_value") {
4507 Some(Value::Array(items)) => EnumKind::Tuple(items),
4508 Some(other) => EnumKind::Newtype(other),
4509 None if m.is_empty() => EnumKind::Unit,
4510 None => EnumKind::Struct(m),
4511 };
4512 return visitor.visit_enum(EnumDeserializer { variant, kind });
4513 }
4514 if m.len() == 1 {
4518 let (k, v) = m.pop_first().expect("len==1 必有键");
4519 let kind = match v {
4520 Value::Str(s) if s == k => EnumKind::Unit,
4521 other => EnumKind::Newtype(other),
4522 };
4523 return visitor.visit_enum(EnumDeserializer { variant: k, kind });
4524 }
4525 Err(de::Error::custom(
4526 "枚举块需要 `__type` 键(SML 约定)或单键外部标签 `{ VariantName: ... }`",
4527 ))
4528 }
4529 other => Err(type_err(&other, "枚举")),
4530 }
4531 }
4532
4533 fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Error>
4534 where
4535 V: Visitor<'de>,
4536 {
4537 self.deserialize_str(visitor)
4538 }
4539 fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
4540 where
4541 V: Visitor<'de>,
4542 {
4543 self.deserialize_any(visitor)
4544 }
4545 }
4546
4547 struct SeqDeserializer {
4548 items: Vec<Value>,
4549 idx: usize,
4550 }
4551
4552 impl<'de> SeqAccess<'de> for SeqDeserializer {
4553 type Error = Error;
4554 fn next_element_seed<T: de::DeserializeSeed<'de>>(
4555 &mut self,
4556 seed: T,
4557 ) -> Result<Option<T::Value>, Error> {
4558 if self.idx >= self.items.len() {
4559 return Ok(None);
4560 }
4561 let item = self.items[self.idx].clone();
4562 self.idx += 1;
4563 seed.deserialize(ValueDeserializer(item)).map(Some)
4564 }
4565 }
4566
4567 struct MapDeserializer {
4568 map: BTreeMap<String, Value>,
4569 pending: Option<Value>,
4570 }
4571
4572 impl<'de> MapAccess<'de> for MapDeserializer {
4573 type Error = Error;
4574 fn next_key_seed<K: de::DeserializeSeed<'de>>(
4575 &mut self,
4576 seed: K,
4577 ) -> Result<Option<K::Value>, Error> {
4578 let Some((k, v)) = self.map.pop_first() else {
4579 return Ok(None);
4580 };
4581 self.pending = Some(v);
4582 seed.deserialize(KeyDeserializer(&k)).map(Some)
4583 }
4584 fn next_value_seed<V: de::DeserializeSeed<'de>>(
4585 &mut self,
4586 seed: V,
4587 ) -> Result<V::Value, Error> {
4588 let v = self.pending.take().ok_or_else(|| {
4589 de::Error::custom("value 缺失:需先调用 next_key_seed")
4590 })?;
4591 seed.deserialize(ValueDeserializer(v))
4592 }
4593 }
4594
4595 struct KeyDeserializer<'a>(&'a str);
4597
4598 macro_rules! key_delegate {
4599 ($($m:ident),* $(,)?) => {
4600 $(
4601 fn $m<V>(self, visitor: V) -> Result<V::Value, Error>
4602 where V: Visitor<'de> {
4603 self.deserialize_any(visitor)
4604 }
4605 )*
4606 };
4607 }
4608
4609 impl<'de, 'a> Deserializer<'de> for KeyDeserializer<'a> {
4610 type Error = Error;
4611
4612 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
4613 where
4614 V: Visitor<'de>,
4615 {
4616 visitor.visit_str(self.0)
4617 }
4618 fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Error>
4619 where
4620 V: Visitor<'de>,
4621 {
4622 visitor.visit_str(self.0)
4623 }
4624 fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Error>
4625 where
4626 V: Visitor<'de>,
4627 {
4628 visitor.visit_str(self.0)
4629 }
4630 fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Error>
4631 where
4632 V: Visitor<'de>,
4633 {
4634 visitor.visit_str(self.0)
4635 }
4636 fn deserialize_enum<V>(
4637 self,
4638 _name: &'static str,
4639 _variants: &'static [&'static str],
4640 visitor: V,
4641 ) -> Result<V::Value, Error>
4642 where
4643 V: Visitor<'de>,
4644 {
4645 visitor.visit_enum(EnumDeserializer {
4646 variant: self.0.to_string(),
4647 kind: EnumKind::Unit,
4648 })
4649 }
4650 fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
4651 where
4652 V: Visitor<'de>,
4653 {
4654 visitor.visit_some(self)
4655 }
4656 fn deserialize_unit_struct<V>(
4657 self,
4658 _name: &'static str,
4659 visitor: V,
4660 ) -> Result<V::Value, Error>
4661 where
4662 V: Visitor<'de>,
4663 {
4664 self.deserialize_unit(visitor)
4665 }
4666 fn deserialize_newtype_struct<V>(
4667 self,
4668 _name: &'static str,
4669 visitor: V,
4670 ) -> Result<V::Value, Error>
4671 where
4672 V: Visitor<'de>,
4673 {
4674 self.deserialize_any(visitor)
4675 }
4676 fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
4677 where
4678 V: Visitor<'de>,
4679 {
4680 self.deserialize_seq(visitor)
4681 }
4682 fn deserialize_tuple_struct<V>(
4683 self,
4684 _name: &'static str,
4685 _len: usize,
4686 visitor: V,
4687 ) -> Result<V::Value, Error>
4688 where
4689 V: Visitor<'de>,
4690 {
4691 self.deserialize_seq(visitor)
4692 }
4693 fn deserialize_struct<V>(
4694 self,
4695 _name: &'static str,
4696 _fields: &'static [&'static str],
4697 visitor: V,
4698 ) -> Result<V::Value, Error>
4699 where
4700 V: Visitor<'de>,
4701 {
4702 self.deserialize_map(visitor)
4703 }
4704 fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Error>
4705 where
4706 V: Visitor<'de>,
4707 {
4708 self.deserialize_any(visitor)
4709 }
4710 key_delegate! {
4711 deserialize_bool, deserialize_i8, deserialize_i16, deserialize_i32,
4712 deserialize_i64, deserialize_u8, deserialize_u16, deserialize_u32,
4713 deserialize_u64, deserialize_f32, deserialize_f64, deserialize_char,
4714 deserialize_bytes, deserialize_byte_buf, deserialize_unit,
4715 deserialize_seq, deserialize_map,
4716 }
4717 }
4718
4719 #[derive(Debug)]
4722 enum EnumKind {
4723 Unit,
4724 Newtype(Value),
4725 Tuple(Vec<Value>),
4726 Struct(BTreeMap<String, Value>),
4727 }
4728
4729 struct EnumDeserializer {
4730 variant: String,
4731 kind: EnumKind,
4732 }
4733
4734 impl<'de> de::EnumAccess<'de> for EnumDeserializer {
4735 type Error = Error;
4736 type Variant = VariantAccess;
4737 fn variant_seed<V: de::DeserializeSeed<'de>>(
4738 self,
4739 seed: V,
4740 ) -> Result<(V::Value, Self::Variant), Error> {
4741 let variant = seed.deserialize(KeyDeserializer(&self.variant))?;
4742 Ok((variant, VariantAccess { kind: self.kind }))
4743 }
4744 }
4745
4746 struct VariantAccess {
4747 kind: EnumKind,
4748 }
4749
4750 impl<'de> de::VariantAccess<'de> for VariantAccess {
4751 type Error = Error;
4752 fn unit_variant(self) -> Result<(), Error> {
4753 match self.kind {
4754 EnumKind::Unit => Ok(()),
4755 _ => Err(de::Error::custom("该变体携带数据,不能按单元变体解析")),
4756 }
4757 }
4758 fn newtype_variant_seed<T: de::DeserializeSeed<'de>>(
4759 self,
4760 seed: T,
4761 ) -> Result<T::Value, Error> {
4762 match self.kind {
4763 EnumKind::Newtype(v) => seed.deserialize(ValueDeserializer(v)),
4764 EnumKind::Tuple(items) => {
4765 seed.deserialize(ValueDeserializer(Value::Array(items)))
4766 }
4767 _ => Err(de::Error::custom("该变体没有单值数据")),
4768 }
4769 }
4770 fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
4771 where
4772 V: Visitor<'de>,
4773 {
4774 match self.kind {
4775 EnumKind::Tuple(items) => {
4776 visitor.visit_seq(SeqDeserializer { items, idx: 0 })
4777 }
4778 _ => Err(de::Error::custom("该变体不是元组形态")),
4779 }
4780 }
4781 fn struct_variant<V>(
4782 self,
4783 _fields: &'static [&'static str],
4784 visitor: V,
4785 ) -> Result<V::Value, Error>
4786 where
4787 V: Visitor<'de>,
4788 {
4789 match self.kind {
4790 EnumKind::Struct(m) => {
4791 visitor.visit_map(MapDeserializer { map: m, pending: None })
4792 }
4793 _ => Err(de::Error::custom("该变体不是结构体形态")),
4794 }
4795 }
4796 }
4797}
4798
4799pub trait SmlSerialize {
4810 fn to_sml_value(&self) -> Value;
4811
4812 fn to_sml(&self) -> String {
4814 crate::to_sml(&self.to_sml_value())
4815 }
4816}
4817
4818pub trait SmlDeserialize: Sized {
4820 fn from_sml_value(v: &Value) -> Result<Self, String>;
4821
4822 fn from_sml(text: &str) -> Result<Self, String> {
4824 let v = crate::parse(text).map_err(|e| format!("SML 解析失败: {e}"))?;
4825 Self::from_sml_value(&v)
4826 }
4827}
4828
4829#[cfg(feature = "derive")]
4830pub use swsml_derive::{SmlDeserialize, SmlSerialize};
4831
4832pub fn to_string<T: SmlSerialize + ?Sized>(value: &T) -> String {
4845 crate::to_sml(&value.to_sml_value())
4846}
4847
4848pub fn from_str<T: SmlDeserialize>(text: &str) -> Result<T, String> {
4859 T::from_sml(text)
4860}
4861
4862#[doc(hidden)]
4864pub mod __private {
4865 use super::{SmlDeserialize, SmlSerialize, Value};
4866 use std::collections::{BTreeMap, HashMap};
4867
4868 pub fn describe_value(v: &Value) -> String {
4870 match v {
4871 Value::Null => "null".to_string(),
4872 Value::Bool(b) => b.to_string(),
4873 Value::Int(i) => i.to_string(),
4874 Value::Float(f) => f.to_string(),
4875 Value::Str(s) => format!("字符串 `{s}`"),
4876 Value::Array(a) => format!("数组({} 个元素)", a.len()),
4877 Value::Object(o) => format!("块({} 个键)", o.len()),
4878 }
4879 }
4880
4881 pub fn take_value(m: &BTreeMap<String, Value>) -> Result<Value, String> {
4883 m.get("_value")
4884 .cloned()
4885 .ok_or_else(|| "缺少 _value 键".to_string())
4886 }
4887
4888 pub fn take_array(m: &BTreeMap<String, Value>) -> Result<Vec<Value>, String> {
4890 match m.get("_value") {
4891 Some(Value::Array(a)) => Ok(a.clone()),
4892 Some(other) => Err(format!("_value 期望数组,实际为 {}", describe_value(other))),
4893 None => Err("缺少 _value 键".to_string()),
4894 }
4895 }
4896
4897 pub fn flatten_from<T: SmlDeserialize>(m: &BTreeMap<String, Value>) -> Result<T, String> {
4899 T::from_sml_value(&Value::Object(m.clone()))
4900 }
4901
4902 impl SmlSerialize for bool {
4905 #[inline]
4906 fn to_sml_value(&self) -> Value {
4907 Value::Bool(*self)
4908 }
4909 }
4910 impl SmlDeserialize for bool {
4911 #[inline]
4912 fn from_sml_value(v: &Value) -> Result<Self, String> {
4913 match v {
4914 Value::Bool(b) => Ok(*b),
4915 other => Err(format!("期望布尔,实际为 {}", describe_value(other))),
4916 }
4917 }
4918 }
4919
4920 macro_rules! impl_int {
4921 ($($t:ty),* $(,)?) => {$(
4922 impl SmlSerialize for $t {
4923 #[inline]
4924 fn to_sml_value(&self) -> Value { Value::Int(*self as i64) }
4925 }
4926 impl SmlDeserialize for $t {
4927 #[inline]
4928 fn from_sml_value(v: &Value) -> Result<Self, String> {
4929 match v {
4930 Value::Int(i) => <$t>::try_from(*i)
4931 .map_err(|_| format!("整数 {i} 超出 {} 范围", stringify!($t))),
4932 Value::Float(f)
4933 if f.fract() == 0.0
4934 && *f >= <$t>::MIN as f64
4935 && *f <= <$t>::MAX as f64 => Ok(*f as $t),
4936 Value::Float(f) => Err(format!("期望整数,实际为小数 {f}")),
4937 other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4938 }
4939 }
4940 }
4941 )*};
4942 }
4943 impl_int!(i8, i16, i32, i64, isize, u8, u16, u32, usize);
4944
4945 impl SmlSerialize for u64 {
4946 #[inline]
4947 fn to_sml_value(&self) -> Value {
4948 i64::try_from(*self).map(Value::Int).unwrap_or_else(|_| Value::Float(*self as f64))
4949 }
4950 }
4951 impl SmlDeserialize for u64 {
4952 #[inline]
4953 fn from_sml_value(v: &Value) -> Result<Self, String> {
4954 match v {
4955 Value::Int(i) => u64::try_from(*i).map_err(|_| format!("整数 {i} 为负数,超出 u64 范围")),
4956 Value::Float(f) if f.fract() == 0.0 && *f >= 0.0 => Ok(*f as u64),
4957 Value::Float(f) => Err(format!("期望非负整数,实际为 {f}")),
4958 other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4959 }
4960 }
4961 }
4962
4963 macro_rules! impl_big {
4964 ($($t:ty),* $(,)?) => {$(
4965 impl SmlSerialize for $t {
4966 #[inline]
4967 fn to_sml_value(&self) -> Value {
4968 i64::try_from(*self).map(Value::Int).unwrap_or_else(|_| Value::Float(*self as f64))
4969 }
4970 }
4971 impl SmlDeserialize for $t {
4972 #[inline]
4973 fn from_sml_value(v: &Value) -> Result<Self, String> {
4974 match v {
4975 Value::Int(i) => Ok(*i as $t),
4976 Value::Float(f) if f.fract() == 0.0 => Ok(*f as $t),
4977 Value::Float(f) => Err(format!("期望整数,实际为小数 {f}")),
4978 other => Err(format!("期望整数,实际为 {}", describe_value(other))),
4979 }
4980 }
4981 }
4982 )*};
4983 }
4984 impl_big!(i128, u128);
4985
4986 macro_rules! impl_float {
4987 ($($t:ty),* $(,)?) => {$(
4988 impl SmlSerialize for $t {
4989 #[inline]
4990 fn to_sml_value(&self) -> Value { Value::Float(*self as f64) }
4991 }
4992 impl SmlDeserialize for $t {
4993 #[inline]
4994 fn from_sml_value(v: &Value) -> Result<Self, String> {
4995 match v {
4996 Value::Int(i) => Ok(*i as $t),
4997 Value::Float(f) => Ok(*f as $t),
4998 other => Err(format!("期望数字,实际为 {}", describe_value(other))),
4999 }
5000 }
5001 }
5002 )*};
5003 }
5004 impl_float!(f32, f64);
5005
5006 impl SmlSerialize for char {
5007 #[inline]
5008 fn to_sml_value(&self) -> Value {
5009 Value::Str(self.to_string())
5010 }
5011 }
5012 impl SmlDeserialize for char {
5013 #[inline]
5014 fn from_sml_value(v: &Value) -> Result<Self, String> {
5015 match v {
5016 Value::Str(s) => {
5017 let mut it = s.chars();
5018 match (it.next(), it.next()) {
5019 (Some(c), None) => Ok(c),
5020 _ => Err(format!("期望单个字符,实际为 `{s}`")),
5021 }
5022 }
5023 other => Err(format!("期望字符串,实际为 {}", describe_value(other))),
5024 }
5025 }
5026 }
5027
5028 impl SmlSerialize for String {
5029 #[inline]
5030 fn to_sml_value(&self) -> Value {
5031 Value::Str(self.clone())
5032 }
5033 }
5034 impl SmlDeserialize for String {
5035 #[inline]
5036 fn from_sml_value(v: &Value) -> Result<Self, String> {
5037 match v {
5038 Value::Str(s) => Ok(s.clone()),
5039 other => Err(format!("期望字符串,实际为 {}", describe_value(other))),
5040 }
5041 }
5042 }
5043
5044 impl SmlSerialize for str {
5045 #[inline]
5046 fn to_sml_value(&self) -> Value {
5047 Value::Str(self.to_string())
5048 }
5049 }
5050
5051 impl SmlSerialize for &str {
5052 #[inline]
5053 fn to_sml_value(&self) -> Value {
5054 Value::Str(self.to_string())
5055 }
5056 }
5057
5058 impl SmlSerialize for () {
5059 #[inline]
5060 fn to_sml_value(&self) -> Value {
5061 Value::Null
5062 }
5063 }
5064 impl SmlDeserialize for () {
5065 #[inline]
5066 fn from_sml_value(v: &Value) -> Result<Self, String> {
5067 match v {
5068 Value::Null => Ok(()),
5069 other => Err(format!("期望 null,实际为 {}", describe_value(other))),
5070 }
5071 }
5072 }
5073
5074 impl SmlSerialize for Value {
5075 #[inline]
5076 fn to_sml_value(&self) -> Value {
5077 self.clone()
5078 }
5079 }
5080 impl SmlDeserialize for Value {
5081 #[inline]
5082 fn from_sml_value(v: &Value) -> Result<Self, String> {
5083 Ok(v.clone())
5084 }
5085 }
5086
5087 impl<T: SmlSerialize> SmlSerialize for Option<T> {
5088 #[inline]
5089 fn to_sml_value(&self) -> Value {
5090 match self {
5091 Some(v) => v.to_sml_value(),
5092 None => Value::Null,
5093 }
5094 }
5095 }
5096 impl<T: SmlDeserialize> SmlDeserialize for Option<T> {
5097 #[inline]
5098 fn from_sml_value(v: &Value) -> Result<Self, String> {
5099 match v {
5100 Value::Null => Ok(None),
5101 other => Ok(Some(T::from_sml_value(other)?)),
5102 }
5103 }
5104 }
5105
5106 impl<T: SmlSerialize> SmlSerialize for Vec<T> {
5107 #[inline]
5108 fn to_sml_value(&self) -> Value {
5109 Value::Array(self.iter().map(SmlSerialize::to_sml_value).collect())
5110 }
5111 }
5112 impl<T: SmlDeserialize> SmlDeserialize for Vec<T> {
5113 #[inline]
5114 fn from_sml_value(v: &Value) -> Result<Self, String> {
5115 match v {
5116 Value::Array(a) => a.iter().map(SmlDeserialize::from_sml_value).collect(),
5117 other => Err(format!("期望数组,实际为 {}", describe_value(other))),
5118 }
5119 }
5120 }
5121
5122 impl<T: SmlSerialize> SmlSerialize for Box<T> {
5123 #[inline]
5124 fn to_sml_value(&self) -> Value {
5125 (**self).to_sml_value()
5126 }
5127 }
5128 impl<T: SmlDeserialize> SmlDeserialize for Box<T> {
5129 #[inline]
5130 fn from_sml_value(v: &Value) -> Result<Self, String> {
5131 Ok(Box::new(T::from_sml_value(v)?))
5132 }
5133 }
5134
5135 impl<V: SmlSerialize> SmlSerialize for BTreeMap<String, V> {
5136 #[inline]
5137 fn to_sml_value(&self) -> Value {
5138 Value::Object(
5139 self.iter()
5140 .map(|(k, v)| (k.clone(), v.to_sml_value()))
5141 .collect(),
5142 )
5143 }
5144 }
5145 impl<V: SmlDeserialize> SmlDeserialize for BTreeMap<String, V> {
5146 #[inline]
5147 fn from_sml_value(v: &Value) -> Result<Self, String> {
5148 match v {
5149 Value::Object(m) => {
5150 let mut out = BTreeMap::new();
5151 for (k, val) in m {
5152 out.insert(k.clone(), V::from_sml_value(val)?);
5153 }
5154 Ok(out)
5155 }
5156 other => Err(format!("期望块(object),实际为 {}", describe_value(other))),
5157 }
5158 }
5159 }
5160
5161 impl<V: SmlSerialize> SmlSerialize for HashMap<String, V> {
5162 #[inline]
5163 fn to_sml_value(&self) -> Value {
5164 Value::Object(
5165 self.iter()
5166 .map(|(k, v)| (k.clone(), v.to_sml_value()))
5167 .collect(),
5168 )
5169 }
5170 }
5171 impl<V: SmlDeserialize> SmlDeserialize for HashMap<String, V> {
5172 #[inline]
5173 fn from_sml_value(v: &Value) -> Result<Self, String> {
5174 match v {
5175 Value::Object(m) => {
5176 let mut out = HashMap::new();
5177 for (k, val) in m {
5178 out.insert(k.clone(), V::from_sml_value(val)?);
5179 }
5180 Ok(out)
5181 }
5182 other => Err(format!("期望块(object),实际为 {}", describe_value(other))),
5183 }
5184 }
5185 }
5186}
5187
5188#[cfg(test)]
5193mod tests {
5194 use super::*;
5195
5196 #[test]
5199 fn version_defaults_to_v1_when_absent() {
5200 let (v, ver) = parse_versioned("a: 1\n").unwrap();
5202 assert_eq!(ver, Version::V1);
5203 assert_eq!(v.get("a"), Some(&Value::Int(1)));
5204 }
5205
5206 #[test]
5207 fn version_declared_as_v1() {
5208 let (v, ver) = parse_versioned("@version v1\na: 1\n").unwrap();
5209 assert_eq!(ver, Version::V1);
5210 assert_eq!(v.get("a"), Some(&Value::Int(1)));
5211 }
5212
5213 #[test]
5214 fn version_declaration_is_stripped_not_parsed_as_content() {
5215 let v = parse("@version v1\na: 1\n").unwrap();
5217 assert_eq!(v.get("a"), Some(&Value::Int(1)));
5218 assert!(v.get("version").is_none(), "@version 不应进入数据");
5219 }
5220
5221 #[test]
5222 fn unsupported_version_is_rejected() {
5223 let err = parse_versioned("@version v99\na: 1\n").unwrap_err();
5224 assert!(err.contains("不支持"), "应拒绝不支持的版本,got: {err}");
5225 assert!(err.contains("v99"), "错误应含版本号,got: {err}");
5226 }
5227
5228 #[test]
5229 fn conflicting_version_is_rejected() {
5230 let err = parse_versioned("@version v1\n@version v2\n").unwrap_err();
5231 assert!(!err.is_empty());
5233 let (_, ver) = parse_versioned("@version v1\n@version v1\n").unwrap();
5235 assert_eq!(ver, Version::V1, "重复但一致的声明应被接受");
5236 }
5237
5238 #[test]
5239 fn version_is_reserved_as_fragment_name() {
5240 let err = parse("@version { x: 1 }\n").unwrap_err();
5241 assert!(err.contains("保留") || err.contains("版本声明"), "got: {err}");
5242 }
5243
5244 #[test]
5245 fn version_works_with_include() {
5246 let d = tmpdir("version");
5247 std::fs::write(d.join("p.sml"), "@version v1\nb: 2\n").unwrap();
5248 std::fs::write(d.join("main.sml"), "@version v1\ninclude \"p.sml\"\n").unwrap();
5249 let (v, ver) = parse_file_versioned(d.join("main.sml")).unwrap();
5250 assert_eq!(ver, Version::V1);
5251 assert_eq!(v.get("b"), Some(&Value::Int(2)), "版本与 include 应协同");
5252 let _ = std::fs::remove_dir_all(&d);
5253 }
5254
5255 #[test]
5256 fn version_display_matches_name() {
5257 assert_eq!(Version::V1.name(), "v1");
5258 assert_eq!(format!("{}", Version::V1), "v1");
5259 }
5260
5261 fn tmpdir(tag: &str) -> std::path::PathBuf {
5265 let mut d = std::env::temp_dir();
5266 d.push(format!("sml_test_{tag}_{}", std::process::id()));
5267 let _ = std::fs::remove_dir_all(&d);
5268 std::fs::create_dir_all(&d).expect("create tmpdir");
5269 d
5270 }
5271
5272 #[test]
5273 fn include_inlines_external_file() {
5274 let d = tmpdir("inline");
5275 std::fs::write(d.join("part.sml"), "port: 8080\n").unwrap();
5276 std::fs::write(d.join("main.sml"), "@version v1\nhost: local\ninclude \"part.sml\"\n").unwrap();
5277
5278 let v = parse_file(d.join("main.sml")).unwrap();
5279 assert_eq!(v.get("host").unwrap().as_str(), Some("local"));
5280 assert_eq!(v.get("port"), Some(&Value::Int(8080)));
5281 let _ = std::fs::remove_dir_all(&d);
5282 }
5283
5284 #[test]
5285 fn include_at_prefix_is_equivalent() {
5286 let d = tmpdir("at");
5287 std::fs::write(d.join("p.sml"), "b: 2\n").unwrap();
5288 std::fs::write(d.join("m.sml"), "@include \"p.sml\"\n").unwrap();
5289 let v = parse_file(d.join("m.sml")).unwrap();
5290 assert_eq!(v.get("b"), Some(&Value::Int(2)));
5291 let _ = std::fs::remove_dir_all(&d);
5292 }
5293
5294 #[test]
5295 fn include_resolves_relative_to_including_file() {
5296 let d = tmpdir("nested");
5298 std::fs::create_dir_all(d.join("sub")).unwrap();
5299 std::fs::write(d.join("sub/leaf.sml"), "@version v1\nleaf: yes\n").unwrap();
5300 std::fs::write(d.join("sub/mid2.sml"), "@version v1\ninclude \"leaf.sml\"\n").unwrap();
5302 std::fs::write(d.join("main.sml"), "@version v1\ninclude \"sub/mid2.sml\"\n").unwrap();
5303
5304 let v = parse_file(d.join("main.sml")).unwrap();
5305 assert_eq!(
5306 v.get("leaf").unwrap().as_str(),
5307 Some("yes"),
5308 "嵌套 include 的路径应相对各自所在目录解析"
5309 );
5310 let _ = std::fs::remove_dir_all(&d);
5311 }
5312
5313 #[test]
5314 fn include_inside_block_injects_fields() {
5315 let d = tmpdir("block");
5317 std::fs::write(d.join("fields.sml"), "@version v1\nregion: cn-north-1\nzone: a\n").unwrap();
5318 std::fs::write(d.join("main.sml"), "@version v1\nserver web {\ninclude \"fields.sml\"\nport: 8080\n}\n").unwrap();
5319
5320 let v = parse_file(d.join("main.sml")).unwrap();
5321 let server = v.get("server").expect("应有 server 块");
5322 assert_eq!(server.get("region").unwrap().as_str(), Some("cn-north-1"));
5323 assert_eq!(server.get("zone").unwrap().as_str(), Some("a"));
5324 assert_eq!(server.get("port"), Some(&Value::Int(8080)));
5325 let _ = std::fs::remove_dir_all(&d);
5326 }
5327
5328 #[test]
5329 fn include_detects_cycles() {
5330 let d = tmpdir("cycle");
5331 std::fs::write(d.join("a.sml"), "include \"b.sml\"\n").unwrap();
5332 std::fs::write(d.join("b.sml"), "include \"a.sml\"\n").unwrap();
5333 let err = parse_file(d.join("a.sml")).unwrap_err();
5334 assert!(err.contains("循环引用"), "应报循环引用,got: {err}");
5335 let _ = std::fs::remove_dir_all(&d);
5336 }
5337
5338 #[test]
5339 fn include_missing_file_is_error() {
5340 let d = tmpdir("missing");
5341 std::fs::write(d.join("m.sml"), "include \"nope.sml\"\n").unwrap();
5342 let err = parse_file(d.join("m.sml")).unwrap_err();
5343 assert!(err.contains("nope.sml"), "错误应含缺失文件名,got: {err}");
5344 let _ = std::fs::remove_dir_all(&d);
5345 }
5346
5347 #[test]
5348 fn hash_in_quoted_string_is_not_a_comment() {
5349 assert_eq!(strip_line_comment("k: \"a#b\""), "k: \"a#b\"");
5351 assert_eq!(strip_line_comment("k: v # comment"), "k: v ");
5352 }
5353
5354 #[test]
5355 fn glob_include_requires_feature() {
5356 let d = tmpdir("globoff");
5358 std::fs::write(d.join("a.sml"), "x: 1\n").unwrap();
5359 std::fs::write(d.join("main.sml"), "@version v1\ninclude \"*.sml\"\n").unwrap();
5360 let err = parse_file(d.join("main.sml")).unwrap_err();
5361 assert!(err.contains("glob-include"), "应要求 glob-include,got: {err}");
5362 let _ = std::fs::remove_dir_all(&d);
5363 }
5364
5365 #[test]
5366 fn glob_include_expands_multiple_files() {
5367 let d = tmpdir("glob");
5369 std::fs::create_dir_all(d.join("lib")).unwrap();
5370 std::fs::write(d.join("lib/a.sml"), "@version v1\nx: 1\n").unwrap();
5371 std::fs::write(d.join("lib/b.sml"), "@version v1\ny: 2\n").unwrap();
5372 std::fs::write(d.join("note.txt"), "ignored\n").unwrap();
5373 std::fs::write(d.join("main.sml"), "@version v1\n@feature enable glob-include\ninclude \"lib/*.sml\"\n").unwrap();
5374 let v = parse_file(d.join("main.sml")).unwrap();
5375 assert_eq!(v.get("x"), Some(&Value::Int(1)));
5376 assert_eq!(v.get("y"), Some(&Value::Int(2)));
5377 let _ = std::fs::remove_dir_all(&d);
5378 }
5379
5380 #[test]
5381 fn regex_include_requires_feature() {
5382 let d = tmpdir("regexoff");
5383 std::fs::write(d.join("a.sml"), "x: 1\n").unwrap();
5384 std::fs::write(d.join("main.sml"), "@version v1\ninclude \"re:.*\\.sml\"\n").unwrap();
5385 let err = parse_file(d.join("main.sml")).unwrap_err();
5386 assert!(err.contains("regex-include"), "应要求 regex-include,got: {err}");
5387 let _ = std::fs::remove_dir_all(&d);
5388 }
5389
5390 #[test]
5391 fn regex_include_matches_files() {
5392 let d = tmpdir("regex");
5393 std::fs::write(d.join("widget_a.sml"), "@version v1\nx: 1\n").unwrap();
5394 std::fs::write(d.join("widget_b.sml"), "@version v1\ny: 2\n").unwrap();
5395 std::fs::write(d.join("other.sml"), "@version v1\nz: 3\n").unwrap();
5396 std::fs::write(
5397 d.join("main.sml"),
5398 "@version v1\n@feature enable regex-include\ninclude \"re:widget_.*\\.sml\"\n",
5399 )
5400 .unwrap();
5401 let v = parse_file(d.join("main.sml")).unwrap();
5402 assert_eq!(v.get("x"), Some(&Value::Int(1)));
5403 assert_eq!(v.get("y"), Some(&Value::Int(2)));
5404 assert_eq!(v.get("z"), None, "other.sml 不应被正则匹配");
5405 let _ = std::fs::remove_dir_all(&d);
5406 }
5407
5408 #[test]
5409 fn ext_rewrite_allows_non_sml() {
5410 let d = tmpdir("exrew");
5412 std::fs::write(d.join("conf.smlc"), "@version v1\nx: 9\n").unwrap();
5413 std::fs::write(
5414 d.join("main.sml"),
5415 "@version v1\n@feature enable ext-rewrite\ninclude \"conf.smlc\"\n",
5416 )
5417 .unwrap();
5418 let v = parse_file(d.join("main.sml")).unwrap();
5419 assert_eq!(v.get("x"), Some(&Value::Int(9)));
5420 let _ = std::fs::remove_dir_all(&d);
5421 }
5422
5423 #[test]
5424 fn include_line_is_not_confused_with_key_named_include() {
5425 let f = FeatureSet::baseline();
5426 assert_eq!(parse_include_line("key: include", f), Ok(None));
5428 assert_eq!(
5430 parse_include_line("include \"a.sml\"", f),
5431 Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false, keys: None }]))
5432 );
5433 assert_eq!(
5435 parse_include_line("@include \"a.sml\"", f),
5436 Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false, keys: None }]))
5437 );
5438 assert_eq!(
5440 parse_include_line("include \"a.sml\" as ui.form", f),
5441 Ok(Some(vec![IncludeTarget { raw: "a.sml".into(), namespace: Some("ui.form".into()), via_import: false, keys: None }]))
5442 );
5443 assert_eq!(
5445 parse_include_line("include \"widgets\"", f),
5446 Ok(Some(vec![IncludeTarget { raw: "widgets".into(), namespace: Some("widgets".into()), via_import: false, keys: None }]))
5447 );
5448 assert_eq!(
5450 parse_include_line("import ui.buttons", f),
5451 Ok(Some(vec![IncludeTarget { raw: "ui.buttons".into(), namespace: Some("ui.buttons".into()), via_import: true, keys: None }]))
5452 );
5453 let fm = FeatureSet::all();
5455 assert_eq!(
5456 parse_include_line("include \"a.sml\", \"b\" as y", fm),
5457 Ok(Some(vec![
5458 IncludeTarget { raw: "a.sml".into(), namespace: None, via_import: false, keys: None },
5459 IncludeTarget { raw: "b".into(), namespace: Some("y".into()), via_import: false, keys: None },
5460 ]))
5461 );
5462 assert_eq!(parse_include_line("# include \"a.sml\"", f), Ok(None));
5464 }
5465
5466 #[test]
5467 fn import_partial_keys_both_syntaxes() {
5468 let f = FeatureSet::all();
5469 assert_eq!(
5471 parse_include_line("import \"m.sml\" as w { a, b }", f),
5472 Ok(Some(vec![IncludeTarget {
5473 raw: "m.sml".into(),
5474 namespace: Some("w".into()),
5475 via_import: true,
5476 keys: Some(vec!["a".into(), "b".into()]),
5477 }]))
5478 );
5479 assert_eq!(
5481 parse_include_line("import \"m.sml\" { a, b }", f),
5482 Ok(Some(vec![IncludeTarget {
5483 raw: "m.sml".into(),
5484 namespace: None,
5485 via_import: true,
5486 keys: Some(vec!["a".into(), "b".into()]),
5487 }]))
5488 );
5489 assert_eq!(
5491 parse_include_line("import { a, b } as w in \"m.sml\"", f),
5492 Ok(Some(vec![IncludeTarget {
5493 raw: "m.sml".into(),
5494 namespace: Some("w".into()),
5495 via_import: true,
5496 keys: Some(vec!["a".into(), "b".into()]),
5497 }]))
5498 );
5499 assert_eq!(
5501 parse_include_line("import { a, b } in \"m.sml\"", f),
5502 Ok(Some(vec![IncludeTarget {
5503 raw: "m.sml".into(),
5504 namespace: None,
5505 via_import: true,
5506 keys: Some(vec!["a".into(), "b".into()]),
5507 }]))
5508 );
5509 assert!(parse_include_line("import \"m.sml\" { }", f).is_err());
5511 assert!(parse_include_line("import { a, b } as w", f).is_err());
5513 assert!(parse_include_line("import \"*.sml\" { a }", f).is_err());
5515 }
5516
5517 #[test]
5520 fn email_in_bare_word_survives() {
5521 let v = parse("to: a@b.c\nfrom: \"SML Team <dev@mail.swebase.cn>\"\n").unwrap();
5523 assert_eq!(v.get("to").unwrap().as_str(), Some("a@b.c"), "got: {v:?}");
5524 assert_eq!(
5525 v.get("from").unwrap().as_str(),
5526 Some("SML Team <dev@mail.swebase.cn>"),
5527 "got: {v:?}"
5528 );
5529 }
5530
5531 #[test]
5532 fn email_roundtrips_through_to_sml() {
5533 let v = Value::Object(BTreeMap::from([(
5534 "to".to_string(),
5535 Value::Str("dev@mail.swebase.cn".into()),
5536 )]));
5537 let back = parse(&to_sml(&v)).unwrap();
5538 assert_eq!(back, v, "邮箱必须能往返,got:\n{}", to_sml(&v));
5539 }
5540
5541 #[test]
5542 fn fragment_definition_still_works() {
5543 let v = parse("@base { region: cn }\nregion: &base\n").unwrap();
5547 assert_eq!(
5548 v.get("region").unwrap().get("region").unwrap().as_str(),
5549 Some("cn"),
5550 "片段引用应展开为定义的内容,got: {v:?}"
5551 );
5552 }
5553
5554 #[test]
5557 fn toplevel_array_roundtrips() {
5558 let v = Value::Array(vec![
5561 Value::Object(BTreeMap::from([
5562 ("ts".to_string(), Value::Str("2026-01-01".into())),
5563 ("to".to_string(), Value::Str("a@b.c".into())),
5564 ])),
5565 Value::Object(BTreeMap::from([
5566 ("ts".to_string(), Value::Str("2026-01-02".into())),
5567 ("to".to_string(), Value::Str("x@y.z".into())),
5568 ])),
5569 ]);
5570 let text = to_sml(&v);
5571 let back = parse(&text).unwrap();
5572 assert_eq!(back, v, "顶层对象数组必须能往返,got text:\n{text}");
5573 }
5574
5575 #[test]
5576 fn toplevel_array_of_scalars_roundtrips() {
5577 let v = Value::Array(vec![
5578 Value::Int(1),
5579 Value::Str("two".into()),
5580 Value::Bool(true),
5581 ]);
5582 let back = parse(&to_sml(&v)).unwrap();
5583 assert_eq!(back, v, "顶层标量数组必须能往返");
5584 }
5585
5586 #[test]
5587 fn toplevel_object_block_roundtrips() {
5588 let mut m = BTreeMap::new();
5589 m.insert("k".to_string(), Value::Int(1));
5590 let v = Value::Object(m);
5591 let back = parse(&to_sml(&v)).unwrap();
5592 assert_eq!(back, v, "顶层对象块必须能往返");
5593 }
5594
5595 #[test]
5596 fn toplevel_empty_array_roundtrips() {
5597 let v = Value::Array(vec![]);
5598 let back = parse(&to_sml(&v)).unwrap();
5599 assert_eq!(back, v, "空数组必须能往返");
5600 }
5601
5602 #[cfg(feature = "serde")]
5605 #[test]
5606 fn serde_roundtrip_preserves_shape() {
5607 let v = parse("name: John\nage: 27\ntags: [a b]\nnested { k: v }\n").unwrap();
5608 let json = serde_json::to_string(&v).unwrap();
5609 assert!(json.contains("\"name\":\"John\""), "got: {json}");
5611 assert!(json.contains("\"age\":27"), "got: {json}");
5612 assert!(json.contains("\"tags\":[\"a\",\"b\"]"), "got: {json}");
5613 assert!(json.contains("\"nested\":{\"k\":\"v\"}"), "got: {json}");
5614
5615 let back: Value = serde_json::from_str(&json).unwrap();
5616 assert_eq!(back, v, "serde 往返应还原原值");
5617 }
5618
5619 #[cfg(feature = "serde")]
5620 #[test]
5621 fn serde_deserializes_json_into_value() {
5622 let v: Value = serde_json::from_str(r#"{"s":"x","i":5,"f":1.5,"b":true,"n":null,"a":[1,2]}"#).unwrap();
5623 assert_eq!(v.get("s").unwrap().as_str(), Some("x"));
5624 assert_eq!(v.get("i"), Some(&Value::Int(5)));
5625 assert_eq!(v.get("f"), Some(&Value::Float(1.5)));
5626 assert_eq!(v.get("b"), Some(&Value::Bool(true)));
5627 assert_eq!(v.get("n"), Some(&Value::Null));
5628 assert!(matches!(v.get("a"), Some(Value::Array(a)) if a.len() == 2));
5629 }
5630
5631 #[test]
5632 fn nested_array_inside_object_inside_array_survives_roundtrip() {
5633 let mut item = BTreeMap::new();
5636 item.insert("path".to_string(), Value::Str("a.txt".into()));
5637 item.insert(
5638 "chunks".to_string(),
5639 Value::Array(vec![
5640 Value::Str("c1".into()),
5641 Value::Str("c2".into()),
5642 ]),
5643 );
5644 let mut root = BTreeMap::new();
5645 root.insert(
5646 "entries".to_string(),
5647 Value::Array(vec![Value::Object(item)]),
5648 );
5649 let text = to_sml(&Value::Object(root));
5650 assert!(!text.contains("[..]"), "嵌套数组不得被缩略: {text}");
5651
5652 let back = parse(&text).unwrap();
5653 let chunks = back.get("entries").and_then(|e| match e {
5654 Value::Array(a) => a.first(),
5655 _ => None,
5656 });
5657 let chunks = match chunks {
5658 Some(Value::Object(m)) => m.get("chunks"),
5659 _ => None,
5660 };
5661 match chunks {
5662 Some(Value::Array(a)) => {
5663 assert_eq!(a.len(), 2, "两个块都应保留: {text}");
5664 assert_eq!(
5665 a.iter().filter_map(|c| c.as_str()).collect::<Vec<_>>(),
5666 vec!["c1", "c2"]
5667 );
5668 }
5669 other => panic!("chunks 应解析为数组,实际 {other:?}"),
5670 }
5671 }
5672
5673 #[test]
5674 fn utf8_in_quoted_string_survives_roundtrip() {
5675 let v = parse(r#"note: "修复若干问题""#).unwrap();
5679 assert_eq!(
5680 v.get("note").and_then(|x| x.as_str()),
5681 Some("修复若干问题"),
5682 "引号串中的中文不应被破坏"
5683 );
5684 let v2 = parse("region: 华北").unwrap();
5686 assert_eq!(v2.get("region").and_then(|x| x.as_str()), Some("华北"));
5687 let v3 = parse(r#"k: "\u{4fee}\u{590d}""#).unwrap();
5689 assert_eq!(v3.get("k").and_then(|x| x.as_str()), Some("修复"));
5690 }
5691
5692 #[test]
5693 fn parse_basic() {
5694 let text = "firstName: John\nage: 27\nisAlive: true\nspouse: null\n";
5695 let v = parse(text).unwrap();
5696 assert_eq!(v.get("firstName"), Some(&Value::Str("John".into())));
5697 assert_eq!(v.get("age"), Some(&Value::Int(27)));
5698 assert_eq!(v.get("isAlive"), Some(&Value::Bool(true)));
5699 assert_eq!(v.get("spouse"), Some(&Value::Null));
5700 }
5701
5702 #[test]
5703 fn parse_nested() {
5704 let text = "address:\n{\n streetAddress: \"21 2nd Street\"\n state: NY\n}\n";
5705 let v = parse(text).unwrap();
5706 assert_eq!(
5707 v.get("address.streetAddress"),
5708 Some(&Value::Str("21 2nd Street".into()))
5709 );
5710 assert_eq!(v.get("address.state"), Some(&Value::Str("NY".into())));
5711 }
5712
5713 #[test]
5714 fn parse_array() {
5715 let text = "phoneNumbers:\n[\n { type: home }\n { type: office }\n]\n";
5716 let v = parse(text).unwrap();
5717 if let Some(Value::Array(a)) = v.get("phoneNumbers") {
5718 assert_eq!(a.len(), 2);
5719 assert_eq!(a[0].get("type"), Some(&Value::Str("home".into())));
5720 } else {
5721 panic!("not array");
5722 }
5723 }
5724
5725 #[test]
5726 fn parse_fragment() {
5727 let text = "@base { region: cn-north-1 }\nserver web { &base }\n";
5728 let v = parse(text).unwrap();
5729 assert_eq!(
5731 v.get("server.&base.region"),
5732 Some(&Value::Str("cn-north-1".into()))
5733 );
5734 assert_eq!(v.get("server.__type"), Some(&Value::Str("server".into())));
5735 assert_eq!(v.get("server.__name"), Some(&Value::Str("web".into())));
5736 }
5737
5738 #[test]
5739 fn roundtrip() {
5740 let text = "name: myapp\nport: 8080\nflags: [ a b c ]\n";
5741 let v = parse(text).unwrap();
5742 let out = to_sml(&v);
5743 let v2 = parse(&out).unwrap();
5744 assert_eq!(v, v2);
5745 }
5746
5747 #[test]
5748 fn env_inline() {
5749 unsafe { std::env::set_var("SML_TEST_VAR", "hello") };
5751 let text = "greeting: $env.SML_TEST_VAR\n";
5752 let v = parse(text).unwrap();
5753 assert_eq!(v.get("greeting"), Some(&Value::Str("hello".into())));
5754 }
5755
5756 #[test]
5757 fn c_abi_json_bridge() {
5758 let text = "name: John\nage: 27\n";
5759 let v = parse(text).unwrap();
5760 let j = jsonify(&v);
5761 assert!(j.contains("\"name\":\"John\""));
5762 let back = json_to_value(&j).unwrap();
5763 assert_eq!(back, v);
5764 }
5765}
5766
5767#[cfg(test)]
5772mod feature {
5773 use super::*;
5774
5775 #[test]
5776 fn feature_unknown_name_errors() {
5777 let r = parse("@feature enable nope\nx: 1\n");
5778 assert!(r.is_err());
5779 assert!(r.unwrap_err().contains("未知特性"));
5780 }
5781
5782 #[test]
5783 fn feature_whitelist_narrows() {
5784 let v = match parse("@feature whitelist bareword-string,include\nx: John\n").unwrap() {
5786 Value::Object(m) => m,
5787 _ => panic!("应为对象"),
5788 };
5789 assert_eq!(v.get("x"), Some(&Value::Str("John".into())));
5790 }
5791
5792 #[test]
5793 fn feature_blacklist_removes() {
5794 let r = parse("@feature blacklist bareword-string\nx: John\n");
5796 assert!(r.is_err());
5797 assert!(r.unwrap_err().contains("字符串必须加引号"));
5798 }
5799
5800 #[test]
5801 fn feature_mode_whitelist_enable() {
5802 let r = parse("@feature mode whitelist\n@feature enable fragment\nx: &frag\n");
5804 assert!(r.is_ok());
5806 }
5807
5808 #[test]
5809 fn caller_allowed_intersection_empty_errors() {
5810 let allowed = FeatureSet::none().with(Feature::Env);
5812 let r = parse_with_features(
5813 "@feature mode whitelist\n@feature enable contract\nx: 1\n",
5814 allowed,
5815 );
5816 assert!(r.is_err());
5817 }
5818
5819 #[test]
5820 fn caller_allowed_subset_ok() {
5821 let allowed = FeatureSet::all();
5823 let (v, eff) = parse_with_features(
5824 "@feature whitelist bareword-string,include\nx: John\n",
5825 allowed,
5826 )
5827 .unwrap();
5828 assert!(eff.has(Feature::BarewordStr));
5829 assert!(eff.has(Feature::Include));
5830 assert!(!eff.has(Feature::Env));
5831 assert_eq!(v.get("x"), Some(&Value::Str("John".into())));
5832 }
5833
5834 #[test]
5835 fn feature_namespace_include() {
5836 let dir = std::env::temp_dir().join("sml_feat_ns_test");
5840 let _ = std::fs::create_dir_all(&dir);
5841 let sub = dir.join("sub.sml");
5842 let main = dir.join("main.sml");
5843 std::fs::write(&sub, "a: 1\nb: 2\n").unwrap();
5844 let rel = format!("include \"sub.sml\" as pkg\n");
5846 std::fs::write(&main, &rel).unwrap();
5847 let v = match parse_file(&main) {
5848 Ok(v) => v,
5849 Err(e) => {
5850 let _ = std::fs::remove_dir_all(&dir);
5851 panic!("parse_file 失败: {e}");
5852 }
5853 };
5854 let _ = std::fs::remove_dir_all(&dir);
5855 let pkg = match v.get("pkg") {
5856 Some(Value::Object(m)) => m.clone(),
5857 _ => panic!("pkg 应为对象"),
5858 };
5859 assert_eq!(pkg.get("a"), Some(&Value::Int(1)));
5860 assert_eq!(pkg.get("b"), Some(&Value::Int(2)));
5861 }
5862
5863 #[test]
5864 fn version_v3_disables_bareword() {
5865 let r = parse("@version v3\nname: John\n");
5867 assert!(r.is_err());
5868 let v = parse("@version v3\nname: \"John\"\nage: 27\n").unwrap();
5870 assert_eq!(v.get("name"), Some(&Value::Str("John".into())));
5871 assert_eq!(v.get("age"), Some(&Value::Int(27)));
5872 }
5873
5874 #[test]
5875 fn feature_base_derives_strict() {
5876 let r = parse("@feature base v3\nname: John\n");
5878 assert!(r.is_err());
5879 }
5880}