indexing and field access

This commit is contained in:
Freya Murphy 2024-02-22 19:40:09 -05:00
parent 671301383b
commit e649cef425
Signed by: freya
GPG key ID: 744AB800E383AE52
15 changed files with 585 additions and 196 deletions

4
Cargo.lock generated
View file

@ -223,6 +223,10 @@ dependencies = [
"rustyline", "rustyline",
] ]
[[package]]
name = "matrix-stdlib"
version = "0.1.0"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.1" version = "2.7.1"

View file

@ -1,3 +1,3 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = [ "matrix", "matrix-bin" ] members = [ "matrix", "matrix-bin" , "matrix-stdlib"]

5
a.mat Normal file
View file

@ -0,0 +1,5 @@
a = 0;
while a < 1000000000 { a = a + 1 };

View file

@ -54,6 +54,7 @@ impl<'a> State<'a> {
let compiler = CompilerBuilder::new() let compiler = CompilerBuilder::new()
.repl(repl) .repl(repl)
.debug(args.debug) .debug(args.debug)
.names(vm.names())
.build(); .build();
(Self { parser, vm, compiler, repl }, file) (Self { parser, vm, compiler, repl }, file)

8
matrix-stdlib/Cargo.toml Normal file
View file

@ -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]

14
matrix-stdlib/src/lib.rs Normal file
View file

@ -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);
}
}

View file

@ -31,7 +31,6 @@ pub enum BinaryOp {
LessEquals, LessEquals,
GreaterThan, GreaterThan,
LessThan, LessThan,
Range,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -46,7 +45,7 @@ pub enum Expr {
Index(Box<Expr>, Vec<Expr>), Index(Box<Expr>, Vec<Expr>),
FnCall(Box<Expr>, Vec<Expr>), FnCall(Box<Expr>, Vec<Expr>),
FieldAccess(Box<Expr>, Box<Expr>), FieldAccess(Box<Expr>, Rc<str>),
List(InlineList), List(InlineList),
Matrix(InlineMatrix), Matrix(InlineMatrix),
@ -60,7 +59,6 @@ pub enum Expr {
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>), If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
Function(Rc<str>, Vec<Rc<str>>, Box<Expr>), Function(Rc<str>, Vec<Rc<str>>, Box<Expr>),
Loop(Box<Expr>), Loop(Box<Expr>),
While(Box<Expr>, Box<Expr>), While(Box<Expr>, Box<Expr>),
DoWhile(Box<Expr>, Box<Expr>), DoWhile(Box<Expr>, Box<Expr>),
@ -178,10 +176,9 @@ pub fn optimize(expr: Expr) -> Result<Expr> {
.map(optimize) .map(optimize)
.collect::<Result<Vec<Expr>>>()?) .collect::<Result<Vec<Expr>>>()?)
} }
E::FieldAccess(key, val) => { E::FieldAccess(expr, ident) => {
let key = optimize(*key)?; let expr = optimize(*expr)?;
let val = optimize(*val)?; E::FieldAccess(Box::new(expr), ident)
E::FieldAccess(Box::new(key), Box::new(val))
}, },
E::List(list) => E::List(list) =>
E::List(list.into_iter() E::List(list.into_iter()
@ -333,7 +330,6 @@ impl From<Token> for BinaryOp {
Divide => Self::Divide, Divide => Self::Divide,
Modulo => Self::Modulo, Modulo => Self::Modulo,
Power => Self::Power, Power => Self::Power,
Range => Self::Range,
_ => panic!("aaaaa") _ => panic!("aaaaa")
} }
} }

View file

@ -71,6 +71,8 @@ pub enum Instruction {
NewTable(u16), NewTable(u16),
NewMatrix(u16, u8), NewMatrix(u16, u8),
Field(u16),
StoreField(u16),
Index(u8), Index(u8),
StoreIndex(u8), StoreIndex(u8),
@ -112,6 +114,8 @@ impl Display for Instruction {
JumpFalse(idx) => write!(f, "jumpf \x1b[33m{idx}\x1b[0m"), JumpFalse(idx) => write!(f, "jumpf \x1b[33m{idx}\x1b[0m"),
Call(arity) => write!(f, "call \x1b[35m{arity}\x1b[0m"), Call(arity) => write!(f, "call \x1b[35m{arity}\x1b[0m"),
Return => write!(f, "return"), 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"),
} }
} }
} }

