treescript-interpreter 0.1.1

TreeScript interpreter, with some built-in libraries and API to create more
Documentation
extern crate serde;
use crate::util::GeneratorIterator;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::Generator;
use std::slice::{Iter, IterMut};

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Float(pub f32);

#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum Prim {
  Integer(i32),
  Float(Float),
  String(String),
}

#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum Value {
  Splice(usize),
  Prim(Prim),
  Record { head: String, props: Vec<Value> },
}

impl PartialEq for Float {
  fn eq(&self, other: &Float) -> bool {
    return self.0.to_bits() == other.0.to_bits();
  }
}

impl Eq for Float {}

impl Hash for Float {
  fn hash<H: Hasher>(&self, hasher: &mut H) {
    self.0.to_bits().hash(hasher);
  }
}

impl Display for Float {
  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    return self.0.fmt(f);
  }
}

impl Display for Prim {
  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    match self {
      Prim::Integer(x) => x.fmt(f),
      Prim::Float(x) => x.fmt(f),
      Prim::String(x) => write!(
        f,
        "\"{}\"",
        x.chars()
          .flat_map(|c| c.escape_default())
          .collect::<String>()
      ),
    }
  }
}

impl Prim {
  pub fn type_str(&self) -> &'static str {
    match self {
      Prim::Integer(_) => "integer",
      Prim::Float(_) => "float",
      Prim::String(_) => "string",
    }
  }
}

impl Display for Value {
  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
    match self {
      Value::Splice(idx) => write!(f, "\\{}", idx),
      Value::Prim(prim) => prim.fmt(f),
      Value::Record { head, props } => {
        write!(f, "{}[", head)?;
        let mut first = true;
        for prop in props {
          if first {
            first = false;
          } else {
            write!(f, ", ")?;
          }
          prop.fmt(f)?;
        }
        return write!(f, "]");
      }
    }
  }
}

#[allow(dead_code)]
impl Value {
  pub fn unit() -> Value {
    return Value::Record {
      head: String::from("Unit"),
      props: Vec::default(),
    };
  }

  pub fn true_() -> Value {
    return Value::Record {
      head: String::from("True"),
      props: Vec::default(),
    };
  }

  pub fn false_() -> Value {
    return Value::Record {
      head: String::from("False"),
      props: Vec::default(),
    };
  }

  pub fn nil() -> Value {
    return Value::Record {
      head: String::from("Nil"),
      props: Vec::default(),
    };
  }

  pub fn bool(x: bool) -> Value {
    if x {
      return Value::true_();
    } else {
      return Value::false_();
    }
  }

  pub fn cons(first: Value, rest: Value) -> Value {
    return Value::Record {
      head: String::from("Cons"),
      props: vec![first, rest],
    };
  }

  pub fn hole(idx: i32) -> Value {
    return Value::Record {
      head: String::from("Hole"),
      props: vec![Value::Prim(Prim::Integer(idx))],
    };
  }

  pub fn option(val: Option<Value>) -> Value {
    match val {
      None => {
        return Value::Record {
          head: String::from("None"),
          props: Vec::default(),
        };
      }
      Some(val) => {
        return Value::Record {
          head: String::from("Some"),
          props: vec![val],
        };
      }
    };
  }

  pub fn list<I: Iterator<Item = Value>>(vals: &mut I) -> Value {
    match vals.next() {
      None => return Value::nil(),
      Some(fst) => return Value::cons(fst, Value::list(vals)),
    };
  }

  pub fn record_head_to_fun(head: &String) -> Option<(String, String)> {
    if let Some(sep_pos) = head.chars().position(|c| c == '_') {
      let (lib, name) = head.split_at(sep_pos);
      let name = &name[1..];
      return Some((String::from(lib), String::from(name)));
    } else {
      return None;
    }
  }

  pub fn is_splice(&self) -> bool {
    if let Value::Splice(_) = self {
      return true;
    } else {
      return false;
    }
  }

  pub fn is_hole(&self) -> bool {
    if let Value::Record { head, .. } = self {
      return head == "Hole";
    } else {
      return false;
    }
  }

  pub fn matches(&self, other: &Value) -> bool {
    if self.is_hole() {
      return true;
    }
    if let Value::Record { head, props } = self {
      if let Value::Record {
        head: other_head,
        props: other_props,
      } = other
      {
        return head == other_head
          && Iterator::zip(props.iter(), other_props.iter())
            .all(|(prop, other_prop)| prop.matches(other_prop));
      }
    } else {
      return self == other;
    }
    return false;
  }

