hyperon/metta/runner/stdlib/
string.rs1use 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}