diff --git a/Cargo.lock b/Cargo.lock index 30ca9f6..45a0c7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -223,6 +223,10 @@ dependencies = [ "rustyline", ] +[[package]] +name = "matrix-stdlib" +version = "0.1.0" + [[package]] name = "memchr" version = "2.7.1" diff --git a/Cargo.toml b/Cargo.toml index f489827..d1bda86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] resolver = "2" -members = [ "matrix", "matrix-bin" ] +members = [ "matrix", "matrix-bin" , "matrix-stdlib"] diff --git a/a.mat b/a.mat new file mode 100644 index 0000000..e689317 --- /dev/null +++ b/a.mat @@ -0,0 +1,5 @@ +a = 0; + +while a < 1000000000 { a = a + 1 }; + + diff --git a/matrix-bin/src/main.rs b/matrix-bin/src/main.rs index 3ae8135..72972c6 100644 --- a/matrix-bin/src/main.rs +++ b/matrix-bin/src/main.rs @@ -54,6 +54,7 @@ impl<'a> State<'a> { let compiler = CompilerBuilder::new() .repl(repl) .debug(args.debug) + .names(vm.names()) .build(); (Self { parser, vm, compiler, repl }, file) diff --git a/matrix-stdlib/Cargo.toml b/matrix-stdlib/Cargo.toml new file mode 100644 index 0000000..5140bfa --- /dev/null +++ b/matrix-stdlib/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "matrix-stdlib" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/matrix-stdlib/src/lib.rs b/matrix-stdlib/src/lib.rs new file mode 100644 index 0000000..7d12d9a --- /dev/null +++ b/matrix-stdlib/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/matrix/src/ast.rs b/matrix/src/ast.rs index 594cd48..19a4d04 100644 --- a/matrix/src/ast.rs +++ b/matrix/src/ast.rs @@ -31,7 +31,6 @@ pub enum BinaryOp { LessEquals, GreaterThan, LessThan, - Range, } #[derive(Debug, Clone, PartialEq)] @@ -46,7 +45,7 @@ pub enum Expr { Index(Box, Vec), FnCall(Box, Vec), - FieldAccess(Box, Box), + FieldAccess(Box, Rc), List(InlineList), Matrix(InlineMatrix), @@ -60,7 +59,6 @@ pub enum Expr { If(Box, Box, Option>), Function(Rc, Vec>, Box), - Loop(Box), While(Box, Box), DoWhile(Box, Box), @@ -178,10 +176,9 @@ pub fn optimize(expr: Expr) -> Result { .map(optimize) .collect::>>()?) } - E::FieldAccess(key, val) => { - let key = optimize(*key)?; - let val = optimize(*val)?; - E::FieldAccess(Box::new(key), Box::new(val)) + E::FieldAccess(expr, ident) => { + let expr = optimize(*expr)?; + E::FieldAccess(Box::new(expr), ident) }, E::List(list) => E::List(list.into_iter() @@ -333,7 +330,6 @@ impl From for BinaryOp { Divide => Self::Divide, Modulo => Self::Modulo, Power => Self::Power, - Range => Self::Range, _ => panic!("aaaaa") } } diff --git a/matrix/src/chunk.rs b/matrix/src/chunk.rs index 3906535..276ffe3 100644 --- a/matrix/src/chunk.rs +++ b/matrix/src/chunk.rs @@ -71,6 +71,8 @@ pub enum Instruction { NewTable(u16), NewMatrix(u16, u8), + Field(u16), + StoreField(u16), Index(u8), StoreIndex(u8), @@ -112,6 +114,8 @@ impl Display for Instruction { JumpFalse(idx) => write!(f, "jumpf \x1b[33m{idx}\x1b[0m"), Call(arity) => write!(f, "call \x1b[35m{arity}\x1b[0m"), Return => write!(f, "return"), + Field(name_idx) => write!(f, "field \x1b[33m{name_idx}\x1b[0m"), + StoreField(name_idx) => write!(f, "store field \x1b[33m{name_idx}\x1b[0m"), } } } diff --git a/matrix/src/compiler.rs b/matrix/src/compiler.rs index 49594ad..5531d7e 100644 --- a/matrix/src/compiler.rs +++ b/matrix/src/compiler.rs @@ -7,10 +7,11 @@ use Expr as E; pub struct CompilerBuilder<'c> { globals: Rc>>>, + names: Rc>>>, repl: bool, debug: bool, name: Rc, - parent: Option<&'c Compiler<'c>> + parent: Option<&'c Compiler<'c>>, } impl<'c> CompilerBuilder<'c> { @@ -22,6 +23,7 @@ impl<'c> CompilerBuilder<'c> { debug: false, name: "".into(), parent: None, + names: Rc::new(RefCell::new(Vec::new())) } } @@ -40,6 +42,11 @@ impl<'c> CompilerBuilder<'c> { self } + pub fn names(mut self, names: Rc>>>) -> Self { + self.names = names; + self + } + pub fn parent(mut self, parent: &'c Compiler) -> Self { self.parent = Some(parent); self @@ -53,6 +60,7 @@ impl<'c> CompilerBuilder<'c> { pub fn build(self) -> Compiler<'c> { Compiler { name: self.name, + names: self.names, parent: self.parent, globals: self.globals, repl: self.repl, @@ -73,6 +81,7 @@ pub struct Compiler<'c> { locals: Vec>, globals: Rc>>>, + names: Rc>>>, root_is_block: bool, @@ -207,6 +216,12 @@ impl<'c> Compiler<'c> { None } + fn get_name(&mut self, name: Rc) -> usize { + let idx = self.names.borrow().len(); + self.names.borrow_mut().push(name); + idx + } + fn emit_const(&mut self, val: Value) { // TODO: find constant if already exists self.chunk.constants.push(val); @@ -244,7 +259,7 @@ impl<'c> Compiler<'c> { fn compile_expr(&mut self, expr: &Expr) -> Result<()> { match expr { - E::NoOp => {}, + E::NoOp => self.emit(I::Nil), E::If(cond, ifb, elseb) => { self.compile_expr(cond)?; let jmpidx = self.emit_temp(); @@ -375,6 +390,18 @@ impl<'c> Compiler<'c> { self.emit(I::CreateLocal); } }, + E::Index(expr, params) => { + self.compile_expr(expr)?; + for param in params { + self.compile_expr(param)?; + } + self.emit(I::StoreIndex(params.len() as u8)); + }, + E::FieldAccess(expr, ident) => { + self.compile_expr(expr)?; + let name = self.get_name(ident.clone()); + self.emit(I::StoreField(name as u16)); + } _ => return Err(self::Error::InvAssign(*lhs.clone()).into()) } } @@ -387,7 +414,13 @@ impl<'c> Compiler<'c> { self.compile_expr(rhs)?; self.emit(I::BinaryOp(*op)); }, - E::Index(_, _) => return Err(self::Error::NotImplemented("indexing").into()), + E::Index(expr, params) => { + self.compile_expr(expr)?; + for param in params { + self.compile_expr(param)?; + } + self.emit(I::Index(params.len() as u8)) + }, E::FnCall(fun, params) => { for expr in params { self.compile_expr(expr)?; @@ -395,7 +428,11 @@ impl<'c> Compiler<'c> { self.compile_expr(fun)?; self.emit(I::Call(params.len() as u8)); }, - E::FieldAccess(_, _) => return Err(self::Error::NotImplemented("filed access").into()), + E::FieldAccess(expr, field) => { + self.compile_expr(expr)?; + let idx = self.get_name(field.clone()); + self.emit(I::Field(idx as u16)) + } E::List(list) => { for expr in list { self.compile_expr(expr)?; diff --git a/matrix/src/gc.rs b/matrix/src/gc.rs index 85129dc..98d3228 100644 --- a/matrix/src/gc.rs +++ b/matrix/src/gc.rs @@ -1,112 +1,126 @@ -use std::cmp::Ordering; -use std::fmt::{Debug, Display}; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use std::ptr::NonNull; -use std::rc::Rc; +use std::{ops::{Index, IndexMut, Deref, DerefMut}, marker::PhantomData, ptr::NonNull, fmt::{Debug, Display}}; pub struct Gc { ptr: NonNull>, - phantom: PhantomData>, + phantom: PhantomData> } -pub struct GcInner { +struct GcInner { rc: usize, - data: T, + data: T } impl Gc { - pub fn new(data: T) -> Gc { + pub fn new(data: T) -> Self { let boxed = Box::new(GcInner { rc: 1, data, }); Self { ptr: NonNull::new(Box::into_raw(boxed)).unwrap(), - phantom: PhantomData, + phantom: PhantomData } } } -impl From> for Gc { - fn from(value: Rc) -> Self { - Self::new(Rc::unwrap_or_clone(value)) +impl Gc { + pub fn clone_inside(&mut self) -> Self { + unsafe { + let data = self.ptr.as_mut().data.clone(); + Self::new(data) + } } } impl From for Gc { fn from(value: T) -> Self { - Self::new(value) + Gc::new(value) + } +} + +impl, Idx> IndexMut for Gc { + fn index_mut(&mut self, index: Idx) -> &mut Self::Output { + self.deref_mut().index_mut(index) + } +} + +impl, Idx> Index for Gc { + type Output = T::Output; + + fn index(&self, index: Idx) -> &Self::Output { + self.deref().index(index) + } +} + +impl DerefMut for Gc { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.ptr.as_mut().data + } } } impl Deref for Gc { type Target = T; - fn deref(&self) -> &T { - let inner = unsafe { self.ptr.as_ref() }; - &inner.data - } -} -impl Debug for Gc { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let inner = unsafe { self.ptr.as_ref() }; - write!(f, "{:?}", inner.data) - } -} - -impl Display for Gc { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let inner = unsafe { self.ptr.as_ref() }; - write!(f, "{}", inner.data) - } -} - -impl PartialEq for Gc { - fn eq(&self, other: &Self) -> bool { - let inner = unsafe { self.ptr.as_ref() }; - let other = unsafe { other.ptr.as_ref() }; - inner.data == other.data - } -} - -impl PartialOrd for Gc { - fn partial_cmp(&self, other: &Self) -> Option { - let inner = unsafe { self.ptr.as_ref() }; - let other = unsafe { other.ptr.as_ref() }; - inner.data.partial_cmp(&other.data) - } -} - -impl DerefMut for Gc { - fn deref_mut(&mut self) -> &mut Self::Target { - let inner = unsafe { self.ptr.as_mut() }; - if inner.rc > 1 { - *self = Self::new(inner.data.clone()); + fn deref(&self) -> &Self::Target { + unsafe { + &self.ptr.as_ref().data } - &mut inner.data } } +impl PartialEq for Gc { + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other.deref()) + } +} + +impl Iterator for Gc { + type Item = T::Item; + + fn next(&mut self) -> Option { + self.deref_mut().next() + } +} + +impl Eq for Gc {} + impl Clone for Gc { fn clone(&self) -> Self { - let inner = unsafe { self.ptr.as_ptr().as_mut().unwrap() }; - inner.rc += 1; - Self { - ptr: self.ptr, - phantom: PhantomData, + unsafe { + let inner = self.ptr.as_ptr().as_mut().unwrap(); + inner.rc += 1; + + Self { + ptr: self.ptr, + phantom: PhantomData + } } } } impl Drop for Gc { fn drop(&mut self) { - let inner = unsafe { self.ptr.as_mut() }; - inner.rc -= 1; - if inner.rc > 0 { - return; + unsafe { + let inner = self.ptr.as_mut(); + if inner.rc > 1 { + inner.rc -= 1; + } else { + let _ = Box::from_raw(self.ptr.as_ptr()); + } } - unsafe { let _ = Box::from_raw(self.ptr.as_ptr()); } } } +impl Debug for Gc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.deref()) + } +} + +impl Display for Gc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.deref()) + } +} diff --git a/matrix/src/lex.rs b/matrix/src/lex.rs index 953a495..ab0359b 100644 --- a/matrix/src/lex.rs +++ b/matrix/src/lex.rs @@ -38,9 +38,7 @@ pub enum Token { LeftBrack, RightBrack, LeftBrace, - LeftLeftBrace, RightBrace, - RightRightBrace, Assign, Access, SemiColon, @@ -48,6 +46,15 @@ pub enum Token { ThinArrow, Comma, Range, + Colon, + + // math + Regex(RegexToken), + Int(i64), + Float(f64), + Complex(f64), + String(Rc), + Ident(Rc), // equality Equal, @@ -67,14 +74,6 @@ pub enum Token { BitwiseOr, BitwiseXor, - // math - Regex(RegexToken), - Int(i64), - Float(f64), - Complex(f64), - String(Rc), - Ident(Rc), - Add, Subtract, Multiply, @@ -82,6 +81,22 @@ pub enum Token { Modulo, Power, + AssignAnd, + AssignOr, + + AssignBitwiseShiftLeft, + AssignBitwiseShiftRight, + AssignBitwiseAnd, + AssignBitwiseOr, + AssignBitwiseXor, + + AssignAdd, + AssignSubtract, + AssignMultiply, + AssignDivide, + AssignModulo, + AssignPower, + // keywords If, Else, @@ -193,7 +208,7 @@ impl Lexer { } fn skip_whitespace(&mut self, ignore_newlines: bool) { - while self.peek().is_whitespace() && (!ignore_newlines || self.peek() != '\n') { + while self.peek().is_whitespace() && (ignore_newlines || self.peek() != '\n') { self.next(); } } @@ -420,42 +435,62 @@ impl Lexer { } Ok(match char { + '\n' => SemiColon, '(' => LeftParen, ')' => RightParen, '[' => LeftBrack, ']' => RightBrack, - '{' => { - match next { - '{' => { - self.next(); - LeftLeftBrace - } - _ => LeftBrace - } - }, - '}' => { - match next { - '}' => { - self.next(); - RightRightBrace - } - _ => RightBrace - } - }, + '{' => LeftBrace, + '}' => RightBrace, + ':' => Colon, ';' => SemiColon, - '+' => Add, + '+' => { + match next { + '=' => { + self.next(); + AssignAdd + } + _ => Add + } + }, + '/' => { + match next { + '=' => { + self.next(); + AssignDivide + } + _ => Divide + } + }, + '%' => { + match next { + '=' => { + self.next(); + AssignModulo + } + _ => Modulo + } + }, ',' => Comma, '*' => { match next { '*' => { self.next(); - Power + match self.peek() { + '=' => { + self.next(); + AssignPower + }, + _ => Power + } + }, + '=' => { + self.next(); + AssignMultiply } _ => Multiply } }, - '/' => Divide, - '%' => Modulo, '!' => { match next { '=' => { @@ -469,8 +504,18 @@ impl Lexer { match next { '&' => { self.next(); - And - } + match self.peek() { + '=' => { + self.next(); + AssignAnd + }, + _ => And + } + }, + '=' => { + self.next(); + AssignBitwiseAnd + }, _ => BitwiseAnd } }, @@ -478,8 +523,18 @@ impl Lexer { match next { '|' => { self.next(); - Or - } + match self.peek() { + '=' => { + self.next(); + AssignOr + }, + _ => Or + } + }, + '=' => { + self.next(); + AssignBitwiseOr + }, _ => BitwiseOr } }, @@ -488,7 +543,11 @@ impl Lexer { '>' => { self.next(); ThinArrow - } + }, + '=' => { + self.next(); + AssignSubtract + }, _ => Subtract } }, @@ -509,7 +568,13 @@ impl Lexer { match next { '>' => { self.next(); - BitwiseShiftRight + match self.peek() { + '=' => { + self.next(); + AssignBitwiseShiftRight + }, + _ => BitwiseShiftRight + } } '=' => { self.next(); @@ -522,7 +587,13 @@ impl Lexer { match next { '<' => { self.next(); - BitwiseShiftLeft + match self.peek() { + '=' => { + self.next(); + AssignBitwiseShiftLeft + }, + _ => BitwiseShiftLeft + } } '=' => { self.next(); @@ -531,7 +602,15 @@ impl Lexer { _ => LessThan } }, - '^' => BitwiseXor, + '^' => { + match next { + '=' => { + self.next(); + AssignBitwiseXor + }, + _ => BitwiseXor + } + } '\'' | '\"' => String(self.lex_string(char)?), 'r' => { match next { diff --git a/matrix/src/parse.rs b/matrix/src/parse.rs index 046b86d..4e1de2c 100644 --- a/matrix/src/parse.rs +++ b/matrix/src/parse.rs @@ -1,7 +1,7 @@ use std::{fmt::Display, rc::Rc}; use num_complex::Complex64; -use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, optimize}, gc::Gc, value::{Value, self}, Result}; +use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, optimize}, value::{Value, self}, Result}; use Value as V; use Expr as E; @@ -230,9 +230,10 @@ impl Parser { } fn parse_table(&mut self) -> Result { - self.force_token(T::LeftLeftBrace)?; + self.force_token(T::Colon)?; + self.force_token(T::LeftBrace)?; let mut table = Vec::new(); - if self.lexer.peek_token()? == T::RightRightBrace { + if self.lexer.peek_token()? == T::RightBrace { self.lexer.next_token()?; return Ok(E::Table(table)) } @@ -244,7 +245,7 @@ impl Parser { let next = self.lexer.next_token()?; match next { T::Comma => continue, - T::RightRightBrace => break, + T::RightBrace => break, _ => return Err(Error::UnexpectedToken(next).into()) } } @@ -402,7 +403,7 @@ impl Parser { T::Int(i) => E::Literal(V::Int(i)), T::Float(f) => E::Literal(V::Float(f)), T::Complex(c) => E::Literal(V::Complex(Complex64::new(0.0, c))), - T::Regex(r) => E::Literal(V::Regex(Gc::new(r.into()))), + T::Regex(r) => E::Literal(V::Regex(Rc::new(r.into()))), T::String(s) => E::Literal(V::String(s.to_string().into())), T::True => E::Literal(V::Bool(true)), T::False => E::Literal(V::Bool(false)), @@ -431,7 +432,7 @@ impl Parser { Ok(E::Continue) }, LeftBrack => self.parse_matrix(), - LeftLeftBrace => self.parse_table(), + Colon => self.parse_table(), LeftParen => self.parse_paren(), _ => self.parse_value(), } @@ -444,8 +445,8 @@ impl Parser { match tok { T::Access => { self.force_token(T::Access)?; - let temp = self.parse_term()?; - expr = E::FieldAccess(Box::new(expr), Box::new(temp)); + let temp = self.parse_ident()?; + expr = E::FieldAccess(Box::new(expr), temp); }, _ => break } @@ -563,13 +564,66 @@ impl Parser { } fn parse_expr(&mut self) -> Result { + use BinaryOp as B; let expr = self.parse_expr_or()?; let tok = self.lexer.peek_token_nl()?; Ok(match tok { T::Assign => { self.lexer.next_token_nl()?; - E::Assign(Box::new(expr),Box::new(self.parse_expr()?)) - } + E::Assign(Box::new(expr.clone()),Box::new(self.parse_expr()?)) + }, + T::AssignAnd => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::And(Box::new(expr), Box::new(self.parse_expr()?)))) + }, + T::AssignOr => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::Or(Box::new(expr), Box::new(self.parse_expr()?)))) + }, + T::AssignAdd => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Add))) + }, + T::AssignSubtract => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Subtract))) + }, + T::AssignMultiply => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Multiply))) + }, + T::AssignDivide => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Divide))) + }, + T::AssignModulo => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Modulo))) + }, + T::AssignPower => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Power))) + }, + T::AssignBitwiseAnd => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseAnd))) + }, + T::AssignBitwiseOr => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseOr))) + }, + T::AssignBitwiseXor => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseXor))) + }, + T::AssignBitwiseShiftLeft => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseShiftLeft))) + }, + T::AssignBitwiseShiftRight => { + self.lexer.next_token_nl()?; + E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseShiftRight))) + }, _ => expr }) } diff --git a/matrix/src/value.rs b/matrix/src/value.rs index 3ff7e56..b7a8218 100644 --- a/matrix/src/value.rs +++ b/matrix/src/value.rs @@ -4,7 +4,7 @@ use num_complex::Complex64; use num_rational::Rational64; use regex::Regex; -use crate::{ast::{Expr, BinaryOp, UnaryOp}, gc::Gc, chunk::Function, Result}; +use crate::{ast::{Expr, BinaryOp, UnaryOp}, chunk::Function, Result, gc::Gc}; pub type List = Vec; pub type Matrix = (usize, usize, Vec); @@ -43,12 +43,14 @@ pub enum Error { Exponent(Value, Value), Compare(Value, Value), IndexOutOfBounds(usize, usize), - Index(Value, Value), + CannotIndex(Value), + BadIndex(Value, Value), Concat(Value, Value), Bitwise(Value, Value), DivideByZero, ZeroExpZero, CannotHash(Value), + FieldAccess(Value), } impl Display for self::Error { @@ -64,12 +66,14 @@ impl Display for self::Error { Exponent(a, b) => write!(f, "cannot compute {a:?} pow {b:?}"), Compare(a, b) => write!(f, "cannot compare {a:?} and {b:?}"), IndexOutOfBounds(a, b) => write!(f, "index {a} out of bounds for list of length {b}"), - Index(a, b) => write!(f, "cannot index {a:?} with {b:?}"), + BadIndex(a, b) => write!(f, "cannot index {a:?} with {b:?}"), + CannotIndex(a) => write!(f, "cannot index {a:?}"), Concat(a, b) => write!(f, "cannot concat {a:?} and {b:?}"), Bitwise(a, b) => write!(f, "cannot bitwise between {a:?} and {b:?}"), DivideByZero => write!(f, "attempted to divide by zero"), ZeroExpZero => write!(f, "cannot exponent zero with zero"), CannotHash(v) => write!(f, "cannot hash {v:?}"), + FieldAccess(a) => write!(f, "{a:?} cannot be field accessed"), } } } @@ -84,8 +88,8 @@ pub enum Value { Float(f64), Ratio(Rational64), Complex(Complex64), - Regex(Gc), - String(Gc), + Regex(Rc), + String(Rc), List(Gc), Matrix(Gc), Table(Gc), @@ -153,21 +157,21 @@ impl Value { Float(l) => format!("{l}"), Ratio(r) => format!("{r}"), Complex(c) => format!("{c}"), - Regex(r) => format!("{r}"), + Regex(r) => format!("/{r}/"), String(s) => format!("{s}"), List(l) => { - let mut str = "[ ".to_string(); + let mut str = "[".to_string(); for (i, el) in l.iter().enumerate() { if i != 0 { str.push_str(" "); } str.push_str(&el.boring_print()); } - str.push_str(" ]"); + str.push_str("]"); str }, Matrix(m) => { - let mut str = "[[ ".to_string(); + let mut str = "[[".to_string(); for (i, el) in m.2.iter().enumerate() { if i != 0 { if (i % m.1) == 0 { @@ -178,11 +182,11 @@ impl Value { } str.push_str(&el.boring_print()); } - str.push_str(" ]]"); + str.push_str("]]"); str }, Table(t) => { - let mut str = "{{ ".to_string(); + let mut str = "{".to_string(); for (i, (key, val)) in t.0.iter().enumerate() { if i != 0 { str.push_str(", "); @@ -191,7 +195,7 @@ impl Value { str.push_str(" = "); str.push_str(&val.boring_print()); } - str.push_str(" }}"); + str.push_str("}"); str }, Function(fun) => { @@ -212,18 +216,18 @@ impl Value { Regex(_) => format!("\x1b[31m{}\x1b[0m", self.boring_print()), String(_) => format!("\x1b[32m'{}'\x1b[0m", self.boring_print()), List(l) => { - let mut str = "[ ".to_string(); + let mut str = "[".to_string(); for (i, el) in l.iter().enumerate() { if i != 0 { str.push_str(" "); } str.push_str(&el.pretty_print()); } - str.push_str(" ]"); + str.push_str("]"); str }, Matrix(m) => { - let mut str = "[[ ".to_string(); + let mut str = "[[".to_string(); for (i, el) in m.2.iter().enumerate() { if i != 0 { if (i % m.1) == 0 { @@ -234,11 +238,11 @@ impl Value { } str.push_str(&el.pretty_print()); } - str.push_str(" ]]"); + str.push_str("]]"); str }, Table(t) => { - let mut str = "{{ ".to_string(); + let mut str = "{".to_string(); for (i, (key, val)) in t.0.iter().enumerate() { if i != 0 { str.push_str(", "); @@ -247,7 +251,7 @@ impl Value { str.push_str(" = "); str.push_str(&val.pretty_print()); } - str.push_str(" }}"); + str.push_str("}"); str }, Function(_) => { @@ -295,10 +299,10 @@ impl Add for Value { (Float(x), Float(y)) => Ok(Float(x + y)), (Ratio(x), Ratio(y)) => Ok(Ratio(x + y)), (Complex(x), Complex(y)) => Ok(Complex(x + y)), - (String(str), value) => Ok(String(Gc::new( + (String(str), value) => Ok(String(Rc::new( format!("{str}{}", value.boring_print()) ))), - (value, String(str)) => Ok(String(Gc::new( + (value, String(str)) => Ok(String(Rc::new( format!("{}{str}", value.boring_print()) ))), (List(mut l1), List(l2)) => { @@ -420,28 +424,18 @@ fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> { } impl Value { + pub fn modulo(self, rhs: Value) -> Result { use Value::*; match promote(self, rhs) { - (Int(x), Int(y)) => Ok(Int(x.rem_euclid(y))), - (Float(x), Float(y)) => Ok(Float(x.rem_euclid(y))), - (Ratio(_x), Ratio(_y)) => todo!("ratio modulo"), - (Complex(_x), Complex(_y)) => todo!("complex modulo"), + (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::Modulo(r, l).into()) } } - pub fn int_div(self, rhs: Value) -> Result { - use Value::*; - match promote(self, rhs) { - (Int(x), Int(y)) => Ok(Int(x.div_euclid(y))), - (Float(x), Float(y)) => Ok(Float(x.div_euclid(y))), - (Ratio(_x), Ratio(_y)) => todo!("ratio integer division"), - (Complex(_x), Complex(_y)) => todo!("complex integer division"), - (l, r) => Err(Error::Divide(l, r).into()) - } - } - pub fn pow(self, rhs: Value) -> Result { use Value::*; if let (Ratio(x), Int(y)) = (&self, &rhs) { @@ -518,24 +512,123 @@ impl Value { .map_or_else(|| Err(Error::Compare(self.clone(), other.clone()).into()), Ok) } - pub fn store_index(&self, _other: &Vec, _value: &Self) -> Result<()> { - todo!() + fn index_single(&self, index: &Value) -> Result { + 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 Err(Error::IndexOutOfBounds(*i as usize, l.len()).into()) + } + Ok(l[*i as usize].clone()) + } + _ => return Err(self::Error::BadIndex(self.clone(), index.clone()).into()) + } } - pub fn index(&self, _other: &Vec) -> Result { - todo!() - //use Value::*; - //match (self, other) { - // (List(l), Int(i)) => { - // if *i >= 0 && *i < l.len() as i64 { - // Ok(l[*i as usize].clone()) - // } else { - // Err(Error::IndexOutOfBounds(*i as usize, l.len())) - // } - // }, - // (l, r) => Err(Error::Index(l.clone(), r.clone())) - //} - } + fn index_multiple(&self, indexes: &Vec) -> Result { + 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())) + } + _ => return Err(self::Error::CannotIndex(self.clone()).into()) + } + } + + pub fn index(&self, index: &Vec) -> Result { + if index.len() == 0 { + Ok(self.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 = self.clone(); + 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 Err(Error::IndexOutOfBounds(*i as usize, l.len()).into()) + } + l[*i as usize] = store; + Ok(()) + } + _ => return Err(self::Error::BadIndex(err, index.clone()).into()) + } + } + + fn store_index_multiple(&mut self, indexes: &Vec, 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 Err(self::Error::CannotIndex(self.clone()).into()) + } + } + + pub fn store_index(&mut self, index: &Vec, 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::new(ident.to_string())); + Ok(t.insert(key, val)?) + }, + _ => return Err(self::Error::FieldAccess(self.clone()).into()) + } + } + + pub fn field_access(&self, ident: &str) -> Result { + use Value as V; + match self { + V::Table(t) => { + let key = V::String(Rc::new(ident.to_string())); + Ok(t.get(&key)?.unwrap_or(&V::Nil).clone()) + }, + _ => return Err(self::Error::FieldAccess(self.clone()).into()) + } + } pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result { use BinaryOp::*; @@ -557,7 +650,6 @@ impl Value { LessEquals => Ok(Self::Bool(lhs <= rhs)), GreaterThan => Ok(Self::Bool(lhs > rhs)), LessThan => Ok(Self::Bool(lhs < rhs)), - Range => todo!(), } } diff --git a/matrix/src/vm.rs b/matrix/src/vm.rs index d5408c9..d0729eb 100644 --- a/matrix/src/vm.rs +++ b/matrix/src/vm.rs @@ -1,4 +1,4 @@ -use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap}; +use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap, cell::RefCell}; use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result}; #[derive(Debug)] @@ -108,6 +108,7 @@ pub struct Vm { locals: Stack, frames: Vec, globals: HashMap, + names: Rc>>>, } impl Vm { @@ -120,12 +121,17 @@ impl Vm { self.stack.pop() } + pub fn names(&self) -> Rc>>> { + self.names.clone() + } + pub fn new() -> Self { Self { stack: Stack::new(), locals: Stack::new(), frames: Vec::new(), globals: HashMap::new(), + names: Rc::new(RefCell::new(Vec::new())), } } @@ -135,11 +141,12 @@ impl Vm { use Instruction::*; let ins = frame.fun.body.code[frame.ip].clone(); frame.ip += 1; + match ins { NoOp => {}, CreateLocal => self.locals.push(self.stack.pop()), LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());}, - StoreLocal(idx) => self.stack[frame.bp + idx as usize] = self.pop(), + StoreLocal(idx) => self.locals[frame.bp + idx as usize] = self.pop(), DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)}, LoadGlobal(idx) => { let val = self.globals @@ -187,18 +194,6 @@ impl Vm { let domain = list.len() / codomain; self.push(Value::Matrix(Gc::new((domain, codomain, list.inner)))); } - Index(count) => { - let index = self.stack.split_off(self.stack.len() - count as usize); - let collection = self.pop(); - let value = collection.index(&index.inner)?; - self.stack.push(value); - }, - StoreIndex(count) => { - let value = self.pop(); - let index = self.stack.split_off(self.stack.len() - count as usize); - let collection = self.pop(); - collection.store_index(&index.inner, &value)?; - } Jump(idx) => frame.ip = idx as usize, JumpTrue(idx) => { if !!self.pop() { @@ -231,6 +226,29 @@ impl Vm { self.push(ret); frame = prev_frame; }, + Field(name_idx) => { + let expr = self.pop(); + let name = self.names.borrow()[name_idx as usize].clone(); + self.push(expr.field_access(&name)?); + }, + StoreField(name_idx) => { + let mut expr = self.pop(); + let value = self.pop(); + let name = self.names.borrow()[name_idx as usize].clone(); + expr.store_field_access(&name, value)?; + }, + Index(count) => { + let index = self.stack.split_off(self.stack.len() - count as usize); + let collection = self.pop(); + let value = collection.index(&index.inner)?; + self.stack.push(value); + }, + StoreIndex(count) => { + let index = self.stack.split_off(self.stack.len() - count as usize); + let mut collection = self.pop(); + let value = self.pop(); + collection.store_index(&index.inner, value)?; + } } } Ok(self.pop()) diff --git a/syntax_thing b/syntax_thing new file mode 100644 index 0000000..8f48af7 --- /dev/null +++ b/syntax_thing @@ -0,0 +1,63 @@ +root => root_expr* +root_expr => function +root_expr => expr +function => FUNCTION IDENT params block +params => IDENT +params => OP CP +params => OP params_impl +params_impl => IDENT COMMA params_impl +params_impl => IDENT CP +block => expr* +expr => if_expr +if_expr => IF math_expr block ELSE if_expr +if_expr => IF math_expr block ELSE block +if_expr => IF math_expr block +expr => DO block WHILE math_expr +expr => WHILE math_expr block +expr => LET IDENT EQ math_expr END +expr => LET IDENT END +expr => IDENT EQ math_expr END +expr => block +expr => RETURN math_expr END +expr => BREAK +expr => CONTINUE +expr => math_expr END +math_expr => (math_expr_and OR)* math_expr_and +math_expr_and => math_expr_and AND math_expr_and +math_expr_and => math_expr_compare +math_expr_compare => math_expr_compare math_expr_compare + +power_term => power_term POWER power_term +power_term => power_term BIT_AND power_term +power_term => power_term BIT_OR power_term +power_term => power_term SHIFT_LEFT power_term +power_term => power_term SHIFT_RIGHT power_term +power_term => term +term => value +term => tuple +term => list +term => table +term => IDENT +value => INT DIVIDE INT +value => INT +value => FLOAT +value => COMPLEX +value => STRING +value => REGEX +value => TRUE +value => FALSE +tuple => OP CP +tuple => OP tuple_impl +tuple_impl => math_expr COMMA tuple_impl +tuple_impl => math_expr CP +list => LBRK RBRK +list => LBRK list_impl +list_impl => math_expr COMMA tuple_impl +list_impl => math_expr RBRK +table => LBRC RBRC +table => LBRC table_impl +table_impl => table_key EQ math_expr COMMA table_impl +table_impl => table_key EQ math_expr RBRC +table_key => LBRK math_expr RBRK +table_key => IDENT +table_key => STRING