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",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -138,16 +138,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
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]]
|
[[package]]
|
||||||
name = "endian-type"
|
name = "endian-type"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -229,29 +219,10 @@ name = "matrix-bin"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"ctrlc",
|
|
||||||
"matrix",
|
"matrix",
|
||||||
"matrix-stdlib",
|
|
||||||
"rustyline",
|
"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]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.1"
|
version = "2.7.1"
|
||||||
|
@ -432,17 +403,6 @@ version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.48"
|
version = "2.0.48"
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [ "matrix", "matrix-bin" , "matrix-macros", "matrix-stdlib"]
|
members = [ "matrix", "matrix-bin" ]
|
||||||
|
|
|
@ -9,7 +9,5 @@ path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4", features = [ "derive" ] }
|
clap = { version = "4", features = [ "derive" ] }
|
||||||
ctrlc = "3"
|
|
||||||
matrix = { path = "../matrix" }
|
matrix = { path = "../matrix" }
|
||||||
matrix-stdlib = { path = "../matrix-stdlib" }
|
|
||||||
rustyline = "13"
|
rustyline = "13"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs};
|
use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs};
|
||||||
use clap::Parser as ArgParser;
|
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;
|
use repl::Repl;
|
||||||
|
|
||||||
mod repl;
|
mod repl;
|
||||||
|
@ -50,24 +50,23 @@ impl<'a> State<'a> {
|
||||||
let parser = ParserBuilder::new()
|
let parser = ParserBuilder::new()
|
||||||
.optimize(!args.disable_optimizations)
|
.optimize(!args.disable_optimizations)
|
||||||
.build();
|
.build();
|
||||||
let mut vm = Vm::new();
|
let vm = Vm::new();
|
||||||
let compiler = CompilerBuilder::new()
|
let compiler = CompilerBuilder::new()
|
||||||
.repl(repl)
|
.repl(repl)
|
||||||
.debug(args.debug)
|
.debug(args.debug)
|
||||||
.names(vm.names())
|
|
||||||
.globals(vm.global_names())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
matrix_stdlib::load(&mut vm);
|
|
||||||
|
|
||||||
(Self { parser, vm, compiler, repl }, file)
|
(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 ast = self.parser.parse(code)?;
|
||||||
let fun = self.compiler.compile(&ast)?;
|
let fun = self.compiler.compile(&ast)?;
|
||||||
let val = self.vm.run(fun)?;
|
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;
|
use crate::State;
|
||||||
|
|
||||||
pub struct Repl<'a> {
|
pub struct Repl<'a> {
|
||||||
|
@ -16,29 +11,14 @@ impl<'a> Repl<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
|
let mut rl = rustyline::DefaultEditor::new().unwrap();
|
||||||
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();
|
|
||||||
loop {
|
loop {
|
||||||
let Ok(line) = rl.readline(">> ") else {
|
let Ok(line) = rl.readline(">> ") else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
match self.state.execute(line) {
|
if let Err(err) = self.state.execute(line) {
|
||||||
Err(err) => crate::error(err),
|
crate::error(err);
|
||||||
Ok(val) => {
|
|
||||||
if val != Value::Nil {
|
|
||||||
println!("{val}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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,
|
LessEquals,
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
LessThan,
|
LessThan,
|
||||||
|
Range,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -45,7 +46,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>, Rc<str>),
|
FieldAccess(Box<Expr>, Box<Expr>),
|
||||||
|
|
||||||
List(InlineList),
|
List(InlineList),
|
||||||
Matrix(InlineMatrix),
|
Matrix(InlineMatrix),
|
||||||
|
@ -57,8 +58,8 @@ pub enum Expr {
|
||||||
Assign(Box<Expr>, Box<Expr>),
|
Assign(Box<Expr>, Box<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>, bool),
|
Function(Rc<str>, Vec<Rc<str>>, Box<Expr>),
|
||||||
Lambda(Vec<Rc<str>>, Box<Expr>, bool),
|
|
||||||
|
|
||||||
Loop(Box<Expr>),
|
Loop(Box<Expr>),
|
||||||
While(Box<Expr>, Box<Expr>),
|
While(Box<Expr>, Box<Expr>),
|
||||||
|
@ -177,9 +178,10 @@ pub fn optimize(expr: Expr) -> Result<Expr> {
|
||||||
.map(optimize)
|
.map(optimize)
|
||||||
.collect::<Result<Vec<Expr>>>()?)
|
.collect::<Result<Vec<Expr>>>()?)
|
||||||
}
|
}
|
||||||
E::FieldAccess(expr, ident) => {
|
E::FieldAccess(key, val) => {
|
||||||
let expr = optimize(*expr)?;
|
let key = optimize(*key)?;
|
||||||
E::FieldAccess(Box::new(expr), ident)
|
let val = optimize(*val)?;
|
||||||
|
E::FieldAccess(Box::new(key), Box::new(val))
|
||||||
},
|
},
|
||||||
E::List(list) =>
|
E::List(list) =>
|
||||||
E::List(list.into_iter()
|
E::List(list.into_iter()
|
||||||
|
@ -280,14 +282,10 @@ pub fn optimize(expr: Expr) -> Result<Expr> {
|
||||||
let block = Box::new(optimize(*block)?);
|
let block = Box::new(optimize(*block)?);
|
||||||
E::Loop(block)
|
E::Loop(block)
|
||||||
},
|
},
|
||||||
E::Function(ident, params, stmt, varadic) => {
|
E::Function(ident, params, stmt) => {
|
||||||
let stmt = Box::new(optimize(*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, expr) => {
|
||||||
E::Let(ident, Box::new(optimize(*expr)?))
|
E::Let(ident, Box::new(optimize(*expr)?))
|
||||||
},
|
},
|
||||||
|
@ -335,6 +333,7 @@ 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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
use std::{fmt::{Debug, Display}, rc::Rc};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -36,30 +36,11 @@ impl Display for Chunk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub name: Rc<str>,
|
pub name: Rc<str>,
|
||||||
pub arity: usize,
|
pub arity: usize,
|
||||||
pub variadic: bool,
|
pub body: Chunk
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -90,8 +71,6 @@ 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),
|
||||||
|
|
||||||
|
@ -133,8 +112,6 @@ 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"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
use std::{fmt::Display, rc::Rc, cell::RefCell};
|
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 Instruction as I;
|
||||||
use Value as V;
|
use Value as V;
|
||||||
use Expr as E;
|
use Expr as E;
|
||||||
|
|
||||||
pub type NamesTable = Rc<RefCell<Vec<Rc<str>>>>;
|
|
||||||
|
|
||||||
pub struct CompilerBuilder<'c> {
|
pub struct CompilerBuilder<'c> {
|
||||||
globals: NamesTable,
|
globals: Rc<RefCell<Vec<Rc<str>>>>,
|
||||||
names: NamesTable,
|
|
||||||
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> {
|
||||||
|
@ -25,7 +22,6 @@ 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()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,16 +35,11 @@ impl<'c> CompilerBuilder<'c> {
|
||||||
self
|
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.globals = globals;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn names(mut self, names: NamesTable) -> 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
|
||||||
|
@ -62,7 +53,6 @@ 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,
|
||||||
|
@ -83,7 +73,6 @@ 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,
|
||||||
|
|
||||||
|
@ -135,8 +124,6 @@ impl<'c> Compiler<'c> {
|
||||||
CompilerBuilder::new()
|
CompilerBuilder::new()
|
||||||
.name(name)
|
.name(name)
|
||||||
.debug(self.debug)
|
.debug(self.debug)
|
||||||
.globals(self.globals.clone())
|
|
||||||
.names(self.names.clone())
|
|
||||||
.repl(false)
|
.repl(false)
|
||||||
.parent(self)
|
.parent(self)
|
||||||
.build()
|
.build()
|
||||||
|
@ -220,12 +207,6 @@ 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);
|
||||||
|
@ -263,7 +244,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 => self.emit(I::Nil),
|
E::NoOp => {},
|
||||||
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();
|
||||||
|
@ -273,14 +254,13 @@ impl<'c> Compiler<'c> {
|
||||||
self.compile_expr(elseb)?;
|
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 chunk = self.compile_function(name.clone(), params, body)?;
|
||||||
let fun = Value::Function(Rc::new(
|
let fun = Value::Function(Rc::new(
|
||||||
chunk::Function {
|
chunk::Function {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
arity: params.len(),
|
arity: params.len(),
|
||||||
fun: InnerFunction::Compiled(chunk.into()),
|
body: chunk
|
||||||
variadic: *varadic
|
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
self.emit_const(fun);
|
self.emit_const(fun);
|
||||||
|
@ -293,19 +273,6 @@ impl<'c> Compiler<'c> {
|
||||||
self.emit(I::CreateLocal);
|
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) => {
|
E::Loop(expr) => {
|
||||||
let idx = self.cur();
|
let idx = self.cur();
|
||||||
self.loop_top.push((idx as usize, self.scopes.len()));
|
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::Literal(val) => self.compile_value(val),
|
||||||
E::Ident(name) => {
|
E::Ident(name) => {
|
||||||
if name.as_ref() == "_" {
|
if let Some(local) = self.find_local(name) {
|
||||||
self.emit(I::Nil);
|
|
||||||
} else if let Some(local) = self.find_local(name) {
|
|
||||||
self.emit(I::LoadLocal(local.idx as u16));
|
self.emit(I::LoadLocal(local.idx as u16));
|
||||||
} else if let Some(global) = self.find_global(name) {
|
} else if let Some(global) = self.find_global(name) {
|
||||||
self.emit(I::LoadGlobal(global as u16));
|
self.emit(I::LoadGlobal(global as u16));
|
||||||
|
@ -397,7 +362,7 @@ impl<'c> Compiler<'c> {
|
||||||
self.compile_expr(rhs)?;
|
self.compile_expr(rhs)?;
|
||||||
self.emit(I::Dup);
|
self.emit(I::Dup);
|
||||||
match lhs.as_ref() {
|
match lhs.as_ref() {
|
||||||
E::Ident(name) if name.as_ref() != "_" => {
|
E::Ident(name) => {
|
||||||
if let Some(local) = self.find_local(&name) {
|
if let Some(local) = self.find_local(&name) {
|
||||||
self.emit(I::StoreLocal(local.idx as u16));
|
self.emit(I::StoreLocal(local.idx as u16));
|
||||||
} else if let Some(global) = self.find_global(&name) {
|
} else if let Some(global) = self.find_global(&name) {
|
||||||
|
@ -410,18 +375,6 @@ 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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,13 +387,7 @@ impl<'c> Compiler<'c> {
|
||||||
self.compile_expr(rhs)?;
|
self.compile_expr(rhs)?;
|
||||||
self.emit(I::BinaryOp(*op));
|
self.emit(I::BinaryOp(*op));
|
||||||
},
|
},
|
||||||
E::Index(expr, params) => {
|
E::Index(_, _) => return Err(self::Error::NotImplemented("indexing").into()),
|
||||||
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)?;
|
||||||
|
@ -448,11 +395,7 @@ 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(expr, field) => {
|
E::FieldAccess(_, _) => return Err(self::Error::NotImplemented("filed access").into()),
|
||||||
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)?;
|
||||||
|
@ -560,7 +503,7 @@ impl<'c> Compiler<'c> {
|
||||||
self.chunk = Chunk::new();
|
self.chunk = Chunk::new();
|
||||||
self.compile_expr(body)?;
|
self.compile_expr(body)?;
|
||||||
self.finish()?;
|
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))
|
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> {
|
pub struct Gc<T> {
|
||||||
ptr: NonNull<GcInner<T>>,
|
ptr: NonNull<GcInner<T>>,
|
||||||
phantom: PhantomData<GcInner<T>>
|
phantom: PhantomData<GcInner<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GcInner<T> {
|
pub struct GcInner<T> {
|
||||||
rc: usize,
|
rc: usize,
|
||||||
data: T
|
data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Gc<T> {
|
impl<T> Gc<T> {
|
||||||
pub fn new(data: T) -> Self {
|
pub fn new(data: T) -> Gc<T> {
|
||||||
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> Gc<T> {
|
impl<T: Clone> From<Rc<T>> for Gc<T> {
|
||||||
pub fn clone_inside(&self) -> Self {
|
fn from(value: Rc<T>) -> Self {
|
||||||
unsafe {
|
Self::new(Rc::unwrap_or_clone(value))
|
||||||
let data = self.ptr.as_ref().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 {
|
||||||
Gc::new(value)
|
Self::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 {
|
||||||
fn deref(&self) -> &Self::Target {
|
let inner = unsafe { self.ptr.as_ref() };
|
||||||
unsafe {
|
&inner.data
|
||||||
&self.ptr.as_ref().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 {
|
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> {
|
impl<T: PartialOrd> PartialOrd for Gc<T> {
|
||||||
type Item = T::Item;
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
let inner = unsafe { self.ptr.as_ref() };
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
let other = unsafe { other.ptr.as_ref() };
|
||||||
self.deref_mut().next()
|
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> {
|
impl<T> Clone for Gc<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
unsafe {
|
let inner = unsafe { self.ptr.as_ptr().as_mut().unwrap() };
|
||||||
let inner = self.ptr.as_ptr().as_mut().unwrap();
|
inner.rc += 1;
|
||||||
inner.rc += 1;
|
Self {
|
||||||
|
ptr: self.ptr,
|
||||||
Self {
|
phantom: PhantomData,
|
||||||
ptr: self.ptr,
|
|
||||||
phantom: PhantomData
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for Gc<T> {
|
impl<T> Drop for Gc<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
let inner = unsafe { self.ptr.as_mut() };
|
||||||
let inner = self.ptr.as_mut();
|
inner.rc -= 1;
|
||||||
if inner.rc > 1 {
|
if inner.rc > 0 {
|
||||||
inner.rc -= 1;
|
return;
|
||||||
} else {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -38,7 +38,9 @@ pub enum Token {
|
||||||
LeftBrack,
|
LeftBrack,
|
||||||
RightBrack,
|
RightBrack,
|
||||||
LeftBrace,
|
LeftBrace,
|
||||||
|
LeftLeftBrace,
|
||||||
RightBrace,
|
RightBrace,
|
||||||
|
RightRightBrace,
|
||||||
Assign,
|
Assign,
|
||||||
Access,
|
Access,
|
||||||
SemiColon,
|
SemiColon,
|
||||||
|
@ -46,17 +48,6 @@ pub enum Token {
|
||||||
ThinArrow,
|
ThinArrow,
|
||||||
Comma,
|
Comma,
|
||||||
Range,
|
Range,
|
||||||
Colon,
|
|
||||||
Backslash,
|
|
||||||
Varadic,
|
|
||||||
|
|
||||||
// math
|
|
||||||
Regex(RegexToken),
|
|
||||||
Int(i64),
|
|
||||||
Float(f64),
|
|
||||||
Complex(f64),
|
|
||||||
String(Rc<str>),
|
|
||||||
Ident(Rc<str>),
|
|
||||||
|
|
||||||
// equality
|
// equality
|
||||||
Equal,
|
Equal,
|
||||||
|
@ -76,6 +67,14 @@ 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,
|
||||||
|
@ -83,22 +82,6 @@ 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,
|
||||||
|
@ -210,7 +193,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,63 +420,42 @@ impl Lexer {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(match char {
|
Ok(match char {
|
||||||
'\n' => SemiColon,
|
|
||||||
'(' => LeftParen,
|
'(' => LeftParen,
|
||||||
')' => RightParen,
|
')' => RightParen,
|
||||||
'[' => LeftBrack,
|
'[' => LeftBrack,
|
||||||
']' => RightBrack,
|
']' => RightBrack,
|
||||||
'{' => LeftBrace,
|
'{' => {
|
||||||
'}' => RightBrace,
|
match next {
|
||||||
':' => Colon,
|
'{' => {
|
||||||
'\\' => Backslash,
|
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();
|
||||||
match self.peek() {
|
Power
|
||||||
'=' => {
|
|
||||||
self.next();
|
|
||||||
AssignPower
|
|
||||||
},
|
|
||||||
_ => Power
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'=' => {
|
|
||||||
self.next();
|
|
||||||
AssignMultiply
|
|
||||||
}
|
}
|
||||||
_ => Multiply
|
_ => Multiply
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'/' => Divide,
|
||||||
|
'%' => Modulo,
|
||||||
'!' => {
|
'!' => {
|
||||||
match next {
|
match next {
|
||||||
'=' => {
|
'=' => {
|
||||||
|
@ -507,18 +469,8 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'&' => {
|
'&' => {
|
||||||
self.next();
|
self.next();
|
||||||
match self.peek() {
|
And
|
||||||
'=' => {
|
}
|
||||||
self.next();
|
|
||||||
AssignAnd
|
|
||||||
},
|
|
||||||
_ => And
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'=' => {
|
|
||||||
self.next();
|
|
||||||
AssignBitwiseAnd
|
|
||||||
},
|
|
||||||
_ => BitwiseAnd
|
_ => BitwiseAnd
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -526,18 +478,8 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'|' => {
|
'|' => {
|
||||||
self.next();
|
self.next();
|
||||||
match self.peek() {
|
Or
|
||||||
'=' => {
|
}
|
||||||
self.next();
|
|
||||||
AssignOr
|
|
||||||
},
|
|
||||||
_ => Or
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'=' => {
|
|
||||||
self.next();
|
|
||||||
AssignBitwiseOr
|
|
||||||
},
|
|
||||||
_ => BitwiseOr
|
_ => BitwiseOr
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -546,11 +488,7 @@ impl Lexer {
|
||||||
'>' => {
|
'>' => {
|
||||||
self.next();
|
self.next();
|
||||||
ThinArrow
|
ThinArrow
|
||||||
},
|
}
|
||||||
'=' => {
|
|
||||||
self.next();
|
|
||||||
AssignSubtract
|
|
||||||
},
|
|
||||||
_ => Subtract
|
_ => Subtract
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -571,13 +509,7 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'>' => {
|
'>' => {
|
||||||
self.next();
|
self.next();
|
||||||
match self.peek() {
|
BitwiseShiftRight
|
||||||
'=' => {
|
|
||||||
self.next();
|
|
||||||
AssignBitwiseShiftRight
|
|
||||||
},
|
|
||||||
_ => BitwiseShiftRight
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
'=' => {
|
'=' => {
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -590,13 +522,7 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'<' => {
|
'<' => {
|
||||||
self.next();
|
self.next();
|
||||||
match self.peek() {
|
BitwiseShiftLeft
|
||||||
'=' => {
|
|
||||||
self.next();
|
|
||||||
AssignBitwiseShiftLeft
|
|
||||||
},
|
|
||||||
_ => BitwiseShiftLeft
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
'=' => {
|
'=' => {
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -605,15 +531,7 @@ 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 {
|
||||||
|
@ -630,14 +548,7 @@ impl Lexer {
|
||||||
},
|
},
|
||||||
'.' => {
|
'.' => {
|
||||||
if next == '.' {
|
if next == '.' {
|
||||||
self.next();
|
Range
|
||||||
match self.peek() {
|
|
||||||
'.' => {
|
|
||||||
self.next();
|
|
||||||
Varadic
|
|
||||||
},
|
|
||||||
_ => Range
|
|
||||||
}
|
|
||||||
} else if next.is_digit(10) {
|
} else if next.is_digit(10) {
|
||||||
self.lex_number(char)?
|
self.lex_number(char)?
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -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}, 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 Value as V;
|
||||||
use Expr as E;
|
use Expr as E;
|
||||||
|
@ -40,7 +40,7 @@ pub enum Error {
|
||||||
UnexpectedToken(Token),
|
UnexpectedToken(Token),
|
||||||
ExpectedToken(Token),
|
ExpectedToken(Token),
|
||||||
ExpectedTokenName(&'static str),
|
ExpectedTokenName(&'static str),
|
||||||
MatrixInvDomain(usize, usize, usize),
|
MatrixCoDomainError(usize, usize, usize),
|
||||||
NotAssignable(Expr),
|
NotAssignable(Expr),
|
||||||
ValueError(value::Error),
|
ValueError(value::Error),
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ impl Display for Error {
|
||||||
UnexpectedToken(tok) => write!(f, "Unexpected token: '{tok:?}'"),
|
UnexpectedToken(tok) => write!(f, "Unexpected token: '{tok:?}'"),
|
||||||
ExpectedToken(tok) => write!(f, "Expected token: '{tok:?}'"),
|
ExpectedToken(tok) => write!(f, "Expected token: '{tok:?}'"),
|
||||||
ExpectedTokenName(name) => write!(f, "Expected {name} token"),
|
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"),
|
NotAssignable(expr) => write!(f, "{expr:?} is not assignable"),
|
||||||
ValueError(err) => write!(f, "{err}"),
|
ValueError(err) => write!(f, "{err}"),
|
||||||
}
|
}
|
||||||
|
@ -199,11 +199,11 @@ impl Parser {
|
||||||
if parts.len() == 1 {
|
if parts.len() == 1 {
|
||||||
Ok(E::List(parts.pop().unwrap()))
|
Ok(E::List(parts.pop().unwrap()))
|
||||||
} else {
|
} else {
|
||||||
let codomain = parts.len();
|
let codomain = parts[0].len();
|
||||||
let domain = parts[0].len();
|
let domain = parts.len();
|
||||||
for (i, part) in parts.iter().enumerate() {
|
for (i, part) in parts.iter().enumerate() {
|
||||||
if part.len() != codomain {
|
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();
|
let mut data = Vec::new();
|
||||||
|
@ -230,10 +230,9 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_table(&mut self) -> Result<Expr> {
|
fn parse_table(&mut self) -> Result<Expr> {
|
||||||
self.force_token(T::Colon)?;
|
self.force_token(T::LeftLeftBrace)?;
|
||||||
self.force_token(T::LeftBrace)?;
|
|
||||||
let mut table = Vec::new();
|
let mut table = Vec::new();
|
||||||
if self.lexer.peek_token()? == T::RightBrace {
|
if self.lexer.peek_token()? == T::RightRightBrace {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
return Ok(E::Table(table))
|
return Ok(E::Table(table))
|
||||||
}
|
}
|
||||||
|
@ -245,7 +244,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::RightBrace => break,
|
T::RightRightBrace => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
_ => return Err(Error::UnexpectedToken(next).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,29 +258,20 @@ impl Parser {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_params(&mut self) -> Result<(Vec<Rc<str>>, bool)> {
|
fn parse_params(&mut self) -> Result<Vec<Rc<str>>> {
|
||||||
use T::*;
|
use T::*;
|
||||||
let tok = self.lexer.next_token()?;
|
let tok = self.lexer.next_token()?;
|
||||||
match tok {
|
match tok {
|
||||||
Ident(ident) => {
|
Ident(ident) => return Ok(vec![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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LeftParen => (),
|
LeftParen => (),
|
||||||
_ => return Err(Error::UnexpectedToken(tok).into()),
|
_ => return Err(Error::UnexpectedToken(tok).into()),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut params = Vec::new();
|
let mut params = Vec::new();
|
||||||
let mut varadic = false;
|
|
||||||
|
|
||||||
if self.lexer.peek_token()? == T::RightParen {
|
if self.lexer.peek_token()? == T::RightParen {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
return Ok((params, varadic));
|
return Ok(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -289,18 +279,13 @@ impl Parser {
|
||||||
params.push(ident);
|
params.push(ident);
|
||||||
let next = self.lexer.next_token()?;
|
let next = self.lexer.next_token()?;
|
||||||
match next {
|
match next {
|
||||||
Varadic => {
|
|
||||||
varadic = true;
|
|
||||||
self.force_token(T::RightParen)?;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Comma => continue,
|
Comma => continue,
|
||||||
RightParen => break,
|
RightParen => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into()),
|
_ => return Err(Error::UnexpectedToken(next).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((params, varadic))
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident(&mut self) -> Result<Rc<str>> {
|
fn parse_ident(&mut self) -> Result<Rc<str>> {
|
||||||
|
@ -322,23 +307,12 @@ impl Parser {
|
||||||
fn parse_function(&mut self) -> Result<Expr> {
|
fn parse_function(&mut self) -> Result<Expr> {
|
||||||
self.force_token(T::Function)?;
|
self.force_token(T::Function)?;
|
||||||
let ident = self.parse_ident()?;
|
let ident = self.parse_ident()?;
|
||||||
let (params, varadic) = match self.lexer.peek_token()? {
|
let params = match self.lexer.peek_token()? {
|
||||||
T::LeftBrace => (vec![], false),
|
T::LeftBrace => vec![],
|
||||||
_ => self.parse_params()?,
|
_ => self.parse_params()?,
|
||||||
};
|
};
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
Ok(E::Function(ident, params, Box::new(expr), varadic))
|
Ok(E::Function(ident, params, Box::new(expr)))
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_do_while(&mut self) -> Result<Expr> {
|
fn parse_do_while(&mut self) -> Result<Expr> {
|
||||||
|
@ -412,7 +386,7 @@ impl Parser {
|
||||||
match next {
|
match next {
|
||||||
T::SemiColon => continue,
|
T::SemiColon => continue,
|
||||||
T::RightBrace => break,
|
T::RightBrace => break,
|
||||||
_ => return Err(Error::ExpectedToken(T::SemiColon).into())
|
_ => return Err(Error::UnexpectedToken(next).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.lexer.peek_token()? == T::RightBrace {
|
if self.lexer.peek_token()? == T::RightBrace {
|
||||||
|
@ -428,7 +402,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(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::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)),
|
||||||
|
@ -441,7 +415,6 @@ impl Parser {
|
||||||
use T::*;
|
use T::*;
|
||||||
match self.lexer.peek_token()? {
|
match self.lexer.peek_token()? {
|
||||||
Function => self.parse_function(),
|
Function => self.parse_function(),
|
||||||
Backslash => self.parse_lambda(),
|
|
||||||
Do => self.parse_do_while(),
|
Do => self.parse_do_while(),
|
||||||
While => self.parse_while(),
|
While => self.parse_while(),
|
||||||
Let => self.parse_let(),
|
Let => self.parse_let(),
|
||||||
|
@ -458,7 +431,7 @@ impl Parser {
|
||||||
Ok(E::Continue)
|
Ok(E::Continue)
|
||||||
},
|
},
|
||||||
LeftBrack => self.parse_matrix(),
|
LeftBrack => self.parse_matrix(),
|
||||||
Colon => self.parse_table(),
|
LeftLeftBrace => self.parse_table(),
|
||||||
LeftParen => self.parse_paren(),
|
LeftParen => self.parse_paren(),
|
||||||
_ => self.parse_value(),
|
_ => self.parse_value(),
|
||||||
}
|
}
|
||||||
|
@ -471,8 +444,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_ident()?;
|
let temp = self.parse_term()?;
|
||||||
expr = E::FieldAccess(Box::new(expr), temp);
|
expr = E::FieldAccess(Box::new(expr), Box::new(temp));
|
||||||
},
|
},
|
||||||
_ => break
|
_ => break
|
||||||
}
|
}
|
||||||
|
@ -590,66 +563,13 @@ 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.clone()),Box::new(self.parse_expr()?))
|
E::Assign(Box::new(expr),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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -667,11 +587,6 @@ impl Parser {
|
||||||
};
|
};
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
block.push(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))
|
Ok(E::Block(block))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}, chunk::Function, Result, gc::Gc};
|
use crate::{ast::{Expr, BinaryOp, UnaryOp}, gc::Gc, chunk::Function, Result};
|
||||||
|
|
||||||
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,14 +43,12 @@ pub enum Error {
|
||||||
Exponent(Value, Value),
|
Exponent(Value, Value),
|
||||||
Compare(Value, Value),
|
Compare(Value, Value),
|
||||||
IndexOutOfBounds(usize, usize),
|
IndexOutOfBounds(usize, usize),
|
||||||
CannotIndex(Value),
|
Index(Value, 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 {
|
||||||
|
@ -66,14 +64,12 @@ 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}"),
|
||||||
BadIndex(a, b) => write!(f, "cannot index {a:?} with {b:?}"),
|
Index(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"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,8 +84,8 @@ pub enum Value {
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Ratio(Rational64),
|
Ratio(Rational64),
|
||||||
Complex(Complex64),
|
Complex(Complex64),
|
||||||
Regex(Rc<Regex>),
|
Regex(Gc<Regex>),
|
||||||
String(Rc<String>),
|
String(Gc<String>),
|
||||||
List(Gc<List>),
|
List(Gc<List>),
|
||||||
Matrix(Gc<Matrix>),
|
Matrix(Gc<Matrix>),
|
||||||
Table(Gc<Table>),
|
Table(Gc<Table>),
|
||||||
|
@ -157,35 +153,36 @@ 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();
|
||||||
for (i, el) in l.iter().enumerate() {
|
for (i, el) in l.iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
str.push_str(" ");
|
str.push_str(" ");
|
||||||
}
|
}
|
||||||
str.push_str(&el.boring_print());
|
str.push_str(&el.boring_print());
|
||||||
}
|
}
|
||||||
str.push_str("]");
|
str.push_str(" ]");
|
||||||
str
|
str
|
||||||
},
|
},
|
||||||
Matrix(m) => {
|
Matrix(m) => {
|
||||||
let mut str = "\n".to_string();
|
let mut str = "[[ ".to_string();
|
||||||
for row in m.2.chunks(m.0) {
|
for (i, el) in m.2.iter().enumerate() {
|
||||||
str.push_str(" ");
|
if i != 0 {
|
||||||
for (i, v) in row.iter().enumerate() {
|
if (i % m.1) == 0 {
|
||||||
if i != 0 {
|
str.push_str(" ; ");
|
||||||
str.push(' ');
|
} else {
|
||||||
|
str.push_str(" ");
|
||||||
}
|
}
|
||||||
str.push_str(&v.boring_print());
|
|
||||||
}
|
}
|
||||||
str.push('\n');
|
str.push_str(&el.boring_print());
|
||||||
}
|
}
|
||||||
|
str.push_str(" ]]");
|
||||||
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(", ");
|
||||||
|
@ -194,11 +191,11 @@ 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) => {
|
||||||
format!("{fun:?}")
|
format!("[Function: {}]", fun.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,32 +212,33 @@ impl Value {
|
||||||
Regex(_) => format!("\x1b[31m{}\x1b[0m", self.boring_print()),
|
Regex(_) => format!("\x1b[31m{}\x1b[0m", self.boring_print()),
|
||||||
String(_) => format!("\x1b[32m'{}'\x1b[0m", self.boring_print()),
|
String(_) => format!("\x1b[32m'{}'\x1b[0m", self.boring_print()),
|
||||||
List(l) => {
|
List(l) => {
|
||||||
let mut str = "[".to_string();
|
let mut str = "[ ".to_string();
|
||||||
for (i, el) in l.iter().enumerate() {
|
for (i, el) in l.iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
str.push_str(" ");
|
str.push_str(" ");
|
||||||
}
|
}
|
||||||
str.push_str(&el.pretty_print());
|
str.push_str(&el.pretty_print());
|
||||||
}
|
}
|
||||||
str.push_str("]");
|
str.push_str(" ]");
|
||||||
str
|
str
|
||||||
},
|
},
|
||||||
Matrix(m) => {
|
Matrix(m) => {
|
||||||
let mut str = "\n".to_string();
|
let mut str = "[[ ".to_string();
|
||||||
for row in m.2.chunks(m.0) {
|
for (i, el) in m.2.iter().enumerate() {
|
||||||
str.push_str(" ");
|
if i != 0 {
|
||||||
for (i, v) in row.iter().enumerate() {
|
if (i % m.1) == 0 {
|
||||||
if i != 0 {
|
str.push_str(" ; ");
|
||||||
str.push(' ');
|
} else {
|
||||||
|
str.push_str(" ");
|
||||||
}
|
}
|
||||||
str.push_str(&v.pretty_print());
|
|
||||||
}
|
}
|
||||||
str.push('\n');
|
str.push_str(&el.pretty_print());
|
||||||
}
|
}
|
||||||
|
str.push_str(" ]]");
|
||||||
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(", ");
|
||||||
|
@ -249,12 +247,12 @@ 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(_) => {
|
||||||
format!("\x1b[36m{}\x1b[0m", self.boring_print())
|
format!("\x1b[36m{}\x1b[0m", self.boring_print())
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,10 +295,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(Rc::new(
|
(String(str), value) => Ok(String(Gc::new(
|
||||||
format!("{str}{}", value.boring_print())
|
format!("{str}{}", value.boring_print())
|
||||||
))),
|
))),
|
||||||
(value, String(str)) => Ok(String(Rc::new(
|
(value, String(str)) => Ok(String(Gc::new(
|
||||||
format!("{}{str}", value.boring_print())
|
format!("{}{str}", value.boring_print())
|
||||||
))),
|
))),
|
||||||
(List(mut l1), List(l2)) => {
|
(List(mut l1), List(l2)) => {
|
||||||
|
@ -422,18 +420,28 @@ 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 % y)),
|
(Int(x), Int(y)) => Ok(Int(x.rem_euclid(y))),
|
||||||
(Float(x), Float(y)) => Ok(Float(x % y)),
|
(Float(x), Float(y)) => Ok(Float(x.rem_euclid(y))),
|
||||||
(Ratio(x), Ratio(y)) => Ok(Ratio(x % y)),
|
(Ratio(_x), Ratio(_y)) => todo!("ratio modulo"),
|
||||||
(Complex(x), Complex(y)) => Ok(Complex(x % y)),
|
(Complex(_x), Complex(_y)) => todo!("complex modulo"),
|
||||||
(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) {
|
||||||
|
@ -447,16 +455,6 @@ impl Value {
|
||||||
(l, r) => Err(Error::Exponent(l, r).into())
|
(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 {}
|
impl Eq for Value {}
|
||||||
|
@ -520,123 +518,24 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_single(&self, index: &Value) -> Result<Self> {
|
pub fn store_index(&self, _other: &Vec<Self>, _value: &Self) -> Result<()> {
|
||||||
use Value as V;
|
todo!()
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index_multiple(&self, indexes: &Vec<Value>) -> Result<Self> {
|
pub fn index(&self, _other: &Vec<Self>) -> Result<Self> {
|
||||||
use Value as V;
|
todo!()
|
||||||
match self {
|
//use Value::*;
|
||||||
V::List(..) => {
|
//match (self, other) {
|
||||||
let mut ret = Vec::new();
|
// (List(l), Int(i)) => {
|
||||||
for index in indexes {
|
// if *i >= 0 && *i < l.len() as i64 {
|
||||||
let res = self.index_single(index)?;
|
// Ok(l[*i as usize].clone())
|
||||||
ret.push(res);
|
// } else {
|
||||||
}
|
// Err(Error::IndexOutOfBounds(*i as usize, l.len()))
|
||||||
Ok(V::List(ret.into()))
|
// }
|
||||||
}
|
// },
|
||||||
V::Table(..) => {
|
// (l, r) => Err(Error::Index(l.clone(), r.clone()))
|
||||||
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 binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
|
pub fn binary_op(op: BinaryOp, lhs: Value, rhs: Value) -> Result<Self> {
|
||||||
use BinaryOp::*;
|
use BinaryOp::*;
|
||||||
|
@ -658,6 +557,7 @@ 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!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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 std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap};
|
||||||
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction, Chunk, InnerFunction}, Result, compiler::NamesTable};
|
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -7,7 +7,6 @@ pub enum Error {
|
||||||
NotFunction(Value),
|
NotFunction(Value),
|
||||||
InvArity(usize, usize, Rc<str>),
|
InvArity(usize, usize, Rc<str>),
|
||||||
UndefinedGlobal(Rc<str>),
|
UndefinedGlobal(Rc<str>),
|
||||||
ExecNative,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error {}
|
impl std::error::Error for Error {}
|
||||||
|
@ -20,7 +19,6 @@ impl Display for Error {
|
||||||
NotFunction(v) => write!(f, "{v:?} is not a function"),
|
NotFunction(v) => write!(f, "{v:?} is not a function"),
|
||||||
InvArity(wanted, had, name) => write!(f, "function {name} takes {wanted} params but was given {had}"),
|
InvArity(wanted, had, name) => write!(f, "function {name} takes {wanted} params but was given {had}"),
|
||||||
UndefinedGlobal(name) => write!(f, "{name} is not defined"),
|
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 {
|
struct StackFrame {
|
||||||
#[allow(dead_code)]
|
fun: Rc<Function>,
|
||||||
name: Rc<str>,
|
|
||||||
body: Rc<Chunk>,
|
|
||||||
ip: usize,
|
ip: usize,
|
||||||
bp: usize,
|
bp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackFrame {
|
impl StackFrame {
|
||||||
fn new(vm: &Vm, name: Rc<str>, body: Rc<Chunk>, arity: usize) -> Self {
|
fn new(vm: &Vm, fun: Rc<Function>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
bp: vm.stack.len() - fun.arity,
|
||||||
body,
|
|
||||||
bp: vm.stack.len() - arity,
|
|
||||||
ip: 0,
|
ip: 0,
|
||||||
|
fun,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Interupt {
|
|
||||||
KeyboardInterupt = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
stack: Stack<Value>,
|
stack: Stack<Value>,
|
||||||
locals: Stack<Value>,
|
locals: Stack<Value>,
|
||||||
frames: Vec<StackFrame>,
|
frames: Vec<StackFrame>,
|
||||||
globals: HashMap<u16, Value>,
|
globals: HashMap<u16, Value>,
|
||||||
names: NamesTable,
|
|
||||||
global_names: NamesTable,
|
|
||||||
interupt: Arc<AtomicUsize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
|
@ -132,66 +120,26 @@ impl Vm {
|
||||||
self.stack.pop()
|
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 {
|
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())),
|
|
||||||
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> {
|
pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> {
|
||||||
let mut frame = self.init_frame(fun)?;
|
let mut frame = StackFrame::new(&self, fun);
|
||||||
self.interupt.store(0, Ordering::SeqCst);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
use Instruction::*;
|
use Instruction::*;
|
||||||
let ins = frame.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.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)},
|
DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
|
||||||
LoadGlobal(idx) => {
|
LoadGlobal(idx) => {
|
||||||
let val = self.globals
|
let val = self.globals
|
||||||
|
@ -204,7 +152,7 @@ impl Vm {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
self.globals.insert(idx, val);
|
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)),
|
Int(i) => self.push(Value::Int(i as i64)),
|
||||||
True => self.push(Value::Bool(true)),
|
True => self.push(Value::Bool(true)),
|
||||||
False => self.push(Value::Bool(false)),
|
False => self.push(Value::Bool(false)),
|
||||||
|
@ -239,24 +187,25 @@ 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))));
|
||||||
}
|
}
|
||||||
Jump(idx) => {
|
Index(count) => {
|
||||||
if self.check_interupt() {
|
let index = self.stack.split_off(self.stack.len() - count as usize);
|
||||||
return Ok(Value::Nil)
|
let collection = self.pop();
|
||||||
}
|
let value = collection.index(&index.inner)?;
|
||||||
frame.ip = idx as usize;
|
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) => {
|
JumpTrue(idx) => {
|
||||||
if self.check_interupt() {
|
|
||||||
return Ok(Value::Nil)
|
|
||||||
}
|
|
||||||
if !!self.pop() {
|
if !!self.pop() {
|
||||||
frame.ip = idx as usize;
|
frame.ip = idx as usize;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
JumpFalse(idx) => {
|
JumpFalse(idx) => {
|
||||||
if self.check_interupt() {
|
|
||||||
return Ok(Value::Nil)
|
|
||||||
}
|
|
||||||
if !self.pop() {
|
if !self.pop() {
|
||||||
frame.ip = idx as usize;
|
frame.ip = idx as usize;
|
||||||
}
|
}
|
||||||
|
@ -266,38 +215,14 @@ impl Vm {
|
||||||
let Value::Function(fun) = fun else {
|
let Value::Function(fun) = fun else {
|
||||||
return Err(Error::NotFunction(fun).into())
|
return Err(Error::NotFunction(fun).into())
|
||||||
};
|
};
|
||||||
let arity = arity as usize;
|
if fun.arity != arity as usize {
|
||||||
let normal_args = if fun.variadic { fun.arity - 1 } else { fun.arity };
|
return Err(Error::InvArity(fun.arity, arity as usize, fun.name.clone()).into())
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let new_frame = StackFrame::new(&self, fun);
|
||||||
|
self.frames.push(frame);
|
||||||
|
frame = new_frame;
|
||||||
},
|
},
|
||||||
Return => {
|
Return => {
|
||||||
if self.check_interupt() {
|
|
||||||
return Ok(Value::Nil)
|
|
||||||
}
|
|
||||||
let Some(prev_frame) = self.frames.pop() else {
|
let Some(prev_frame) = self.frames.pop() else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
@ -306,29 +231,6 @@ 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())
|
||||||
|
|
Loading…
Reference in a new issue