  pub fn subst(&mut self, old: &Value, new: &Value) {
    if self == old {
      *self = new.clone();
    } else if let Value::Record { props, .. } = self {
      for prop in props {
        prop.subst(old, new);
      }
    }
  }

  pub fn fill_splices<F: Copy + Fn(usize) -> Value>(&mut self, f: F) {
    match self {
      Value::Splice(idx) => *self = f(*idx),
      Value::Prim(_) => (),
      Value::Record { head: _, props } => {
        for prop in props {
          prop.fill_splices(f);
        }
      }
    };
  }

  pub fn flush(&mut self) {
    self.fill_splices(|idx| Value::hole(idx as i32));
  }

  pub fn modify_children<F: FnMut(&mut Value) -> bool>(&mut self, f: &mut F) {
    if let Value::Record { props, .. } = self {
      for prop in props {
        if f(prop) {
          prop.modify_children(f);
        }
      }
    }
  }

  pub fn breadth_first(&self) -> GeneratorIterator<impl Generator<Yield = &Value, Return = ()>> {
    return GeneratorIterator(move || {
      if let Value::Record { props, .. } = self {
        let mut yielded = true;
        let mut level = 0;
        let mut props_stack: Vec<Iter<Value>> = Vec::new();
        while yielded {
          yielded = false;
          level = level + 1;
          props_stack.push(props.iter());
          while let Option::Some(top_props) = props_stack.last_mut() {
            if let Option::Some(top_prop) = top_props.next() {
              if props_stack.len() == level {
                yield top_prop;
                yielded = true;
              } else {
                if let Value::Record {
                  props: top_sub_props,
                  ..
                } = top_prop
                {
                  props_stack.push(top_sub_props.iter())
                }
              }
            } else {
              props_stack.pop();
            }
          }
        }
      }
    });
  }

  pub fn breadth_first_mut(
    &mut self,
  ) -> GeneratorIterator<impl Generator<Yield = &mut Value, Return = ()>> {
    return GeneratorIterator(move || unsafe {
      if let Value::Record { props, .. } = self {
        let props = props as *mut Vec<Value>;
        let mut yielded = true;
        let mut level = 0;
        let mut props_stack: Vec<IterMut<Value>> = Vec::new();
        while yielded {
          yielded = false;
          level = level + 1;
          props_stack.push((&mut *props).iter_mut());
          while let Option::Some(top_props) = props_stack.last_mut() {
            if let Option::Some(top_prop) = top_props.next() {
              if props_stack.len() == level {
                yield top_prop;
                yielded = true;
              } else {
                if let Value::Record {
                  props: top_sub_props,
                  ..
                } = top_prop
                {
                  props_stack.push(top_sub_props.iter_mut())
                }
              }
            } else {
              props_stack.pop();
            }
          }
        }
      }
    });
  }

  pub fn sub_splices(&self) -> Vec<usize> {
    let mut res: Vec<usize> = Vec::new();
    if let Value::Splice(idx) = self {
      res.push(*idx);
    }
    for child in self.breadth_first() {
      if let Value::Splice(idx) = child {
        res.push(*idx);
      }
    }
    return res;
  }

  pub fn any_sub<F: Fn(&Value) -> bool>(&self, pred: F) -> bool {
    if pred(self) {
      return true;
    }
    for child in self.breadth_first() {
      if pred(child) {
        return true;
      }
    }
    return false;
  }
}

#[test]
fn test_breadth_first_mut() {
  let mut x = Value::Record {
    head: String::from("Foo"),
    props: vec![
      Value::Record {
        head: String::from("Bar"),
        props: vec![
          Value::Record {
            head: String::from("Baz"),
            props: vec![Value::Prim(Prim::Integer(2)), Value::Prim(Prim::Integer(3))],
          },
          Value::Prim(Prim::Integer(1)),
          Value::Record {
            head: String::from("Qux"),
            props: vec![Value::Prim(Prim::Integer(4))],
          },
        ],
      },
      Value::Prim(Prim::Integer(0)),
    ],
  };
  for i in 0..5 {
    let mut cur_idx = i;
    for prop in x.breadth_first_mut() {
      if let Value::Prim(Prim::Integer(idx)) = prop {
        if *idx >= 0 {
          assert_eq!(cur_idx, *idx);
          *prop = Value::Record {
            head: String::from("Lower"),
            props: vec![Value::Prim(Prim::Integer(-(*idx + 1)))],
          };
          cur_idx = cur_idx + 1;
        }
      }
    }
    for prop in x.breadth_first_mut() {
      if let Value::Prim(Prim::Integer(idx)) = prop {
        if *idx < 0 {
          *idx = -*idx;
        }
      }
    }
  }
}