View file

@ -7,10 +7,11 @@ use Expr as E;
pub struct CompilerBuilder<'c> { pub struct CompilerBuilder<'c> {
globals: Rc<RefCell<Vec<Rc<str>>>>, globals: Rc<RefCell<Vec<Rc<str>>>>,
names: Rc<RefCell<Vec<Rc<str>>>>,
repl: bool, repl: bool,
debug: bool, debug: bool,
name: Rc<str>, name: Rc<str>,
parent: Option<&'c Compiler<'c>> parent: Option<&'c Compiler<'c>>,
} }
impl<'c> CompilerBuilder<'c> { impl<'c> CompilerBuilder<'c> {
@ -22,6 +23,7 @@ impl<'c> CompilerBuilder<'c> {
debug: false, debug: false,
name: "<root>".into(), name: "<root>".into(),
parent: None, parent: None,
names: Rc::new(RefCell::new(Vec::new()))
} }
} }
@ -40,6 +42,11 @@ impl<'c> CompilerBuilder<'c> {
self self
} }
pub fn names(mut self, names: Rc<RefCell<Vec<Rc<str>>>>) -> Self {
self.names = names;
self
}
pub fn parent(mut self, parent: &'c Compiler) -> Self { pub fn parent(mut self, parent: &'c Compiler) -> Self {
self.parent = Some(parent); self.parent = Some(parent);
self self
@ -53,6 +60,7 @@ impl<'c> CompilerBuilder<'c> {
pub fn build(self) -> Compiler<'c> { pub fn build(self) -> Compiler<'c> {
Compiler { Compiler {
name: self.name, name: self.name,
names: self.names,
parent: self.parent, parent: self.parent,
globals: self.globals, globals: self.globals,
repl: self.repl, repl: self.repl,
@ -73,6 +81,7 @@ pub struct Compiler<'c> {
locals: Vec<Rc<Local>>, locals: Vec<Rc<Local>>,
globals: Rc<RefCell<Vec<Rc<str>>>>, globals: Rc<RefCell<Vec<Rc<str>>>>,
names: Rc<RefCell<Vec<Rc<str>>>>,
root_is_block: bool, root_is_block: bool,
@ -207,6 +216,12 @@ impl<'c> Compiler<'c> {
None None
} }
fn get_name(&mut self, name: Rc<str>) -> usize {
let idx = self.names.borrow().len();
self.names.borrow_mut().push(name);
idx
}
fn emit_const(&mut self, val: Value) { fn emit_const(&mut self, val: Value) {
// TODO: find constant if already exists // TODO: find constant if already exists
self.chunk.constants.push(val); self.chunk.constants.push(val);
@ -244,7 +259,7 @@ impl<'c> Compiler<'c> {
fn compile_expr(&mut self, expr: &Expr) -> Result<()> { fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
match expr { match expr {
E::NoOp => {}, E::NoOp => self.emit(I::Nil),
E::If(cond, ifb, elseb) => { E::If(cond, ifb, elseb) => {
self.compile_expr(cond)?; self.compile_expr(cond)?;
let jmpidx = self.emit_temp(); let jmpidx = self.emit_temp();
@ -375,6 +390,18 @@ impl<'c> Compiler<'c> {
self.emit(I::CreateLocal); 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()) _ => return Err(self::Error::InvAssign(*lhs.clone()).into())
} }
} }
@ -387,7 +414,13 @@ impl<'c> Compiler<'c> {
self.compile_expr(rhs)?; self.compile_expr(rhs)?;
self.emit(I::BinaryOp(*op)); 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) => { E::FnCall(fun, params) => {
for expr in params { for expr in params {
self.compile_expr(expr)?; self.compile_expr(expr)?;
@ -395,7 +428,11 @@ impl<'c> Compiler<'c> {
self.compile_expr(fun)?; self.compile_expr(fun)?;
self.emit(I::Call(params.len() as u8)); 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) => { E::List(list) => {
for expr in list { for expr in list {
self.compile_expr(expr)?; self.compile_expr(expr)?;

View file

@ -1,112 +1,126 @@
use std::cmp::Ordering; use std::{ops::{Index, IndexMut, Deref, DerefMut}, marker::PhantomData, ptr::NonNull, fmt::{Debug, Display}};
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::rc::Rc;
pub struct Gc<T> { pub struct Gc<T> {
ptr: NonNull<GcInner<T>>, ptr: NonNull<GcInner<T>>,
phantom: PhantomData<GcInner<T>>, phantom: PhantomData<GcInner<T>>
} }
pub struct GcInner<T> { struct GcInner<T> {
rc: usize, rc: usize,
data: T, data: T
} }
impl<T> Gc<T> { impl<T> Gc<T> {
pub fn new(data: T) -> Gc<T> { pub fn new(data: T) -> Self {
let boxed = Box::new(GcInner { let boxed = Box::new(GcInner {
rc: 1, rc: 1,
data, data,
}); });
Self { Self {
ptr: NonNull::new(Box::into_raw(boxed)).unwrap(), ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
phantom: PhantomData, phantom: PhantomData
} }
} }
} }
impl<T: Clone> From<Rc<T>> for Gc<T> { impl <T: Clone> Gc<T> {
fn from(value: Rc<T>) -> Self { pub fn clone_inside(&mut self) -> Self {
Self::new(Rc::unwrap_or_clone(value)) unsafe {
let data = self.ptr.as_mut().data.clone();
Self::new(data)
}
} }
} }
impl<T> From<T> for Gc<T> { impl<T> From<T> for Gc<T> {
fn from(value: T) -> Self { fn from(value: T) -> Self {
Self::new(value) Gc::new(value)
}
}
impl<T: IndexMut<Idx>, Idx> IndexMut<Idx> for Gc<T> {
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
self.deref_mut().index_mut(index)
}
}
impl<T: Index<Idx>, Idx> Index<Idx> for Gc<T> {
type Output = T::Output;
fn index(&self, index: Idx) -> &Self::Output {
self.deref().index(index)
}
}
impl<T> DerefMut for Gc<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
&mut self.ptr.as_mut().data
}
} }
} }
impl<T> Deref for Gc<T> { impl<T> Deref for Gc<T> {
type Target = T; type Target = T;
fn deref(&self) -> &T {
let inner = unsafe { self.ptr.as_ref() };
&inner.data
}
}
impl<T: Debug> Debug for Gc<T> { fn deref(&self) -> &Self::Target {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { unsafe {
let inner = unsafe { self.ptr.as_ref() }; &self.ptr.as_ref().data
write!(f, "{:?}", inner.data)
} }
} }
impl<T: Display> Display for Gc<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let inner = unsafe { self.ptr.as_ref() };
write!(f, "{}", inner.data)
}
} }
impl <T: PartialEq> PartialEq for Gc<T> { impl <T: PartialEq> PartialEq for Gc<T> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
let inner = unsafe { self.ptr.as_ref() }; self.deref().eq(other.deref())
let other = unsafe { other.ptr.as_ref() };
inner.data == other.data
} }
} }
impl<T: PartialOrd> PartialOrd for Gc<T> { impl <T: Iterator> Iterator for Gc<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { type Item = T::Item;
let inner = unsafe { self.ptr.as_ref() };
let other = unsafe { other.ptr.as_ref() }; fn next(&mut self) -> Option<Self::Item> {
inner.data.partial_cmp(&other.data) self.deref_mut().next()
} }
} }
impl<T: Clone> DerefMut for Gc<T> { impl<T: Eq> Eq for Gc<T> {}
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());
}
&mut inner.data
}
}
impl<T> Clone for Gc<T> { impl<T> Clone for Gc<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let inner = unsafe { self.ptr.as_ptr().as_mut().unwrap() }; unsafe {
let inner = self.ptr.as_ptr().as_mut().unwrap();
inner.rc += 1; inner.rc += 1;
Self { Self {
ptr: self.ptr, ptr: self.ptr,
phantom: PhantomData, phantom: PhantomData
}
} }
} }
} }
impl<T> Drop for Gc<T> { impl<T> Drop for Gc<T> {
fn drop(&mut self) { fn drop(&mut self) {
let inner = unsafe { self.ptr.as_mut() }; unsafe {
let inner = self.ptr.as_mut();
if inner.rc > 1 {
inner.rc -= 1; inner.rc -= 1;
if inner.rc > 0 { } else {
return; let _ = Box::from_raw(self.ptr.as_ptr());
}
} }
unsafe { let _ = Box::from_raw(self.ptr.as_ptr()); }
} }
} }
impl<T: Debug> Debug for Gc<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.deref())
}
}
impl<T: Display> Display for Gc<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.deref())
}
}

