diff options
author | Freya Murphy <freya@freyacat.org> | 2024-02-29 17:04:28 -0500 |
---|---|---|
committer | Freya Murphy <freya@freyacat.org> | 2024-02-29 17:04:28 -0500 |
commit | 5d2747e26f51cc2344a6bd95f93457248fdfebd8 (patch) | |
tree | 8755b4068166c3854d26817683ce438a771ab319 /matrix-lang | |
parent | more mat, sys, and os stdlib functions, better matrix printing, other fixes (diff) | |
download | matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.gz matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.tar.bz2 matrix-5d2747e26f51cc2344a6bd95f93457248fdfebd8.zip |
fin prob
Diffstat (limited to '')
25 files changed, 3252 insertions, 372 deletions
diff --git a/matrix/Cargo.lock b/matrix-lang/Cargo.lock index ed6e714..ed6e714 100644 --- a/matrix/Cargo.lock +++ b/matrix-lang/Cargo.lock diff --git a/matrix/Cargo.toml b/matrix-lang/Cargo.toml index 64e9210..067f77c 100644 --- a/matrix/Cargo.toml +++ b/matrix-lang/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "matrix" +name = "matrix-lang" version = "0.1.0" edition = "2021" diff --git a/matrix/src/ast.rs b/matrix-lang/src/ast.rs index de63630..5720f76 100644 --- a/matrix/src/ast.rs +++ b/matrix-lang/src/ast.rs @@ -1,42 +1,70 @@ -use std::{rc::Rc, ops::{Neg, Not}, fmt::Debug}; -use crate::{lex::{Position, TokenData}, value::{Value, InlineList, InlineMatrix, InlineTable}, Result}; +use std::{ops::{Neg, Not}, fmt::{Debug, Display}}; + +use crate::prelude::*; + +pub type AstName = (Rc<str>, Position); +pub type InlineList = Vec<Expr>; +pub type InlineMatrix = (usize, usize, Vec<Expr>); +pub type InlineTable = Vec<(Expr, Expr)>; #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum UnaryOp { // normal math - Negate, + Negate = 1, // equality - Not, + Not = 2, +} + +impl TryFrom<u8> for UnaryOp { + type Error = Exception; + + fn try_from(value: u8) -> std::prelude::v1::Result<Self, Self::Error> { + if value < 1 || value > 2 { + Err(exception!(BINARY_EXCEPTION, "cannot convert {value} to UnaryOp")) + } else { + unsafe { Ok(std::mem::transmute(value)) } + } + } } #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum BinaryOp { // normal math - Add, - Subtract, - Multiply, - Divide, - Modulo, - Power, + Add = 1, + Subtract = 2, + Multiply = 3, + Divide = 4, + Modulo = 5, + Power = 6, // binary math - BitwiseAnd, - BitwiseOr, - BitwiseXor, - BitwiseShiftLeft, - BitwiseShiftRight, + BitwiseAnd = 7, + BitwiseOr = 8, + BitwiseXor = 9, + BitwiseShiftLeft = 10, + BitwiseShiftRight = 11, // equality - Equals, - NotEquals, - GreaterEquals, - LessEquals, - GreaterThan, - LessThan, + Equals = 12, + NotEquals = 13, + GreaterEquals = 14, + LessEquals = 15, + GreaterThan = 16, + LessThan = 17, // iter - Range, - RangeEq + Range = 18, + RangeEq = 19 } -pub type AstName = (Rc<str>, Position); +impl TryFrom<u8> for BinaryOp { + type Error = Exception; + + fn try_from(value: u8) -> std::prelude::v1::Result<Self, Self::Error> { + if value < 1 || value > 19 { + Err(exception!(BINARY_EXCEPTION, "cannot convert {value} to BinaryOp")) + } else { + unsafe { Ok(std::mem::transmute(value)) } + } + } +} #[derive(Debug, Clone, PartialEq)] pub enum ExprData { @@ -75,6 +103,7 @@ pub enum ExprData { Try(Box<Expr>, AstName, Box<Expr>), Let(AstName, Box<Expr>), + Const(AstName, Box<Expr>), Pipeline(Box<Expr>, Box<Expr>), @@ -83,22 +112,24 @@ pub enum ExprData { Return(Box<Expr>), } -#[derive(Clone, PartialEq)] -pub struct Expr { - pub data: ExprData, - pub pos: Position +impl Display for Expr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } } impl Debug for Expr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if f.alternate() { - write!(f, "{:#?}", self.data) - } else { - write!(f, "{:?}", self.data) - } + write!(f, "{:?}", self.data) } } +#[derive(Clone, PartialEq)] +pub struct Expr { + pub data: ExprData, + pub pos: Position +} + impl From<(ExprData, Position)> for Expr { fn from(value: (ExprData, Position)) -> Self { Self { data: value.0, pos: value.1 } @@ -377,6 +408,9 @@ pub fn optimize(mut expr: Expr) -> Result<Expr> { E::Let(ident, expr) => { E::Let(ident, Box::new(optimize(*expr)?)) }, + E::Const(ident, expr) => { + E::Const(ident, Box::new(optimize(*expr)?)) + }, E::Assign(lhs, rhs) => { let lhs = Box::new(optimize(*lhs)?); let rhs = Box::new(optimize(*rhs)?); diff --git a/matrix-lang/src/binary/deserialize.rs b/matrix-lang/src/binary/deserialize.rs new file mode 100644 index 0000000..679f6e5 --- /dev/null +++ b/matrix-lang/src/binary/deserialize.rs @@ -0,0 +1,160 @@ +use crate::prelude::*; + +use super::{prim::VarInt, Deserialize, Deserializer}; + +macro_rules! error { + ($($arg:tt)*) => { + exception!(BINARY_EXCEPTION, $($arg)*) + }; +} + +impl Deserialize for Program { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + for _ in 0..5 { s.read::<u8>()?; } // skip header + let version: u8 = s.read()?; + if version != 0 { + return Err(error!("invalid program version {version}")) + } + let fun = <Rc<Function>>::deserialize(s)?; + Ok(Self { version, fun }) + } +} + +impl Deserialize for Instruction { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + use Instruction as I; + let ins: u8 = s.read()?; + let ins = match ins { + 0 => I::NoOp, + 1 => I::CreateLocal, + 2 => I::LoadLocal(s.read()?), + 3 => I::StoreLocal(s.read()?), + 4 => I::DiscardLocals(s.read()?), + 5 => I::LoadGlobal(s.read()?), + 6 => I::StoreGlobal(s.read()?), + 7 => I::Const(s.read()?), + 8 => I::Int(s.read()?), + 9 => I::True, + 10 => I::False, + 11 => I::Nil, + 12 => I::Dup, + 13 => I::Discard(s.read()?), + 14 => I::UnaryOp(UnaryOp::try_from(s.read::<u8>()?)?), + 15 => I::BinaryOp(BinaryOp::try_from(s.read::<u8>()?)?), + 16 => I::NewList(s.read()?), + 17 => I::NewTable(s.read()?), + 18 => I::NewMatrix(s.read()?, s.read()?), + 19 => I::Field(s.read()?), + 20 => I::StoreField(s.read()?), + 21 => I::Index(s.read()?), + 22 => I::StoreIndex(s.read()?), + 23 => I::Jump(s.read()?), + 24 => I::JumpTrue(s.read()?), + 25 => I::JumpFalse(s.read()?), + 26 => I::JumpNil(s.read()?), + 27 => I::IterCreate, + 28 => I::IterNext, + 29 => I::Try(s.read()?), + 30 => I::TryEnd, + 31 => I::Call(s.read()?), + 32 => I::Return, + n => return Err(error!("invalid instruction op code {n}")) + }; + Ok(ins) + } +} + +impl<T: Deserialize> Deserialize for Vec<T> { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + let len = s.read::<VarInt>()?.0; + let mut vec = Vec::with_capacity(len); + for _ in 0..len { + let v = T::deserialize(s)?; + vec.push(v); + } + Ok(vec) + } +} + +impl<T: Deserialize> Deserialize for Gc<T> { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + Ok(Gc::new(T::deserialize(s)?)) + } +} + +impl<T: Deserialize> Deserialize for Rc<T> { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + Ok(Rc::new(T::deserialize(s)?)) + } +} + +impl Deserialize for Position { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + let row = s.read::<VarInt>()?.0; + let col = s.read::<VarInt>()?.0; + Ok(Self { row, col }) + } +} + +impl Deserialize for Chunk { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + let constants = <Vec<Value>>::deserialize(s)?; + let code = <Vec<Instruction>>::deserialize(s)?; + let pos = <Vec<Position>>::deserialize(s)?; + Ok(Self { constants, code, pos }) + } +} + +impl Deserialize for Value { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + use Value as V; + let ty = s.read::<u8>()?; + let value = match ty { + 0 => V::Nil, + 1 => V::Bool(s.read()?), + 2 => V::Int(s.read()?), + 3 => V::Float(s.read()?), + 4 => V::Ratio(Rational64::new(s.read()?, s.read()?)), + 5 => V::Complex(Complex64::new(s.read()?, s.read()?)), + 6 => V::to_regex(s.read::<String>()?.as_str())?, + 7 => V::String(s.read::<String>()?.into()), + 8 => V::List(<Vec<Value>>::deserialize(s)?.into()), + 9 => { + let domain = s.read()?; + let codomain = s.read()?; + let values = <Vec<Value>>::deserialize(s)?; + V::Matrix(Matrix::new(domain, codomain, values).into()) + }, + 10 => { + let len = s.read::<VarInt>()?.0; + let mut table = ValueMap::new(); + for _ in 0..len { + let key = <Value>::deserialize(s)?; + let value = <Value>::deserialize(s)?; + table.insert(key, value)?; + } + V::Table(table.into()) + }, + 11 => V::Function(<Rc<Function>>::deserialize(s)?), + 12 => V::Range((s.read()?, s.read()?, s.read()?).into()), + 13 => V::Iter(<Rc<Function>>::deserialize(s)?), + n => return Err(error!("invalid value code {n}")) + }; + Ok(value) + } +} + +impl Deserialize for Function { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self> { + let name = s.read::<String>()?; + let arity = s.read()?; + let variadic = s.read()?; + let chunk = <Chunk>::deserialize(s)?; + Ok(Function { + name: Rc::from(name.as_str()), + arity, + variadic, + fun: InnerFunction::Compiled(chunk.into()) + }) + } +} diff --git a/matrix-lang/src/binary/mod.rs b/matrix-lang/src/binary/mod.rs new file mode 100644 index 0000000..53b3fe5 --- /dev/null +++ b/matrix-lang/src/binary/mod.rs @@ -0,0 +1,154 @@ +use crate::prelude::*; +use std::io::{self, Read, Write}; + +mod serialize; +mod deserialize; +mod prim; + +pub struct Program { + version: u8, + fun: Rc<Function> +} + +const PROGRAM_HEADER: [u8; 5] = [0x00, 0x4d, 0x41, 0x54, 0x0a]; + +impl Program { + pub fn load(body: &str) -> Result<Option<Rc<Function>>> { + let mut bytes = body.as_bytes(); + if bytes.len() < 6 { + return Ok(None) + } + let header = &bytes[0..5]; + if header != &PROGRAM_HEADER { + return Ok(None) + } + let mut s = ProgramDeserializer::from(&mut bytes); + let program = <Self>::deserialize(&mut s)?; + s.finish()?; + Ok(Some(program.fun.clone())) + } + + pub fn save<W: Write>(fun: Rc<Function>, w: &mut W) -> Result<()> { + let mut s = ProgramSerializer::from(w); + let p = Program { + version: 0, + fun + }; + s.serialize(&p)?; + s.finish()?; + Ok(()) + } +} + +pub trait Primitive : Sized { + fn write<W: Write>(&self, w: &mut W) -> io::Result<()>; + fn read<R: Read>(r: &mut R) -> io::Result<Self>; +} + +pub trait Serialize : Sized { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()>; +} + +pub trait Serializer : Sized { + fn serialize<S: Serialize>(&mut self, val: &S) -> Result<()> { + val.serialize(self) + } + fn write<P: Primitive>(&mut self, val: P) -> Result<()>; +} + +pub trait Deserialize : Sized { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self>; +} + +pub trait Deserializer : Sized { + fn deserialize<D: Deserialize>(&mut self) -> Result<D> { + D::deserialize(self) + } + fn read<P: Primitive>(&mut self) -> Result<P>; +} + +macro_rules! error { + ($($arg:tt)*) => { + exception!(BINARY_EXCEPTION, $($arg)*) + }; +} + +pub struct ProgramSerializer<'w, W: Write> { + writer: &'w mut W, + checksum: u64, +} + +impl<'w, W: Write> ProgramSerializer<'w, W> { + fn finish(self) -> Result<()> { + let bytes = self.checksum.to_le_bytes(); + self.writer.write(&bytes).map_err(|e| error!("{e}"))?; + Ok(()) + } +} + +impl<'w, W: Write> Serializer for ProgramSerializer<'w, W> { + fn write<P: Primitive>(&mut self, val: P) -> Result<()> { + val.write(self).map_err(|e| error!("{e}")) + } +} + +impl<'w, W: Write> Write for ProgramSerializer<'w, W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + for b in buf { + self.checksum %= 0xf1e3beef; + self.checksum += *b as u64; + } + self.writer.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.writer.flush() + } +} + +impl<'w, W: Write> From<&'w mut W> for ProgramSerializer<'w, W> { + fn from(writer: &'w mut W) -> Self { + Self { writer, checksum: 0xfe } + } +} + +pub struct ProgramDeserializer<'r, R: Read> { + reader: &'r mut R, + checksum: u64, +} + +impl<'r, R: Read> ProgramDeserializer<'r, R> { + fn finish(self) -> Result<()> { + let mut bytes = [0u8; 8]; + self.reader.read_exact(&mut bytes).map_err(|e| error!("{e}"))?; + let checksum = u64::from_le_bytes(bytes); + if self.checksum != checksum { + return Err(error!("checksum doesnt match")) + } + Ok(()) + } +} + +impl<'r, R: Read> Deserializer for ProgramDeserializer<'r, R> { + fn read<P: Primitive>(&mut self) -> Result<P> { + P::read(self).map_err(|e| error!("{e}")) + } +} + +impl<'r, R: Read> Read for ProgramDeserializer<'r, R> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let c = self.reader.read(buf)?; + for i in 0..c { + let b = buf[i]; + self.checksum %= 0xf1e3beef; + self.checksum += b as u64; + } + Ok(c) + } +} + +impl<'r, R: Read> From<&'r mut R> for ProgramDeserializer<'r, R> { + fn from(reader: &'r mut R) -> Self { + Self { reader, checksum: 0xfe } + } +} diff --git a/matrix-lang/src/binary/prim.rs b/matrix-lang/src/binary/prim.rs new file mode 100644 index 0000000..44e6898 --- /dev/null +++ b/matrix-lang/src/binary/prim.rs @@ -0,0 +1,109 @@ +use super::Primitive; +use std::io::{self, Read, Write}; + +macro_rules! marshal_number { + ($type:ident, $byte:expr) => { + impl Primitive for $type { + fn write<W: Write>(&self, write: &mut W) -> io::Result<()> { + write.write(&self.to_le_bytes())?; + Ok(()) + } + + fn read<R: Read>(read: &mut R) -> io::Result<Self> { + let mut bytes = [0u8; $byte]; + read.read_exact(&mut bytes)?; + Ok(Self::from_le_bytes(bytes)) + } + } + }; +} + +marshal_number!(u8, 1); +marshal_number!(u16, 2); +marshal_number!(i16, 2); +marshal_number!(u32, 4); +marshal_number!(i64, 8); +marshal_number!(f64, 8); + +impl Primitive for bool { + fn write<W: Write>(&self, write: &mut W) -> io::Result<()> { + if *self { + write.write(&[1u8; 1])?; + } else { + write.write(&[0u8; 1])?; + } + Ok(()) + } + + fn read<R: Read>(read: &mut R) -> io::Result<Self> { + let mut bytes = [0u8; 1]; + read.read_exact(&mut bytes)?; + if bytes[0] == 1 { + Ok(true) + } else { + Ok(false) + } + } +} + +impl Primitive for String { + fn write<W: Write>(&self, write: &mut W) -> io::Result<()> { + let bytes = self.as_bytes(); + let len = bytes.len(); + write.write(&(len as u32).to_le_bytes())?; + write.write(&bytes)?; + Ok(()) + } + + fn read<R: Read>(read: &mut R) -> io::Result<Self> { + let len = usize::read(read)?; + let mut bytes = vec![0u8; len]; + read.read_exact(&mut bytes)?; + Ok(String::from_utf8_lossy(bytes.as_slice()).to_string()) + } +} + +impl Primitive for usize { + fn write<W: Write>(&self, write: &mut W) -> io::Result<()> { + (*self as u32).write(write) + } + + fn read<R: Read>(read: &mut R) -> io::Result<Self> { + Ok(u32::read(read)? as usize) + } +} + +pub struct VarInt(pub usize); + +impl Primitive for VarInt { + fn write<W: Write>(&self, write: &mut W) -> io::Result<()> { + let mut data = self.0; + loop { + let mut byte = (data & 0x7F) as u8; + data >>= 7; + if data != 0 { + byte += 0x80; + } + write.write(&[byte; 1])?; + if data == 0 { + return Ok(()) + } + } + } + + fn read<R: Read>(read: &mut R) -> io::Result<Self> { + let mut buf = [0]; + let mut result = 0usize; + for count in 0..8 { + if read.read(&mut buf)? != 1 { + return Ok(Self(0)) + } + let byte = buf[0]; + result |= ((byte & 0x7F) as usize) << (7 * count); + if byte & 0x80 == 0 { + return Ok(Self(result)) + } + } + Ok(Self(0)) + } +} diff --git a/matrix-lang/src/binary/serialize.rs b/matrix-lang/src/binary/serialize.rs new file mode 100644 index 0000000..2f2b199 --- /dev/null +++ b/matrix-lang/src/binary/serialize.rs @@ -0,0 +1,283 @@ +use crate::{prelude::*, binary::PROGRAM_HEADER}; +use std::ops::Deref; +use super::{prim::VarInt, Program, Serializer, Serialize}; + +macro_rules! error { + ($($arg:tt)*) => { + exception!(BINARY_EXCEPTION, $($arg)*) + }; +} + +impl Serialize for Program { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + for b in PROGRAM_HEADER { + s.write(b)?; + } + s.write(self.version)?; + s.serialize(self.fun.as_ref())?; + Ok(()) + } +} + +impl Serialize for Instruction { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + use Instruction as I; + match self { + I::NoOp => { + s.write(0u8)?; + }, + I::CreateLocal => { + s.write(1u8)?; + }, + I::LoadLocal(idx) => { + s.write(2u8)?; + s.write(*idx)?; + }, + I::StoreLocal(idx) => { + s.write(3u8)?; + s.write(*idx)?; + }, + I::DiscardLocals(idx) => { + s.write(4u8)?; + s.write(*idx)?; + }, + I::LoadGlobal(idx) => { + s.write(5u8)?; + s.write(*idx)?; + } + I::StoreGlobal(idx) => { + s.write(6u8)?; + s.write(*idx)?; + }, + I::Const(idx) => { + s.write(7u8)?; + s.write(*idx)?; + }, + I::Int(i) => { + s.write(8u8)?; + s.write(*i)?; + }, + I::True => { + s.write(9u8)?; + }, + I::False => { + s.write(10u8)?; + }, + I::Nil => { + s.write(11u8)?; + }, + I::Dup => { + s.write(12u8)?; + }, + I::Discard(idx) => { + s.write(13u8)?; + s.write(*idx)?; + }, + I::UnaryOp(op) => { + s.write(14u8)?; + s.write(*op as u8)?; + }, + I::BinaryOp(op) => { + s.write(15u8)?; + s.write(*op as u8)?; + }, + I::NewList(len) => { + s.write(16u8)?; + s.write(*len)?; + }, + I::NewTable(len) => { + s.write(17u8)?; + s.write(*len)?; + }, + I::NewMatrix(d, c) => { + s.write(18u8)?; + s.write(*d)?; + s.write(*c)?; + }, + I::Field(idx) => { + s.write(19u8)?; + s.write(*idx)?; + }, + I::StoreField(idx) => { + s.write(20u8)?; + s.write(*idx)?; + }, + I::Index(idx) => { + s.write(21u8)?; + s.write(*idx)?; + }, + I::StoreIndex(idx) => { + s.write(22u8)?; + s.write(*idx)?; + }, + I::Jump(ip) => { + s.write(23u8)?; + s.write(*ip)?; + }, + I::JumpTrue(ip) => { + s.write(24u8)?; + s.write(*ip)?; + }, + I::JumpFalse(ip) => { + s.write(25u8)?; + s.write(*ip)?; + }, + I::JumpNil(ip) => { + s.write(26u8)?; + s.write(*ip)?; + }, + I::IterCreate => { + s.write(27u8)?; + }, + I::IterNext => { + s.write(28u8)?; + }, + I::Try(ip) => { + s.write(29u8)?; + s.write(*ip)?; + }, + I::TryEnd => { + s.write(30u8)?; + }, + I::Call(arity) => { + s.write(31u8)?; + s.write(*arity)?; + }, + I::Return => { + s.write(32u8)?; + }, + }; + Ok(()) + } +} + +impl<T: Serialize> Serialize for Vec<T> { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + s.write(VarInt(self.len()))?; + for val in self { + val.serialize(s)?; + } + Ok(()) + } +} + +impl<T: Serialize + Deref> Serialize for Gc<T> { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + self.deref().serialize(s) + } +} + +impl<T: Serialize + Deref> Serialize for Rc<T> { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + self.deref().serialize(s) + } +} + +impl Serialize for Position { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + s.write(VarInt(self.row))?; + s.write(VarInt(self.col))?; + Ok(()) + } +} + +impl Serialize for Chunk { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + self.constants.serialize(s)?; + self.code.serialize(s)?; + self.pos.serialize(s)?; + Ok(()) + } +} + +impl Serialize for Value { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + use Value as V; + match self { + V::Nil => { + s.write(0u8)?; + }, + V::Bool(b) => { + s.write(1u8)?; + s.write(*b)?; + }, + V::Int(i) => { + s.write(2u8)?; + s.write(*i)?; + }, + V::Float(f) => { + s.write(3u8)?; + s.write(*f)?; + }, + V::Ratio(r) => { + s.write(4u8)?; + s.write(*r.numer())?; + s.write(*r.denom())?; + }, + V::Complex(c) => { + s.write(5u8)?; + s.write(c.re)?; + s.write(c.im)?; + }, + V::Regex(r) => { + s.write(6u8)?; + s.write(r.to_string())?; + }, + V::String(str) => { + s.write(7u8)?; + s.write(str.to_string())?; + }, + V::List(l) => { + s.write(8u8)?; + l.serialize(s)?; + }, + V::Matrix(m) => { + s.write(9u8)?; + s.write(m.domain)?; + s.write(m.codomain)?; + m.values.serialize(s)?; + }, + V::Table(t) => { + s.write(10u8)?; + s.write(VarInt(t.len()))?; + for (key, value) in t.entries() { + key.serialize(s)?; + value.serialize(s)?; + } + }, + V::Function(f) => { + s.write(11u8)?; + f.serialize(s)?; + }, + V::Range(r) => { + s.write(12u8)?; + s.write(r.0)?; + s.write(r.1)?; + s.write(r.2)?; + }, + V::Iter(f) => { + s.write(13u8)?; + f.serialize(s)?; + }, + V::File(_) => return Err(error!("cannot compile file")), + V::Exception(_) => return Err(error!("cannot compile exception")), + }; + Ok(()) + } +} + +impl Serialize for Function { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()> { + s.write(self.name.to_string())?; + s.write(self.arity)?; + s.write(self.variadic)?; + use InnerFunction as F; + match &self.fun { + F::Compiled(c) => { + c.serialize(s)?; + }, + F::Native(_) => return Err(error!("cannot compile native function")), + }; + Ok(()) + } +} diff --git a/matrix/src/chunk.rs b/matrix-lang/src/chunk.rs index 495b787..2fc3d9e 100644 --- a/matrix/src/chunk.rs +++ b/matrix-lang/src/chunk.rs @@ -1,5 +1,5 @@ -use crate::{value::Value, ast::{UnaryOp, BinaryOp}, vm::{Vm, StackFrame}, Result, lex::Position}; -use std::{fmt::{Debug, Display}, rc::Rc}; +use std::fmt::{Debug, Display}; +use crate::prelude::*; #[derive(Clone, Default)] pub struct Chunk { @@ -18,53 +18,6 @@ impl Chunk { } } -impl Debug for Chunk { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Chunk({})", self.code.len()) - } -} - -impl Display for Chunk { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "constants: ")?; - for (i, c) in self.constants.iter().enumerate() { - writeln!(f, " {i:04}: {c}")?; - } - writeln!(f, "code:")?; - for (i, ins) in self.code.iter().enumerate() { - writeln!(f, " {i:04}: {ins}")?; - } - Ok(()) - } -} - -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, "[NativeFunction {}]", self.name) - } - } - } -} - #[derive(Clone, Debug)] #[repr(align(4))] pub enum Instruction { @@ -113,6 +66,26 @@ pub enum Instruction { Return, } +impl Debug for Chunk { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "[Chunk {}]", self.code.len()) + } +} + +impl Display for Chunk { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "constants: ")?; + for (i, c) in self.constants.iter().enumerate() { + writeln!(f, " {i:04}: {c}")?; + } + writeln!(f, "code:")?; + for (i, ins) in self.code.iter().enumerate() { + writeln!(f, " {i:04}: {ins}")?; + } + Ok(()) + } +} + impl Display for Instruction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use Instruction::*; diff --git a/matrix/src/compiler.rs b/matrix-lang/src/compiler.rs index 6b6a94b..95c6ccf 100644 --- a/matrix/src/compiler.rs +++ b/matrix-lang/src/compiler.rs @@ -1,14 +1,14 @@ -use std::{fmt::Display, rc::Rc, cell::RefCell}; -use crate::{ast::{Expr, ExprData, AstName}, chunk::{Function, Instruction, InnerFunction}, chunk::{Chunk, self}, value::Value, Result, lex::Position}; +use crate::prelude::*; use Instruction as I; use Value as V; use ExprData as E; pub type NamesTable = Rc<RefCell<Vec<Rc<str>>>>; +pub type GlobalsTable = Rc<RefCell<Vec<Global>>>; pub struct CompilerBuilder<'c> { - globals: NamesTable, + globals: GlobalsTable, names: NamesTable, repl: bool, debug: bool, @@ -39,7 +39,7 @@ impl<'c> CompilerBuilder<'c> { self } - pub fn globals(mut self, globals: NamesTable) -> Self { + pub fn globals(mut self, globals: GlobalsTable) -> Self { self.globals = globals; self } @@ -81,9 +81,9 @@ pub struct Compiler<'c> { name: Rc<str>, parent: Option<&'c Compiler<'c>>, - locals: Vec<Rc<Local>>, - globals: Rc<RefCell<Vec<Rc<str>>>>, - names: Rc<RefCell<Vec<Rc<str>>>>, + locals: Vec<Local>, + globals: GlobalsTable, + names: NamesTable, root_is_block: bool, @@ -97,50 +97,25 @@ pub struct Compiler<'c> { debug: bool, } +#[derive(Clone)] struct Local { name: Rc<str>, idx: usize, - scope: usize -} - -#[derive(Debug, Clone)] -pub enum InnerError { - Undefined(Rc<str>), - Redefined(Rc<str>), - InvAssign(Expr), - InvContinue, - InvBreak, - NotImplemented(&'static str), -} - -#[derive(Debug, Clone)] -pub struct Error { - pos: Position, - err: InnerError, + scope: usize, + is_const: bool, } -impl std::error::Error for self::Error {} - -impl Display for self::Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use InnerError as E; - write!(f, "parse failed at {}:{}, ", self.pos.row, self.pos.col)?; - match &self.err { - E::Undefined(name) => write!(f, "value {name} is undefined"), - E::Redefined(name) => write!(f, "cannot redefine {name} in the same scope"), - E::InvAssign(expr) => write!(f, "cannot assign to {expr:?}"), - E::InvContinue => write!(f, "cannot continue outside a loop"), - E::InvBreak => write!(f, "cannot break outside a loop"), - E::NotImplemented(str) => write!(f, "{str} is not implemented yet") - } - } +#[derive(Clone)] +pub struct Global { + pub name: Rc<str>, + pub idx: usize, + pub is_const: bool, } -fn error<T>(err: InnerError, pos: Position) -> Result<T> { - Err(self::Error { - pos, - err - }.into()) +macro_rules! error { + ($($arg:tt)*) => { + exception!(COMPILE_EXCEPTION, $($arg)*) + }; } impl<'c> Compiler<'c> { @@ -185,35 +160,35 @@ impl<'c> Compiler<'c> { }; } - fn create_local(&mut self, name: Rc<str>) { - let local = Local { name, idx: self.locals.len(), scope: self.scopes.len()}; - self.locals.push(Rc::new(local)); + fn create_local(&mut self, name: Rc<str>, is_const: bool) -> Local { + let local = Local { name, idx: self.locals.len(), scope: self.scopes.len(), is_const }; + self.locals.push(local.clone()); + local } - fn create_global(&mut self, name: Rc<str>) -> usize { - self.globals.borrow_mut().push(name); - let c = self.globals.borrow().len() - 1; - c + fn create_global(&mut self, name: Rc<str>, is_const: bool) -> Global { + let global = Global { name, idx: self.globals.borrow().len(), is_const }; + self.globals.borrow_mut().push(global.clone()); + global } - fn create_local_checked(&mut self, name: Rc<str>, pos: Position) -> Result<()> { + fn create_local_checked(&mut self, name: Rc<str>, is_const: bool, pos: Position) -> Result<Local> { if let Some(local) = self.find_local(&name) { if local.scope == self.scopes.len() { - return error(InnerError::Redefined(name), pos) + return Err(error!("redefined {name}").pos(pos)) } }; - self.create_local(name); - Ok(()) + Ok(self.create_local(name, is_const)) } - fn create_global_checked(&mut self, name: Rc<str>, pos: Position) -> Result<usize> { + fn create_global_checked(&mut self, name: Rc<str>, is_const: bool, pos: Position) -> Result<Global> { if let Some(_) = self.find_global(&name) { - return error(InnerError::Redefined(name).into(), pos) + return Err(error!("redefined {name}").pos(pos)) } - Ok(self.create_global(name)) + Ok(self.create_global(name, is_const)) } - fn find_local(&self, name: &str) -> Option<Rc<Local>> { + fn find_local(&self, name: &str) -> Option<Local> { for local in self.locals.iter().rev() { if local.name.as_ref() == name { return Some(local.clone()) @@ -222,13 +197,13 @@ impl<'c> Compiler<'c> { None } - fn find_global(&self, name: &str) -> Option<usize> { + fn find_global(&self, name: &str) -> Option<Global> { if let Some(parent) = self.parent { return parent.find_global(name) } - for (i, global) in self.globals.borrow().iter().enumerate() { - if global.as_ref() == name { - return Some(i) + for global in self.globals.borrow().iter() { + if global.name.as_ref() == name { + return Some(global.clone()) } } None @@ -294,7 +269,7 @@ impl<'c> Compiler<'c> { let chunk = self.compile_function(name.clone(), params, body)?; let arity = params.len() - if *varadic { 1 } else { 0 }; let fun = Value::Function(Rc::new( - chunk::Function { + Function { name: name.0.clone(), arity, fun: InnerFunction::Compiled(chunk.into()), @@ -304,10 +279,10 @@ impl<'c> Compiler<'c> { self.emit_const(fun, expr.pos); self.emit(I::Dup, expr.pos); if self.can_make_globals() { - let idx = self.create_global_checked(name.0.clone(), name.1)?; - self.emit(I::StoreGlobal(idx as u16), expr.pos); + let global = self.create_global_checked(name.0.clone(), false, name.1)?; + self.emit(I::StoreGlobal(global.idx as u16), expr.pos); } else { - self.create_local_checked(name.0.clone(), name.1)?; + self.create_local_checked(name.0.clone(), false, name.1)?; self.emit(I::CreateLocal, expr.pos); } }, @@ -316,7 +291,7 @@ impl<'c> Compiler<'c> { let chunk = self.compile_function(name.clone(), params, body)?; let arity = params.len() - if *varadic { 1 } else { 0 }; let fun = Value::Function(Rc::new( - chunk::Function { + Function { name: name.0.clone(), arity, fun: InnerFunction::Compiled(chunk.into()), @@ -341,7 +316,7 @@ impl<'c> Compiler<'c> { let jmpidx2 = self.emit_temp(expr.pos); self.re_emit(I::Try(self.cur()), jmpidx); self.begin_scope(); - self.create_local(err.0.clone()); + self.create_local(err.0.clone(), true); self.emit(I::CreateLocal, err.1); self.compile_expr(catch)?; self.end_scope(); @@ -378,7 +353,7 @@ impl<'c> Compiler<'c> { let jumpidx = self.emit_temp(expr.pos); self.loop_top.push((top as usize, self.scopes.len())); self.begin_scope(); - self.create_local(name.0.clone()); + self.create_local(name.0.clone(), true); self.emit(I::CreateLocal, name.1); self.compile_expr(expr)?; self.emit(I::Discard(1), expr.pos); @@ -407,10 +382,21 @@ impl<'c> Compiler<'c> { self.compile_expr(expr)?; self.emit(I::Dup, expr.pos); if self.can_make_globals() { - let global = self.create_global_checked(name.0.clone(), name.1)?; - self.emit(I::StoreGlobal(global as u16), expr.pos); + let global = self.create_global_checked(name.0.clone(), false, name.1)?; + self.emit(I::StoreGlobal(global.idx as u16), expr.pos); + } else { + self.create_local_checked(name.0.clone(), false, name.1)?; + self.emit(I::CreateLocal, expr.pos); + } + }, + E::Const(name, expr) => { + self.compile_expr(expr)?; + self.emit(I::Dup, expr.pos); + if self.can_make_globals() { + let global = self.create_global_checked(name.0.clone(), true, name.1)?; + self.emit(I::StoreGlobal(global.idx as u16), expr.pos); } else { - self.create_local_checked(name.0.clone(), name.1)?; + self.create_local_checked(name.0.clone(), true, name.1)?; self.emit(I::CreateLocal, expr.pos); } }, @@ -420,7 +406,7 @@ impl<'c> Compiler<'c> { self.collapse_scopes(scope); self.emit(I::Jump(top as u16), expr.pos); } else { - return error(InnerError::InvContinue, expr.pos) + return Err(error!("invalid continue outside loop").pos(expr.pos)) } }, E::Break => { @@ -430,7 +416,7 @@ impl<'c> Compiler<'c> { let tmpidx = self.emit_temp(expr.pos); self.loop_bot.push(tmpidx); } else { - return error(InnerError::InvBreak, expr.pos) + return Err(error!("invalid break outside loop").pos(expr.pos)) } }, E::Return(expr) => { @@ -444,9 +430,9 @@ impl<'c> Compiler<'c> { } else if let Some(local) = self.find_local(name) { self.emit(I::LoadLocal(local.idx as u16), expr.pos); } else if let Some(global) = self.find_global(name) { - self.emit(I::LoadGlobal(global as u16), expr.pos); + self.emit(I::LoadGlobal(global.idx as u16), expr.pos); } else { - return error(InnerError::Undefined(name.clone()), expr.pos) + return Err(error!("variable '{name}' is undefined").pos(expr.pos)) }; }, E::Assign(lhs, rhs) => { @@ -455,14 +441,20 @@ impl<'c> Compiler<'c> { match &lhs.data { E::Ident(name) if name.as_ref() != "_" => { if let Some(local) = self.find_local(&name) { + if local.is_const { + return Err(error!("cannot assign to const '{name}'").pos(lhs.pos)) + } self.emit(I::StoreLocal(local.idx as u16), lhs.pos); } else if let Some(global) = self.find_global(&name) { - self.emit(I::StoreGlobal(global as u16), lhs.pos); + if global.is_const { + return Err(error!("cannot assign to const '{name}'").pos(lhs.pos)) + } + self.emit(I::StoreGlobal(global.idx as u16), lhs.pos); } else if self.can_make_globals() { - let global = self.create_global_checked(name.clone(), lhs.pos)?; - self.emit(I::StoreGlobal(global as u16), lhs.pos); + let global = self.create_global_checked(name.clone(), false, lhs.pos)?; + self.emit(I::StoreGlobal(global.idx as u16), lhs.pos); } else { - self.create_local_checked(name.clone(), lhs.pos)?; + self.create_local_checked(name.clone(), false, lhs.pos)?; self.emit(I::CreateLocal, lhs.pos); } }, @@ -478,7 +470,7 @@ impl<'c> Compiler<'c> { let name = self.get_name(ident.0.clone()); self.emit(I::StoreField(name as u16), expr.pos); } - _ => return error(InnerError::InvAssign(*lhs.clone()), lhs.pos) + _ => return Err(error!("assignment to {lhs} is not allowed").pos(lhs.pos)) } } E::UnaryOp(expr, op) => { @@ -554,7 +546,7 @@ impl<'c> Compiler<'c> { fn compile_function(&mut self, name: AstName, params: &Vec<AstName>, body: &Box<Expr>) -> Result<Chunk> { let mut compiler = self.child(name.0); for (name, pos) in params { - compiler.create_local(name.clone()); + compiler.create_local(name.clone(), false); compiler.emit(I::CreateLocal, *pos); } compiler.compile_expr(body)?; @@ -611,7 +603,7 @@ impl<'c> Compiler<'c> { }; if self.loop_bot.len() > 0 { - return error(InnerError::InvBreak, pos) + return Err(error!("invalid break outside loop").pos(pos)) } if self.debug { diff --git a/matrix/src/lex.rs b/matrix-lang/src/lex.rs index 8a07234..b2487ad 100644 --- a/matrix/src/lex.rs +++ b/matrix-lang/src/lex.rs @@ -1,6 +1,5 @@ -use std::{rc::Rc, fmt::Debug}; -use regex::Regex; -use crate::Result; +use std::fmt::{Debug, Display}; +use crate::prelude::*; pub struct RegexToken { regex: Regex @@ -30,6 +29,36 @@ impl From<RegexToken> for Regex { } } +#[derive(Debug, Clone, PartialEq, Eq, Copy)] +pub struct Position { + pub row: usize, + pub col: usize, +} + +impl Default for Position { + fn default() -> Self { + Self { row: 1, col: 1 } + } +} + +impl Display for Position { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}:{}", self.row, self.col) + } +} + +impl Display for TokenData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +impl Display for Token { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.data) + } +} + #[derive(Debug, PartialEq)] pub enum TokenData { //syntax @@ -106,6 +135,7 @@ pub enum TokenData { Else, While, Let, + Const, Function, True, False, @@ -133,48 +163,6 @@ pub struct Token { pub blen: usize, } -#[derive(Debug)] -pub enum Error { - UnexpectedCharacter(char), - ExpectedChar(char, char), - InvalidCodepoint, - UnexpectedEof, - InvalidDigit(char), - InvalidStringEscape(char), - InvalidRegex(anyhow::Error), - InvalidNumber(String), -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use Error::*; - match self { - UnexpectedCharacter(char) => write!(f, "Unexpected char: '{char}'"), - UnexpectedEof => write!(f, "Unexpected end of file"), - ExpectedChar(expected, got) => write!(f, "Expected char: '{expected}', instead got: '{got}'"), - InvalidCodepoint => write!(f, "Invalid codepoint"), - InvalidDigit(char) => write!(f, "Invalid digit: '{char}'"), - InvalidStringEscape(char) => write!(f, "Invalid string escape: '\\{char}"), - InvalidRegex(err) => write!(f, "{err}"), - InvalidNumber(num) => write!(f, "Invalid number: '{num}'") - } - } -} - -impl std::error::Error for Error {} - -#[derive(Debug, Clone, PartialEq, Eq, Copy)] -pub struct Position { - pub row: usize, - pub col: usize, -} - -impl Default for Position { - fn default() -> Self { - Self { row: 1, col: 1 } - } -} - pub struct Lexer { pub index: usize, len: usize, @@ -203,6 +191,12 @@ impl<T: Into<String>> From<T> for Lexer { } } +macro_rules! error { + ($($arg:tt)*) => { + exception!(PARSE_EXCEPTION, $($arg)*) + }; +} + impl Lexer { pub fn new<T: Into<String>>(input: T) -> Self { let data: Vec<char> = input.into().chars().collect(); @@ -239,7 +233,7 @@ impl Lexer { fn next_not_eof(&mut self) -> Result<char> { let c = self.next(); if c == '\0' { - return Err(Error::UnexpectedEof.into()) + return Err(error!("unexpected end of file")) } Ok(c) } @@ -247,7 +241,7 @@ impl Lexer { fn next_expect(&mut self, expected: char) -> Result<char> { let c = self.next(); if c != expected { - return Err(Error::ExpectedChar(expected, c).into()) + return Err(error!("expected character '{c}'")) } Ok(c) } @@ -259,7 +253,6 @@ impl Lexer { } fn lex_string(&mut self, delimit: char) -> Result<Rc<str>> { - use Error::*; let mut buf = String::new(); @@ -291,8 +284,8 @@ impl Lexer { let n1 = self.next_not_eof()?; let n2 = self.next_not_eof()?; buf.push(char::from_u32( - n1.to_digit(16).ok_or(InvalidDigit(n1))? * 16 + - n2.to_digit(16).ok_or(InvalidDigit(n2))? + n1.to_digit(16).ok_or(error!("invalid digit '{n1}'"))? * 16 + + n2.to_digit(16).ok_or(error!("invalid digit '{n2}'"))? ).unwrap()); }, 'u' => { @@ -302,15 +295,15 @@ impl Lexer { let c = self.next_not_eof()?; if c == '}' { break } if n >= 0x1000_0000_u32 { - return Err(InvalidCodepoint.into()) + return Err(error!("invalid utf8 codepoint '{n}'")) } - n = n * 16 + c.to_digit(16).ok_or::<crate::Error>(InvalidDigit(c).into())?; + n = n * 16 + c.to_digit(16).ok_or(error!("invalid digit '{c}'"))?; } - let ch = char::from_u32(n).ok_or::<crate::Error>(InvalidCodepoint.into())?; + let ch = char::from_u32(n).ok_or(error!("invalid codepoint '{n}'"))?; buf.push(ch); }, - _ => return Err(InvalidStringEscape(next).into()) + _ => return Err(error!("invalid string escape '\\{next}'")) } } @@ -318,13 +311,12 @@ impl Lexer { } fn lex_ident(&mut self, initial: char) -> Result<TokenData> { - use Error as E; use TokenData as T; let mut buf = std::string::String::new(); if !initial.is_initial_ident() { - return Err(E::UnexpectedCharacter(initial).into()) + return Err(error!("unexpected character '{initial}'")) } buf.push(initial); @@ -342,6 +334,7 @@ impl Lexer { "else" => T::Else, "while" => T::While, "let" => T::Let, + "const" => T::Const, "fn" | "function" => T::Function, "true" => T::True, "false" => T::False, @@ -364,7 +357,6 @@ impl Lexer { fn lex_radix(&mut self, radix: i64, radix_char: char) -> Result<TokenData> { use TokenData as T; - use Error as E; let mut n = 0i64; let mut char_found = false; @@ -375,7 +367,7 @@ impl Lexer { n = n * radix + (i as i64); char_found = true; } else if self.peek().is_ident() { - return Err(E::InvalidDigit(self.peek()).into()) + return Err(error!("invalid digit '{}'", self.peek())) } else { break; } @@ -384,13 +376,11 @@ impl Lexer { if char_found { Ok(T::Int(n)) } else { - Err(E::InvalidNumber(format!("0{radix_char}")).into()) + Err(error!("invalid number radix specifier '0{radix_char}'")) } } fn lex_number(&mut self, initial: char) -> Result<TokenData> { - use Error as E; - if initial == '0' { match self.peek() { 'x' => { @@ -459,7 +449,7 @@ impl Lexer { } if self.peek().is_ident() { - return Err(E::UnexpectedCharacter(self.peek()).into()) + return Err(error!("unexpected character '{}'", self.peek())) } if let Ok(int) = buf.parse::<i64>() { @@ -478,23 +468,11 @@ impl Lexer { return Ok(T::Float(float)) } - Err(E::InvalidNumber(buf).into()) + Err(error!("invalid number '{buf}'")) } - fn peek_token_impl(&mut self, ignore_newlines: bool) -> Result<Token> { - let idx = self.index; - let pos = self.pos; - let bidx = self.byte_len; - let token = self.next_token_impl(ignore_newlines); - self.index = idx; - self.pos = pos; - self.byte_len = bidx; - token - } - - fn next_token_impl(&mut self, ignore_newlines: bool) -> Result<Token> { + fn read_token(&mut self, ignore_newlines: bool) -> Result<Token> { use TokenData as T; - use Error as E; self.skip_whitespace(ignore_newlines); @@ -705,7 +683,7 @@ impl Lexer { self.next(); T::Regex(regex::Regex::new(&self.lex_string(next)?) .map(|e| e.into()) - .map_err(|e| E::InvalidRegex(e.into()))?) + .map_err(|e| error!("invalid regex: '{e}'"))?) } _ => { self.lex_ident(char)? @@ -744,7 +722,6 @@ impl Lexer { let str_end = self.index; let byte_end = self.byte_len; let str = self.data[str_start..str_end].to_owned().into_iter().collect(); - Ok(Token { data, pos, @@ -754,19 +731,47 @@ impl Lexer { }) } - pub fn peek_token(&mut self) -> Result<Token> { - self.peek_token_impl(true) + pub fn next_token(&mut self) -> Result<Token> { + let pos = self.pos; + match self.read_token(true) { + Ok(token) => Ok(token), + Err(e) => Err(e.pos(pos)), + } } - pub fn next_token(&mut self) -> Result<Token> { - self.next_token_impl(true) + pub fn next_token_nl(&mut self) -> Result<Token> { + let pos = self.pos; + match self.read_token(false) { + Ok(token) => Ok(token), + Err(e) => Err(e.pos(pos)), + } } - pub fn peek_token_nl(&mut self) -> Result<Token> { - self.peek_token_impl(false) + pub fn peek_token(&mut self) -> Result<Token> { + let idx = self.index; + let pos = self.pos; + let bidx = self.byte_len; + let token = self.read_token(true); + self.index = idx; + self.pos = pos; + self.byte_len = bidx; + match token { + Ok(token) => Ok(token), + Err(e) => Err(e.pos(pos)), + } } - pub fn next_token_nl(&mut self) -> Result<Token> { - self.next_token_impl(false) + pub fn peek_token_nl(&mut self) -> Result<Token> { + let idx = self.index; + let pos = self.pos; + let bidx = self.byte_len; + let token = self.read_token(false); + self.index = idx; + self.pos = pos; + self.byte_len = bidx; + match token { + Ok(token) => Ok(token), + Err(e) => Err(e.pos(pos)), + } } } diff --git a/matrix-lang/src/lib.rs b/matrix-lang/src/lib.rs new file mode 100644 index 0000000..1452a09 --- /dev/null +++ b/matrix-lang/src/lib.rs @@ -0,0 +1,42 @@ +mod compiler; +mod value; +mod lex; +mod vm; +mod parse; +mod chunk; +mod ast; +mod binary; + +pub mod prelude; + +#[macro_export] +macro_rules! iter { + ($fn:expr) => { + $crate::prelude::Value::Iter( + ::std::rc::Rc::new( + $crate::prelude::Function { + name: ::std::rc::Rc::from("<iterator>"), + arity: 0, + variadic: false, + fun: $crate::prelude::InnerFunction::Native( + ::std::rc::Rc::new($fn + ))})) + }; +} + +#[macro_export] +macro_rules! native { + ($name:expr, $arity:expr, $varadic:expr, $fn:expr) => { + $crate::prelude::Value::Function( + ::std::rc::Rc::new( $crate::prelude::Function { + name: std::rc::Rc::from($name), + arity: $arity, + variadic: $varadic, + fun: $crate::prelude::InnerFunction::Native( + ::std::rc::Rc::new($fn) + ) + }) + ) + } +} + diff --git a/matrix/src/parse.rs b/matrix-lang/src/parse.rs index d967130..3a4c5f2 100644 --- a/matrix/src/parse.rs +++ b/matrix-lang/src/parse.rs @@ -1,6 +1,4 @@ -use std::{fmt::Display, rc::Rc}; -use num_complex::Complex64; -use crate::{lex::{Lexer, self, Token, TokenData, Position}, ast::{Expr, BinaryOp, UnaryOp, optimize, ExprData, AstName}, value::{Value, self}, Result}; +use crate::prelude::*; use Value as V; use ExprData as E; @@ -33,38 +31,6 @@ pub struct Parser { optimize: bool } -#[derive(Debug)] -pub enum Error { - LexerError(crate::lex::Error), - UnexpectedToken(Token), - ExpectedToken(TokenData, Position), - MatrixInvDomain(usize, usize, usize), - NotAssignable(Expr), - ValueError(value::Error), -} - -impl Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use Error::*; - match self { - LexerError(err) => write!(f, "{err}"), - UnexpectedToken(tok) => write!(f, "Unexpected token: '{:?}' at {}:{}", tok.data, tok.pos.row, tok.pos.col), - ExpectedToken(tok, pos) => write!(f, "Expected token: '{tok:?}' at {}:{}", pos.row, pos.col), - MatrixInvDomain(row, should, was) => write!(f, "In row {row} of matrix, domain was expected to be {should} but was given {was}"), - NotAssignable(expr) => write!(f, "{expr:?} is not assignable"), - ValueError(err) => write!(f, "{err}"), - } - } -} - -impl From<lex::Error> for Error { - fn from(value: lex::Error) -> Self { - Self::LexerError(value) - } -} - -impl std::error::Error for Error {} - macro_rules! expr_parser { ($parser:ident, $pattern:pat, $fn:ident) => {{ let mut expr = $parser.$fn()?; @@ -99,12 +65,18 @@ macro_rules! expr_parser_reverse { }}; } +macro_rules! error { + ($($arg:tt)*) => { + exception!(PARSE_EXCEPTION, $($arg)*) + }; +} + impl Parser { fn force_token(&mut self, tok: TokenData) -> Result<TokenData> { let next = self.lexer.next_token()?; if next.data != tok { - Err(Error::ExpectedToken(tok, next.pos).into()) + Err(error!("expected token '{tok}'").pos(next.pos)) } else { Ok(tok) } @@ -113,7 +85,7 @@ impl Parser { fn force_token_nl(&mut self, tok: TokenData) -> Result<TokenData> { let next = self.lexer.next_token_nl()?; if next.data != tok { - Err(Error::ExpectedToken(tok, next.pos).into()) + Err(error!("expected token '{tok}'").pos(next.pos)) } else { Ok(tok) } @@ -135,7 +107,7 @@ impl Parser { match next.data { T::Comma => continue, T::RightParen => break, - _ => return Err(Error::UnexpectedToken(next).into()) + _ => return Err(error!("unexpected token '{next}'").pos(next.pos)) }; } Ok(params) @@ -157,7 +129,7 @@ impl Parser { match next.data { T::SemiColon => continue, T::RightBrack => break, - _ => return Err(Error::UnexpectedToken(next).into()) + _ => return Err(error!("unexpected token '{next}'").pos(next.pos)) }; } Ok(indicies) @@ -193,7 +165,7 @@ impl Parser { match next.data { T::SemiColon => continue, T::RightBrack => break, - _ => return Err(Error::UnexpectedToken(next).into()), + _ => return Err(error!("unexpected token '{next}'").pos(next.pos)) }; } if parts.len() == 1 { @@ -201,9 +173,9 @@ impl Parser { } else { let codomain = parts.len(); let domain = parts[0].len(); - for (i, part) in parts.iter().enumerate() { + for part in parts.iter() { if part.len() != domain { - return Err(Error::MatrixInvDomain(i, domain, part.len()).into()) + return Err(error!("matrix row domains do not match: {} != {}", domain, part.len()).pos(pos)) } } let mut data = Vec::new(); @@ -225,7 +197,7 @@ impl Parser { }, T::Ident(ident) => (E::Literal(V::String(ident.to_string().into())), tok.pos).into(), T::String(string) => (E::Literal(V::String(string.to_string().into())), tok.pos).into(), - _ => return Err(Error::UnexpectedToken(tok).into()) + t => return Err(error!("unexpected token '{t}'").pos(tok.pos)) }) } @@ -247,7 +219,7 @@ impl Parser { match next.data { T::Comma => continue, T::RightBrace => break, - _ => return Err(Error::UnexpectedToken(next).into()) + _ => return Err(error!("unexpected token '{next}'").pos(next.pos)) } } Ok((E::Table(table), pos).into()) @@ -273,7 +245,7 @@ impl Parser { } } T::LeftParen => (), - _ => return Err(Error::UnexpectedToken(tok).into()), + t => return Err(error!("unexpected token '{t}'").pos(tok.pos)) } let mut params = Vec::new(); @@ -295,7 +267,7 @@ impl Parser { } T::Comma => continue, T::RightParen => break, - _ => return Err(Error::UnexpectedToken(next).into()), + _ => return Err(error!("unexpected token '{next}'").pos(next.pos)) } } @@ -307,7 +279,7 @@ impl Parser { if let T::Ident(ident) = next.data { Ok((ident, next.pos)) } else { - Err(Error::UnexpectedToken(next).into()) + Err(error!("unexpected token '{next}'").pos(next.pos)) } } @@ -327,7 +299,7 @@ impl Parser { if let T::Ident(ident) = next.data { Ok((ident, next.pos)) } else { - Err(Error::UnexpectedToken(next).into()) + Err(error!("unexpected token '{next}'").pos(next.pos)) } } @@ -419,6 +391,15 @@ impl Parser { } } + fn parse_const(&mut self) -> Result<Expr> { + let pos = self.lexer.peek_token()?.pos; + self.force_token(T::Const)?; + let ident = self.parse_ident_nl()?; + self.force_token(T::Assign)?; + let expr = self.parse_expr()?; + Ok((E::Const(ident, Box::new(expr)), pos).into()) + } + fn parse_return(&mut self) -> Result<Expr> { let pos = self.lexer.peek_token()?.pos; self.force_token(T::Return)?; @@ -431,7 +412,10 @@ impl Parser { self.force_token(T::LeftBrace)?; loop { let expr = match self.lexer.peek_token()?.data { - T::RightBrace => break, + T::RightBrace => { + self.lexer.next_token()?; + break + }, T::SemiColon => { self.lexer.next_token()?; continue; @@ -443,12 +427,9 @@ impl Parser { match next.data { T::SemiColon => continue, T::RightBrace => break, - _ => return Err(Error::ExpectedToken(T::SemiColon, next.pos).into()) + _ => return Err(error!("expected a semicolon").pos(next.pos)) } } - if self.lexer.peek_token()?.data == T::RightBrace { - self.lexer.next_token()?; - } Ok((E::Block(block), pos).into()) } @@ -474,7 +455,7 @@ impl Parser { T::True => E::Literal(V::Bool(true)), T::False => E::Literal(V::Bool(false)), T::Ident(ident) => E::Ident(ident), - _ => return Err(Error::UnexpectedToken(tok).into()), + t => return Err(error!("unexpected token '{t}'").pos(tok.pos)) }; Ok((data, tok.pos).into()) } @@ -488,6 +469,7 @@ impl Parser { While => self.parse_while(), For => self.parse_for(), Let => self.parse_let(), + Const => self.parse_const(), LeftBrace => self.parse_block(), Return => self.parse_return(), If => self.parse_if(), @@ -752,11 +734,11 @@ impl Parser { }; let expr = self.parse_expr()?; block.push(expr); - let next = self.lexer.next_token()?; + let next = self.lexer.next_token_nl()?; match next.data { T::Eof => break, T::SemiColon => continue, - _ => return Err(Error::ExpectedToken(T::SemiColon, next.pos).into()) + _ => return Err(error!("expected a semicolon").pos(next.pos)) }; } Ok((E::Block(block), Position::default()).into()) diff --git a/matrix-lang/src/prelude.rs b/matrix-lang/src/prelude.rs new file mode 100644 index 0000000..c5af0c8 --- /dev/null +++ b/matrix-lang/src/prelude.rs @@ -0,0 +1,60 @@ +pub type Result<T> = std::result::Result<T, Exception>; + +pub use crate::value::Value as Value; +pub use crate::value::exception::Exception as Exception; +pub use crate::value::matrix::Matrix as Matrix; +pub use crate::value::gc::Gc as Gc; +pub use crate::value::hash::ValueMap as ValueMap; +pub use crate::value::function::Function as Function; +pub use crate::value::function::InnerFunction as InnerFunction; + +pub use num_complex::Complex64 as Complex64; +pub use num_rational::Rational64 as Rational64; +pub use regex::Regex as Regex; +pub use std::fs::File as File; + +pub use std::rc::Rc as Rc; +pub use std::cell::RefCell as RefCell; + +pub use crate::exception as exception; +pub use crate::native as native; +pub use crate::iter as iter; + +pub use crate::value::exception::HASH_EXCEPTION as HASH_EXCEPTION; +pub use crate::value::exception::VALUE_EXCEPTION as VALUE_EXCEPTION; +pub use crate::value::exception::PARSE_EXCEPTION as PARSE_EXCEPTION; +pub use crate::value::exception::COMPILE_EXCEPTION as COMPILE_EXCEPTION; +pub use crate::value::exception::RUNTIME_EXCEPTION as RUNTIME_EXCEPTION; +pub use crate::value::exception::BINARY_EXECPTION as BINARY_EXCEPTION; +pub use crate::value::exception::IO_EXECPTION as IO_EXCEPTION; + +pub use crate::value::clone::ValueClone as ValueClone; +pub use crate::value::hash::TryHash as TryHash; + +pub use crate::vm::Vm as Vm; +pub use crate::vm::StackFrame as StackFrame; +pub use crate::vm::Interupt as Interupt; + +pub use crate::lex::Lexer as Lexer; +pub use crate::lex::Position as Position; +pub use crate::lex::Token as Token; +pub use crate::lex::TokenData as TokenData; +pub use crate::parse::Parser as Parser; +pub use crate::parse::ParserBuilder as ParserBuilder; +pub use crate::compiler::Compiler as Compiler; +pub use crate::compiler::CompilerBuilder as CompilerBuilder; +pub use crate::compiler::NamesTable as NamesTable; +pub use crate::compiler::GlobalsTable as GlobalsTable; +pub use crate::compiler::Global as Global; + +pub use crate::ast::AstName as AstName; +pub use crate::ast::Expr as Expr; +pub use crate::ast::ExprData as ExprData; +pub use crate::ast::BinaryOp as BinaryOp; +pub use crate::ast::UnaryOp as UnaryOp; +pub use crate::ast::optimize as optimize; + +pub use crate::chunk::Chunk as Chunk; +pub use crate::chunk::Instruction as Instruction; + +pub use crate::binary::Program as Program; 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/src/gc.rs b/matrix-lang/src/value/gc.rs index 7af020b..5ef8b80 100644 --- a/matrix/src/gc.rs +++ b/matrix-lang/src/value/gc.rs @@ -1,4 +1,5 @@ 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>>, @@ -24,22 +25,31 @@ impl<T> Gc<T> { } impl <T: Clone> Gc<T> { - pub fn clone_inside(&self) -> Self { + pub fn into_inner(self) -> T { unsafe { - let data = self.ptr.as_ref().data.clone(); - Self::new(data) + self.ptr.as_ref().data.clone() } } - pub fn into_inner(self) -> T { + fn data(&self) -> T { unsafe { self.ptr.as_ref().data.clone() } } +} - fn data(&self) -> T { +impl <T: ValueClone> ValueClone for Gc<T> { + fn deep_clone(&self) -> Self { unsafe { - self.ptr.as_ref().data.clone() + 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) } } } 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) +} diff --git a/matrix/src/vm.rs b/matrix-lang/src/vm.rs index e511adf..bac6341 100644 --- a/matrix/src/vm.rs +++ b/matrix-lang/src/vm.rs @@ -1,33 +1,6 @@ -use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap, cell::RefCell, sync::{atomic::{AtomicUsize, Ordering}, Arc}}; -use crate::{value::{Value, self, ValueMap, Matrix}, Result, gc::Gc, chunk::{Function, Instruction, Chunk, InnerFunction}, compiler::NamesTable, native}; +use std::{fmt::Display, ops::{IndexMut, Index}, sync::{atomic::{AtomicUsize, Ordering}, Arc}, collections::HashMap}; +use crate::prelude::*; -#[derive(Debug)] -pub enum Error { - ValueError(value::Error), - NotFunction(Value), - InvArity(usize, usize, Rc<str>), - ExecNative, -} - -impl std::error::Error for Error {} - -impl Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use Error::*; - match self { - ValueError(err) => write!(f, "{err}"), - NotFunction(v) => write!(f, "{v:?} is not a function"), - InvArity(wanted, had, name) => write!(f, "function {name} takes {wanted} params but was given {had}"), - ExecNative => write!(f, "cannot execute a native function"), - } - } -} - -impl From<value::Error> for Error { - fn from(value: value::Error) -> Self { - Error::ValueError(value) - } -} pub struct Stack<T> { inner: Vec<T> } @@ -99,12 +72,12 @@ pub struct StackFrame { } struct VmError { - err: crate::Error, + err: Exception, frames: Vec<StackFrame> } -impl From<crate::Error> for VmError { - fn from(err: crate::Error) -> Self { +impl From<Exception> for VmError { + fn from(err: Exception) -> Self { VmError { err, frames: Vec::new() @@ -112,15 +85,6 @@ impl From<crate::Error> for VmError { } } -impl From<self::Error> for VmError { - fn from(err: self::Error) -> Self { - VmError { - err: err.into(), - frames: Vec::new() - } - } -} - type VmResult<T> = std::result::Result<T, VmError>; impl StackFrame { @@ -166,10 +130,16 @@ pub struct Vm { trystack: Vec<TryScope>, globals: Rc<RefCell<HashMap<u16, Value>>>, names: NamesTable, - global_names: NamesTable, + global_names: GlobalsTable, interupt: Arc<AtomicUsize>, } +macro_rules! error { + ($($arg:tt)*) => { + exception!(RUNTIME_EXCEPTION, $($arg)*) + }; +} + impl Vm { fn push(&mut self, val: Value) { @@ -188,7 +158,7 @@ impl Vm { self.names.clone() } - pub fn global_names(&self) -> NamesTable { + pub fn globals(&self) -> GlobalsTable { self.global_names.clone() } @@ -210,7 +180,7 @@ impl Vm { pub fn load_global(&mut self, value: Value, name: &str) { let idx = self.global_names.borrow().len(); - self.global_names.borrow_mut().push(name.into()); + self.global_names.borrow_mut().push(Global { idx, name: Rc::from(name), is_const: true }); self.globals.borrow_mut().insert(idx as u16, value); } @@ -220,7 +190,7 @@ impl Vm { fn init_frame(&mut self, fun: Rc<Function>) -> Result<StackFrame> { let InnerFunction::Compiled(ref compiled_chunk) = fun.fun else { - return Err(self::Error::ExecNative.into()) + return Err(error!("cannot create stack frame on builtin function")) }; Ok(StackFrame::new( self, @@ -240,7 +210,7 @@ impl Vm { match ins { I::NoOp => {}, I::CreateLocal => self.locals.push(self.stack.pop()), - I::LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());}, + I::LoadLocal(idx) => {self.stack.push(self.locals[frame.lp + idx as usize].clone());}, I::StoreLocal(idx) => self.locals[frame.bp + idx as usize] = self.pop(), I::DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)}, I::LoadGlobal(idx) => { @@ -325,11 +295,12 @@ impl Vm { let fun = self.pop(); let Value::Function(fun) = fun else { - return Err(Error::NotFunction(fun).into()) + Err(error!("cannot call {fun} (not a function)"))? }; if !fun.variadic && arity > fun.arity { - return Err(Error::InvArity(fun.arity, arity as usize, fun.name.clone()).into()) + let needs = fun.arity; + Err(error!("function {fun} takes {needs} args, given {arity}"))? } let mut params = self.stack.split_off(self.stack.len() - arity).inner; @@ -416,14 +387,14 @@ impl Vm { Ok(None) } - fn stack_trace(&mut self, frames: Vec<StackFrame>) -> String { - let mut trace = String::from("\x1b[33m\x1b[1mStack Trace:\x1b[0m\n"); + fn stack_trace(&mut self, frames: Vec<StackFrame>, e: Exception) -> Exception { + let mut e = e; for frame in frames { let ip = frame.ip - 1; let pos = frame.body.pos[ip]; - trace.push_str(&format!(" {} at {}:{}\n", &frame.name, pos.row, pos.col)); + e = e.trace(frame.name, pos); } - trace + e } fn exec_fn(&mut self, frame: &mut StackFrame, fun: Rc<Function>, params: Vec<Value>) -> VmResult<Value> { @@ -438,7 +409,8 @@ impl Vm { self.stack.push(param); } let mut new_frame = StackFrame::new(self, name, body.clone(), params_len, frame.depth + 1); - self.exec(&mut new_frame) + let res = self.exec(&mut new_frame); + res }, InnerFunction::Native(native_fun) => { Ok(native_fun((self, frame), params)?) @@ -462,7 +434,7 @@ impl Vm { self.stack.truncate(catch.stack_len); self.locals.truncate(catch.locals_len); frame.ip = catch.err_idx; - self.stack.push(Value::Error(err.err)); + self.stack.push(Value::Exception(err.err)); } else { let mut err = err; err.frames.push(frame.clone()); @@ -478,13 +450,12 @@ impl Vm { } pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> { - let mut frame = self.init_frame(fun)?; self.interupt.store(0, Ordering::SeqCst); self.stack = Stack::new(); self.locals = Stack::new(); + let mut frame = self.init_frame(fun)?; self.exec(&mut frame).map_err(|e| { - let trace = self.stack_trace(e.frames); - (e.err, trace).into() + self.stack_trace(e.frames, e.err) }) } } |