summaryrefslogtreecommitdiff
path: root/matrix-lang/src/value
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-02-29 17:04:28 -0500
committerFreya Murphy <freya@freyacat.org>2024-02-29 17:04:28 -0500
commit5d2747e26f51cc2344a6bd95f93457248fdfebd8 (patch)
tree8755b4068166c3854d26817683ce438a771ab319 /matrix-lang/src/value
parentmore mat, sys, and os stdlib functions, better matrix printing, other fixes (diff)
downloadmatrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.gz
matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.bz2
matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.zip
fin prob
Diffstat (limited to 'matrix-lang/src/value')
-rw-r--r--matrix-lang/src/value/clone.rs54
-rw-r--r--matrix-lang/src/value/comp.rs373
-rw-r--r--matrix-lang/src/value/exception.rs78
-rw-r--r--matrix-lang/src/value/fmt.rs186
-rw-r--r--matrix-lang/src/value/function.rs43
-rw-r--r--matrix-lang/src/value/gc.rs186
-rw-r--r--matrix-lang/src/value/hash.rs240
-rw-r--r--matrix-lang/src/value/index.rs230
-rw-r--r--matrix-lang/src/value/matrix.rs337
-rw-r--r--matrix-lang/src/value/mod.rs42
-rw-r--r--matrix-lang/src/value/value.rs522
11 files changed, 2291 insertions, 0 deletions
diff --git a/matrix-lang/src/value/clone.rs b/matrix-lang/src/value/clone.rs
new file mode 100644
index 0000000..d5ac983
--- /dev/null
+++ b/matrix-lang/src/value/clone.rs
@@ -0,0 +1,54 @@
+use crate::prelude::*;
+
+pub trait ValueClone {
+ fn deep_clone(&self) -> Self;
+ fn shallow_clone(&self) -> Self;
+}
+
+impl ValueClone for Value {
+ fn deep_clone(&self) -> Self {
+ use Value as V;
+ match self {
+ V::List(l) => V::List(l.deep_clone()),
+ V::Table(t) => V::Table(t.deep_clone()),
+ V::Matrix(m) => V::Matrix(m.deep_clone()),
+ _ => self.clone()
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ use Value as V;
+ match self {
+ V::List(l) => V::List(l.shallow_clone()),
+ V::Table(t) => V::Table(t.shallow_clone()),
+ V::Matrix(m) => V::Matrix(m.shallow_clone()),
+ _ => self.clone()
+ }
+ }
+}
+
+impl ValueClone for Vec<Value> {
+ fn deep_clone(&self) -> Self {
+ let mut vals = Vec::new();
+ for val in self {
+ vals.push(val.deep_clone())
+ }
+ vals
+ }
+
+ fn shallow_clone(&self) -> Self {
+ self.clone()
+ }
+}
+
+impl ValueClone for Matrix {
+ fn deep_clone(&self) -> Self {
+ let values = self.values.deep_clone();
+ Self::new(self.domain, self.codomain, values)
+ }
+
+ fn shallow_clone(&self) -> Self {
+ let values = self.values.shallow_clone();
+ Self::new(self.domain, self.codomain, values)
+ }
+}
diff --git a/matrix-lang/src/value/comp.rs b/matrix-lang/src/value/comp.rs
new file mode 100644
index 0000000..3557927
--- /dev/null
+++ b/matrix-lang/src/value/comp.rs
@@ -0,0 +1,373 @@
+use std::{ops::{Add, Sub, Mul, Div, Shl, Shr, BitOr, BitAnd, BitXor, Neg, Not}, cmp::Ordering};
+use crate::prelude::*;
+
+fn ratio_to_f64(r: Rational64) -> f64 {
+ *r.numer() as f64 / *r.denom() as f64
+}
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(VALUE_EXCEPTION, $($arg)*)
+ };
+}
+
+///
+/// MATH OPERATIONS
+///
+
+fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> {
+ Ok(match (n, d, p) {
+ (0, _, 0) => Err(error!("cannot exponent 0 ** 0"))?,
+ (0, _, _) => (0, 1),
+ (_, _, 0) => (1, 1),
+ (1, 1, _) => (1, 1),
+ (n, d, p) if p < 0 => (d.pow((-p) as u32), n.pow((-p) as u32)),
+ (n, d, p) => (n.pow(p as u32), d.pow(p as u32)),
+ })
+}
+
+fn promote(a: Value, b: Value) -> (Value, Value) {
+ use Value as V;
+ match (&a, &b) {
+ (V::Int(x), V::Ratio(..)) => (V::Ratio((*x).into()), b),
+ (V::Int(x), V::Float(..)) => (V::Float(*x as f64), b),
+ (V::Int(x), V::Complex(..)) => (V::Complex((*x as f64).into()), b),
+ (V::Ratio(x), V::Float(..)) => (V::Float(ratio_to_f64(*x)), b),
+ (V::Ratio(x), V::Complex(..)) => (V::Complex(ratio_to_f64(*x).into()), b),
+ (V::Float(x), V::Complex(..)) => (V::Complex((*x).into()), b),
+ (V::Ratio(..), V::Int(y)) => (a, V::Ratio((*y).into())),
+ (V::Float(..), V::Int(y)) => (a, V::Float(*y as f64)),
+ (V::Complex(..), V::Int(y)) => (a, V::Complex((*y as f64).into())),
+ (V::Float(..), V::Ratio(y)) => (a, V::Float(ratio_to_f64(*y))),
+ (V::Complex(..), V::Ratio(y)) => (a, V::Complex(ratio_to_f64(*y).into())),
+ (V::Complex(..), V::Float(y)) => (a, V::Complex((*y).into())),
+ (V::List(l1), V::List(l2)) if l1.len() > 0 && l2.len() > 0
+ => (V::Matrix(Matrix::from_list(l1.to_vec()).into()), V::Matrix(Matrix::from_list(l2.to_vec()).into())),
+ (_, V::List(l)) if l.len() > 0
+ => (a, V::Matrix(Matrix::from_list(l.to_vec()).into())),
+ (V::List(l), _) if l.len() > 0
+ => (V::Matrix(Matrix::from_list(l.to_vec()).into()), b),
+ _ => (a, b),
+ }
+}
+
+
+impl Add for Value {
+ type Output = Result<Self>;
+ fn add(self, rhs: Self) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x + y)),
+ (Float(x), Float(y)) => Ok(Float(x + y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x + y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x + y)),
+ (Matrix(x), Matrix(y)) => Ok(Matrix((x + y)?.into())),
+ (Matrix(x), r) => Ok(Matrix(x.increment(r)?.into())),
+ (l, Matrix(y)) => Ok(Matrix(y.increment(l)?.into())),
+ (String(str), value) => Ok(String(Rc::from(
+ format!("{str}{value}")
+ ))),
+ (value, String(str)) => Ok(String(Rc::from(
+ format!("{value}{str}")
+ ))),
+ (List(mut l1), List(l2)) => {
+ l1.extend_from_slice(&l2);
+ Ok(List(l1))
+ },
+ (l, r) => Err(error!("cannot add {l:?} + {r:?}"))
+ }
+ }
+}
+
+impl Sub for Value {
+ type Output = Result<Self>;
+ fn sub(self, rhs: Self) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x - y)),
+ (Float(x), Float(y)) => Ok(Float(x - y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x - y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x - y)),
+ (Matrix(x), Matrix(y)) => Ok(Matrix((x - y)?.into())),
+ (Matrix(x), r) => Ok(Matrix(x.decrement(r)?.into())),
+ (l, r) => Err(error!("cannot subtract {l:?} - {r:?}"))
+ }
+ }
+}
+
+impl Mul for Value {
+ type Output = Result<Self>;
+ fn mul(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x * y)),
+ (Float(x), Float(y)) => Ok(Float(x * y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x * y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x * y)),
+ (Matrix(x), Matrix(y)) => Ok(Matrix((x * y)?.into())),
+ (Matrix(x), r) => Ok(Matrix(x.scale(r)?.into())),
+ (l, Matrix(y)) => Ok(Matrix(y.scale(l)?.into())),
+ (l, r) => Err(error!("cannot multiply {l:?} * {r:?}"))
+ }
+ }
+}
+
+impl Div for Value {
+ type Output = Result<Self>;
+ fn div(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(_), Int(0)) => Err(error!("cannot divide by zero")),
+ (Int(x), Int(y)) => Ok(Ratio(Rational64::new(x, y))),
+ (Float(x), Float(y)) => Ok(Float(x / y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x / y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x / y)),
+ (l, r) => Err(error!("cannot divide {l:?} / {r:?}"))
+ }
+ }
+}
+
+impl BitOr for Value {
+ type Output = Result<Self>;
+ fn bitor(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x | y)),
+ (l, r) => Err(error!("cannot bitwise or {l:?} | {r:?}"))
+ }
+ }
+}
+
+impl BitAnd for Value {
+ type Output = Result<Self>;
+ fn bitand(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x & y)),
+ (l, r) => Err(error!("cannot bitwise and {l:?} & {r:?}"))
+ }
+ }
+}
+
+impl BitXor for Value {
+ type Output = Result<Self>;
+ fn bitxor(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x ^ y)),
+ (l, r) => Err(error!("cannot bitwise xor {l:?} ^ {r:?}"))
+ }
+ }
+}
+
+impl Shl for Value {
+ type Output = Result<Self>;
+ fn shl(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x << y)),
+ (l, r) => Err(error!("cannot bitwise shift left {l:?} << {r:?}"))
+ }
+ }
+}
+
+impl Shr for Value {
+ type Output = Result<Self>;
+ fn shr(self, rhs: Value) -> Self::Output {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x >> y)),
+ (l, r) => Err(error!("cannot bitwise shift right {l:?} >> {r:?}"))
+ }
+ }
+}
+
+impl PartialEq for Value {
+ fn eq(&self, other: &Self) -> bool {
+ use Value::*;
+ match (self, other) {
+ (Nil, Nil) => true,
+ (Bool(a), Bool(b)) => a == b,
+ (Int(a), Int(b)) => *a == *b,
+ (Ratio(a), Ratio(b)) => *a == *b,
+ (Float(a), Float(b)) => *a == *b,
+ (Complex(a), Complex(b)) => *a == *b,
+ (Int(a), Ratio(b)) => Rational64::from(*a) == *b,
+ (Ratio(a), Int(b)) => *a == Rational64::from(*b),
+ (Int(a), Float(b)) => *a as f64 == *b,
+ (Float(a), Int(b)) => *a == *b as f64,
+ (Int(a), Complex(b)) => Complex64::from(*a as f64) == *b,
+ (Complex(a), Int(b)) => *a == Complex64::from(*b as f64),
+ (Ratio(a), Float(b)) => ratio_to_f64(*a) == *b,
+ (Float(a), Ratio(b)) => *a == ratio_to_f64(*b),
+ (Ratio(a), Complex(b)) => Complex64::from(ratio_to_f64(*a)) == *b,
+ (Complex(a), Ratio(b)) => *a == Complex64::from(ratio_to_f64(*b)),
+ (Float(a), Complex(b)) => Complex64::from(*a) == *b,
+ (Complex(a), Float(b)) => *a == Complex64::from(*b),
+ (String(a), String(b)) => *a == *b,
+ (List(a), List(b)) => *a == *b,
+ (Matrix(a), Matrix(b)) => a == b,
+ _ => false,
+ }
+ }
+}
+
+impl PartialOrd for Value {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ use Value::*;
+ match (self, other) {
+ (Nil, Nil) => Some(Ordering::Equal),
+ (Bool(a), Bool(b)) => a.partial_cmp(b),
+ (Int(a), Int(b)) => a.partial_cmp(b),
+ (Ratio(a), Ratio(b)) => a.partial_cmp(b),
+ (Float(a), Float(b)) => a.partial_cmp(b),
+ (Int(a), Ratio(b)) => Rational64::from(*a).partial_cmp(b),
+ (Ratio(a), Int(b)) => a.partial_cmp(&Rational64::from(*b)),
+ (Int(a), Float(b)) => (*a as f64).partial_cmp(b),
+ (Float(a), Int(b)) => a.partial_cmp(&(*b as f64)),
+ (Ratio(a), Float(b)) => ratio_to_f64(*a).partial_cmp(b),
+ (Float(a), Ratio(b)) => a.partial_cmp(&ratio_to_f64(*b)),
+ (String(a), String(b)) => a.partial_cmp(b),
+ (List(a), List(b)) => a.partial_cmp(b),
+ (Matrix(a), Matrix(b)) => a.values.partial_cmp(&b.values),
+ _ => None,
+ }
+ }
+}
+
+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::Exception(_) => false,
+ }
+ }
+}
+
+
+impl Value {
+
+ pub fn modulo(self, rhs: Value) -> Result<Self> {
+ use Value::*;
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Int(x % y)),
+ (Float(x), Float(y)) => Ok(Float(x % y)),
+ (Ratio(x), Ratio(y)) => Ok(Ratio(x % y)),
+ (Complex(x), Complex(y)) => Ok(Complex(x % y)),
+ (l, r) => Err(error!("cannot modulo: {l:?} % {r:?}"))
+ }
+ }
+
+ pub fn pow(self, rhs: Value) -> Result<Self> {
+ use Value::*;
+ if let (Ratio(x), Int(y)) = (&self, &rhs) {
+ return Ok(Ratio(ipow(*(*x).numer(), *(*x).denom(), *y)?.into()));
+ }
+ match promote(self, rhs) {
+ (Int(x), Int(y)) => Ok(Ratio(ipow(x, 1, y)?.into())),
+ (Float(x), Float(y)) => Ok(Float(x.powf(y))),
+ (Ratio(x), Ratio(y)) => Ok(Float(ratio_to_f64(x).powf(ratio_to_f64(y)))),
+ (Complex(x), Complex(y)) => Ok(Complex(x.powc(y))),
+ (l, r) => Err(error!("cannot exponent: {l:?} ** {r:?}"))
+ }
+ }
+
+ pub fn floaty(self) -> Self {
+ use Value as V;
+ match self {
+ V::Int(i) => V::Float(i as f64),
+ V::Ratio(r) => V::Float(ratio_to_f64(r)),
+ a => a
+ }
+ }
+
+ 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,
+ }
+ }
+
+ 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 Err(error!("range can only take [Int]'s"))
+ };
+ let Value::Int(rhs) = rhs else {
+ return Err(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),
+ }
+ }
+
+ pub fn to_regex(value: &str) -> Result<Self> {
+ match Regex::new(value) {
+ Ok(r) => Ok(Self::Regex(r.into())),
+ Err(e) => Err(error!("{e}")),
+ }
+ }
+}
diff --git a/matrix-lang/src/value/exception.rs b/matrix-lang/src/value/exception.rs
new file mode 100644
index 0000000..0df6f5c
--- /dev/null
+++ b/matrix-lang/src/value/exception.rs
@@ -0,0 +1,78 @@
+use std::{fmt::{Debug, Display}, error::Error};
+use crate::prelude::*;
+
+#[macro_export]
+macro_rules! exception {
+ ($type:expr) => {
+ $crate::prelude::Exception::new($type)
+ };
+ ($type:expr, $($arg:tt)*) => {
+ $crate::prelude::Exception::msg($type, format!($($arg)*).as_str())
+ };
+}
+
+pub const HASH_EXCEPTION: &'static str = "hash";
+pub const VALUE_EXCEPTION: &'static str = "value";
+pub const PARSE_EXCEPTION: &'static str = "parse";
+pub const COMPILE_EXCEPTION: &'static str = "compile";
+pub const RUNTIME_EXCEPTION: &'static str = "runtime";
+pub const BINARY_EXECPTION: &'static str = "binary";
+pub const IO_EXECPTION: &'static str = "io";
+
+#[derive(Clone)]
+pub struct Exception(Gc<ExceptionInner>);
+
+#[derive(Clone)]
+struct ExceptionInner {
+ ty: Rc<str>,
+ msg: Rc<str>,
+ trace: Vec<(Rc<str>, Position)>
+}
+
+impl Exception {
+ pub fn msg(ty: &str, msg: &str) -> Self {
+ Self(Gc::new(ExceptionInner { ty: ty.into(), msg: msg.into(), trace: Vec::new() }))
+ }
+
+ pub fn pos(mut self, pos: Position) -> Self {
+ self.0.trace.push((
+ Rc::from("<root>"),
+ pos
+ ));
+ self
+ }
+
+ pub fn trace(mut self, block: Rc<str>, pos: Position) -> Self {
+ self.0.trace.push((
+ block,
+ pos
+ ));
+ self
+ }
+}
+
+impl Display for Exception {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let ty = self.0.ty.as_ref();
+ let msg = self.0.msg.as_ref();
+ write!(f, "{}\n Type <{}>", msg, ty)?;
+ for (block, pos) in self.0.trace.iter() {
+ write!(f, "\n In {block} at {pos}\n")?;
+ }
+ Ok(())
+ }
+}
+
+impl Debug for Exception {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[Exception {}]", self.0.ty.as_ref())
+ }
+}
+
+impl Error for Exception {}
+
+impl<T> From<Exception> for Result<T> {
+ fn from(value: Exception) -> Self {
+ Err(value)
+ }
+}
diff --git a/matrix-lang/src/value/fmt.rs b/matrix-lang/src/value/fmt.rs
new file mode 100644
index 0000000..f276bf1
--- /dev/null
+++ b/matrix-lang/src/value/fmt.rs
@@ -0,0 +1,186 @@
+use std::fmt::{Debug, Display};
+use crate::prelude::*;
+
+use Value as V;
+
+impl Debug for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ V::Nil => write!(f, "[Nil]"),
+ V::Int(i) => write!(f, "[Int {i}]"),
+ V::Bool(b) => write!(f, "[Bool {b}]"),
+ 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.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::Exception(_) => write!(f, "[Error]"),
+ V::File(_) => write!(f, "[File]"),
+ }
+ }
+}
+
+impl Display for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ 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) => {
+ if l.len() < 1 {
+ write!(f, "[]")?;
+ return Ok(())
+ }
+ 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) => {
+ if f.alternate() {
+ write!(f, "{t:#}")?;
+ } else {
+ write!(f, "{t}")?;
+ }
+ },
+ V::Function(fun) => {
+ write!(f, "{cyan}{fun}{clear}")?;
+ }
+ 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::Exception(e) => {write!(f, "{red}{e}{clear}")?;},
+ };
+ Ok(())
+ }
+}
+
+impl Debug for Matrix {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[Matrix {}x{}]", self.domain, self.codomain)
+ }
+}
+
+impl Display for Matrix {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let mut max_cols = vec![0; self.domain];
+ let mut vals: Vec<String> = Vec::with_capacity(self.domain * self.codomain);
+ for row in 0..self.codomain {
+ for col in 0..self.domain {
+ let idx = col + row * self.domain;
+ let el = &self.values[idx];
+ let s = match f.alternate() {
+ true => format!("{:#}", el),
+ false => format!("{}", el)
+ };
+ max_cols[col] = max_cols[col].max(s.len());
+ vals.push(s);
+ }
+ }
+
+ write!(f, "\n")?;
+ for row in 0..self.codomain {
+ for col in 0..self.domain {
+ let idx = col + row * self.domain;
+ let s = vals[idx].as_str();
+ let width = max_cols[col];
+ write!(f, " {s:>width$}")?;
+ }
+ write!(f, "\n")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl Debug for ValueMap {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[Table {}]", self.len())
+ }
+}
+
+impl Display for ValueMap {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if self.len() < 1 {
+ write!(f, "{{}}")?;
+ return Ok(())
+ }
+ write!(f, "{{ ")?;
+ for (i, (key, value)) in self.entries().enumerate() {
+ if i != 0 {
+ write!(f, ", ")?;
+ }
+ if f.alternate() {
+ write!(f, "{key:#} = {value:#}")?
+ } else {
+ write!(f, "{key} = {value}")?
+ }
+ }
+ write!(f, " }}")?;
+ Ok(())
+ }
+}
diff --git a/matrix-lang/src/value/function.rs b/matrix-lang/src/value/function.rs
new file mode 100644
index 0000000..38d8b0b
--- /dev/null
+++ b/matrix-lang/src/value/function.rs
@@ -0,0 +1,43 @@
+use crate::prelude::*;
+use std::fmt::{Debug, Display};
+
+pub struct Function {
+ pub name: Rc<str>,
+ pub arity: usize,
+ pub variadic: bool,
+ pub fun: InnerFunction
+}
+
+#[derive(Clone)]
+pub enum InnerFunction {
+ Compiled(Rc<Chunk>),
+ Native(Rc<dyn Fn((&mut Vm, &mut StackFrame), Vec<Value>) -> Result<Value>>),
+}
+
+impl Debug for Function {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use InnerFunction as F;
+ match self.fun {
+ F::Compiled(_) => {
+ write!(f, "[Function {}]", self.name)
+ },
+ F::Native(_) => {
+ write!(f, "[Builtin {}]", self.name)
+ }
+ }
+ }
+}
+
+impl Display for Function {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use InnerFunction as F;
+ match self.fun {
+ F::Compiled(_) => {
+ write!(f, "[Function {}]", self.name)
+ },
+ F::Native(_) => {
+ write!(f, "[Builtin {}]", self.name)
+ }
+ }
+ }
+}
diff --git a/matrix-lang/src/value/gc.rs b/matrix-lang/src/value/gc.rs
new file mode 100644
index 0000000..5ef8b80
--- /dev/null
+++ b/matrix-lang/src/value/gc.rs
@@ -0,0 +1,186 @@
+use std::{ops::{Index, IndexMut, Deref, DerefMut, Add, Sub, Mul}, marker::PhantomData, ptr::NonNull, fmt::{Debug, Display}};
+use crate::prelude::*;
+
+pub struct Gc<T> {
+ ptr: NonNull<GcInner<T>>,
+ phantom: PhantomData<GcInner<T>>
+}
+
+struct GcInner<T> {
+ rc: usize,
+ data: T
+}
+
+impl<T> Gc<T> {
+ pub fn new(data: T) -> Self {
+ let boxed = Box::new(GcInner {
+ rc: 1,
+ data,
+ });
+ Self {
+ ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
+ phantom: PhantomData
+ }
+ }
+}
+
+impl <T: Clone> Gc<T> {
+ pub fn into_inner(self) -> T {
+ unsafe {
+ self.ptr.as_ref().data.clone()
+ }
+ }
+
+ fn data(&self) -> T {
+ unsafe {
+ self.ptr.as_ref().data.clone()
+ }
+ }
+}
+
+impl <T: ValueClone> ValueClone for Gc<T> {
+ fn deep_clone(&self) -> Self {
+ unsafe {
+ let data = self.ptr.as_ref().data.deep_clone();
+ Self::new(data)
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ unsafe {
+ let data = self.ptr.as_ref().data.shallow_clone();
+ Self::new(data)
+ }
+ }
+}
+
+impl<T> From<T> for Gc<T> {
+ fn from(value: T) -> Self {
+ Gc::new(value)
+ }
+}
+
+impl<T: IndexMut<Idx>, Idx> IndexMut<Idx> for Gc<T> {
+ fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
+ self.deref_mut().index_mut(index)
+ }
+}
+
+impl<T: Index<Idx>, Idx> Index<Idx> for Gc<T> {
+ type Output = T::Output;
+
+ fn index(&self, index: Idx) -> &Self::Output {
+ self.deref().index(index)
+ }
+}
+
+impl<T> DerefMut for Gc<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ unsafe {
+ &mut self.ptr.as_mut().data
+ }
+ }
+}
+
+impl<T> Deref for Gc<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ unsafe {
+ &self.ptr.as_ref().data
+ }
+ }
+}
+
+impl <T: PartialEq> PartialEq for Gc<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.deref().eq(other.deref())
+ }
+}
+
+impl <T: Iterator> Iterator for Gc<T> {
+ type Item = T::Item;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.deref_mut().next()
+ }
+}
+
+impl<T: Eq> Eq for Gc<T> {}
+
+impl<T> Clone for Gc<T> {
+ fn clone(&self) -> Self {
+ unsafe {
+ let inner = self.ptr.as_ptr().as_mut().unwrap();
+ inner.rc += 1;
+
+ Self {
+ ptr: self.ptr,
+ phantom: PhantomData
+ }
+ }
+ }
+}
+
+impl<T> Drop for Gc<T> {
+ fn drop(&mut self) {
+ unsafe {
+ let inner = self.ptr.as_mut();
+ if inner.rc > 1 {
+ inner.rc -= 1;
+ } else {
+ let _ = Box::from_raw(self.ptr.as_ptr());
+ }
+ }
+ }
+}
+
+impl<T: Debug> Debug for Gc<T> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if f.alternate() {
+ write!(f, "{:#?}", self.deref())
+ } else {
+ write!(f, "{:?}", self.deref())
+ }
+ }
+}
+
+impl<T: Display> Display for Gc<T> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if f.alternate() {
+ write!(f, "{:#}", self.deref())
+ } else {
+ write!(f, "{}", self.deref())
+ }
+ }
+}
+
+impl <T: Add + Clone> Add for Gc<T> {
+ type Output = T::Output;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ let a = self.data();
+ let b = rhs.data();
+ a + b
+ }
+}
+
+impl <T: Sub + Clone> Sub for Gc<T> {
+ type Output = T::Output;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ let a = self.data();
+ let b = rhs.data();
+ a - b
+ }
+}
+
+impl <T: Mul + Clone> Mul for Gc<T> {
+ type Output = T::Output;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ let a = self.data();
+ let b = rhs.data();
+ a * b
+ }
+}
diff --git a/matrix-lang/src/value/hash.rs b/matrix-lang/src/value/hash.rs
new file mode 100644
index 0000000..35c1343
--- /dev/null
+++ b/matrix-lang/src/value/hash.rs
@@ -0,0 +1,240 @@
+use crate::prelude::*;
+use std::hash::{Hash, DefaultHasher, Hasher};
+
+#[derive(Clone)]
+pub struct ValueMap {
+ values: Vec<ValueEntry>,
+ size: usize,
+ used: usize,
+}
+
+#[derive(Clone)]
+enum ValueEntry {
+ Empty,
+ Taken((Value, Value)),
+ Gravestone(Value),
+}
+
+impl Default for ValueMap {
+ fn default() -> Self {
+ ValueMap {
+ values: vec![ValueEntry::Empty; 8],
+ size: 8,
+ used: 0,
+ }
+ }
+}
+
+impl ValueMap {
+
+ fn get_index(values: &Vec<ValueEntry>, size: usize, key: &Value, hash: usize) -> usize {
+ let mut nearest_grave = None;
+ let start = hash & size;
+ for offset in 0..size {
+ let idx = (start + offset) % size;
+ match &values[idx] {
+ ValueEntry::Empty => return idx,
+ ValueEntry::Taken((marker, _)) => {
+ if marker.eq(key) { return idx };
+ continue;
+ },
+ ValueEntry::Gravestone(grave) => {
+ if grave.eq(key) { return idx };
+ if nearest_grave.is_none() {
+ nearest_grave = Some(idx);
+ }
+ continue;
+ },
+ }
+ }
+
+ match nearest_grave {
+ Some(idx) => idx,
+ None => panic!("cannot get value map index: full!!!"),
+ }
+ }
+
+ fn expand(&mut self) -> Result<()> {
+ let pairs = self.values.iter()
+ .filter_map(|e| {
+ match e {
+ ValueEntry::Taken(s) => Some(s.clone()),
+ _ => None
+ }
+ })
+ .collect::<Vec<(Value, Value)>>();
+
+ let new_used = pairs.len();
+ let new_size = self.size * 2 + pairs.len();
+ let mut new_values = vec![ValueEntry::Empty; new_size];
+
+ for (key, value) in pairs.into_iter() {
+ let hash = self.hash(&key)?;
+ let idx = ValueMap::get_index(&new_values, new_size, &key, hash);
+ new_values[idx] = ValueEntry::Taken((key, value));
+ }
+
+ self.used = new_used;
+ self.size = new_size;
+ self.values = new_values;
+
+ Ok(())
+ }
+
+ fn hash(&self, key: &Value) -> Result<usize> {
+ let mut hasher = DefaultHasher::new();
+ key.try_hash(&mut hasher)?;
+ Ok(hasher.finish() as usize)
+ }
+
+ pub fn get<'a>(&'a self, key: &Value) -> Result<Option<&'a Value>> {
+ let hash = self.hash(key)?;
+ let idx = ValueMap::get_index(&self.values, self.size, key, hash);
+ match &self.values[idx] {
+ ValueEntry::Taken((_, value)) => Ok(Some(value)),
+ _ => Ok(None)
+ }
+ }
+
+ pub fn insert(&mut self, key: Value, value: Value) -> Result<()> {
+ if self.used * 3 >= self.size * 2 {
+ self.expand()?;
+ }
+ let key = key.deep_clone();
+ let hash = self.hash(&key)?;
+ let idx = ValueMap::get_index(&self.values, self.size, &key, hash);
+ self.values[idx] = ValueEntry::Taken((key, value));
+ self.used += 1;
+ Ok(())
+ }
+
+ pub fn remove(&mut self, key: &Value) -> Result<Option<Value>> {
+ let hash = self.hash(key)?;
+ let idx = ValueMap::get_index(&self.values, self.size, key, hash);
+ let mut value = ValueEntry::Gravestone(key.clone());
+ std::mem::swap(&mut value, &mut self.values[idx]);
+ match value {
+ ValueEntry::Taken((_, v)) => {
+ self.used -= 1;
+ Ok(Some(v))
+ }
+ _ => Ok(None),
+ }
+ }
+
+ pub fn entries<'a>(&'a self) -> ValueMapIterator<'a> {
+ ValueMapIterator::new(self)
+ }
+
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn len(&self) -> usize {
+ self.used
+ }
+}
+
+pub struct ValueMapIterator<'a> {
+ map: &'a ValueMap,
+ index: usize
+}
+
+impl<'a> ValueMapIterator<'a> {
+ fn new(map: &'a ValueMap) -> Self {
+ Self { map, index: 0 }
+ }
+}
+
+impl<'a> Iterator for ValueMapIterator<'a> {
+ type Item = (&'a Value, &'a Value);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let mut idx = self.index;
+ loop {
+ if idx >= self.map.size {
+ return None
+ }
+ use ValueEntry as E;
+ let E::Taken((k, v)) = &self.map.values[idx] else {
+ idx += 1;
+ continue;
+ };
+
+ self.index = idx + 1;
+ return Some((k, v))
+ }
+ }
+}
+
+pub trait TryHash {
+ fn try_hash<H: std::hash::Hasher>(&self, state: &mut H) -> Result<()>;
+}
+
+impl TryHash for Value {
+ fn try_hash<H: std::hash::Hasher>(&self, state: &mut H) -> Result<()> {
+ use Value::*;
+ match self {
+ Nil => 0x23845.hash(state),
+ Bool(b) => b.hash(state),
+ Int(i) => i.hash(state),
+ Ratio(r) => r.hash(state),
+ Regex(r) => r.as_str().hash(state),
+ String(s) => s.hash(state),
+ List(l) => {
+ for val in l.iter() {
+ val.try_hash(state)?;
+ }
+ }
+ Matrix(m) => {
+ m.domain.hash(state);
+ m.codomain.hash(state);
+ for val in m.values.iter() {
+ val.try_hash(state)?;
+ }
+ },
+ _ => return Err(exception!(HASH_EXCEPTION, "cannot hash {self:?}"))
+ };
+ Ok(())
+ }
+}
+
+impl ValueClone for ValueEntry {
+ fn deep_clone(&self) -> Self {
+ use ValueEntry as E;
+ match self {
+ E::Empty => E::Empty,
+ E::Taken((k, v)) => E::Taken((k.deep_clone(), v.deep_clone())),
+ E::Gravestone(g) => E::Gravestone(g.deep_clone()),
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ use ValueEntry as E;
+ match self {
+ E::Empty => E::Empty,
+ E::Taken((k, v)) => E::Taken((k.clone(), v.clone())),
+ E::Gravestone(g) => E::Gravestone(g.clone()),
+ }
+ }
+}
+
+impl ValueClone for ValueMap {
+ fn deep_clone(&self) -> Self {
+ let values = self.values.iter().map(|e| e.deep_clone()).collect();
+ Self {
+ values,
+ size: self.size,
+ used: self.used
+ }
+ }
+
+ fn shallow_clone(&self) -> Self {
+ let values = self.values.iter().map(|e| e.clone()).collect();
+ Self {
+ values,
+ size: self.size,
+ used: self.used
+ }
+ }
+}
diff --git a/matrix-lang/src/value/index.rs b/matrix-lang/src/value/index.rs
new file mode 100644
index 0000000..a5725e8
--- /dev/null
+++ b/matrix-lang/src/value/index.rs
@@ -0,0 +1,230 @@
+use std::cmp::Ordering;
+
+use crate::prelude::*;
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ Err(exception!(VALUE_EXCEPTION, $($arg)*))
+ };
+}
+
+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.shallow_clone()))
+ },
+ (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.shallow_clone())
+ } 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:?}")
+ }
+ }
+
+}
+
+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")
+ })
+ }
+}
+
diff --git a/matrix-lang/src/value/matrix.rs b/matrix-lang/src/value/matrix.rs
new file mode 100644
index 0000000..91e3ec2
--- /dev/null
+++ b/matrix-lang/src/value/matrix.rs
@@ -0,0 +1,337 @@
+use std::ops::{Add, Sub, Mul};
+
+use crate::prelude::*;
+
+#[derive(Clone)]
+pub struct Matrix {
+ pub domain: usize,
+ pub codomain: usize,
+ pub values: Vec<Value>
+}
+
+macro_rules! error {
+ ($($arg:tt)*) => {
+ exception!(VALUE_EXCEPTION, $($arg)*)
+ };
+}
+
+impl Matrix {
+ pub fn new(
+ domain: usize,
+ codomain: usize,
+ values: Vec<Value>
+ ) -> Self {
+ Self {
+ domain,
+ codomain,
+ values
+ }
+ }
+
+ pub fn from_list(
+ values: Vec<Value>
+ ) -> Self {
+ Self {
+ domain: values.len(),
+ codomain: 1,
+ values
+ }
+ }
+
+ pub fn empty(
+ domain: usize,
+ codomain: usize
+ ) -> Self {
+ let values = (0..(domain * codomain)).into_iter()
+ .map(|_| Value::Int(0))
+ .collect();
+ Self {
+ domain,
+ codomain,
+ values
+ }
+ }
+
+ pub fn get(&self, row: usize, col: usize) -> Result<Value> {
+ if row >= self.codomain || col >= self.domain {
+ return Err(error!("[{};{}] out of bounds for [Matrix {}x{}]", row, col, self.domain, self.codomain))
+ }
+ let idx = col + row * self.domain;
+ Ok(self.values[idx].clone())
+ }
+
+
+
+ pub fn set(&mut self, row: usize, col: usize, val: Value) -> Result<()> {
+ if row >= self.codomain || col >= self.domain {
+ return Err(error!("[{};{}] out of bounds for [Matrix {}x{}]", row, col, self.domain, self.codomain))
+ }
+ let idx = col + row * self.domain;
+ self.values[idx] = val;
+ Ok(())
+ }
+
+ pub fn rows<'a>(&'a self) -> MatrixRows<'a> {
+ MatrixRows {
+ matrix: self,
+ row: 0
+ }
+ }
+
+ pub fn cols<'a>(&'a self) -> MatrixCols<'a> {
+ MatrixCols {
+ matrix: self,
+ col: 0
+ }
+ }
+
+ // SPLCIE DOMAIN
+ pub fn splice_cols(&self, col_start: usize, col_end: usize) -> Result<Self> {
+ if col_start <= col_end || col_end > self.domain {
+ return Err(error!("[_;{}..{}] invalid for [Matrix {}x{}]", col_start, col_end, self.domain, self.codomain))
+ }
+
+ let mut cols = Vec::new();
+
+ for (i, col) in self.cols().enumerate() {
+ if i >= col_start && i < col_end {
+ cols.push(col);
+ }
+ }
+
+ let domain = cols.len();
+ let codomain = cols[0].len();
+ let mut res = Self::empty(domain, codomain);
+
+ for i in 0..domain {
+ for j in 0..codomain {
+ res.set(j, i, cols[i][j].clone())?;
+ }
+ }
+
+ Ok(res)
+ }
+
+ // SPLICE CODOMAIN
+ pub fn splice_rows(&self, row_start: usize, row_end: usize) -> Result<Self> {
+ if row_start <= row_end || row_end > self.codomain {
+ return Err(error!("[{}..{};_] invalid for [Matrix {}x{}]", row_start, row_end, self.domain, self.codomain))
+ }
+
+ let mut rows = Vec::new();
+
+ for (i, row) in self.rows().enumerate() {
+ if i >= row_start && i < row_end {
+ rows.push(row);
+ }
+ }
+
+ let domain = rows[0].len();
+ let codomain = rows.len();
+ let mut res = Self::empty(domain, codomain);
+
+ for i in 0..domain {
+ for j in 0..codomain {
+ res.set(j, i, rows[j][i].clone())?;
+ }
+ }
+
+ Ok(res)
+ }
+
+ pub fn increment(&self, increment: Value) -> Result<Self> {
+ let values = self.values.iter()
+ .map(|v| v.clone() + increment.clone())
+ .collect::<Result<Vec<Value>>>()?;
+ Ok(Matrix::new(self.domain, self.codomain, values))
+ }
+
+ pub fn decrement(&self, decrement: Value) -> Result<Self> {
+ let values = self.values.iter()
+ .map(|v| v.clone() - decrement.clone())
+ .collect::<Result<Vec<Value>>>()?;
+ Ok(Matrix::new(self.domain, self.codomain, values))
+ }
+
+ pub fn scale(&self, scale: Value) -> Result<Self> {
+ let values = self.values.iter()
+ .map(|v| v.clone() * scale.clone())
+ .collect::<Result<Vec<Value>>>()?;
+ Ok(Matrix::new(self.domain, self.codomain, values))
+ }
+
+ pub fn join_right(&self, other: &Matrix) -> Result<Self> {
+ if self.codomain != other.codomain {
+ return Err(error!("matrix codomain's do not match"))
+ }
+ let mut r1 = self.rows();
+ let mut r2 = other.rows();
+ let mut rows = Vec::new();
+ loop {
+ let Some(r1) = r1.next() else { break; };
+ let Some(r2) = r2.next() else { break; };
+
+ let mut row = r1
+ .into_iter()
+ .map(|v| v.clone())
+ .collect::<Vec<Value>>();
+
+ row.extend(r2.into_iter().map(|v| v.clone()));
+
+ rows.push(row);
+ }
+
+ let values = rows
+ .into_iter()
+ .reduce(|mut a,b| {a.extend(b); a})
+ .unwrap();
+
+ Ok(Matrix::new(self.domain + other.domain, self.codomain, values))
+ }
+
+ pub fn join_bottom(&self, other: &Matrix) -> Result<Self> {
+ if self.domain != other.domain {
+ return Err(error!("matrix domain's do not match"))
+ }
+ let mut values = self.values.clone();
+ values.extend(other.values.clone());
+ Ok(Matrix::new(self.domain, self.codomain + other.codomain, values))
+ }
+}
+
+impl PartialEq for Matrix {
+ fn eq(&self, other: &Self) -> bool {
+ if self.domain != other.domain || self.codomain != other.codomain {
+ return false
+ }
+
+ for i in 0..self.values.len() {
+ if self.values[i] != other.values[i] {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
+impl Add for Matrix {
+ type Output = Result<Self>;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ if self.domain != rhs.domain || self.codomain != rhs.codomain {
+ return Err(error!("cannot add {self:?} + {rhs:?}"))
+ }
+ let mut res = Matrix::empty(self.domain, self.codomain);
+ for col in 0..self.domain {
+ for row in 0..self.codomain {
+ let add = self.get(row, col)? + rhs.get(row, col)?;
+ res.set(row, col, add?)?;
+ }
+ }
+ Ok(res)
+ }
+}
+
+impl Sub for Matrix {
+ type Output = Result<Self>;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ if self.domain != rhs.domain || self.codomain != rhs.codomain {
+ return Err(error!("cannot subtract {self:?} - {rhs:?}"))
+ }
+ let mut res = Matrix::empty(self.domain, self.codomain);
+ for col in 0..self.domain {
+ for row in 0..self.codomain {
+ let sub = self.get(row, col)? - rhs.get(row, col)?;
+ res.set(row, col, sub?)?;
+ }
+ }
+ Ok(res)
+ }
+}
+
+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)
+}
+
+impl Mul for Matrix {
+ type Output = Result<Self>;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ if self.domain != rhs.codomain {
+ return Err(error!("cannot multiply {self:?} * {rhs:?}"))
+ }
+ let mut res = Self::empty(rhs.domain, self.codomain);
+ for (i, row) in self.rows().enumerate() {
+ for (j, col) in rhs.cols().enumerate() {
+ let dot = dot(row.clone(), col.clone())?;
+ res.set(i, j, dot)?;
+ }
+ }
+ Ok(res)
+ }
+}
+
+pub struct MatrixRows<'a> {
+ matrix: &'a Matrix,
+ row: usize
+}
+
+impl<'a> Iterator for MatrixRows<'a> {
+ type Item = Vec<&'a Value>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.row >= self.matrix.codomain {
+ return None
+ }
+
+ let row_start = self.row * self.matrix.domain;
+ let row_end = row_start + self.matrix.domain;
+
+ let res = self.matrix.values
+ .iter()
+ .enumerate()
+ .filter(|(idx, _)| *idx >= row_start && *idx < row_end)
+ .map(|v| v.1)
+ .collect();
+
+ self.row += 1;
+
+ Some(res)
+ }
+}
+
+pub struct MatrixCols<'a> {
+ matrix: &'a Matrix,
+ col: usize
+}
+
+impl<'a> Iterator for MatrixCols<'a> {
+ type Item = Vec<&'a Value>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.col >= self.matrix.domain {
+ return None
+ }
+
+ let res = self.matrix.values
+ .iter()
+ .enumerate()
+ .filter(|(idx, _)| *idx % self.matrix.domain == self.col)
+ .map(|v| v.1)
+ .collect();
+
+ self.col += 1;
+
+ Some(res)
+ }
+}
diff --git a/matrix-lang/src/value/mod.rs b/matrix-lang/src/value/mod.rs
new file mode 100644
index 0000000..9094bb6
--- /dev/null
+++ b/matrix-lang/src/value/mod.rs
@@ -0,0 +1,42 @@
+pub mod comp;
+pub mod gc;
+pub mod matrix;
+pub mod hash;
+pub mod exception;
+pub mod function;
+pub mod fmt;
+pub mod index;
+pub mod clone;
+
+use crate::prelude::*;
+
+#[derive(Clone)]
+pub enum Value {
+ Nil,
+
+ Bool(bool),
+ Int(i64),
+ Float(f64),
+ Ratio(Rational64),
+ Complex(Complex64),
+
+ Regex(Rc<Regex>),
+ String(Rc<str>),
+
+ List(Gc<Vec<Value>>),
+ Matrix(Gc<Matrix>),
+ Table(Gc<ValueMap>),
+
+ Function(Rc<Function>),
+ Range(Rc<(i64, i64, bool)>),
+ Iter(Rc<Function>),
+ File(Rc<RefCell<File>>),
+
+ Exception(Exception),
+}
+
+impl From<&str> for Value {
+ fn from(value: &str) -> Self {
+ Value::String(Rc::from(value))
+ }
+}
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)
+}