Compare commits
No commits in common. "a9c5ffe62f8b287677dc539b3728c58d5c17f527" and "671301383b965bb3d59bcda03e0775733e96d398" have entirely different histories.
a9c5ffe62f
...
671301383b
18 changed files with 258 additions and 905 deletions
42
Cargo.lock
generated
42
Cargo.lock
generated
|
@ -114,7 +114,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.48",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -138,16 +138,6 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "endian-type"
|
||||
version = "0.1.2"
|
||||
|
@ -229,29 +219,10 @@ name = "matrix-bin"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"ctrlc",
|
||||
"matrix",
|
||||
"matrix-stdlib",
|
||||
"rustyline",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matrix-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"matrix",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matrix-stdlib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"matrix",
|
||||
"matrix-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
|
@ -432,17 +403,6 @@ version = "0.11.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.48"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [ "matrix", "matrix-bin" , "matrix-macros", "matrix-stdlib"]
|
||||
members = [ "matrix", "matrix-bin" ]
|
||||
|
|
|
@ -9,7 +9,5 @@ path = "src/main.rs"
|
|||
|
||||
[dependencies]
|
||||
clap = { version = "4", features = [ "derive" ] }
|
||||
ctrlc = "3"
|
||||
matrix = { path = "../matrix" }
|
||||
matrix-stdlib = { path = "../matrix-stdlib" }
|
||||
rustyline = "13"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs};
|
||||
use clap::Parser as ArgParser;
|
||||
use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}, value::Value};
|
||||
use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}};
|
||||
use repl::Repl;
|
||||
|
||||
mod repl;
|
||||
|
@ -50,24 +50,23 @@ impl<'a> State<'a> {
|
|||
let parser = ParserBuilder::new()
|
||||
.optimize(!args.disable_optimizations)
|
||||
.build();
|
||||
let mut vm = Vm::new();
|
||||
let vm = Vm::new();
|
||||
let compiler = CompilerBuilder::new()
|
||||
.repl(repl)
|
||||
.debug(args.debug)
|
||||
.names(vm.names())
|
||||
.globals(vm.global_names())
|
||||
.build();
|
||||
|
||||
matrix_stdlib::load(&mut vm);
|
||||
|
||||
(Self { parser, vm, compiler, repl }, file)
|
||||
}
|
||||
|
||||
pub fn execute(&mut self, code: String) -> matrix::Result<Value> {
|
||||
pub fn execute(&mut self, code: String) -> matrix::Result<()> {
|
||||
let ast = self.parser.parse(code)?;
|
||||
let fun = self.compiler.compile(&ast)?;
|
||||
let val = self.vm.run(fun)?;
|
||||
Ok(val)
|
||||
if self.repl {
|
||||
println!("{val}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
use std::{io::Write, sync::atomic::Ordering};
|
||||
|
||||
use matrix::{value::Value, vm::Interupt};
|
||||
use rustyline::Config;
|
||||
|
||||
use crate::State;
|
||||
|
||||
pub struct Repl<'a> {
|
||||
|
@ -16,29 +11,14 @@ impl<'a> Repl<'a> {
|
|||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
|
||||
let interupt = self.state.vm.interupt();
|
||||
ctrlc::set_handler(move || {
|
||||
interupt.store(Interupt::KeyboardInterupt as usize, Ordering::SeqCst);
|
||||
}).unwrap();
|
||||
|
||||
let config = Config::builder()
|
||||
.check_cursor_position(true)
|
||||
.build();
|
||||
let mut rl = rustyline::DefaultEditor::with_config(config).unwrap();
|
||||
let mut rl = rustyline::DefaultEditor::new().unwrap();
|
||||
loop {
|
||||
let Ok(line) = rl.readline(">> ") else {
|
||||
break;
|
||||
};
|
||||
match self.state.execute(line) {
|
||||
Err(err) => crate::error(err),
|
||||
Ok(val) => {
|
||||
if val != Value::Nil {
|
||||
println!("{val}");
|
||||
}
|
||||
}
|
||||
if let Err(err) = self.state.execute(line) {
|
||||
crate::error(err);
|
||||
}
|
||||
let _ = std::io::stdout().flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
[package]
|
||||
name = "matrix-macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "1", features = ["full"] }
|
||||
quote = "1"
|
||||
matrix = { path = "../matrix" }
|
|
@ -1,52 +0,0 @@
|
|||
use proc_macro::TokenStream;
|
||||
use syn::{ItemFn, parse::Parse, Token, LitBool, LitInt};
|
||||
use quote::quote;
|
||||
|
||||
struct NativeFuncParams {
|
||||
arity: LitInt,
|
||||
variadic: LitBool,
|
||||
}
|
||||
|
||||
impl Parse for NativeFuncParams {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let arity = input.parse()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
let variadic = input.parse()?;
|
||||
Ok(Self { arity , variadic })
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn native_func(input: TokenStream, annotated_item: TokenStream) -> TokenStream {
|
||||
let itemfn: ItemFn = syn::parse(annotated_item).unwrap();
|
||||
|
||||
let input: NativeFuncParams = syn::parse(input).unwrap();
|
||||
let arity = input.arity;
|
||||
let variadic = input.variadic;
|
||||
|
||||
let visibility = itemfn.vis;
|
||||
let block = itemfn.block;
|
||||
let name = itemfn.sig.ident;
|
||||
let name_str = name.to_string();
|
||||
let inputs = itemfn.sig.inputs;
|
||||
let output = itemfn.sig.output;
|
||||
|
||||
assert!(itemfn.sig.constness.is_none(), "item must not be const");
|
||||
assert!(itemfn.sig.asyncness.is_none(), "item must not be async");
|
||||
assert!(itemfn.sig.unsafety.is_none(), "item must not be unsafe");
|
||||
assert!(itemfn.sig.abi.is_none(), "item must not contain an ABI specifier");
|
||||
assert!(itemfn.sig.variadic.is_none(), "item must not be variadic");
|
||||
|
||||
let expanded = quote! {
|
||||
#visibility fn #name() -> ::std::rc::Rc< ::matrix::chunk::Function> {
|
||||
::std::rc::Rc::new( ::matrix::chunk::Function {
|
||||
name: ::std::rc::Rc::from( #name_str ),
|
||||
arity: #arity,
|
||||
variadic: #variadic,
|
||||
fun: ::matrix::chunk::InnerFunction::Native(Box::new(|#inputs| #output #block))
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
[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]
|
||||
matrix = { path = "../matrix" }
|
||||
matrix-macros = { path = "../matrix-macros" }
|
|
@ -1,36 +0,0 @@
|
|||
use matrix::{value::Value, self, vm::Vm, Result};
|
||||
use matrix_macros::native_func;
|
||||
|
||||
#[native_func(1, true)]
|
||||
fn print(_vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [values] = args.try_into().unwrap();
|
||||
if let Value::List(list) = values {
|
||||
for (i, value) in list.iter().enumerate() {
|
||||
print!("{}", value.boring_print());
|
||||
if i != 0 {
|
||||
print!(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
|
||||
#[native_func(1, true)]
|
||||
fn println(_vm: &mut Vm, args: Vec<Value>) -> Result<Value> {
|
||||
let [values] = args.try_into().unwrap();
|
||||
if let Value::List(list) = values {
|
||||
for (i, value) in list.iter().enumerate() {
|
||||
print!("{}", value.boring_print());
|
||||
if i != 0 {
|
||||
print!(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
print!("\n");
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
|
||||
pub fn load(vm: &mut Vm) {
|
||||
vm.load_native_fn(print());
|
||||
vm.load_native_fn(println());
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
use matrix::vm::Vm;
|
||||
|
||||
mod io;
|
||||
|
||||
pub fn load(compiler: &mut Vm) {
|
||||
io::load(compiler);
|
||||
}
|
|
@ -31,6 +31,7 @@ pub enum BinaryOp {
|
|||
LessEquals,
|
||||
GreaterThan,
|
||||
LessThan,
|
||||
Range,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -45,7 +46,7 @@ pub enum Expr {
|
|||
|
||||
Index(Box<Expr>, Vec<Expr>),
|
||||
FnCall(Box<Expr>, Vec<Expr>),
|
||||
FieldAccess(Box<Expr>, Rc<str>),
|
||||
FieldAccess(Box<Expr>, Box<Expr>),
|
||||
|
||||
List(InlineList),
|
||||
Matrix(InlineMatrix),
|
||||
|
@ -57,8 +58,8 @@ pub enum Expr {
|
|||
Assign(Box<Expr>, Box<Expr>),
|
||||
|
||||
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
|
||||
Function(Rc<str>, Vec<Rc<str>>, Box<Expr>, bool),
|
||||
Lambda(Vec<Rc<str>>, Box<Expr>, bool),
|
||||
Function(Rc<str>, Vec<Rc<str>>, Box<Expr>),
|
||||
|
||||
|
||||
Loop(Box<Expr>),
|
||||
While(Box<Expr>, Box<Expr>),
|
||||
|
@ -177,9 +178,10 @@ pub fn optimize(expr: Expr) -> Result<Expr> {
|
|||
.map(optimize)
|
||||
.collect::<Result<Vec<Expr>>>()?)
|
||||
}
|
||||
E::FieldAccess(expr, ident) => {
|
||||
let expr = optimize(*expr)?;
|
||||
E::FieldAccess(Box::new(expr), ident)
|
||||
E::FieldAccess(key, val) => {
|
||||
let key = optimize(*key)?;
|
||||
let val = optimize(*val)?;
|
||||
E::FieldAccess(Box::new(key), Box::new(val))
|
||||
},
|
||||
E::List(list) =>
|
||||
E::List(list.into_iter()
|
||||
|
@ -280,14 +282,10 @@ pub fn optimize(expr: Expr) -> Result<Expr> {
|
|||
let block = Box::new(optimize(*block)?);
|
||||
E::Loop(block)
|
||||
},
|
||||
E::Function(ident, params, stmt, varadic) => {
|
||||
E::Function(ident, params, stmt) => {
|
||||
let stmt = Box::new(optimize(*stmt)?);
|
||||
E::Function(ident, params, stmt, varadic)
|
||||
E::Function(ident, params, stmt)
|
||||
}
|
||||
E::Lambda(params, stmt, varadic) => {
|
||||
let stmt = Box::new(optimize(*stmt)?);
|
||||
E::Lambda(params, stmt, varadic)
|
||||
},
|
||||
E::Let(ident, expr) => {
|
||||
E::Let(ident, Box::new(optimize(*expr)?))
|
||||
},
|
||||
|
@ -335,6 +333,7 @@ impl From<Token> for BinaryOp {
|
|||
Divide => Self::Divide,
|
||||
Modulo => Self::Modulo,
|
||||
Power => Self::Power,
|
||||
Range => Self::Range,
|
||||
_ => panic!("aaaaa")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{value::Value, ast::{UnaryOp, BinaryOp}, vm::Vm, Result};
|
||||
use crate::{value::Value, ast::{UnaryOp, BinaryOp}};
|
||||
use std::{fmt::{Debug, Display}, rc::Rc};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -36,30 +36,11 @@ impl Display for Chunk {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
pub name: Rc<str>,
|
||||
pub arity: usize,
|
||||
pub variadic: bool,
|
||||
pub fun: InnerFunction
|
||||
}
|
||||
|
||||
pub enum InnerFunction {
|
||||
Compiled(Rc<Chunk>),
|
||||
Native(Box<dyn Fn(&mut Vm, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub body: Chunk
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -90,8 +71,6 @@ pub enum Instruction {
|
|||
NewTable(u16),
|
||||
NewMatrix(u16, u8),
|
||||
|
||||
Field(u16),
|
||||
StoreField(u16),
|
||||
Index(u8),
|
||||
StoreIndex(u8),
|
||||
|
||||
|
@ -133,8 +112,6 @@ 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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
use std::{fmt::Display, rc::Rc, cell::RefCell};
|
||||
use crate::{ast::Expr, chunk::{Function, Instruction, InnerFunction}, chunk::{Chunk, self}, value::Value, Result};
|
||||
use crate::{ast::Expr, chunk::{Function, Instruction}, chunk::{Chunk, self}, value::Value, Result};
|
||||
|
||||
use Instruction as I;
|
||||
use Value as V;
|
||||
use Expr as E;
|
||||
|
||||
pub type NamesTable = Rc<RefCell<Vec<Rc<str>>>>;
|
||||
|
||||
pub struct CompilerBuilder<'c> {
|
||||
globals: NamesTable,
|
||||
names: NamesTable,
|
||||
globals: Rc<RefCell<Vec<Rc<str>>>>,
|
||||
repl: bool,
|
||||
debug: bool,
|
||||
name: Rc<str>,
|
||||
parent: Option<&'c Compiler<'c>>,
|
||||
parent: Option<&'c Compiler<'c>>
|
||||
}
|
||||
|
||||
impl<'c> CompilerBuilder<'c> {
|
||||
|
@ -25,7 +22,6 @@ impl<'c> CompilerBuilder<'c> {
|
|||
debug: false,
|
||||
name: "<root>".into(),
|
||||
parent: None,
|
||||
names: Rc::new(RefCell::new(Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,16 +35,11 @@ impl<'c> CompilerBuilder<'c> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn globals(mut self, globals: NamesTable) -> Self {
|
||||
pub fn globals(mut self, globals: Rc<RefCell<Vec<Rc<str>>>>) -> Self {
|
||||
self.globals = globals;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn names(mut self, names: NamesTable) -> Self {
|
||||
self.names = names;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parent(mut self, parent: &'c Compiler) -> Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
|
@ -62,7 +53,6 @@ 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,
|
||||
|
@ -83,7 +73,6 @@ pub struct Compiler<'c> {
|
|||
|
||||
locals: Vec<Rc<Local>>,
|
||||
globals: Rc<RefCell<Vec<Rc<str>>>>,
|
||||
names: Rc<RefCell<Vec<Rc<str>>>>,
|
||||
|
||||
root_is_block: bool,
|
||||
|
||||
|
@ -135,8 +124,6 @@ impl<'c> Compiler<'c> {
|
|||
CompilerBuilder::new()
|
||||
.name(name)
|
||||
.debug(self.debug)
|
||||
.globals(self.globals.clone())
|
||||
.names(self.names.clone())
|
||||
.repl(false)
|
||||
.parent(self)
|
||||
.build()
|
||||
|
@ -220,12 +207,6 @@ impl<'c> Compiler<'c> {
|
|||
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) {
|
||||
// TODO: find constant if already exists
|
||||
self.chunk.constants.push(val);
|
||||
|
@ -263,7 +244,7 @@ impl<'c> Compiler<'c> {
|
|||
|
||||
fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
|
||||
match expr {
|
||||
E::NoOp => self.emit(I::Nil),
|
||||
E::NoOp => {},
|
||||
E::If(cond, ifb, elseb) => {
|
||||
self.compile_expr(cond)?;
|
||||
let jmpidx = self.emit_temp();
|
||||
|
@ -273,14 +254,13 @@ impl<'c> Compiler<'c> {
|
|||
self.compile_expr(elseb)?;
|
||||
}
|
||||
},
|
||||
E::Function(name, params, body, varadic) => {
|
||||
E::Function(name, params, body) => {
|
||||
let chunk = self.compile_function(name.clone(), params, body)?;
|
||||
let fun = Value::Function(Rc::new(
|
||||
chunk::Function {
|
||||
name: name.clone(),
|
||||
arity: params.len(),
|
||||
fun: InnerFunction::Compiled(chunk.into()),
|
||||
variadic: *varadic
|
||||
body: chunk
|
||||
}
|
||||
));
|
||||
self.emit_const(fun);
|
||||
|
@ -293,19 +273,6 @@ impl<'c> Compiler<'c> {
|
|||
self.emit(I::CreateLocal);
|
||||
}
|
||||
},
|
||||
E::Lambda(params, body, varadic) => {
|
||||
let name: Rc<str> = Rc::from("<lambda>");
|
||||
let chunk = self.compile_function(name.clone(), params, body)?;
|
||||
let fun = Value::Function(Rc::new(
|
||||
chunk::Function {
|
||||
name: name.clone(),
|
||||
arity: params.len(),
|
||||
fun: InnerFunction::Compiled(chunk.into()),
|
||||
variadic: *varadic
|
||||
}
|
||||
));
|
||||
self.emit_const(fun);
|
||||
},
|
||||
E::Loop(expr) => {
|
||||
let idx = self.cur();
|
||||
self.loop_top.push((idx as usize, self.scopes.len()));
|
||||
|
@ -383,9 +350,7 @@ impl<'c> Compiler<'c> {
|
|||
},
|
||||
E::Literal(val) => self.compile_value(val),
|
||||
E::Ident(name) => {
|
||||
if name.as_ref() == "_" {
|
||||
self.emit(I::Nil);
|
||||
} else if let Some(local) = self.find_local(name) {
|
||||
if let Some(local) = self.find_local(name) {
|
||||
self.emit(I::LoadLocal(local.idx as u16));
|
||||
} else if let Some(global) = self.find_global(name) {
|
||||
self.emit(I::LoadGlobal(global as u16));
|
||||
|
@ -397,7 +362,7 @@ impl<'c> Compiler<'c> {
|
|||
self.compile_expr(rhs)?;
|
||||
self.emit(I::Dup);
|
||||
match lhs.as_ref() {
|
||||
E::Ident(name) if name.as_ref() != "_" => {
|
||||
E::Ident(name) => {
|
||||
if let Some(local) = self.find_local(&name) {
|
||||
self.emit(I::StoreLocal(local.idx as u16));
|
||||
} else if let Some(global) = self.find_global(&name) {
|
||||
|
@ -410,18 +375,6 @@ 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())
|
||||
}
|
||||
}
|
||||
|
@ -434,13 +387,7 @@ impl<'c> Compiler<'c> {
|
|||
self.compile_expr(rhs)?;
|
||||
self.emit(I::BinaryOp(*op));
|
||||
},
|
||||
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::Index(_, _) => return Err(self::Error::NotImplemented("indexing").into()),
|
||||
E::FnCall(fun, params) => {
|
||||
for expr in params {
|
||||
self.compile_expr(expr)?;
|
||||
|
@ -448,11 +395,7 @@ impl<'c> Compiler<'c> {
|
|||
self.compile_expr(fun)?;
|
||||
self.emit(I::Call(params.len() as u8));
|
||||
},
|
||||
E::FieldAccess(expr, field) => {
|
||||
self.compile_expr(expr)?;
|
||||
let idx = self.get_name(field.clone());
|
||||
self.emit(I::Field(idx as u16))
|
||||
}
|
||||
E::FieldAccess(_, _) => return Err(self::Error::NotImplemented("filed access").into()),
|
||||
E::List(list) => {
|
||||
for expr in list {
|
||||
self.compile_expr(expr)?;
|
||||
|
@ -560,7 +503,7 @@ impl<'c> Compiler<'c> {
|
|||
self.chunk = Chunk::new();
|
||||
self.compile_expr(body)?;
|
||||
self.finish()?;
|
||||
let fun = Function { name: self.name.clone(), fun: InnerFunction::Compiled(self.chunk.clone().into()), arity: 0, variadic: false };
|
||||
let fun = Function { name: self.name.clone(), body: self.chunk.clone(), arity: 0 };
|
||||
Ok(Rc::new(fun))
|
||||
}
|
||||
}
|
||||
|
|
134
matrix/src/gc.rs
134
matrix/src/gc.rs
|
@ -1,126 +1,112 @@
|
|||
use std::{ops::{Index, IndexMut, Deref, DerefMut}, marker::PhantomData, ptr::NonNull, fmt::{Debug, Display}};
|
||||
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;
|
||||
|
||||
pub struct Gc<T> {
|
||||
ptr: NonNull<GcInner<T>>,
|
||||
phantom: PhantomData<GcInner<T>>
|
||||
phantom: PhantomData<GcInner<T>>,
|
||||
}
|
||||
|
||||
struct GcInner<T> {
|
||||
pub struct GcInner<T> {
|
||||
rc: usize,
|
||||
data: T
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T> Gc<T> {
|
||||
pub fn new(data: T) -> Self {
|
||||
pub fn new(data: T) -> Gc<T> {
|
||||
let boxed = Box::new(GcInner {
|
||||
rc: 1,
|
||||
data,
|
||||
});
|
||||
Self {
|
||||
ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
|
||||
phantom: PhantomData
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Clone> Gc<T> {
|
||||
pub fn clone_inside(&self) -> Self {
|
||||
unsafe {
|
||||
let data = self.ptr.as_ref().data.clone();
|
||||
Self::new(data)
|
||||
}
|
||||
impl<T: Clone> From<Rc<T>> for Gc<T> {
|
||||
fn from(value: Rc<T>) -> Self {
|
||||
Self::new(Rc::unwrap_or_clone(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Gc<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Gc::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IndexMut<Idx>, Idx> IndexMut<Idx> for Gc<T> {
|
||||
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
|
||||
self.deref_mut().index_mut(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Index<Idx>, Idx> Index<Idx> for Gc<T> {
|
||||
type Output = T::Output;
|
||||
|
||||
fn index(&self, index: Idx) -> &Self::Output {
|
||||
self.deref().index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Gc<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe {
|
||||
&mut self.ptr.as_mut().data
|
||||
}
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Gc<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe {
|
||||
&self.ptr.as_ref().data
|
||||
}
|
||||
fn deref(&self) -> &T {
|
||||
let inner = unsafe { self.ptr.as_ref() };
|
||||
&inner.data
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: PartialEq> PartialEq for Gc<T> {
|
||||
impl<T: Debug> Debug 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: 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> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.deref().eq(other.deref())
|
||||
let inner = unsafe { self.ptr.as_ref() };
|
||||
let other = unsafe { other.ptr.as_ref() };
|
||||
inner.data == other.data
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Iterator> Iterator for Gc<T> {
|
||||
type Item = T::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.deref_mut().next()
|
||||
impl<T: PartialOrd> PartialOrd for Gc<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
let inner = unsafe { self.ptr.as_ref() };
|
||||
let other = unsafe { other.ptr.as_ref() };
|
||||
inner.data.partial_cmp(&other.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq> Eq for Gc<T> {}
|
||||
impl<T: Clone> DerefMut 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> {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
let inner = self.ptr.as_ptr().as_mut().unwrap();
|
||||
inner.rc += 1;
|
||||
|
||||
Self {
|
||||
ptr: self.ptr,
|
||||
phantom: PhantomData
|
||||
}
|
||||
let inner = unsafe { self.ptr.as_ptr().as_mut().unwrap() };
|
||||
inner.rc += 1;
|
||||
Self {
|
||||
ptr: self.ptr,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Gc<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let inner = self.ptr.as_mut();
|
||||
if inner.rc > 1 {
|
||||
inner.rc -= 1;
|
||||
} else {
|
||||
let _ = Box::from_raw(self.ptr.as_ptr());
|
||||
}
|
||||
let inner = unsafe { self.ptr.as_mut() };
|
||||
inner.rc -= 1;
|
||||
if inner.rc > 0 {
|
||||
return;
|
||||
}
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,9 @@ pub enum Token {
|
|||
LeftBrack,
|
||||
RightBrack,
|
||||
LeftBrace,
|
||||
LeftLeftBrace,
|
||||
RightBrace,
|
||||
RightRightBrace,
|
||||
Assign,
|
||||
Access,
|
||||
SemiColon,
|
||||
|
@ -46,17 +48,6 @@ pub enum Token {
|
|||
ThinArrow,
|
||||
Comma,
|
||||
Range,
|
||||
Colon,
|
||||
Backslash,
|
||||
Varadic,
|
||||
|
||||
// math
|
||||
Regex(RegexToken),
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Complex(f64),
|
||||
String(Rc<str>),
|
||||
Ident(Rc<str>),
|
||||
|
||||
// equality
|
||||
Equal,
|
||||
|
@ -76,6 +67,14 @@ pub enum Token {
|
|||
BitwiseOr,
|
||||
BitwiseXor,
|
||||
|
||||
// math
|
||||
Regex(RegexToken),
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Complex(f64),
|
||||
String(Rc<str>),
|
||||
Ident(Rc<str>),
|
||||
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
|
@ -83,22 +82,6 @@ pub enum Token {
|
|||
Modulo,
|
||||
Power,
|
||||
|
||||
AssignAnd,
|
||||
AssignOr,
|
||||
|
||||
AssignBitwiseShiftLeft,
|
||||
AssignBitwiseShiftRight,
|
||||
AssignBitwiseAnd,
|
||||
AssignBitwiseOr,
|
||||
AssignBitwiseXor,
|
||||
|
||||
AssignAdd,
|
||||
AssignSubtract,
|
||||
AssignMultiply,
|
||||
AssignDivide,
|
||||
AssignModulo,
|
||||
AssignPower,
|
||||
|
||||
// keywords
|
||||
If,
|
||||
Else,
|
||||
|
@ -210,7 +193,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();
|
||||
}
|
||||
}
|
||||
|
@ -437,63 +420,42 @@ impl Lexer {
|
|||
}
|
||||
|
||||
Ok(match char {
|
||||
'\n' => SemiColon,
|
||||
'(' => LeftParen,
|
||||
')' => RightParen,
|
||||
'[' => LeftBrack,
|
||||
']' => RightBrack,
|
||||
'{' => LeftBrace,
|
||||
'}' => RightBrace,
|
||||
':' => Colon,
|
||||
'\\' => Backslash,
|
||||
'{' => {
|
||||
match next {
|
||||
'{' => {
|
||||
self.next();
|
||||
LeftLeftBrace
|
||||
}
|
||||
_ => LeftBrace
|
||||
}
|
||||
},
|
||||
'}' => {
|
||||
match next {
|
||||
'}' => {
|
||||
self.next();
|
||||
RightRightBrace
|
||||
}
|
||||
_ => RightBrace
|
||||
}
|
||||
},
|
||||
';' => SemiColon,
|
||||
'+' => {
|
||||
match next {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignAdd
|
||||
}
|
||||
_ => Add
|
||||
}
|
||||
},
|
||||
'/' => {
|
||||
match next {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignDivide
|
||||
}
|
||||
_ => Divide
|
||||
}
|
||||
},
|
||||
'%' => {
|
||||
match next {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignModulo
|
||||
}
|
||||
_ => Modulo
|
||||
}
|
||||
},
|
||||
'+' => Add,
|
||||
',' => Comma,
|
||||
'*' => {
|
||||
match next {
|
||||
'*' => {
|
||||
self.next();
|
||||
match self.peek() {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignPower
|
||||
},
|
||||
_ => Power
|
||||
}
|
||||
},
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignMultiply
|
||||
Power
|
||||
}
|
||||
_ => Multiply
|
||||
}
|
||||
},
|
||||
'/' => Divide,
|
||||
'%' => Modulo,
|
||||
'!' => {
|
||||
match next {
|
||||
'=' => {
|
||||
|
@ -507,18 +469,8 @@ impl Lexer {
|
|||
match next {
|
||||
'&' => {
|
||||
self.next();
|
||||
match self.peek() {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignAnd
|
||||
},
|
||||
_ => And
|
||||
}
|
||||
},
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignBitwiseAnd
|
||||
},
|
||||
And
|
||||
}
|
||||
_ => BitwiseAnd
|
||||
}
|
||||
},
|
||||
|
@ -526,18 +478,8 @@ impl Lexer {
|
|||
match next {
|
||||
'|' => {
|
||||
self.next();
|
||||
match self.peek() {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignOr
|
||||
},
|
||||
_ => Or
|
||||
}
|
||||
},
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignBitwiseOr
|
||||
},
|
||||
Or
|
||||
}
|
||||
_ => BitwiseOr
|
||||
}
|
||||
},
|
||||
|
@ -546,11 +488,7 @@ impl Lexer {
|
|||
'>' => {
|
||||
self.next();
|
||||
ThinArrow
|
||||
},
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignSubtract
|
||||
},
|
||||
}
|
||||
_ => Subtract
|
||||
}
|
||||
},
|
||||
|
@ -571,13 +509,7 @@ impl Lexer {
|
|||
match next {
|
||||
'>' => {
|
||||
self.next();
|
||||
match self.peek() {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignBitwiseShiftRight
|
||||
},
|
||||
_ => BitwiseShiftRight
|
||||
}
|
||||
BitwiseShiftRight
|
||||
}
|
||||
'=' => {
|
||||
self.next();
|
||||
|
@ -590,13 +522,7 @@ impl Lexer {
|
|||
match next {
|
||||
'<' => {
|
||||
self.next();
|
||||
match self.peek() {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignBitwiseShiftLeft
|
||||
},
|
||||
_ => BitwiseShiftLeft
|
||||
}
|
||||
BitwiseShiftLeft
|
||||
}
|
||||
'=' => {
|
||||
self.next();
|
||||
|
@ -605,15 +531,7 @@ impl Lexer {
|
|||
_ => LessThan
|
||||
}
|
||||
},
|
||||
'^' => {
|
||||
match next {
|
||||
'=' => {
|
||||
self.next();
|
||||
AssignBitwiseXor
|
||||
},
|
||||
_ => BitwiseXor
|
||||
}
|
||||
}
|
||||
'^' => BitwiseXor,
|
||||
'\'' | '\"' => String(self.lex_string(char)?),
|
||||
'r' => {
|
||||
match next {
|
||||
|
@ -630,14 +548,7 @@ impl Lexer {
|
|||
},
|
||||
'.' => {
|
||||
if next == '.' {
|
||||
self.next();
|
||||
match self.peek() {
|
||||
'.' => {
|
||||
self.next();
|
||||
Varadic
|
||||
},
|
||||
_ => Range
|
||||
}
|
||||
Range
|
||||
} else if next.is_digit(10) {
|
||||
self.lex_number(char)?
|
||||
} else {
|
||||
|
|
|
@ -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}, value::{Value, self}, Result};
|
||||
use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, optimize}, gc::Gc, value::{Value, self}, Result};
|
||||
|
||||
use Value as V;
|
||||
use Expr as E;
|
||||
|
@ -40,7 +40,7 @@ pub enum Error {
|
|||
UnexpectedToken(Token),
|
||||
ExpectedToken(Token),
|
||||
ExpectedTokenName(&'static str),
|
||||
MatrixInvDomain(usize, usize, usize),
|
||||
MatrixCoDomainError(usize, usize, usize),
|
||||
NotAssignable(Expr),
|
||||
ValueError(value::Error),
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ impl Display for Error {
|
|||
UnexpectedToken(tok) => write!(f, "Unexpected token: '{tok:?}'"),
|
||||
ExpectedToken(tok) => write!(f, "Expected token: '{tok:?}'"),
|
||||
ExpectedTokenName(name) => write!(f, "Expected {name} token"),
|
||||
MatrixInvDomain(row, should, was) => write!(f, "In row {row} of matrix, domain was expected to be {should} but was given {was}"),
|
||||
MatrixCoDomainError(row, should, was) => write!(f, "In col {row} of matrix, codomain was expected to be {should} but was given {was}"),
|
||||
NotAssignable(expr) => write!(f, "{expr:?} is not assignable"),
|
||||
ValueError(err) => write!(f, "{err}"),
|
||||
}
|
||||
|
@ -199,11 +199,11 @@ impl Parser {
|
|||
if parts.len() == 1 {
|
||||
Ok(E::List(parts.pop().unwrap()))
|
||||
} else {
|
||||
let codomain = parts.len();
|
||||
let domain = parts[0].len();
|
||||
let codomain = parts[0].len();
|
||||
let domain = parts.len();
|
||||
for (i, part) in parts.iter().enumerate() {
|
||||
if part.len() != codomain {
|
||||
return Err(Error::MatrixInvDomain(i, domain, part.len()).into())
|
||||
return Err(Error::MatrixCoDomainError(i, codomain, part.len()).into())
|
||||
}
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
|
@ -230,10 +230,9 @@ impl Parser {
|
|||
}
|
||||
|
||||
fn parse_table(&mut self) -> Result<Expr> {
|
||||
self.force_token(T::Colon)?;
|
||||
self.force_token(T::LeftBrace)?;
|
||||
self.force_token(T::LeftLeftBrace)?;
|
||||
let mut table = Vec::new();
|
||||
if self.lexer.peek_token()? == T::RightBrace {
|
||||
if self.lexer.peek_token()? == T::RightRightBrace {
|
||||
self.lexer.next_token()?;
|
||||
return Ok(E::Table(table))
|
||||
}
|
||||
|
@ -245,7 +244,7 @@ impl Parser {
|
|||
let next = self.lexer.next_token()?;
|
||||
match next {
|
||||
T::Comma => continue,
|
||||
T::RightBrace => break,
|
||||
T::RightRightBrace => break,
|
||||
_ => return Err(Error::UnexpectedToken(next).into())
|
||||
}
|
||||
}
|
||||
|
@ -259,29 +258,20 @@ impl Parser {
|
|||
Ok(expr)
|
||||
}
|
||||
|
||||
fn parse_params(&mut self) -> Result<(Vec<Rc<str>>, bool)> {
|
||||
fn parse_params(&mut self) -> Result<Vec<Rc<str>>> {
|
||||
use T::*;
|
||||
let tok = self.lexer.next_token()?;
|
||||
match tok {
|
||||
Ident(ident) => {
|
||||
let params = vec![ident];
|
||||
if self.lexer.peek_token()? == T::Varadic {
|
||||
self.lexer.next_token()?;
|
||||
return Ok((params, true))
|
||||
} else {
|
||||
return Ok((params, false))
|
||||
}
|
||||
}
|
||||
Ident(ident) => return Ok(vec![ident]),
|
||||
LeftParen => (),
|
||||
_ => return Err(Error::UnexpectedToken(tok).into()),
|
||||
}
|
||||
|
||||
let mut params = Vec::new();
|
||||
let mut varadic = false;
|
||||
|
||||
if self.lexer.peek_token()? == T::RightParen {
|
||||
self.lexer.next_token()?;
|
||||
return Ok((params, varadic));
|
||||
return Ok(params);
|
||||
}
|
||||
|
||||
loop {
|
||||
|
@ -289,18 +279,13 @@ impl Parser {
|
|||
params.push(ident);
|
||||
let next = self.lexer.next_token()?;
|
||||
match next {
|
||||
Varadic => {
|
||||
varadic = true;
|
||||
self.force_token(T::RightParen)?;
|
||||
break;
|
||||
}
|
||||
Comma => continue,
|
||||
RightParen => break,
|
||||
_ => return Err(Error::UnexpectedToken(next).into()),
|
||||
}
|
||||
}
|
||||
|
||||
Ok((params, varadic))
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
fn parse_ident(&mut self) -> Result<Rc<str>> {
|
||||
|
@ -322,23 +307,12 @@ impl Parser {
|
|||
fn parse_function(&mut self) -> Result<Expr> {
|
||||
self.force_token(T::Function)?;
|
||||
let ident = self.parse_ident()?;
|
||||
let (params, varadic) = match self.lexer.peek_token()? {
|
||||
T::LeftBrace => (vec![], false),
|
||||
let params = match self.lexer.peek_token()? {
|
||||
T::LeftBrace => vec![],
|
||||
_ => self.parse_params()?,
|
||||
};
|
||||
let expr = self.parse_expr()?;
|
||||
Ok(E::Function(ident, params, Box::new(expr), varadic))
|
||||
}
|
||||
|
||||
fn parse_lambda(&mut self) -> Result<Expr> {
|
||||
self.force_token(T::Backslash)?;
|
||||
let (params, varadic) = match self.lexer.peek_token()? {
|
||||
T::Arrow => (vec![], false),
|
||||
_ => self.parse_params()?,
|
||||
};
|
||||
self.force_token(T::Arrow)?;
|
||||
let expr = self.parse_expr()?;
|
||||
Ok(E::Lambda(params, Box::new(expr), varadic))
|
||||
Ok(E::Function(ident, params, Box::new(expr)))
|
||||
}
|
||||
|
||||
fn parse_do_while(&mut self) -> Result<Expr> {
|
||||
|
@ -412,7 +386,7 @@ impl Parser {
|
|||
match next {
|
||||
T::SemiColon => continue,
|
||||
T::RightBrace => break,
|
||||
_ => return Err(Error::ExpectedToken(T::SemiColon).into())
|
||||
_ => return Err(Error::UnexpectedToken(next).into())
|
||||
}
|
||||
}
|
||||
if self.lexer.peek_token()? == T::RightBrace {
|
||||
|
@ -428,7 +402,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(Rc::new(r.into()))),
|
||||
T::Regex(r) => E::Literal(V::Regex(Gc::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)),
|
||||
|
@ -441,7 +415,6 @@ impl Parser {
|
|||
use T::*;
|
||||
match self.lexer.peek_token()? {
|
||||
Function => self.parse_function(),
|
||||
Backslash => self.parse_lambda(),
|
||||
Do => self.parse_do_while(),
|
||||
While => self.parse_while(),
|
||||
Let => self.parse_let(),
|
||||
|
@ -458,7 +431,7 @@ impl Parser {
|
|||
Ok(E::Continue)
|
||||
},
|
||||
LeftBrack => self.parse_matrix(),
|
||||
Colon => self.parse_table(),
|
||||
LeftLeftBrace => self.parse_table(),
|
||||
LeftParen => self.parse_paren(),
|
||||
_ => self.parse_value(),
|
||||
}
|
||||
|
@ -471,8 +444,8 @@ impl Parser {
|
|||
match tok {
|
||||
T::Access => {
|
||||
self.force_token(T::Access)?;
|
||||
let temp = self.parse_ident()?;
|
||||
expr = E::FieldAccess(Box::new(expr), temp);
|
||||
let temp = self.parse_term()?;
|
||||
expr = E::FieldAccess(Box::new(expr), Box::new(temp));
|
||||
},
|
||||
_ => break
|
||||
}
|
||||
|
@ -590,66 +563,13 @@ impl Parser {
|
|||
}
|
||||
|
||||
fn parse_expr(&mut self) -> Result<Expr> {
|
||||
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.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)))
|
||||
},
|
||||
E::Assign(Box::new(expr),Box::new(self.parse_expr()?))
|
||||
}
|
||||
_ => expr
|
||||
})
|
||||
}
|
||||
|
@ -667,11 +587,6 @@ impl Parser {
|
|||
};
|
||||
let expr = self.parse_expr()?;
|
||||
block.push(expr);
|
||||
match self.lexer.next_token()? {
|
||||
T::Eof => break,
|
||||
T::SemiColon => continue,
|
||||
_ => return Err(Error::ExpectedToken(T::SemiColon).into())
|
||||
};
|
||||
}
|
||||
Ok(E::Block(block))
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use num_complex::Complex64;
|
|||
use num_rational::Rational64;
|
||||
use regex::Regex;
|
||||
|
||||
use crate::{ast::{Expr, BinaryOp, UnaryOp}, chunk::Function, Result, gc::Gc};
|
||||
use crate::{ast::{Expr, BinaryOp, UnaryOp}, gc::Gc, chunk::Function, Result};
|
||||
|
||||
pub type List = Vec<Value>;
|
||||
pub type Matrix = (usize, usize, Vec<Value>);
|
||||
|
@ -43,14 +43,12 @@ pub enum Error {
|
|||
Exponent(Value, Value),
|
||||
Compare(Value, Value),
|
||||
IndexOutOfBounds(usize, usize),
|
||||
CannotIndex(Value),
|
||||
BadIndex(Value, Value),
|
||||
Index(Value, Value),
|
||||
Concat(Value, Value),
|
||||
Bitwise(Value, Value),
|
||||
DivideByZero,
|
||||
ZeroExpZero,
|
||||
CannotHash(Value),
|
||||
FieldAccess(Value),
|
||||
}
|
||||
|
||||
impl Display for self::Error {
|
||||
|
@ -66,14 +64,12 @@ 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}"),
|
||||
BadIndex(a, b) => write!(f, "cannot index {a:?} with {b:?}"),
|
||||
CannotIndex(a) => write!(f, "cannot index {a:?}"),
|
||||
Index(a, b) => write!(f, "cannot index {a:?} with {b:?}"),
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,8 +84,8 @@ pub enum Value {
|
|||
Float(f64),
|
||||
Ratio(Rational64),
|
||||
Complex(Complex64),
|
||||
Regex(Rc<Regex>),
|
||||
String(Rc<String>),
|
||||
Regex(Gc<Regex>),
|
||||
String(Gc<String>),
|
||||
List(Gc<List>),
|
||||
Matrix(Gc<Matrix>),
|
||||
Table(Gc<Table>),
|
||||
|
@ -157,35 +153,36 @@ 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 = "\n".to_string();
|
||||
for row in m.2.chunks(m.0) {
|
||||
str.push_str(" ");
|
||||
for (i, v) in row.iter().enumerate() {
|
||||
if i != 0 {
|
||||
str.push(' ');
|
||||
let mut str = "[[ ".to_string();
|
||||
for (i, el) in m.2.iter().enumerate() {
|
||||
if i != 0 {
|
||||
if (i % m.1) == 0 {
|
||||
str.push_str(" ; ");
|
||||
} else {
|
||||
str.push_str(" ");
|
||||
}
|
||||
str.push_str(&v.boring_print());
|
||||
}
|
||||
str.push('\n');
|
||||
str.push_str(&el.boring_print());
|
||||
}
|
||||
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(", ");
|
||||
|
@ -194,11 +191,11 @@ impl Value {
|
|||
str.push_str(" = ");
|
||||
str.push_str(&val.boring_print());
|
||||
}
|
||||
str.push_str("}");
|
||||
str.push_str(" }}");
|
||||
str
|
||||
},
|
||||
Function(fun) => {
|
||||
format!("{fun:?}")
|
||||
format!("[Function: {}]", fun.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,32 +212,33 @@ 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 = "\n".to_string();
|
||||
for row in m.2.chunks(m.0) {
|
||||
str.push_str(" ");
|
||||
for (i, v) in row.iter().enumerate() {
|
||||
if i != 0 {
|
||||
str.push(' ');
|
||||
let mut str = "[[ ".to_string();
|
||||
for (i, el) in m.2.iter().enumerate() {
|
||||
if i != 0 {
|
||||
if (i % m.1) == 0 {
|
||||
str.push_str(" ; ");
|
||||
} else {
|
||||
str.push_str(" ");
|
||||
}
|
||||
str.push_str(&v.pretty_print());
|
||||
}
|
||||
str.push('\n');
|
||||
str.push_str(&el.pretty_print());
|
||||
}
|
||||
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(", ");
|
||||
|
@ -249,12 +247,12 @@ impl Value {
|
|||
str.push_str(" = ");
|
||||
str.push_str(&val.pretty_print());
|
||||
}
|
||||
str.push_str("}");
|
||||
str.push_str(" }}");
|
||||
str
|
||||
},
|
||||
Function(_) => {
|
||||
format!("\x1b[36m{}\x1b[0m", self.boring_print())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,10 +295,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(Rc::new(
|
||||
(String(str), value) => Ok(String(Gc::new(
|
||||
format!("{str}{}", value.boring_print())
|
||||
))),
|
||||
(value, String(str)) => Ok(String(Rc::new(
|
||||
(value, String(str)) => Ok(String(Gc::new(
|
||||
format!("{}{str}", value.boring_print())
|
||||
))),
|
||||
(List(mut l1), List(l2)) => {
|
||||
|
@ -422,18 +420,28 @@ fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> {
|
|||
}
|
||||
|
||||
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)),
|
||||
(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"),
|
||||
(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> {
|
||||
use Value::*;
|
||||
if let (Ratio(x), Int(y)) = (&self, &rhs) {
|
||||
|
@ -447,16 +455,6 @@ impl Value {
|
|||
(l, r) => Err(Error::Exponent(l, r).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_inside(&self) -> Self {
|
||||
use Value as V;
|
||||
match self {
|
||||
V::List(l) => V::List(l.clone_inside()),
|
||||
V::Table(t) => V::Table(t.clone_inside()),
|
||||
V::Matrix(m) => V::Matrix(m.clone_inside()),
|
||||
_ => self.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Value {}
|
||||
|
@ -520,123 +518,24 @@ impl Value {
|
|||
.map_or_else(|| Err(Error::Compare(self.clone(), other.clone()).into()), 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 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 store_index(&self, _other: &Vec<Self>, _value: &Self) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
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()))
|
||||
}
|
||||
_ => return Err(self::Error::CannotIndex(self.clone()).into())
|
||||
}
|
||||
}
|
||||
|
||||
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 = 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 index(&self, _other: &Vec<Self>) -> Result<Self> {
|
||||
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()))
|
||||
//}
|
||||
}
|
||||
|
||||
pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
|
||||
use BinaryOp::*;
|
||||
|
@ -658,6 +557,7 @@ impl Value {
|
|||
LessEquals => Ok(Self::Bool(lhs <= rhs)),
|
||||
GreaterThan => Ok(Self::Bool(lhs > rhs)),
|
||||
LessThan => Ok(Self::Bool(lhs < rhs)),
|
||||
Range => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
152
matrix/src/vm.rs
152
matrix/src/vm.rs
|
@ -1,5 +1,5 @@
|
|||
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}, gc::Gc, chunk::{Function, Instruction, Chunk, InnerFunction}, Result, compiler::NamesTable};
|
||||
use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap};
|
||||
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
@ -7,7 +7,6 @@ pub enum Error {
|
|||
NotFunction(Value),
|
||||
InvArity(usize, usize, Rc<str>),
|
||||
UndefinedGlobal(Rc<str>),
|
||||
ExecNative,
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
@ -20,7 +19,6 @@ impl Display for Error {
|
|||
NotFunction(v) => write!(f, "{v:?} is not a function"),
|
||||
InvArity(wanted, had, name) => write!(f, "function {name} takes {wanted} params but was given {had}"),
|
||||
UndefinedGlobal(name) => write!(f, "{name} is not defined"),
|
||||
ExecNative => write!(f, "cannot execute a native function"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,36 +88,26 @@ impl<T> Index<usize> for Stack<T> {
|
|||
}
|
||||
|
||||
struct StackFrame {
|
||||
#[allow(dead_code)]
|
||||
name: Rc<str>,
|
||||
body: Rc<Chunk>,
|
||||
fun: Rc<Function>,
|
||||
ip: usize,
|
||||
bp: usize,
|
||||
}
|
||||
|
||||
impl StackFrame {
|
||||
fn new(vm: &Vm, name: Rc<str>, body: Rc<Chunk>, arity: usize) -> Self {
|
||||
fn new(vm: &Vm, fun: Rc<Function>) -> Self {
|
||||
Self {
|
||||
name,
|
||||
body,
|
||||
bp: vm.stack.len() - arity,
|
||||
bp: vm.stack.len() - fun.arity,
|
||||
ip: 0,
|
||||
fun,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Interupt {
|
||||
KeyboardInterupt = 1
|
||||
}
|
||||
|
||||
pub struct Vm {
|
||||
stack: Stack<Value>,
|
||||
locals: Stack<Value>,
|
||||
frames: Vec<StackFrame>,
|
||||
globals: HashMap<u16, Value>,
|
||||
names: NamesTable,
|
||||
global_names: NamesTable,
|
||||
interupt: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
|
@ -132,66 +120,26 @@ impl Vm {
|
|||
self.stack.pop()
|
||||
}
|
||||
|
||||
pub fn names(&self) -> NamesTable {
|
||||
self.names.clone()
|
||||
}
|
||||
|
||||
pub fn global_names(&self) -> NamesTable {
|
||||
self.global_names.clone()
|
||||
}
|
||||
|
||||
pub fn interupt(&self) -> Arc<AtomicUsize> {
|
||||
self.interupt.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())),
|
||||
global_names: Rc::new(RefCell::new(Vec::new())),
|
||||
interupt: Arc::new(AtomicUsize::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_native_fn(&mut self, fun: Rc<Function>) {
|
||||
let idx = self.global_names.borrow().len();
|
||||
self.global_names.borrow_mut().push(fun.name.clone());
|
||||
self.globals.insert(idx as u16, Value::Function(fun));
|
||||
}
|
||||
|
||||
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())
|
||||
};
|
||||
Ok(StackFrame::new(
|
||||
self,
|
||||
fun.name.clone(),
|
||||
compiled_chunk.clone(),
|
||||
fun.arity
|
||||
))
|
||||
}
|
||||
|
||||
fn check_interupt(&self) -> bool {
|
||||
self.interupt.load(Ordering::Relaxed) != 0
|
||||
}
|
||||
|
||||
pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> {
|
||||
let mut frame = self.init_frame(fun)?;
|
||||
self.interupt.store(0, Ordering::SeqCst);
|
||||
|
||||
let mut frame = StackFrame::new(&self, fun);
|
||||
loop {
|
||||
use Instruction::*;
|
||||
let ins = frame.body.code[frame.ip].clone();
|
||||
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.locals[frame.bp + idx as usize] = self.pop(),
|
||||
StoreLocal(idx) => self.stack[frame.bp + idx as usize] = self.pop(),
|
||||
DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
|
||||
LoadGlobal(idx) => {
|
||||
let val = self.globals
|
||||
|
@ -204,7 +152,7 @@ impl Vm {
|
|||
let val = self.pop();
|
||||
self.globals.insert(idx, val);
|
||||
},
|
||||
Const(idx) => self.push(frame.body.constants[idx as usize].clone()),
|
||||
Const(idx) => self.push(frame.fun.body.constants[idx as usize].clone()),
|
||||
Int(i) => self.push(Value::Int(i as i64)),
|
||||
True => self.push(Value::Bool(true)),
|
||||
False => self.push(Value::Bool(false)),
|
||||
|
@ -239,24 +187,25 @@ impl Vm {
|
|||
let domain = list.len() / codomain;
|
||||
self.push(Value::Matrix(Gc::new((domain, codomain, list.inner))));
|
||||
}
|
||||
Jump(idx) => {
|
||||
if self.check_interupt() {
|
||||
return Ok(Value::Nil)
|
||||
}
|
||||
frame.ip = idx as usize;
|
||||
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.check_interupt() {
|
||||
return Ok(Value::Nil)
|
||||
}
|
||||
if !!self.pop() {
|
||||
frame.ip = idx as usize;
|
||||
}
|
||||
},
|
||||
JumpFalse(idx) => {
|
||||
if self.check_interupt() {
|
||||
return Ok(Value::Nil)
|
||||
}
|
||||
if !self.pop() {
|
||||
frame.ip = idx as usize;
|
||||
}
|
||||
|
@ -266,38 +215,14 @@ impl Vm {
|
|||
let Value::Function(fun) = fun else {
|
||||
return Err(Error::NotFunction(fun).into())
|
||||
};
|
||||
let arity = arity as usize;
|
||||
let normal_args = if fun.variadic { fun.arity - 1 } else { fun.arity };
|
||||
if (fun.variadic && arity < normal_args) || (!fun.variadic && arity != normal_args) {
|
||||
return Err(Error::InvArity(normal_args, arity as usize, fun.name.clone()).into())
|
||||
}
|
||||
if fun.variadic {
|
||||
if arity == normal_args {
|
||||
self.push(Value::List(vec![].into()));
|
||||
} else if arity > normal_args {
|
||||
let count = arity - normal_args;
|
||||
let varadic_params = self.stack.split_off(self.stack.len() - count).inner;
|
||||
self.push(Value::List(varadic_params.into()));
|
||||
}
|
||||
}
|
||||
let name = fun.name.clone();
|
||||
match &fun.fun {
|
||||
InnerFunction::Compiled(body) => {
|
||||
let new_frame = StackFrame::new(self, name, body.clone(), fun.arity);
|
||||
self.frames.push(frame);
|
||||
frame = new_frame;
|
||||
},
|
||||
InnerFunction::Native(native_fun) => {
|
||||
let params = self.stack.split_off(self.stack.len() - fun.arity).inner;
|
||||
let res = native_fun(self, params)?;
|
||||
self.stack.push(res);
|
||||
}
|
||||
if fun.arity != arity as usize {
|
||||
return Err(Error::InvArity(fun.arity, arity as usize, fun.name.clone()).into())
|
||||
}
|
||||
let new_frame = StackFrame::new(&self, fun);
|
||||
self.frames.push(frame);
|
||||
frame = new_frame;
|
||||
},
|
||||
Return => {
|
||||
if self.check_interupt() {
|
||||
return Ok(Value::Nil)
|
||||
}
|
||||
let Some(prev_frame) = self.frames.pop() else {
|
||||
break;
|
||||
};
|
||||
|
@ -306,29 +231,6 @@ 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())
|
||||
|
|
Loading…
Reference in a new issue