1use anyhow::Result;
2use blots_core::{
3 expressions::evaluate_pairs,
4 functions::get_built_in_function_idents,
5 heap::{CONSTANTS, Heap},
6 parser::{Rule, Token, get_pairs, get_tokens},
7 values::SerializableValue,
8};
9use indexmap::IndexMap;
10use serde::{Deserialize, Serialize};
11use std::{
12 cell::RefCell,
13 collections::{HashMap, HashSet},
14 rc::Rc,
15};
16use wasm_bindgen::prelude::*;
17
18#[derive(Debug, Serialize, Deserialize)]
19struct EvaluationResult {
20 values: HashMap<String, SerializableValue>,
21 bindings: HashMap<String, SerializableValue>,
22 outputs: HashSet<String>,
23}
24
25#[wasm_bindgen]
26pub fn evaluate(expr: &str, inputs_js: JsValue) -> Result<JsValue, JsError> {
27 let heap = Rc::new(RefCell::new(Heap::new()));
28 let inputs_given: IndexMap<String, SerializableValue> =
29 serde_wasm_bindgen::from_value(inputs_js)?;
30
31 let inputs = inputs_given
32 .into_iter()
33 .map(|(key, value)| (key, value.to_value(&mut heap.borrow_mut()).unwrap()))
34 .collect();
35
36 let bindings = Rc::new(RefCell::new(HashMap::new()));
37 {
38 bindings.borrow_mut().insert(
39 String::from("inputs"),
40 heap.borrow_mut().insert_record(inputs),
41 );
42 }
43
44 let expr_owned = String::from(expr);
45 let pairs =
46 get_pairs(&expr_owned).map_err(|e| JsError::new(&format!("Parsing error: {}", e)))?;
47
48 let mut outputs = HashSet::new();
49 let mut values = HashMap::new();
50
51 for pair in pairs {
52 match pair.as_rule() {
53 Rule::statement => {
54 if let Some(inner_pair) = pair.into_inner().next() {
55 let rule = inner_pair.as_rule();
56 let start_line_col = inner_pair.as_span().start_pos().line_col();
57 let end_line_col = inner_pair.as_span().end_pos().line_col();
58
59 let inner_pairs = inner_pair.into_inner();
60
61 if rule == Rule::output_declaration {
62 let mut inner_pairs_clone = inner_pairs.clone();
63
64 let next_token = inner_pairs_clone.next().unwrap(); let output_name = match next_token.as_rule() {
66 Rule::identifier => next_token.as_str().to_string(),
67 Rule::assignment => {
68 let next_inner_token = next_token.into_inner().next().unwrap();
69 match next_inner_token.as_rule() {
70 Rule::identifier => next_inner_token.as_str().to_string(),
71 _ => {
72 unreachable!(
73 "unexpected rule: {:?}",
74 next_inner_token.as_rule()
75 )
76 }
77 }
78 }
79 _ => unreachable!("unexpected rule: {:?}", next_token.as_rule()),
80 };
81
82 outputs.insert(output_name);
83 }
84
85 let col_id = format!(
86 "{}-{}__{}-{}",
87 start_line_col.0, start_line_col.1, end_line_col.0, end_line_col.1
88 );
89
90 let value =
91 evaluate_pairs(inner_pairs, Rc::clone(&heap), Rc::clone(&bindings), 0, expr)
92 .map_err(|error| {
93 JsError::new(&format!("Evaluation error: {}", error))
94 })?;
95
96 values.insert(col_id, value);
97 }
98 }
99 Rule::EOI => {}
100 rule => unreachable!("unexpected rule: {:?}", rule),
101 }
102 }
103
104 let values_serializable = values
105 .iter()
106 .map(|(k, v)| (k.clone(), v.to_serializable_value(&heap.borrow()).unwrap()))
107 .collect();
108
109 let bindings_serializable = bindings
110 .borrow()
111 .iter()
112 .map(|(k, v)| (k.clone(), v.to_serializable_value(&heap.borrow()).unwrap()))
113 .collect();
114
115 let serializer = serde_wasm_bindgen::Serializer::json_compatible();
118 Ok(EvaluationResult {
119 values: values_serializable,
120 bindings: bindings_serializable,
121 outputs,
122 }
123 .serialize(&serializer)?)
124}
125
126#[derive(Debug, Serialize, Deserialize)]
127enum SerialToken {
128 Start { rule: String, pos: usize },
129 End { rule: String, pos: usize },
130}
131
132#[wasm_bindgen]
133pub fn tokenize(input: &str) -> Result<JsValue, JsError> {
134 let input = input.to_string();
135 let tokens = get_tokens(&input)?;
136
137 let tokens: Vec<SerialToken> = tokens
138 .iter()
139 .map(|token| match token {
140 Token::Start { rule, pos } => SerialToken::Start {
141 rule: format!("{:?}", rule),
142 pos: pos.pos(),
143 },
144 Token::End { rule, pos } => SerialToken::End {
145 rule: format!("{:?}", rule),
146 pos: pos.pos(),
147 },
148 })
149 .collect();
150
151 let serializer = serde_wasm_bindgen::Serializer::json_compatible();
153 Ok(tokens.serialize(&serializer)?)
154}
155
156#[wasm_bindgen]
157pub fn get_built_in_function_names() -> Result<JsValue, JsError> {
158 let serializer = serde_wasm_bindgen::Serializer::json_compatible();
160 Ok(get_built_in_function_idents().serialize(&serializer)?)
161}
162
163#[wasm_bindgen]
164pub fn get_constants() -> Result<JsValue, JsError> {
165 let mut map = HashMap::new();
166 let constants = SerializableValue::Record(
167 CONSTANTS
168 .clone()
169 .into_iter()
170 .map(|(k, v)| (k, v.into()))
171 .collect(),
172 );
173
174 map.insert(String::from("constants"), constants);
175
176 let serializer = serde_wasm_bindgen::Serializer::json_compatible();
178 Ok(map.serialize(&serializer)?)
179}
180
181#[derive(Debug, Serialize, Deserialize)]
182#[serde(untagged)]
183enum ExpressionResult {
184 Value { value: SerializableValue },
185 Error { error: String },
186}
187
188#[wasm_bindgen]
189pub fn evaluate_inline_expressions(
190 expressions_js: JsValue,
191 inputs_js: JsValue,
192) -> Result<JsValue, JsError> {
193 let expressions: Vec<String> = serde_wasm_bindgen::from_value(expressions_js)?;
194 let inputs_given: IndexMap<String, SerializableValue> =
195 serde_wasm_bindgen::from_value(inputs_js)?;
196
197 let mut results = Vec::new();
198
199 for expr in expressions {
200 let result = evaluate_single_inline_expression(&expr, &inputs_given);
201 results.push(result);
202 }
203
204 let serializer = serde_wasm_bindgen::Serializer::json_compatible();
206 Ok(results.serialize(&serializer)?)
207}
208
209fn evaluate_single_inline_expression(
210 expr: &str,
211 inputs_given: &IndexMap<String, SerializableValue>,
212) -> ExpressionResult {
213 let heap = Rc::new(RefCell::new(Heap::new()));
214
215 let inputs: IndexMap<String, _> = inputs_given
217 .iter()
218 .map(|(key, value)| (key.clone(), value.to_value(&mut heap.borrow_mut()).unwrap()))
219 .collect();
220
221 let bindings = Rc::new(RefCell::new(HashMap::new()));
222
223 {
225 bindings.borrow_mut().insert(
226 String::from("inputs"),
227 heap.borrow_mut().insert_record(inputs.clone()),
228 );
229 }
230
231 for (key, value) in inputs {
233 bindings.borrow_mut().insert(key, value);
234 }
235
236 let expr_string = expr.to_string();
238 let pairs = match get_pairs(&expr_string) {
239 Ok(pairs) => pairs,
240 Err(e) => {
241 return ExpressionResult::Error {
242 error: format!("Parsing error: {}", e),
243 };
244 }
245 };
246
247 for pair in pairs {
249 match pair.as_rule() {
250 Rule::statement => {
251 if let Some(inner_pair) = pair.into_inner().next() {
252 let inner_pairs = inner_pair.into_inner();
253
254 match evaluate_pairs(inner_pairs, Rc::clone(&heap), Rc::clone(&bindings), 0, expr) {
255 Ok(value) => match value.to_serializable_value(&heap.borrow()) {
256 Ok(serializable) => {
257 return ExpressionResult::Value {
258 value: serializable,
259 };
260 }
261 Err(e) => {
262 return ExpressionResult::Error {
263 error: format!("Serialization error: {}", e),
264 };
265 }
266 },
267 Err(e) => {
268 return ExpressionResult::Error {
269 error: format!("Evaluation error: {}", e),
270 };
271 }
272 }
273 }
274 }
275 Rule::EOI => continue,
276 _ => continue,
277 }
278 }
279
280 ExpressionResult::Error {
281 error: "No expression found".to_string(),
282 }
283}