hyperon/metta/runner/stdlib/
string.rs

1use hyperon_atom::*;
2use hyperon_atom::gnd::GroundedFunctionAtom;
3use crate::metta::*;
4use crate::metta::text::Tokenizer;
5use hyperon_atom::gnd::str::*;
6use super::{grounded_op, unit_result, regex};
7
8use std::convert::TryInto;
9
10#[derive(Clone, Debug)]
11pub struct PrintlnOp {}
12
13grounded_op!(PrintlnOp, "println!");
14
15impl Grounded for PrintlnOp {
16    fn type_(&self) -> Atom {
17        Atom::expr([ARROW_SYMBOL, ATOM_TYPE_UNDEFINED, UNIT_TYPE])
18    }
19
20    fn as_execute(&self) -> Option<&dyn CustomExecute> {
21        Some(self)
22    }
23}
24
25impl CustomExecute for PrintlnOp {
26    fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
27        let arg_error = || ExecError::from("println! expects single atom as an argument");
28        let atom = args.get(0).ok_or_else(arg_error)?;
29        println!("{}", atom_to_string(atom));
30        unit_result()
31    }
32}
33
34#[derive(Clone, Debug)]
35pub struct FormatArgsOp {}
36
37grounded_op!(FormatArgsOp, "format-args");
38
39use dyn_fmt::AsStrFormatExt;
40
41impl Grounded for FormatArgsOp {
42    fn type_(&self) -> Atom {
43        Atom::expr([ARROW_SYMBOL, ATOM_TYPE_STRING, ATOM_TYPE_EXPRESSION, ATOM_TYPE_STRING])
44    }
45
46    fn as_execute(&self) -> Option<&dyn CustomExecute> {
47        Some(self)
48    }
49}
50
51impl CustomExecute for FormatArgsOp {
52    fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
53        let arg_error = || ExecError::from("format-args expects format string as a first argument and expression as a second argument");
54        let format = args.get(0).and_then(Str::from_atom).ok_or_else(arg_error)?;
55        let args = TryInto::<&ExpressionAtom>::try_into(args.get(1).ok_or_else(arg_error)?)?;
56        let args: Vec<String> = args.children().iter()
57            .map(|atom| atom_to_string(atom))
58            .collect();
59        let res = format.format(args.as_slice());
60        Ok(vec![Atom::gnd(Str::from_string(res))])
61    }
62}
63
64fn sort_strings(args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
65    let arg_error = "sort-strings expects expression with strings as a first argument";
66    let list = TryInto::<&ExpressionAtom>::try_into(args.get(0).ok_or(arg_error)?).map_err(|_| arg_error)?;
67    let mut strings = Vec::<&str>::with_capacity(list.children().len());
68    for s in list.children() {
69        let s = Atom::as_gnd::<Str>(s).ok_or(arg_error)?;
70        strings.push(s.as_str());
71    }
72    strings.sort();
73    let sorted: Vec::<Atom> = strings.into_iter()
74        .map(|s| Atom::gnd(Str::from_string(s.into()))).collect();
75    Ok(vec![Atom::expr(sorted)])
76}
77
78pub(super) fn register_context_independent_tokens(tref: &mut Tokenizer) {
79    let println_op = Atom::gnd(PrintlnOp{});
80    tref.register_token(regex(r"println!"), move |_| { println_op.clone() });
81    let format_args_op = Atom::gnd(FormatArgsOp{});
82    tref.register_token(regex(r"format-args"), move |_| { format_args_op.clone() });
83    tref.register_token(regex(r#"(?s)^".*"$"#),
84        |token| { let mut s = String::from(token); s.remove(0); s.pop(); Atom::gnd(Str::from_string(s)) });
85    tref.register_function(GroundedFunctionAtom::new(
86        r"sort-strings".into(), 
87        expr!("->" "Expression" "Expression"),
88        sort_strings
89    ));
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn println_op() {
98        assert_eq!(PrintlnOp{}.execute(&mut vec![sym!("A")]), unit_result());
99    }
100}