summaryrefslogtreecommitdiff
path: root/matrix-lang/src/value/value.rs
diff options
context:
space:
mode:
Diffstat (limited to 'matrix-lang/src/value/value.rs')
-rw-r--r--matrix-lang/src/value/value.rs522
1 files changed, 522 insertions, 0 deletions
diff --git a/matrix-lang/src/value/value.rs b/matrix-lang/src/value/value.rs
new file mode 100644
index 0000000..10d8398
--- /dev/null
+++ b/matrix-lang/src/value/value.rs
@@ -0,0 +1,522 @@
+use std::{
+ collections::HashMap,
+ rc::Rc,
+ hash::Hash,
+ fmt::{Display, Debug},
+ ops::{Add, Neg, Not, Sub, Div, Mul, BitOr, BitAnd, BitXor, Shl, Shr},
+ cmp::Ordering,
+ cell::RefCell, fs::File
+};
+
+use crate::iter;
+use num_complex::Complex64;
+use num_rational::Rational64;
+use regex::Regex;
+
+use crate::{ast::{Expr, BinaryOp, UnaryOp}, chunk::Function, Result, gc::Gc};
+
+
+pub type InlineList = Vec<Expr>;
+pub type InlineMatrix = (usize, usize, Vec<Expr>);
+pub type InlineTable = Vec<(Expr, Expr)>;
+
+#[derive(Debug)]
+pub struct Error(String);
+
+impl Display for self::Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.0)
+ }
+}
+
+impl std::error::Error for self::Error {}
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ Err(self::Error(format!($($arg)*)).into())
+ };
+}
+
+
+impl From<&str> for Value {
+ fn from(value: &str) -> Self {
+ Value::String(value.into())
+ }
+}
+
+
+impl Debug for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use Value as V;
+ match self {
+ V::Nil => write!(f, "[Nil]"),
+ V::Bool(b) => write!(f, "[Bool {b}]"),
+ V::Int(i) => write!(f, "[Int {i}]"),
+ V::Float(vf) => write!(f, "[Float {vf}]"),
+ V::Ratio(r) => write!(f, "[Ratio {r}]"),
+ V::Complex(c) => write!(f, "[Complex {c}]"),
+ V::Regex(r) => write!(f, "[Regex /{r}/]"),
+ V::String(s) => write!(f, "[String '{s}']"),
+ V::List(l) => write!(f, "[List {}]", l.len()),
+ V::Matrix(m) => write!(f, "[Matirx {}x{}]", m.domain, m.codomain),
+ V::Table(t) => write!(f, "[Table {}]", t.0.len()),
+ V::Function(vf) => write!(f, "[Function {}]", vf.name),
+ V::Range(r) => write!(f, "[Range {:?}..{:?}]", r.0, r.1),
+ V::Iter(_) => write!(f, "[Iterator]"),
+ V::Error(_) => write!(f, "[Error]"),
+ V::File(_) => write!(f, "[File]"),
+ }
+ }
+}
+
+impl Display for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use Value as V;
+
+ let red;
+ let green;
+ let yellow;
+ let blue;
+ let pink;
+ let cyan;
+ let clear;
+
+ if f.alternate() {
+ red = "\x1b[31m";
+ green = "\x1b[32m";
+ yellow = "\x1b[33m";
+ blue = "\x1b[34m";
+ pink = "\x1b[35m";
+ cyan = "\x1b[36m";
+ clear = "\x1b[0m";
+ } else {
+ red = "";
+ green = "";
+ yellow = "";
+ blue = "";
+ pink = "";
+ cyan = "";
+ clear = "";
+ }
+
+ match self {
+ V::Nil => {write!(f, "{blue}nil{clear}")?;},
+ V::Bool(b) => {write!(f, "{yellow}{b}{clear}")?;},
+ V::Int(i) => {write!(f, "{yellow}{i}{clear}")?;},
+ V::Float(l) => {write!(f, "{yellow}{l}{clear}")?;},
+ V::Ratio(r) => {write!(f, "{yellow}{r}{clear}")?;},
+ V::Complex(c) => {write!(f, "{yellow}{c}{clear}")?;},
+ V::Regex(r) => {write!(f, "/{red}{r}{clear}/")?;},
+ V::String(s) => {
+ if f.alternate() {
+ write!(f, "{green}'{s}'{clear}")?;
+ } else {
+ write!(f, "{s}")?;
+ }
+ }
+ V::List(l) => {
+ write!(f, "[")?;
+ for (i, el) in l.iter().enumerate() {
+ if i != 0 {
+ write!(f, " ")?;
+ }
+ if f.alternate() {
+ write!(f, "{el:#}")?;
+ } else {
+ write!(f, "{el}")?;
+ }
+ }
+ write!(f, "]")?;
+ },
+ V::Matrix(m) => {
+ if f.alternate() {
+ write!(f, "{m:#}")?;
+ } else {
+ write!(f, "{m}")?;
+ }
+ },
+ V::Table(t) => {
+ write!(f, "{{")?;
+ for (i, (key, val)) in t.0.iter().enumerate() {
+ if i != 0 {
+ write!(f, ", ")?;
+ }
+ if f.alternate() {
+ write!(f, "{key:#} = {val:#}")?;
+ } else {
+ write!(f, "{key} = {val}")?;
+ }
+ }
+ write!(f, "}}")?;
+ },
+ V::Function(fun) => {
+ use crate::chunk::InnerFunction as F;
+ match fun.fun {
+ F::Compiled(_) => write!(f, "{cyan}[Function {}]{clear}", fun.name)?,
+ F::Native(_) => write!(f, "{cyan}[Builtin {}]{clear}", fun.name)?,
+ };
+ },
+ V::Range(r) => {
+ if f.alternate() {
+ write!(f, "{:#}..{:#}", r.0, r.1)?;
+ } else {
+ write!(f, "{}..{}", r.0, r.1)?;
+ }
+ }
+ V::Iter(_) => {write!(f, "{pink}[Iterator]{clear}")?;},
+ V::File(_) => {write!(f, "{pink}[File]{clear}")?;},
+ V::Error(e) => {write!(f, "{red}{e}{clear}")?;},
+ };
+ Ok(())
+ }
+}
+
+impl Value {
+ pub fn can_hash(&self) -> Result<()> {
+ use Value::*;
+ match self {
+ Nil => {},
+ Bool(_) => {},
+ Int(_) => {},
+ Ratio(_) => {},
+ Regex(_) => {},
+ String(_) => {}
+ List(l) => {
+ for val in l.iter() {
+ val.can_hash()?;
+ }
+ }
+ Matrix(m) => {
+ for val in m.values.iter() {
+ val.can_hash()?;
+ }
+ },
+ _ => return error!("cannot hash {self:?}")
+ }
+ Ok(())
+ }
+
+ pub fn is_zero(&self) -> bool {
+ use Value as V;
+ match self {
+ V::Int(i) => *i == 0,
+ V::Float(f) => *f == 0.0 || *f == -0.0,
+ V::Ratio(r) => *r.numer() == 0,
+ _ => false,
+ }
+ }
+}
+
+
+impl Value {
+ pub fn val_cmp(&self, other: &Self) -> Result<Ordering> {
+ self.partial_cmp(other)
+ .map_or_else(|| error!("cannot compare: {self:?} and {other:?}"), Ok)
+ }
+
+ fn index_single(&self, index: &Value) -> Result<Self> {
+ use Value as V;
+ match (self, index) {
+ (V::Table(t), index) => {
+ Ok(t.get(index)?.unwrap_or(&Value::Nil).clone())
+ },
+ (V::List(l), V::Int(i)) => {
+ if *i < 0 || *i as usize >= l.len() {
+ return error!("{i} out of bounds for {self:?}")
+ }
+ Ok(l[*i as usize].clone())
+ },
+ (V::Matrix(m), V::Int(i)) => {
+ if *i < 0 || *i as usize >= m.values.len() {
+ return error!("{i} out of bounds for {self:?}")
+ }
+ Ok(m.values[*i as usize].clone())
+ },
+ _ => return error!("{index:?} cant index {self:?}")
+ }
+ }
+
+ fn index_multiple(&self, indexes: &Vec<Value>) -> Result<Self> {
+ use Value as V;
+ match self {
+ V::List(..) => {
+ let mut ret = Vec::new();
+ for index in indexes {
+ let res = self.index_single(index)?;
+ ret.push(res);
+ }
+ Ok(V::List(ret.into()))
+ }
+ V::Table(..) => {
+ let mut ret = ValueMap::new();
+ for index in indexes {
+ let res = self.index_single(index)?;
+ ret.insert(index.clone(), res)?;
+ }
+ Ok(V::Table(ret.into()))
+ }
+ V::Matrix(m) => {
+ let err = || error!("{self:?} can be index by [Int] or [Int;Int]");
+ if indexes.len() != 2 {
+ return err()
+ }
+ let lhs = indexes[0].clone();
+ let rhs = indexes[1].clone();
+ match (lhs, rhs) {
+ (V::Nil, V::Nil) => {
+ Ok(V::Matrix(m.clone_inside()))
+ },
+ (V::Int(row), V::Nil) => {
+ let Some((_, row)) = m.rows().enumerate().filter(|(idx, _)| *idx as i64 == row).next() else {
+ return err();
+ };
+ let row: Vec<Value> = row.into_iter().map(|e| e.clone()).collect();
+ Ok(V::Matrix(Matrix::new(row.len(), 1, row).into()))
+ },
+ (V::Nil, V::Int(col)) => {
+ let Some((_, col)) = m.cols().enumerate().filter(|(idx, _)| *idx as i64 == col).next() else {
+ return err();
+ };
+ let col: Vec<Value> = col.into_iter().map(|e| e.clone()).collect();
+ Ok(V::Matrix(Matrix::new(1, col.len(), col).into()))
+ },
+ (V::Int(row), V::Int(col)) => {
+ if row < 0 || col < 0 {
+ return err();
+ }
+ m.get(row as usize, col as usize)
+ }
+ _ => return err()
+ }
+ }
+ _ => return error!("cannot index {self:?}")
+ }
+ }
+
+ pub fn index(&self, index: &Vec<Value>) -> Result<Self> {
+ if index.len() == 0 {
+ Ok(self.clone_inside())
+ } else if index.len() == 1 {
+ self.index_single(&index[0])
+ } else {
+ self.index_multiple(index)
+ }
+ }
+
+ fn store_index_single(&mut self, index: &Value, store: Value) -> Result<()> {
+ use Value as V;
+ let err = format!("{self:?}");
+ match (self, index) {
+ (V::Table(t), index) => {
+ t.insert(index.clone(), store)
+ },
+ (V::List(l), V::Int(i)) => {
+ if *i < 0 || *i as usize >= l.len() {
+ return error!("{i} out of bounds for {err}")
+ }
+ l[*i as usize] = store;
+ Ok(())
+ },
+ (V::Matrix(m), V::Int(i)) => {
+ if *i < 0 || *i as usize >= m.values.len() {
+ return error!("{i} out of bounds for {err}")
+ }
+ m.values[*i as usize] = store;
+ Ok(())
+ },
+ _ => return error!("{index:?} cant index {err}")
+ }
+ }
+
+ fn store_index_multiple(&mut self, indexes: &Vec<Value>, store: Value) -> Result<()> {
+ use Value as V;
+ match self {
+ V::List(..) => {
+ for index in indexes {
+ self.store_index_single(index, store.clone())?;
+ }
+ Ok(())
+ }
+ V::Table(..) => {
+ for index in indexes {
+ self.store_index_single(index, store.clone())?;
+ }
+ Ok(())
+ }
+ _ => return error!("cannot index {self:?}")
+ }
+ }
+
+ pub fn store_index(&mut self, index: &Vec<Value>, store: Value) -> Result<()> {
+ if index.len() == 0 {
+ Ok(())
+ } else if index.len() == 1 {
+ self.store_index_single(&index[0], store)
+ } else {
+ self.store_index_multiple(index, store)
+ }
+ }
+
+ pub fn store_field_access(&mut self, ident: &str, val: Value) -> Result<()> {
+ use Value as V;
+ match self {
+ V::Table(t) => {
+ let key = V::String(Rc::from(ident));
+ Ok(t.insert(key, val)?)
+ },
+ _ => return error!("cannot field access assign {self:?}")
+ }
+ }
+
+ pub fn field_access(&self, ident: &str) -> Result<Self> {
+ use Value as V;
+ match self {
+ V::Table(t) => {
+ let key = V::String(Rc::from(ident));
+ Ok(t.get(&key)?.unwrap_or(&V::Nil).clone())
+ },
+ _ => return error!("cannot field access {self:?}")
+ }
+ }
+
+ pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
+ use BinaryOp::*;
+ match op {
+ Add => lhs + rhs,
+ Subtract => lhs - rhs,
+ Multiply => lhs * rhs,
+ Divide => lhs / rhs,
+ Modulo => lhs.modulo(rhs),
+ Power => lhs.pow(rhs),
+ BitwiseAnd => lhs & rhs,
+ BitwiseOr => lhs | rhs,
+ BitwiseXor => lhs ^ rhs,
+ BitwiseShiftLeft => lhs << rhs,
+ BitwiseShiftRight => lhs >> rhs,
+ Equals => Ok(Self::Bool(lhs == rhs)),
+ NotEquals => Ok(Self::Bool(lhs != rhs)),
+ GreaterEquals => Ok(Self::Bool(lhs >= rhs)),
+ LessEquals => Ok(Self::Bool(lhs <= rhs)),
+ GreaterThan => Ok(Self::Bool(lhs > rhs)),
+ LessThan => Ok(Self::Bool(lhs < rhs)),
+ Range | RangeEq => {
+ let Value::Int(lhs) = lhs else {
+ return error!("range can only take [Int]'s")
+ };
+ let Value::Int(rhs) = rhs else {
+ return error!("range can only take [Int]'s")
+ };
+ Ok(Self::Range(Rc::new((lhs, rhs, op == RangeEq))))
+ },
+ }
+ }
+
+ pub fn unary_op(op: UnaryOp, val: Value) -> Value {
+ use UnaryOp::*;
+ match op {
+ Negate => -val,
+ Not => Self::Bool(!val),
+ }
+ }
+}
+
+impl Neg for Value {
+ type Output = Value;
+
+ fn neg(self) -> Self::Output {
+ use Value::*;
+ match self {
+ Bool(b) => Bool(!b),
+ Int(i) => Int(-i),
+ Float(f) => Float(-f),
+ Ratio(r) => Ratio(-r),
+ Complex(c) => Complex(-c),
+ _ => return Float(f64::NAN)
+ }
+ }
+}
+
+impl Not for Value {
+ type Output = bool;
+
+ fn not(self) -> Self::Output {
+ use Value as V;
+ match self {
+ V::Nil => true,
+ V::Bool(b) => !b,
+ V::Int(i) => i == 0,
+ V::Float(f) => f == 0.0,
+ V::Ratio(r) => *(r.numer()) == 0 || *(r.denom()) == 0,
+ V::Complex(c) => !c.is_normal(),
+ V::Regex(_) => false,
+ V::List(_) => false,
+ V::Matrix(_) => false,
+ V::Table(_) => false,
+ V::String(s) => s.as_ref() == "",
+ V::Function(_) => false,
+ V::Iter(_) => false,
+ V::Range(_) => false,
+ V::File(_) => false,
+ V::Error(_) => false,
+ }
+ }
+}
+
+impl Value {
+
+ pub fn into_iter_fn(self) -> Result<Rc<Function>> {
+ let Value::Iter(iter) = self.into_iter()? else {
+ return error!("bypassed iter check")
+ };
+ Ok(iter)
+ }
+
+ pub fn into_iter(self) -> Result<Self> {
+ use Value as V;
+ Ok(match self {
+ V::Iter(..) => self,
+ V::List(l) => {
+ let iter = RefCell::new(l.into_inner().into_iter());
+ iter!(move |_,_| {
+ match iter.borrow_mut().next() {
+ Some(v) => Ok(v),
+ None => Ok(V::Nil),
+ }
+ })
+ },
+ V::Range(r) => {
+ let r = (*r).clone();
+ let lhs = RefCell::new(r.0);
+ let rhs = r.1;
+ iter!(move |_,_| {
+ let val = *lhs.borrow();
+ let next = *lhs.borrow() + 1;
+ if (!r.2 && *lhs.borrow() < rhs) || (r.2 && *lhs.borrow() <= rhs) {
+ *lhs.borrow_mut() = next;
+ return Ok(Value::Int(val))
+ }
+ Ok(Value::Nil)
+ })
+ },
+ V::Function(f) => {
+ if f.arity > 0 || f.variadic {
+ return error!("iterator functions cannot be varadic or take arguments")
+ }
+ V::Iter(f)
+ },
+ val => return error!("cannot turn {val:?} into an iterator")
+ })
+ }
+}
+
+fn dot(lhs: Vec<&Value>, rhs: Vec<&Value>) -> Result<Value> {
+ let len = lhs.len();
+
+ let mut res = Value::Int(0);
+ for i in 0..len {
+ let val = (lhs[i].clone() * rhs[i].clone())?;
+ res = (res + val)?;
+ }
+
+ Ok(res)
+}