string_template_plus/
lisp.rs1use anyhow::Context;
2use rust_lisp::default_env;
3use rust_lisp::interpreter::eval_block;
4use rust_lisp::model::{FloatType, RuntimeError, Symbol, Value};
5use rust_lisp::parser::{parse, ParseError};
6use std::num::ParseFloatError;
7use std::{
8 cell::RefCell,
9 collections::{HashMap, HashSet},
10 rc::Rc,
11};
12
13pub fn calculate(variables: &HashMap<String, String>, expr: &str) -> anyhow::Result<String> {
32 let expr = parse(expr)
33 .collect::<Result<Vec<Value>, ParseError>>()
34 .ok()
35 .context("Parse Failed")?;
36 let env = Rc::new(RefCell::new(default_env()));
37
38 let vars1 = variables.clone();
40 env.borrow_mut().define(
41 Symbol::from("st+var"),
42 Value::NativeClosure(Rc::new(RefCell::new(move |_, args: Vec<Value>| {
43 let name: String = match &args[0] {
44 Value::String(s) => s.to_string(),
45 Value::Symbol(s) => s.to_string(),
46 _ => Err(RuntimeError {
47 msg: "Only Symbol and String can be passed to st+var.".into(),
48 })?,
49 };
50 let val: String = if args.len() == 1 {
51 vars1.get(&name).unwrap().into()
52 } else if args.len() == 2 {
53 vars1
54 .get(&name)
55 .map(|s| s.to_string())
56 .unwrap_or(args[1].to_string())
57 } else {
58 Err(RuntimeError {
59 msg: "Too many/few arguments in st+var.".into(),
60 })?
61 };
62 Ok(Value::String(val))
63 }))),
64 );
65
66 let vars2 = variables.clone();
67 env.borrow_mut().define(
68 Symbol::from("st+num"),
69 Value::NativeClosure(Rc::new(RefCell::new(move |_, args: Vec<Value>| {
70 let name: String = match &args[0] {
71 Value::String(s) => s.to_string(),
72 Value::Symbol(s) => s.to_string(),
73 _ => Err(RuntimeError {
74 msg: "Only Symbol and String can be passed to st+num.".into(),
75 })?,
76 };
77 let val: String = if args.len() == 1 {
78 vars2.get(&name).unwrap().into()
79 } else if args.len() == 2 {
80 vars2
81 .get(&name)
82 .map(|s| s.to_string())
83 .unwrap_or(args[1].to_string())
84 } else {
85 Err(RuntimeError {
86 msg: "Too many/few arguments in st+num.".into(),
87 })?
88 };
89
90 let val: FloatType = val
91 .parse()
92 .map_err(|e: ParseFloatError| RuntimeError { msg: e.to_string() })?;
93 Ok(Value::Float(val))
94 }))),
95 );
96
97 let vars3: HashSet<String> = variables.iter().map(|(k, _)| k.to_string()).collect();
98 env.borrow_mut().define(
99 Symbol::from("st+has"),
100 Value::NativeClosure(Rc::new(RefCell::new(move |_, args: Vec<Value>| {
101 let name: String = match &args[0] {
102 Value::String(s) => s.to_string(),
103 Value::Symbol(s) => s.to_string(),
104 _ => Err(RuntimeError {
105 msg: "Only Symbol and String can be passed to st+num.".into(),
106 })?,
107 };
108 Ok(vars3.get(&name).is_some().into())
109 }))),
110 );
111
112 let res = eval_block(env.clone(), expr.into_iter())?;
122 Ok(res.to_string())
123}