yyyi_ru/mtgott/src/lambda_compilation.rs

284 lines
13 KiB
Rust
Raw Normal View History

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<bool, String> {
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<Option<&'i Element>, 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<String, String> {
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<ExpressionResult<'l>, 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<ExpressionResult<'l>, 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<Box<HigherLevelFunc>, 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<Value, String> {
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<Value, String> {
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<Value, String> {
if recc == 0 { return Err("Recursion limit exceeded".into()) }
match x {
Plemege::Package(map) => {
let mut new_dict: HashMap<String, Value> = 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<String, String> {
re.execute_element_block(&el.sub_elements, root, &[], recc)
})))
} else {
let c1 = construct_element_closure(Vec::new(), el, recc).map(Value::Fn);
c1
}
}
}
}