use super::runtime::*; use super::parser::*; use std::error::Error; use std::collections::HashMap; use std::ops::Deref; struct ElementPartsCollector { res: String, cur_col: usize, } impl ElementPartsCollector { fn without_pad(&mut self, thp: &str) { self.res += thp; for ch in thp.chars() { if ch == '\n' { self.cur_col = 0; } else { self.cur_col += 1; } } } fn add_padded_element_piece(&mut self, offset: usize, thp: &str){ for ch in thp.chars() { self.res.push(ch); if ch == '\n' { self.res.push_str(&" ".repeat(offset)); self.cur_col = offset; } else { self.cur_col += 1; } } } fn add_single_padded_element_piece(&mut self, thp: &str) { self.add_padded_element_piece(self.cur_col, thp); } } impl RuntimeEnv { fn value_to_bool(&self, val: &Value) -> Result { match val { Value::Int(num) => Ok(*num != 0), Value::Str(str) => Ok(str.len() > 0), Value::Arr(arr) => Ok(arr.len() > 0), Value::Dict(dict) => Ok(dict.len() > 0), Value::Fn(_) => Err(self.make_error("Can't convert function to bool")), _ => panic!("Get rid of runtime strings in expressions") } } fn get_needed_if_block<'i>( &self, if_sub_el: &'i IfSubElement, root: &Value, arg_stack: &[&Value], recc: u32 ) -> Result, String> { let n = if_sub_el.conditions.len(); for i in 0..n { let expr_res = self.execute_expression(&if_sub_el.conditions[i], root, arg_stack, recc - 1)?; if self.value_to_bool(expr_res.deref())? { return Ok(Some(&if_sub_el.branches[i])); } } if if_sub_el.branches.len() > n { Ok(Some(&if_sub_el.branches[n])) } else { Ok(None) } } fn execute_element_block<'r, 'aa>( &self, el: &[SubElement], root: &'r Value, arg_stack: &[&'aa Value], recc: u32 ) -> Result { if recc == 0 { return Err(self.make_error("Recursion limit exceeded")) } let mut res = ElementPartsCollector{res: String::new(), cur_col: 0}; for se in el { match se { SubElement::Static(ps) => { res.without_pad(ps); }, SubElement::If(if_sub_el) => if let Some(branch_el) = self.get_needed_if_block(if_sub_el, root, arg_stack, recc - 1)? { res.add_single_padded_element_piece( &self.execute_element_block( &branch_el.sub_elements, root, arg_stack, recc - 1)?) } , SubElement::InsertExpr(expr) => res.add_single_padded_element_piece( match self.execute_expression(expr, root, arg_stack, recc - 1)?.deref() { Value::Str(str) => str, _ => return Err(self.make_error("Cannot insert non-string. Try using {{}}")), }), SubElement::For(ForSubElement{iterable, core, join}) => { let _g = self.register("In {%for%}".into()); let expr_val = self.execute_expression(iterable, root, arg_stack, recc - 1)?; let an = arg_stack.len(); let saved_offset = res.cur_col; match expr_val.deref() { Value::Dict(dict) => { let mut it = dict.iter(); for i in 0usize.. { if let Some((key, value)) = it.next() { let itv = Value::Str(key.clone()); let mut arg_stack_updated: Vec<&Value> = Vec::with_capacity(an + 2); arg_stack_updated.extend_from_slice(arg_stack); arg_stack_updated.push(&itv); arg_stack_updated.push(value); if i > 0 {res.add_padded_element_piece(saved_offset, join); } res.add_padded_element_piece( saved_offset, &self.execute_element_block( &core.sub_elements, root, arg_stack, recc - 1)?); } else { break } } } Value::Arr(array) => { for i in 0..array.len() { let itv = Value::Int(i as u64); let mut arg_stack_updated: Vec<&Value> = Vec::with_capacity(an + 2); arg_stack_updated.extend_from_slice(arg_stack); arg_stack_updated.push(&itv); arg_stack_updated.push(&array[i]); if i > 0 { res.add_padded_element_piece(saved_offset, join); } res.add_padded_element_piece( saved_offset, &self.execute_element_block( &core.sub_elements, root, arg_stack, recc - 1)?); } } _ => return Err(self.make_error(&format!("Can't iterate over {}", expr_val.deref().stringify_type()))) } } SubElement::Let(expr, core) => { let expr_val = self.execute_expression(expr, root, arg_stack, recc - 1)?; let mut arg_stack_updated = Vec::with_capacity(arg_stack.len() + 1); arg_stack_updated.extend_from_slice(arg_stack); arg_stack_updated.push(expr_val.deref()); res.add_single_padded_element_piece(&self.execute_element_block( &core.sub_elements, root, arg_stack, recc - 1)?); } }; } Ok(res.res) } } enum ExpressionResult<'l> { LocalRef(&'l Value), Owned(Value), } impl<'l> Deref for ExpressionResult<'l> { type Target = Value; fn deref(&self) -> &Self::Target { match self { ExpressionResult::LocalRef(val) => val, ExpressionResult::Owned(val) => val, } } } impl RuntimeEnv { fn in_expression_index_by_key<'l>(&self, mut base: ExpressionResult<'l>, key: &String) -> Result, String> { match base { ExpressionResult::LocalRef(Value::Dict(dictionary )) => { if let Some(el) = dictionary.get(key) { Ok(ExpressionResult::LocalRef(el)) } else { Err(self.make_error(&format!("Dictionary doesn't have key {}", key))) } }, ExpressionResult::Owned(Value::Dict(mut dictionary)) => { /* I can't think of a single use case for this */ if let Some(el) = dictionary.get_mut(key) { Ok(ExpressionResult::Owned(std::mem::take(el))) } else { Err(self.make_error(&format!("Locally created dictionary doesn't have key {}", key))) } } _ => Err(self.make_error(&format!("Can't take attribute {} (or really any attribute) from {}", key, base.deref().stringify_type()))) } } fn execute_expression<'l>( &self, expr: &Expression, root: &'l Value, arg_stack: &[&'l Value], recc: u32 ) -> Result, String> { if recc == 0 { return Err(self.make_error("Recursion limit exceeded".into())) } let f1: ExpressionResult<'l> = match expr { Expression::Root => ExpressionResult::LocalRef(root), Expression::Argument(id) => ExpressionResult::LocalRef(arg_stack[*id as usize]), Expression::Get(e1, e2) => { let mut r1: ExpressionResult<'l> = self.execute_expression(&e1, root, arg_stack, recc - 1)?; let r2: ExpressionResult = self.execute_expression(&e2, root, arg_stack, recc - 1)?; match (r1, r2.deref()) { (ExpressionResult::LocalRef(Value::Arr(arr)), &Value::Int(index)) => { if index as usize > arr.len() { return Err(self.make_error(&format!( "Indexing array of size {} at position {}", arr.len(), index))) } ExpressionResult::LocalRef(&arr[index as usize]) }, (ExpressionResult::Owned(Value::Arr(mut arr)), &Value::Int(index)) => { /* I can't think of a single use case for this */ if index as usize > arr.len() { return Err(self.make_error(&format!( "Indexing locally created array of size {} at position {}", arr.len(), index))) } ExpressionResult::Owned(std::mem::take(&mut arr[index as usize])) }, (r1, Value::Str(key)) => self.in_expression_index_by_key(r1, key)?, (r1, r2) => return Err(self.make_error(&format!( "Trying to index {} with {}", r1.deref().stringify_type(), r2.stringify_type()))) } } Expression::Attribute(e1, key) => { self.in_expression_index_by_key( self.execute_expression(&e1, root, arg_stack, recc - 1)?, key)? } Expression::Call(e1, e2) => { let r1: ExpressionResult = self.execute_expression(e1, root, arg_stack, recc - 1)?; let r2: ExpressionResult = self.execute_expression(e2, root, arg_stack, recc - 1)?; match r1.deref() { Value::Fn(func) => ExpressionResult::Owned(func(self, root, r2.deref(), recc - 1)?), _ => return Err(self.make_error(&format!( "Can't pass argument to {}", r1.deref().stringify_type()))) } } Expression::Int(num ) => ExpressionResult::Owned(Value::Int(*num)), /* Absurd, and yet possible case */ Expression::None => ExpressionResult::Owned(Value::Int(0)), }; Ok(match f1.deref() { Value::RuntimeStr(fnc) => ExpressionResult::Owned( Value::Str(fnc(self, root, recc - 1)?) ), _ => f1 }) } } /* We construct intermediate closures for elements at runtime */ fn construct_element_closure(prev: Vec<&Value>, el: Element, cr_recc: u32) -> Result, String> { if cr_recc == 0 { return Err("Recursion limit exceeded".into()) } Ok(if prev.len() + 1 == el.argc { Box::new(move |re: &RuntimeEnv, root: &Value, arg: &Value, ecc: u32| -> Result { if ecc == 0 { return Err(re.make_error("Recursion limit exceeded".into())) } let mut new = prev.clone(); new.push(arg); re.execute_element_block(&el.sub_elements, root, &new, ecc - 1).map(Value::Str) }) } else { Box::new(move |re: &RuntimeEnv, root: &Value, arg: &Value, ecc: u32| -> Result { if ecc == 0 { return Err(re.make_error("Recursion limit exceeded".into())) } let mut new = prev.clone(); new.push(arg); construct_element_closure(new, el, cr_recc - 1).map(Value::Fn) }) }) } /* This function is supposed to compile all elements in one particular file */ pub fn plemege_to_value(x: Plemege, file_path: &str, recc: u32) -> Result { if recc == 0 { return Err("Recursion limit exceeded".into()) } match x { Plemege::Package(map) => { let mut new_dict: HashMap = HashMap::new(); for (key, thing) in map { new_dict.insert(key, plemege_to_value(thing, file_path, recc - 1)?); } Ok(Value::Dict(new_dict)) }, Plemege::Element(el) => { /* The only optimization we ever make (we could do more, but sorry, my life is finite) */ if el.sub_elements.iter().all(|se| matches!(se, SubElement::Static(_))) { return Ok(Value::Str(el.sub_elements.into_iter() .fold(String::new(), |mut acc, p| { let SubElement::Static(s) = p else { panic!() }; acc.push_str(&s); acc }))) } if el.argc == 0 { Ok(Value::RuntimeStr(Box::new( move |re: &RuntimeEnv, root: &Value, recc: u32| -> Result { re.execute_element_block(&el.sub_elements, root, &[], recc) }))) } else { let c1 = construct_element_closure(Vec::new(), el, recc).map(Value::Fn); c1 } } } }