View file

@ -38,9 +38,7 @@ pub enum Token {
LeftBrack, LeftBrack,
RightBrack, RightBrack,
LeftBrace, LeftBrace,
LeftLeftBrace,
RightBrace, RightBrace,
RightRightBrace,
Assign, Assign,
Access, Access,
SemiColon, SemiColon,
@ -48,6 +46,15 @@ pub enum Token {
ThinArrow, ThinArrow,
Comma, Comma,
Range, Range,
Colon,
// math
Regex(RegexToken),
Int(i64),
Float(f64),
Complex(f64),
String(Rc<str>),
Ident(Rc<str>),
// equality // equality
Equal, Equal,
@ -67,14 +74,6 @@ pub enum Token {
BitwiseOr, BitwiseOr,
BitwiseXor, BitwiseXor,
// math
Regex(RegexToken),
Int(i64),
Float(f64),
Complex(f64),
String(Rc<str>),
Ident(Rc<str>),
Add, Add,
Subtract, Subtract,
Multiply, Multiply,
@ -82,6 +81,22 @@ pub enum Token {
Modulo, Modulo,
Power, Power,
AssignAnd,
AssignOr,
AssignBitwiseShiftLeft,
AssignBitwiseShiftRight,
AssignBitwiseAnd,
AssignBitwiseOr,
AssignBitwiseXor,
AssignAdd,
AssignSubtract,
AssignMultiply,
AssignDivide,
AssignModulo,
AssignPower,
// keywords // keywords
If, If,
Else, Else,
@ -193,7 +208,7 @@ impl Lexer {
} }
fn skip_whitespace(&mut self, ignore_newlines: bool) { 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(); self.next();
} }
} }
@ -420,42 +435,62 @@ impl Lexer {
} }
Ok(match char { Ok(match char {
'\n' => SemiColon,
'(' => LeftParen, '(' => LeftParen,
')' => RightParen, ')' => RightParen,
'[' => LeftBrack, '[' => LeftBrack,
']' => RightBrack, ']' => RightBrack,
'{' => { '{' => LeftBrace,
match next { '}' => RightBrace,
'{' => { ':' => Colon,
self.next();
LeftLeftBrace
}
_ => LeftBrace
}
},
'}' => {
match next {
'}' => {
self.next();
RightRightBrace
}
_ => RightBrace
}
},
';' => SemiColon, ';' => SemiColon,
'+' => Add, '+' => {
match next {
'=' => {
self.next();
AssignAdd
}
_ => Add
}
},
'/' => {
match next {
'=' => {
self.next();
AssignDivide
}
_ => Divide
}
},
'%' => {
match next {
'=' => {
self.next();
AssignModulo
}
_ => Modulo
}
},
',' => Comma, ',' => Comma,
'*' => { '*' => {
match next { match next {
'*' => { '*' => {
self.next(); self.next();
Power match self.peek() {
'=' => {
self.next();
AssignPower
},
_ => Power
}
},
'=' => {
self.next();
AssignMultiply
} }
_ => Multiply _ => Multiply
} }
}, },
'/' => Divide,
'%' => Modulo,
'!' => { '!' => {
match next { match next {
'=' => { '=' => {
@ -469,8 +504,18 @@ impl Lexer {
match next { match next {
'&' => { '&' => {
self.next(); self.next();
And match self.peek() {
'=' => {
self.next();
AssignAnd
},
_ => And
} }
},
'=' => {
self.next();
AssignBitwiseAnd
},
_ => BitwiseAnd _ => BitwiseAnd
} }
}, },
@ -478,8 +523,18 @@ impl Lexer {
match next { match next {
'|' => { '|' => {
self.next(); self.next();
Or match self.peek() {
'=' => {
self.next();
AssignOr
},
_ => Or
} }
},
'=' => {
self.next();
AssignBitwiseOr
},
_ => BitwiseOr _ => BitwiseOr
} }
}, },
@ -488,7 +543,11 @@ impl Lexer {
'>' => { '>' => {
self.next(); self.next();
ThinArrow ThinArrow
} },
'=' => {
self.next();
AssignSubtract
},
_ => Subtract _ => Subtract
} }
}, },
@ -509,7 +568,13 @@ impl Lexer {
match next { match next {
'>' => { '>' => {
self.next(); self.next();
BitwiseShiftRight match self.peek() {
'=' => {
self.next();
AssignBitwiseShiftRight
},
_ => BitwiseShiftRight
}
} }
'=' => { '=' => {
self.next(); self.next();
@ -522,7 +587,13 @@ impl Lexer {
match next { match next {
'<' => { '<' => {
self.next(); self.next();
BitwiseShiftLeft match self.peek() {
'=' => {
self.next();
AssignBitwiseShiftLeft
},
_ => BitwiseShiftLeft
}
} }
'=' => { '=' => {
self.next(); self.next();
@ -531,7 +602,15 @@ impl Lexer {
_ => LessThan _ => LessThan
} }
}, },
'^' => BitwiseXor, '^' => {
match next {
'=' => {
self.next();
AssignBitwiseXor
},
_ => BitwiseXor
}
}
'\'' | '\"' => String(self.lex_string(char)?), '\'' | '\"' => String(self.lex_string(char)?),
'r' => { 'r' => {
match next { match next {

View file

@ -1,7 +1,7 @@
use std::{fmt::Display, rc::Rc}; use std::{fmt::Display, rc::Rc};
use num_complex::Complex64; 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 Value as V;
use Expr as E; use Expr as E;
@ -230,9 +230,10 @@ impl Parser {
} }
fn parse_table(&mut self) -> Result<Expr> { fn parse_table(&mut self) -> Result<Expr> {
self.force_token(T::LeftLeftBrace)?; self.force_token(T::Colon)?;
self.force_token(T::LeftBrace)?;
let mut table = Vec::new(); let mut table = Vec::new();
if self.lexer.peek_token()? == T::RightRightBrace { if self.lexer.peek_token()? == T::RightBrace {
self.lexer.next_token()?; self.lexer.next_token()?;
return Ok(E::Table(table)) return Ok(E::Table(table))
} }
@ -244,7 +245,7 @@ impl Parser {
let next = self.lexer.next_token()?; let next = self.lexer.next_token()?;
match next { match next {
T::Comma => continue, T::Comma => continue,
T::RightRightBrace => break, T::RightBrace => break,
_ => return Err(Error::UnexpectedToken(next).into()) _ => return Err(Error::UnexpectedToken(next).into())
} }
} }
@ -402,7 +403,7 @@ impl Parser {
T::Int(i) => E::Literal(V::Int(i)), T::Int(i) => E::Literal(V::Int(i)),
T::Float(f) => E::Literal(V::Float(f)), T::Float(f) => E::Literal(V::Float(f)),
T::Complex(c) => E::Literal(V::Complex(Complex64::new(0.0, c))), 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::String(s) => E::Literal(V::String(s.to_string().into())),
T::True => E::Literal(V::Bool(true)), T::True => E::Literal(V::Bool(true)),
T::False => E::Literal(V::Bool(false)), T::False => E::Literal(V::Bool(false)),
@ -431,7 +432,7 @@ impl Parser {
Ok(E::Continue) Ok(E::Continue)
}, },
LeftBrack => self.parse_matrix(), LeftBrack => self.parse_matrix(),
LeftLeftBrace => self.parse_table(), Colon => self.parse_table(),
LeftParen => self.parse_paren(), LeftParen => self.parse_paren(),
_ => self.parse_value(), _ => self.parse_value(),
} }
@ -444,8 +445,8 @@ impl Parser {
match tok { match tok {
T::Access => { T::Access => {
self.force_token(T::Access)?; self.force_token(T::Access)?;
let temp = self.parse_term()?; let temp = self.parse_ident()?;
expr = E::FieldAccess(Box::new(expr), Box::new(temp)); expr = E::FieldAccess(Box::new(expr), temp);
}, },
_ => break _ => break
} }
@ -563,13 +564,66 @@ impl Parser {
} }
fn parse_expr(&mut self) -> Result<Expr> { fn parse_expr(&mut self) -> Result<Expr> {
use BinaryOp as B;
let expr = self.parse_expr_or()?; let expr = self.parse_expr_or()?;
let tok = self.lexer.peek_token_nl()?; let tok = self.lexer.peek_token_nl()?;
Ok(match tok { Ok(match tok {
T::Assign => { T::Assign => {
self.lexer.next_token_nl()?; 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 _ => expr
}) })
} }

View file

@ -4,7 +4,7 @@ use num_complex::Complex64;
use num_rational::Rational64; use num_rational::Rational64;
use regex::Regex; 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<Value>; pub type List = Vec<Value>;
pub type Matrix = (usize, usize, Vec<Value>); pub type Matrix = (usize, usize, Vec<Value>);
@ -43,12 +43,14 @@ pub enum Error {
Exponent(Value, Value), Exponent(Value, Value),
Compare(Value, Value), Compare(Value, Value),
IndexOutOfBounds(usize, usize), IndexOutOfBounds(usize, usize),
Index(Value, Value), CannotIndex(Value),
BadIndex(Value, Value),
Concat(Value, Value), Concat(Value, Value),
Bitwise(Value, Value), Bitwise(Value, Value),
DivideByZero, DivideByZero,
ZeroExpZero, ZeroExpZero,
CannotHash(Value), CannotHash(Value),
FieldAccess(Value),
} }
impl Display for self::Error { impl Display for self::Error {
@ -64,12 +66,14 @@ impl Display for self::Error {
Exponent(a, b) => write!(f, "cannot compute {a:?} pow {b:?}"), Exponent(a, b) => write!(f, "cannot compute {a:?} pow {b:?}"),
Compare(a, b) => write!(f, "cannot compare {a:?} and {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}"), 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:?}"), Concat(a, b) => write!(f, "cannot concat {a:?} and {b:?}"),
Bitwise(a, b) => write!(f, "cannot bitwise between {a:?} and {b:?}"), Bitwise(a, b) => write!(f, "cannot bitwise between {a:?} and {b:?}"),
DivideByZero => write!(f, "attempted to divide by zero"), DivideByZero => write!(f, "attempted to divide by zero"),
ZeroExpZero => write!(f, "cannot exponent zero with zero"), ZeroExpZero => write!(f, "cannot exponent zero with zero"),
CannotHash(v) => write!(f, "cannot hash {v:?}"), 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), Float(f64),
Ratio(Rational64), Ratio(Rational64),
Complex(Complex64), Complex(Complex64),
Regex(Gc<Regex>), Regex(Rc<Regex>),
String(Gc<String>), String(Rc<String>),
List(Gc<List>), List(Gc<List>),
Matrix(Gc<Matrix>), Matrix(Gc<Matrix>),
Table(Gc<Table>), Table(Gc<Table>),
@ -153,7 +157,7 @@ impl Value {
Float(l) => format!("{l}"), Float(l) => format!("{l}"),
Ratio(r) => format!("{r}"), Ratio(r) => format!("{r}"),
Complex(c) => format!("{c}"), Complex(c) => format!("{c}"),
Regex(r) => format!("{r}"), Regex(r) => format!("/{r}/"),
String(s) => format!("{s}"), String(s) => format!("{s}"),
List(l) => { List(l) => {
let mut str = "[".to_string(); let mut str = "[".to_string();
@ -182,7 +186,7 @@ impl Value {
str str
}, },
Table(t) => { Table(t) => {
let mut str = "{{ ".to_string(); let mut str = "{".to_string();
for (i, (key, val)) in t.0.iter().enumerate() { for (i, (key, val)) in t.0.iter().enumerate() {
if i != 0 { if i != 0 {
str.push_str(", "); str.push_str(", ");
@ -191,7 +195,7 @@ impl Value {
str.push_str(" = "); str.push_str(" = ");
str.push_str(&val.boring_print()); str.push_str(&val.boring_print());
} }
str.push_str(" }}"); str.push_str("}");
str str
}, },
Function(fun) => { Function(fun) => {
@ -238,7 +242,7 @@ impl Value {
str str
}, },
Table(t) => { Table(t) => {
let mut str = "{{ ".to_string(); let mut str = "{".to_string();
for (i, (key, val)) in t.0.iter().enumerate() { for (i, (key, val)) in t.0.iter().enumerate() {
if i != 0 { if i != 0 {
str.push_str(", "); str.push_str(", ");
@ -247,7 +251,7 @@ impl Value {
str.push_str(" = "); str.push_str(" = ");
str.push_str(&val.pretty_print()); str.push_str(&val.pretty_print());
} }
str.push_str(" }}"); str.push_str("}");
str str
}, },
Function(_) => { Function(_) => {
@ -295,10 +299,10 @@ impl Add for Value {
(Float(x), Float(y)) => Ok(Float(x + y)), (Float(x), Float(y)) => Ok(Float(x + y)),
(Ratio(x), Ratio(y)) => Ok(Ratio(x + y)), (Ratio(x), Ratio(y)) => Ok(Ratio(x + y)),
(Complex(x), Complex(y)) => Ok(Complex(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()) format!("{str}{}", value.boring_print())
))), ))),
(value, String(str)) => Ok(String(Gc::new( (value, String(str)) => Ok(String(Rc::new(
format!("{}{str}", value.boring_print()) format!("{}{str}", value.boring_print())
))), ))),
(List(mut l1), List(l2)) => { (List(mut l1), List(l2)) => {
@ -420,28 +424,18 @@ fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> {
} }
impl Value { impl Value {
pub fn modulo(self, rhs: Value) -> Result<Self> { pub fn modulo(self, rhs: Value) -> Result<Self> {
use Value::*; use Value::*;
match promote(self, rhs) { match promote(self, rhs) {
(Int(x), Int(y)) => Ok(Int(x.rem_euclid(y))), (Int(x), Int(y)) => Ok(Int(x % y)),
(Float(x), Float(y)) => Ok(Float(x.rem_euclid(y))), (Float(x), Float(y)) => Ok(Float(x % y)),
(Ratio(_x), Ratio(_y)) => todo!("ratio modulo"), (Ratio(x), Ratio(y)) => Ok(Ratio(x % y)),
(Complex(_x), Complex(_y)) => todo!("complex modulo"), (Complex(x), Complex(y)) => Ok(Complex(x % y)),
(l, r) => Err(Error::Modulo(r, l).into()) (l, r) => Err(Error::Modulo(r, l).into())
} }
} }
pub fn int_div(self, rhs: Value) -> Result<Self> {
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<Self> { pub fn pow(self, rhs: Value) -> Result<Self> {
use Value::*; use Value::*;
if let (Ratio(x), Int(y)) = (&self, &rhs) { if let (Ratio(x), Int(y)) = (&self, &rhs) {
@ -518,23 +512,122 @@ impl Value {
.map_or_else(|| Err(Error::Compare(self.clone(), other.clone()).into()), Ok) .map_or_else(|| Err(Error::Compare(self.clone(), other.clone()).into()), Ok)
} }
pub fn store_index(&self, _other: &Vec<Self>, _value: &Self) -> Result<()> { fn index_single(&self, index: &Value) -> Result<Self> {
todo!() 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<Self>) -> Result<Self> { fn index_multiple(&self, indexes: &Vec<Value>) -> Result<Self> {
todo!() use Value as V;
//use Value::*; match self {
//match (self, other) { V::List(..) => {
// (List(l), Int(i)) => { let mut ret = Vec::new();
// if *i >= 0 && *i < l.len() as i64 { for index in indexes {
// Ok(l[*i as usize].clone()) let res = self.index_single(index)?;
// } else { ret.push(res);
// Err(Error::IndexOutOfBounds(*i as usize, l.len())) }
// } Ok(V::List(ret.into()))
// }, }
// (l, r) => Err(Error::Index(l.clone(), r.clone())) 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<Value>) -> Result<Self> {
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<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 Err(self::Error::CannotIndex(self.clone()).into())
}
}
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::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<Self> {
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<Self> { pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
@ -557,7 +650,6 @@ impl Value {
LessEquals => Ok(Self::Bool(lhs <= rhs)), LessEquals => Ok(Self::Bool(lhs <= rhs)),
GreaterThan => Ok(Self::Bool(lhs > rhs)), GreaterThan => Ok(Self::Bool(lhs > rhs)),
LessThan => Ok(Self::Bool(lhs < rhs)), LessThan => Ok(Self::Bool(lhs < rhs)),
Range => todo!(),
} }
} }

View file

@ -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}; use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result};
#[derive(Debug)] #[derive(Debug)]
@ -108,6 +108,7 @@ pub struct Vm {
locals: Stack<Value>, locals: Stack<Value>,
frames: Vec<StackFrame>, frames: Vec<StackFrame>,
globals: HashMap<u16, Value>, globals: HashMap<u16, Value>,
names: Rc<RefCell<Vec<Rc<str>>>>,
} }
impl Vm { impl Vm {
@ -120,12 +121,17 @@ impl Vm {
self.stack.pop() self.stack.pop()
} }
pub fn names(&self) -> Rc<RefCell<Vec<Rc<str>>>> {
self.names.clone()
}
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
stack: Stack::new(), stack: Stack::new(),
locals: Stack::new(), locals: Stack::new(),
frames: Vec::new(), frames: Vec::new(),
globals: HashMap::new(), globals: HashMap::new(),
names: Rc::new(RefCell::new(Vec::new())),
} }
} }
@ -135,11 +141,12 @@ impl Vm {
use Instruction::*; use Instruction::*;
let ins = frame.fun.body.code[frame.ip].clone(); let ins = frame.fun.body.code[frame.ip].clone();
frame.ip += 1; frame.ip += 1;
match ins { match ins {
NoOp => {}, NoOp => {},
CreateLocal => self.locals.push(self.stack.pop()), CreateLocal => self.locals.push(self.stack.pop()),
LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());}, 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)}, DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
LoadGlobal(idx) => { LoadGlobal(idx) => {
let val = self.globals let val = self.globals
@ -187,18 +194,6 @@ impl Vm {
let domain = list.len() / codomain; let domain = list.len() / codomain;
self.push(Value::Matrix(Gc::new((domain, codomain, list.inner)))); 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, Jump(idx) => frame.ip = idx as usize,
JumpTrue(idx) => { JumpTrue(idx) => {
if !!self.pop() { if !!self.pop() {
@ -231,6 +226,29 @@ impl Vm {
self.push(ret); self.push(ret);
frame = prev_frame; 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()) Ok(self.pop())

63
syntax_thing Normal file
View file

@ -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 <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