Compare commits
3 commits
671301383b
...
a9c5ffe62f
Author | SHA1 | Date | |
---|---|---|---|
a9c5ffe62f | |||
a888c09bd5 | |||
e649cef425 |
18 changed files with 911 additions and 264 deletions
42
Cargo.lock
generated
42
Cargo.lock
generated
|
@ -114,7 +114,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -138,6 +138,16 @@ 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"
|
||||||
|
@ -219,10 +229,29 @@ 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"
|
||||||
|
@ -403,6 +432,17 @@ 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" ]
|
members = [ "matrix", "matrix-bin" , "matrix-macros", "matrix-stdlib"]
|
||||||
|
|
|
@ -9,5 +9,7 @@ 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}};
|
use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}, value::Value};
|
||||||
use repl::Repl;
|
use repl::Repl;
|
||||||
|
|
||||||
mod repl;
|
mod repl;
|
||||||
|
@ -50,23 +50,24 @@ impl<'a> State<'a> {
|
||||||
let parser = ParserBuilder::new()
|
let parser = ParserBuilder::new()
|
||||||
.optimize(!args.disable_optimizations)
|
.optimize(!args.disable_optimizations)
|
||||||
.build();
|
.build();
|
||||||
let vm = Vm::new();
|
let mut 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<()> {
|
pub fn execute(&mut self, code: String) -> matrix::Result<Value> {
|
||||||
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)?;
|
||||||
if self.repl {
|
Ok(val)
|
||||||
println!("{val}");
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
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> {
|
||||||
|
@ -11,15 +16,30 @@ 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;
|
||||||
};
|
};
|
||||||
if let Err(err) = self.state.execute(line) {
|
match self.state.execute(line) {
|
||||||
crate::error(err);
|
Err(err) => crate::error(err),
|
||||||
|
Ok(val) => {
|
||||||
|
if val != Value::Nil {
|
||||||
|
println!("{val}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let _ = std::io::stdout().flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
12
matrix-macros/Cargo.toml
Normal file
12
matrix-macros/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[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" }
|
52
matrix-macros/src/lib.rs
Normal file
52
matrix-macros/src/lib.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
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)
|
||||||
|
}
|
10
matrix-stdlib/Cargo.toml
Normal file
10
matrix-stdlib/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[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" }
|
36
matrix-stdlib/src/io.rs
Normal file
36
matrix-stdlib/src/io.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
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());
|
||||||
|
}
|
7
matrix-stdlib/src/lib.rs
Normal file
7
matrix-stdlib/src/lib.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use matrix::vm::Vm;
|
||||||
|
|
||||||
|
mod io;
|
||||||
|
|
||||||
|
pub fn load(compiler: &mut Vm) {
|
||||||
|
io::load(compiler);
|
||||||
|
}
|
|
@ -31,7 +31,6 @@ pub enum BinaryOp {
|
||||||
LessEquals,
|
LessEquals,
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
LessThan,
|
LessThan,
|
||||||
Range,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -46,7 +45,7 @@ pub enum Expr {
|
||||||
|
|
||||||
Index(Box<Expr>, Vec<Expr>),
|
Index(Box<Expr>, Vec<Expr>),
|
||||||
FnCall(Box<Expr>, Vec<Expr>),
|
FnCall(Box<Expr>, Vec<Expr>),
|
||||||
FieldAccess(Box<Expr>, Box<Expr>),
|
FieldAccess(Box<Expr>, Rc<str>),
|
||||||
|
|
||||||
List(InlineList),
|
List(InlineList),
|
||||||
Matrix(InlineMatrix),
|
Matrix(InlineMatrix),
|
||||||
|
@ -58,8 +57,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>),
|
Function(Rc<str>, Vec<Rc<str>>, Box<Expr>, bool),
|
||||||
|
Lambda(Vec<Rc<str>>, Box<Expr>, bool),
|
||||||
|
|
||||||
Loop(Box<Expr>),
|
Loop(Box<Expr>),
|
||||||
While(Box<Expr>, Box<Expr>),
|
While(Box<Expr>, Box<Expr>),
|
||||||
|
@ -178,10 +177,9 @@ pub fn optimize(expr: Expr) -> Result<Expr> {
|
||||||
.map(optimize)
|
.map(optimize)
|
||||||
.collect::<Result<Vec<Expr>>>()?)
|
.collect::<Result<Vec<Expr>>>()?)
|
||||||
}
|
}
|
||||||
E::FieldAccess(key, val) => {
|
E::FieldAccess(expr, ident) => {
|
||||||
let key = optimize(*key)?;
|
let expr = optimize(*expr)?;
|
||||||
let val = optimize(*val)?;
|
E::FieldAccess(Box::new(expr), ident)
|
||||||
E::FieldAccess(Box::new(key), Box::new(val))
|
|
||||||
},
|
},
|
||||||
E::List(list) =>
|
E::List(list) =>
|
||||||
E::List(list.into_iter()
|
E::List(list.into_iter()
|
||||||
|
@ -282,10 +280,14 @@ 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) => {
|
E::Function(ident, params, stmt, varadic) => {
|
||||||
let stmt = Box::new(optimize(*stmt)?);
|
let stmt = Box::new(optimize(*stmt)?);
|
||||||
E::Function(ident, params, stmt)
|
E::Function(ident, params, stmt, varadic)
|
||||||
}
|
}
|
||||||
|
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)?))
|
||||||
},
|
},
|
||||||
|
@ -333,7 +335,6 @@ impl From<Token> for BinaryOp {
|
||||||
Divide => Self::Divide,
|
Divide => Self::Divide,
|
||||||
Modulo => Self::Modulo,
|
Modulo => Self::Modulo,
|
||||||
Power => Self::Power,
|
Power => Self::Power,
|
||||||
Range => Self::Range,
|
|
||||||
_ => panic!("aaaaa")
|
_ => panic!("aaaaa")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{value::Value, ast::{UnaryOp, BinaryOp}};
|
use crate::{value::Value, ast::{UnaryOp, BinaryOp}, vm::Vm, Result};
|
||||||
use std::{fmt::{Debug, Display}, rc::Rc};
|
use std::{fmt::{Debug, Display}, rc::Rc};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -36,11 +36,30 @@ 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 body: Chunk
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -71,6 +90,8 @@ pub enum Instruction {
|
||||||
NewTable(u16),
|
NewTable(u16),
|
||||||
NewMatrix(u16, u8),
|
NewMatrix(u16, u8),
|
||||||
|
|
||||||
|
Field(u16),
|
||||||
|
StoreField(u16),
|
||||||
Index(u8),
|
Index(u8),
|
||||||
StoreIndex(u8),
|
StoreIndex(u8),
|
||||||
|
|
||||||
|
@ -112,6 +133,8 @@ impl Display for Instruction {
|
||||||
JumpFalse(idx) => write!(f, "jumpf \x1b[33m{idx}\x1b[0m"),
|
JumpFalse(idx) => write!(f, "jumpf \x1b[33m{idx}\x1b[0m"),
|
||||||
Call(arity) => write!(f, "call \x1b[35m{arity}\x1b[0m"),
|
Call(arity) => write!(f, "call \x1b[35m{arity}\x1b[0m"),
|
||||||
Return => write!(f, "return"),
|
Return => write!(f, "return"),
|
||||||
|
Field(name_idx) => write!(f, "field \x1b[33m{name_idx}\x1b[0m"),
|
||||||
|
StoreField(name_idx) => write!(f, "store field \x1b[33m{name_idx}\x1b[0m"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
use std::{fmt::Display, rc::Rc, cell::RefCell};
|
use std::{fmt::Display, rc::Rc, cell::RefCell};
|
||||||
use crate::{ast::Expr, chunk::{Function, Instruction}, chunk::{Chunk, self}, value::Value, Result};
|
use crate::{ast::Expr, chunk::{Function, Instruction, InnerFunction}, 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: Rc<RefCell<Vec<Rc<str>>>>,
|
globals: NamesTable,
|
||||||
|
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> {
|
||||||
|
@ -22,6 +25,7 @@ impl<'c> CompilerBuilder<'c> {
|
||||||
debug: false,
|
debug: false,
|
||||||
name: "<root>".into(),
|
name: "<root>".into(),
|
||||||
parent: None,
|
parent: None,
|
||||||
|
names: Rc::new(RefCell::new(Vec::new()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,11 +39,16 @@ impl<'c> CompilerBuilder<'c> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn globals(mut self, globals: Rc<RefCell<Vec<Rc<str>>>>) -> Self {
|
pub fn globals(mut self, globals: NamesTable) -> 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
|
||||||
|
@ -53,6 +62,7 @@ impl<'c> CompilerBuilder<'c> {
|
||||||
pub fn build(self) -> Compiler<'c> {
|
pub fn build(self) -> Compiler<'c> {
|
||||||
Compiler {
|
Compiler {
|
||||||
name: self.name,
|
name: self.name,
|
||||||
|
names: self.names,
|
||||||
parent: self.parent,
|
parent: self.parent,
|
||||||
globals: self.globals,
|
globals: self.globals,
|
||||||
repl: self.repl,
|
repl: self.repl,
|
||||||
|
@ -73,6 +83,7 @@ pub struct Compiler<'c> {
|
||||||
|
|
||||||
locals: Vec<Rc<Local>>,
|
locals: Vec<Rc<Local>>,
|
||||||
globals: Rc<RefCell<Vec<Rc<str>>>>,
|
globals: Rc<RefCell<Vec<Rc<str>>>>,
|
||||||
|
names: Rc<RefCell<Vec<Rc<str>>>>,
|
||||||
|
|
||||||
root_is_block: bool,
|
root_is_block: bool,
|
||||||
|
|
||||||
|
@ -124,6 +135,8 @@ 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()
|
||||||
|
@ -207,6 +220,12 @@ impl<'c> Compiler<'c> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_name(&mut self, name: Rc<str>) -> usize {
|
||||||
|
let idx = self.names.borrow().len();
|
||||||
|
self.names.borrow_mut().push(name);
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_const(&mut self, val: Value) {
|
fn emit_const(&mut self, val: Value) {
|
||||||
// TODO: find constant if already exists
|
// TODO: find constant if already exists
|
||||||
self.chunk.constants.push(val);
|
self.chunk.constants.push(val);
|
||||||
|
@ -244,7 +263,7 @@ impl<'c> Compiler<'c> {
|
||||||
|
|
||||||
fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
|
fn compile_expr(&mut self, expr: &Expr) -> Result<()> {
|
||||||
match expr {
|
match expr {
|
||||||
E::NoOp => {},
|
E::NoOp => self.emit(I::Nil),
|
||||||
E::If(cond, ifb, elseb) => {
|
E::If(cond, ifb, elseb) => {
|
||||||
self.compile_expr(cond)?;
|
self.compile_expr(cond)?;
|
||||||
let jmpidx = self.emit_temp();
|
let jmpidx = self.emit_temp();
|
||||||
|
@ -254,13 +273,14 @@ impl<'c> Compiler<'c> {
|
||||||
self.compile_expr(elseb)?;
|
self.compile_expr(elseb)?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
E::Function(name, params, body) => {
|
E::Function(name, params, body, varadic) => {
|
||||||
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(),
|
||||||
body: chunk
|
fun: InnerFunction::Compiled(chunk.into()),
|
||||||
|
variadic: *varadic
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
self.emit_const(fun);
|
self.emit_const(fun);
|
||||||
|
@ -273,6 +293,19 @@ 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()));
|
||||||
|
@ -350,7 +383,9 @@ 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 let Some(local) = self.find_local(name) {
|
if name.as_ref() == "_" {
|
||||||
|
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));
|
||||||
|
@ -362,7 +397,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) => {
|
E::Ident(name) if name.as_ref() != "_" => {
|
||||||
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) {
|
||||||
|
@ -375,6 +410,18 @@ impl<'c> Compiler<'c> {
|
||||||
self.emit(I::CreateLocal);
|
self.emit(I::CreateLocal);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
E::Index(expr, params) => {
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
for param in params {
|
||||||
|
self.compile_expr(param)?;
|
||||||
|
}
|
||||||
|
self.emit(I::StoreIndex(params.len() as u8));
|
||||||
|
},
|
||||||
|
E::FieldAccess(expr, ident) => {
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
let name = self.get_name(ident.clone());
|
||||||
|
self.emit(I::StoreField(name as u16));
|
||||||
|
}
|
||||||
_ => return Err(self::Error::InvAssign(*lhs.clone()).into())
|
_ => return Err(self::Error::InvAssign(*lhs.clone()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -387,7 +434,13 @@ impl<'c> Compiler<'c> {
|
||||||
self.compile_expr(rhs)?;
|
self.compile_expr(rhs)?;
|
||||||
self.emit(I::BinaryOp(*op));
|
self.emit(I::BinaryOp(*op));
|
||||||
},
|
},
|
||||||
E::Index(_, _) => return Err(self::Error::NotImplemented("indexing").into()),
|
E::Index(expr, params) => {
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
for param in params {
|
||||||
|
self.compile_expr(param)?;
|
||||||
|
}
|
||||||
|
self.emit(I::Index(params.len() as u8))
|
||||||
|
},
|
||||||
E::FnCall(fun, params) => {
|
E::FnCall(fun, params) => {
|
||||||
for expr in params {
|
for expr in params {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
|
@ -395,7 +448,11 @@ impl<'c> Compiler<'c> {
|
||||||
self.compile_expr(fun)?;
|
self.compile_expr(fun)?;
|
||||||
self.emit(I::Call(params.len() as u8));
|
self.emit(I::Call(params.len() as u8));
|
||||||
},
|
},
|
||||||
E::FieldAccess(_, _) => return Err(self::Error::NotImplemented("filed access").into()),
|
E::FieldAccess(expr, field) => {
|
||||||
|
self.compile_expr(expr)?;
|
||||||
|
let idx = self.get_name(field.clone());
|
||||||
|
self.emit(I::Field(idx as u16))
|
||||||
|
}
|
||||||
E::List(list) => {
|
E::List(list) => {
|
||||||
for expr in list {
|
for expr in list {
|
||||||
self.compile_expr(expr)?;
|
self.compile_expr(expr)?;
|
||||||
|
@ -503,7 +560,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(), body: self.chunk.clone(), arity: 0 };
|
let fun = Function { name: self.name.clone(), fun: InnerFunction::Compiled(self.chunk.clone().into()), arity: 0, variadic: false };
|
||||||
Ok(Rc::new(fun))
|
Ok(Rc::new(fun))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
126
matrix/src/gc.rs
126
matrix/src/gc.rs
|
@ -1,112 +1,126 @@
|
||||||
use std::cmp::Ordering;
|
use std::{ops::{Index, IndexMut, Deref, DerefMut}, marker::PhantomData, ptr::NonNull, fmt::{Debug, Display}};
|
||||||
use std::fmt::{Debug, Display};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
use std::ptr::NonNull;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct Gc<T> {
|
pub struct Gc<T> {
|
||||||
ptr: NonNull<GcInner<T>>,
|
ptr: NonNull<GcInner<T>>,
|
||||||
phantom: PhantomData<GcInner<T>>,
|
phantom: PhantomData<GcInner<T>>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GcInner<T> {
|
struct GcInner<T> {
|
||||||
rc: usize,
|
rc: usize,
|
||||||
data: T,
|
data: T
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Gc<T> {
|
impl<T> Gc<T> {
|
||||||
pub fn new(data: T) -> Gc<T> {
|
pub fn new(data: T) -> Self {
|
||||||
let boxed = Box::new(GcInner {
|
let boxed = Box::new(GcInner {
|
||||||
rc: 1,
|
rc: 1,
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
Self {
|
Self {
|
||||||
ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
|
ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> From<Rc<T>> for Gc<T> {
|
impl <T: Clone> Gc<T> {
|
||||||
fn from(value: Rc<T>) -> Self {
|
pub fn clone_inside(&self) -> Self {
|
||||||
Self::new(Rc::unwrap_or_clone(value))
|
unsafe {
|
||||||
|
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 {
|
||||||
Self::new(value)
|
Gc::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: IndexMut<Idx>, Idx> IndexMut<Idx> for Gc<T> {
|
||||||
|
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
|
||||||
|
self.deref_mut().index_mut(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Index<Idx>, Idx> Index<Idx> for Gc<T> {
|
||||||
|
type Output = T::Output;
|
||||||
|
|
||||||
|
fn index(&self, index: Idx) -> &Self::Output {
|
||||||
|
self.deref().index(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DerefMut for Gc<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe {
|
||||||
|
&mut self.ptr.as_mut().data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for Gc<T> {
|
impl<T> Deref for Gc<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
fn deref(&self) -> &T {
|
|
||||||
let inner = unsafe { self.ptr.as_ref() };
|
fn deref(&self) -> &Self::Target {
|
||||||
&inner.data
|
unsafe {
|
||||||
|
&self.ptr.as_ref().data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Debug for Gc<T> {
|
impl <T: PartialEq> PartialEq 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 {
|
||||||
let inner = unsafe { self.ptr.as_ref() };
|
self.deref().eq(other.deref())
|
||||||
let other = unsafe { other.ptr.as_ref() };
|
|
||||||
inner.data == other.data
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PartialOrd> PartialOrd for Gc<T> {
|
impl <T: Iterator> Iterator for Gc<T> {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
type Item = T::Item;
|
||||||
let inner = unsafe { self.ptr.as_ref() };
|
|
||||||
let other = unsafe { other.ptr.as_ref() };
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
inner.data.partial_cmp(&other.data)
|
self.deref_mut().next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> DerefMut for Gc<T> {
|
impl<T: Eq> Eq for Gc<T> {}
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
let inner = unsafe { self.ptr.as_mut() };
|
|
||||||
if inner.rc > 1 {
|
|
||||||
*self = Self::new(inner.data.clone());
|
|
||||||
}
|
|
||||||
&mut inner.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for Gc<T> {
|
impl<T> Clone for Gc<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let inner = unsafe { self.ptr.as_ptr().as_mut().unwrap() };
|
unsafe {
|
||||||
|
let inner = self.ptr.as_ptr().as_mut().unwrap();
|
||||||
inner.rc += 1;
|
inner.rc += 1;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
ptr: self.ptr,
|
ptr: self.ptr,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for Gc<T> {
|
impl<T> Drop for Gc<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let inner = unsafe { self.ptr.as_mut() };
|
unsafe {
|
||||||
|
let inner = self.ptr.as_mut();
|
||||||
|
if inner.rc > 1 {
|
||||||
inner.rc -= 1;
|
inner.rc -= 1;
|
||||||
if inner.rc > 0 {
|
} else {
|
||||||
return;
|
let _ = Box::from_raw(self.ptr.as_ptr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unsafe { let _ = Box::from_raw(self.ptr.as_ptr()); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> Debug for Gc<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?}", self.deref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Display> Display for Gc<T> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.deref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,9 +38,7 @@ pub enum Token {
|
||||||
LeftBrack,
|
LeftBrack,
|
||||||
RightBrack,
|
RightBrack,
|
||||||
LeftBrace,
|
LeftBrace,
|
||||||
LeftLeftBrace,
|
|
||||||
RightBrace,
|
RightBrace,
|
||||||
RightRightBrace,
|
|
||||||
Assign,
|
Assign,
|
||||||
Access,
|
Access,
|
||||||
SemiColon,
|
SemiColon,
|
||||||
|
@ -48,6 +46,17 @@ 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,
|
||||||
|
@ -67,14 +76,6 @@ pub enum Token {
|
||||||
BitwiseOr,
|
BitwiseOr,
|
||||||
BitwiseXor,
|
BitwiseXor,
|
||||||
|
|
||||||
// math
|
|
||||||
Regex(RegexToken),
|
|
||||||
Int(i64),
|
|
||||||
Float(f64),
|
|
||||||
Complex(f64),
|
|
||||||
String(Rc<str>),
|
|
||||||
Ident(Rc<str>),
|
|
||||||
|
|
||||||
Add,
|
Add,
|
||||||
Subtract,
|
Subtract,
|
||||||
Multiply,
|
Multiply,
|
||||||
|
@ -82,6 +83,22 @@ pub enum Token {
|
||||||
Modulo,
|
Modulo,
|
||||||
Power,
|
Power,
|
||||||
|
|
||||||
|
AssignAnd,
|
||||||
|
AssignOr,
|
||||||
|
|
||||||
|
AssignBitwiseShiftLeft,
|
||||||
|
AssignBitwiseShiftRight,
|
||||||
|
AssignBitwiseAnd,
|
||||||
|
AssignBitwiseOr,
|
||||||
|
AssignBitwiseXor,
|
||||||
|
|
||||||
|
AssignAdd,
|
||||||
|
AssignSubtract,
|
||||||
|
AssignMultiply,
|
||||||
|
AssignDivide,
|
||||||
|
AssignModulo,
|
||||||
|
AssignPower,
|
||||||
|
|
||||||
// keywords
|
// keywords
|
||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
|
@ -193,7 +210,7 @@ impl Lexer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_whitespace(&mut self, ignore_newlines: bool) {
|
fn skip_whitespace(&mut self, ignore_newlines: bool) {
|
||||||
while self.peek().is_whitespace() && (!ignore_newlines || self.peek() != '\n') {
|
while self.peek().is_whitespace() && (ignore_newlines || self.peek() != '\n') {
|
||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,42 +437,63 @@ impl Lexer {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(match char {
|
Ok(match char {
|
||||||
|
'\n' => SemiColon,
|
||||||
'(' => LeftParen,
|
'(' => LeftParen,
|
||||||
')' => RightParen,
|
')' => RightParen,
|
||||||
'[' => LeftBrack,
|
'[' => LeftBrack,
|
||||||
']' => RightBrack,
|
']' => RightBrack,
|
||||||
'{' => {
|
'{' => LeftBrace,
|
||||||
match next {
|
'}' => RightBrace,
|
||||||
'{' => {
|
':' => Colon,
|
||||||
self.next();
|
'\\' => Backslash,
|
||||||
LeftLeftBrace
|
|
||||||
}
|
|
||||||
_ => LeftBrace
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'}' => {
|
|
||||||
match next {
|
|
||||||
'}' => {
|
|
||||||
self.next();
|
|
||||||
RightRightBrace
|
|
||||||
}
|
|
||||||
_ => RightBrace
|
|
||||||
}
|
|
||||||
},
|
|
||||||
';' => SemiColon,
|
';' => SemiColon,
|
||||||
'+' => Add,
|
'+' => {
|
||||||
|
match next {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignAdd
|
||||||
|
}
|
||||||
|
_ => Add
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'/' => {
|
||||||
|
match next {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignDivide
|
||||||
|
}
|
||||||
|
_ => Divide
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'%' => {
|
||||||
|
match next {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignModulo
|
||||||
|
}
|
||||||
|
_ => Modulo
|
||||||
|
}
|
||||||
|
},
|
||||||
',' => Comma,
|
',' => Comma,
|
||||||
'*' => {
|
'*' => {
|
||||||
match next {
|
match next {
|
||||||
'*' => {
|
'*' => {
|
||||||
self.next();
|
self.next();
|
||||||
Power
|
match self.peek() {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignPower
|
||||||
|
},
|
||||||
|
_ => Power
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignMultiply
|
||||||
}
|
}
|
||||||
_ => Multiply
|
_ => Multiply
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'/' => Divide,
|
|
||||||
'%' => Modulo,
|
|
||||||
'!' => {
|
'!' => {
|
||||||
match next {
|
match next {
|
||||||
'=' => {
|
'=' => {
|
||||||
|
@ -469,8 +507,18 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'&' => {
|
'&' => {
|
||||||
self.next();
|
self.next();
|
||||||
And
|
match self.peek() {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignAnd
|
||||||
|
},
|
||||||
|
_ => And
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignBitwiseAnd
|
||||||
|
},
|
||||||
_ => BitwiseAnd
|
_ => BitwiseAnd
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -478,8 +526,18 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'|' => {
|
'|' => {
|
||||||
self.next();
|
self.next();
|
||||||
Or
|
match self.peek() {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignOr
|
||||||
|
},
|
||||||
|
_ => Or
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignBitwiseOr
|
||||||
|
},
|
||||||
_ => BitwiseOr
|
_ => BitwiseOr
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -488,7 +546,11 @@ impl Lexer {
|
||||||
'>' => {
|
'>' => {
|
||||||
self.next();
|
self.next();
|
||||||
ThinArrow
|
ThinArrow
|
||||||
}
|
},
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignSubtract
|
||||||
|
},
|
||||||
_ => Subtract
|
_ => Subtract
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -509,7 +571,13 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'>' => {
|
'>' => {
|
||||||
self.next();
|
self.next();
|
||||||
BitwiseShiftRight
|
match self.peek() {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignBitwiseShiftRight
|
||||||
|
},
|
||||||
|
_ => BitwiseShiftRight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'=' => {
|
'=' => {
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -522,7 +590,13 @@ impl Lexer {
|
||||||
match next {
|
match next {
|
||||||
'<' => {
|
'<' => {
|
||||||
self.next();
|
self.next();
|
||||||
BitwiseShiftLeft
|
match self.peek() {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignBitwiseShiftLeft
|
||||||
|
},
|
||||||
|
_ => BitwiseShiftLeft
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'=' => {
|
'=' => {
|
||||||
self.next();
|
self.next();
|
||||||
|
@ -531,7 +605,15 @@ impl Lexer {
|
||||||
_ => LessThan
|
_ => LessThan
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'^' => BitwiseXor,
|
'^' => {
|
||||||
|
match next {
|
||||||
|
'=' => {
|
||||||
|
self.next();
|
||||||
|
AssignBitwiseXor
|
||||||
|
},
|
||||||
|
_ => BitwiseXor
|
||||||
|
}
|
||||||
|
}
|
||||||
'\'' | '\"' => String(self.lex_string(char)?),
|
'\'' | '\"' => String(self.lex_string(char)?),
|
||||||
'r' => {
|
'r' => {
|
||||||
match next {
|
match next {
|
||||||
|
@ -548,7 +630,14 @@ impl Lexer {
|
||||||
},
|
},
|
||||||
'.' => {
|
'.' => {
|
||||||
if next == '.' {
|
if next == '.' {
|
||||||
Range
|
self.next();
|
||||||
|
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}, gc::Gc, value::{Value, self}, Result};
|
use crate::{lex::{Lexer, self, Token}, ast::{Expr, BinaryOp, UnaryOp, optimize}, value::{Value, self}, Result};
|
||||||
|
|
||||||
use Value as V;
|
use Value as V;
|
||||||
use Expr as E;
|
use Expr as E;
|
||||||
|
@ -40,7 +40,7 @@ pub enum Error {
|
||||||
UnexpectedToken(Token),
|
UnexpectedToken(Token),
|
||||||
ExpectedToken(Token),
|
ExpectedToken(Token),
|
||||||
ExpectedTokenName(&'static str),
|
ExpectedTokenName(&'static str),
|
||||||
MatrixCoDomainError(usize, usize, usize),
|
MatrixInvDomain(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"),
|
||||||
MatrixCoDomainError(row, should, was) => write!(f, "In col {row} of matrix, codomain was expected to be {should} but was given {was}"),
|
MatrixInvDomain(row, should, was) => write!(f, "In row {row} of matrix, domain was expected to be {should} but was given {was}"),
|
||||||
NotAssignable(expr) => write!(f, "{expr:?} is not assignable"),
|
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[0].len();
|
let codomain = parts.len();
|
||||||
let domain = parts.len();
|
let domain = parts[0].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::MatrixCoDomainError(i, codomain, part.len()).into())
|
return Err(Error::MatrixInvDomain(i, domain, part.len()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
|
@ -230,9 +230,10 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_table(&mut self) -> Result<Expr> {
|
fn parse_table(&mut self) -> Result<Expr> {
|
||||||
self.force_token(T::LeftLeftBrace)?;
|
self.force_token(T::Colon)?;
|
||||||
|
self.force_token(T::LeftBrace)?;
|
||||||
let mut table = Vec::new();
|
let mut table = Vec::new();
|
||||||
if self.lexer.peek_token()? == T::RightRightBrace {
|
if self.lexer.peek_token()? == T::RightBrace {
|
||||||
self.lexer.next_token()?;
|
self.lexer.next_token()?;
|
||||||
return Ok(E::Table(table))
|
return Ok(E::Table(table))
|
||||||
}
|
}
|
||||||
|
@ -244,7 +245,7 @@ impl Parser {
|
||||||
let next = self.lexer.next_token()?;
|
let next = self.lexer.next_token()?;
|
||||||
match next {
|
match next {
|
||||||
T::Comma => continue,
|
T::Comma => continue,
|
||||||
T::RightRightBrace => break,
|
T::RightBrace => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
_ => return Err(Error::UnexpectedToken(next).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,20 +259,29 @@ impl Parser {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_params(&mut self) -> Result<Vec<Rc<str>>> {
|
fn parse_params(&mut self) -> Result<(Vec<Rc<str>>, bool)> {
|
||||||
use T::*;
|
use T::*;
|
||||||
let tok = self.lexer.next_token()?;
|
let tok = self.lexer.next_token()?;
|
||||||
match tok {
|
match tok {
|
||||||
Ident(ident) => return Ok(vec![ident]),
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
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);
|
return Ok((params, varadic));
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -279,13 +289,18 @@ 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)
|
Ok((params, varadic))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident(&mut self) -> Result<Rc<str>> {
|
fn parse_ident(&mut self) -> Result<Rc<str>> {
|
||||||
|
@ -307,12 +322,23 @@ 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 = match self.lexer.peek_token()? {
|
let (params, varadic) = match self.lexer.peek_token()? {
|
||||||
T::LeftBrace => vec![],
|
T::LeftBrace => (vec![], false),
|
||||||
_ => self.parse_params()?,
|
_ => self.parse_params()?,
|
||||||
};
|
};
|
||||||
let expr = self.parse_expr()?;
|
let expr = self.parse_expr()?;
|
||||||
Ok(E::Function(ident, params, Box::new(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))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_do_while(&mut self) -> Result<Expr> {
|
fn parse_do_while(&mut self) -> Result<Expr> {
|
||||||
|
@ -386,7 +412,7 @@ impl Parser {
|
||||||
match next {
|
match next {
|
||||||
T::SemiColon => continue,
|
T::SemiColon => continue,
|
||||||
T::RightBrace => break,
|
T::RightBrace => break,
|
||||||
_ => return Err(Error::UnexpectedToken(next).into())
|
_ => return Err(Error::ExpectedToken(T::SemiColon).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.lexer.peek_token()? == T::RightBrace {
|
if self.lexer.peek_token()? == T::RightBrace {
|
||||||
|
@ -402,7 +428,7 @@ impl Parser {
|
||||||
T::Int(i) => E::Literal(V::Int(i)),
|
T::Int(i) => E::Literal(V::Int(i)),
|
||||||
T::Float(f) => E::Literal(V::Float(f)),
|
T::Float(f) => E::Literal(V::Float(f)),
|
||||||
T::Complex(c) => E::Literal(V::Complex(Complex64::new(0.0, c))),
|
T::Complex(c) => E::Literal(V::Complex(Complex64::new(0.0, c))),
|
||||||
T::Regex(r) => E::Literal(V::Regex(Gc::new(r.into()))),
|
T::Regex(r) => E::Literal(V::Regex(Rc::new(r.into()))),
|
||||||
T::String(s) => E::Literal(V::String(s.to_string().into())),
|
T::String(s) => E::Literal(V::String(s.to_string().into())),
|
||||||
T::True => E::Literal(V::Bool(true)),
|
T::True => E::Literal(V::Bool(true)),
|
||||||
T::False => E::Literal(V::Bool(false)),
|
T::False => E::Literal(V::Bool(false)),
|
||||||
|
@ -415,6 +441,7 @@ 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(),
|
||||||
|
@ -431,7 +458,7 @@ impl Parser {
|
||||||
Ok(E::Continue)
|
Ok(E::Continue)
|
||||||
},
|
},
|
||||||
LeftBrack => self.parse_matrix(),
|
LeftBrack => self.parse_matrix(),
|
||||||
LeftLeftBrace => self.parse_table(),
|
Colon => self.parse_table(),
|
||||||
LeftParen => self.parse_paren(),
|
LeftParen => self.parse_paren(),
|
||||||
_ => self.parse_value(),
|
_ => self.parse_value(),
|
||||||
}
|
}
|
||||||
|
@ -444,8 +471,8 @@ impl Parser {
|
||||||
match tok {
|
match tok {
|
||||||
T::Access => {
|
T::Access => {
|
||||||
self.force_token(T::Access)?;
|
self.force_token(T::Access)?;
|
||||||
let temp = self.parse_term()?;
|
let temp = self.parse_ident()?;
|
||||||
expr = E::FieldAccess(Box::new(expr), Box::new(temp));
|
expr = E::FieldAccess(Box::new(expr), temp);
|
||||||
},
|
},
|
||||||
_ => break
|
_ => break
|
||||||
}
|
}
|
||||||
|
@ -563,13 +590,66 @@ impl Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(&mut self) -> Result<Expr> {
|
fn parse_expr(&mut self) -> Result<Expr> {
|
||||||
|
use BinaryOp as B;
|
||||||
let expr = self.parse_expr_or()?;
|
let expr = self.parse_expr_or()?;
|
||||||
let tok = self.lexer.peek_token_nl()?;
|
let tok = self.lexer.peek_token_nl()?;
|
||||||
Ok(match tok {
|
Ok(match tok {
|
||||||
T::Assign => {
|
T::Assign => {
|
||||||
self.lexer.next_token_nl()?;
|
self.lexer.next_token_nl()?;
|
||||||
E::Assign(Box::new(expr),Box::new(self.parse_expr()?))
|
E::Assign(Box::new(expr.clone()),Box::new(self.parse_expr()?))
|
||||||
}
|
},
|
||||||
|
T::AssignAnd => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::And(Box::new(expr), Box::new(self.parse_expr()?))))
|
||||||
|
},
|
||||||
|
T::AssignOr => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::Or(Box::new(expr), Box::new(self.parse_expr()?))))
|
||||||
|
},
|
||||||
|
T::AssignAdd => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Add)))
|
||||||
|
},
|
||||||
|
T::AssignSubtract => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Subtract)))
|
||||||
|
},
|
||||||
|
T::AssignMultiply => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Multiply)))
|
||||||
|
},
|
||||||
|
T::AssignDivide => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Divide)))
|
||||||
|
},
|
||||||
|
T::AssignModulo => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Modulo)))
|
||||||
|
},
|
||||||
|
T::AssignPower => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::Power)))
|
||||||
|
},
|
||||||
|
T::AssignBitwiseAnd => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseAnd)))
|
||||||
|
},
|
||||||
|
T::AssignBitwiseOr => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseOr)))
|
||||||
|
},
|
||||||
|
T::AssignBitwiseXor => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseXor)))
|
||||||
|
},
|
||||||
|
T::AssignBitwiseShiftLeft => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseShiftLeft)))
|
||||||
|
},
|
||||||
|
T::AssignBitwiseShiftRight => {
|
||||||
|
self.lexer.next_token_nl()?;
|
||||||
|
E::Assign(Box::new(expr.clone()),Box::new(E::BinaryOp(Box::new(expr), Box::new(self.parse_expr()?), B::BitwiseShiftRight)))
|
||||||
|
},
|
||||||
_ => expr
|
_ => expr
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -587,6 +667,11 @@ 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}, gc::Gc, chunk::Function, Result};
|
use crate::{ast::{Expr, BinaryOp, UnaryOp}, chunk::Function, Result, gc::Gc};
|
||||||
|
|
||||||
pub type List = Vec<Value>;
|
pub type List = Vec<Value>;
|
||||||
pub type Matrix = (usize, usize, Vec<Value>);
|
pub type Matrix = (usize, usize, Vec<Value>);
|
||||||
|
@ -43,12 +43,14 @@ pub enum Error {
|
||||||
Exponent(Value, Value),
|
Exponent(Value, Value),
|
||||||
Compare(Value, Value),
|
Compare(Value, Value),
|
||||||
IndexOutOfBounds(usize, usize),
|
IndexOutOfBounds(usize, usize),
|
||||||
Index(Value, Value),
|
CannotIndex(Value),
|
||||||
|
BadIndex(Value, Value),
|
||||||
Concat(Value, Value),
|
Concat(Value, Value),
|
||||||
Bitwise(Value, Value),
|
Bitwise(Value, Value),
|
||||||
DivideByZero,
|
DivideByZero,
|
||||||
ZeroExpZero,
|
ZeroExpZero,
|
||||||
CannotHash(Value),
|
CannotHash(Value),
|
||||||
|
FieldAccess(Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for self::Error {
|
impl Display for self::Error {
|
||||||
|
@ -64,12 +66,14 @@ impl Display for self::Error {
|
||||||
Exponent(a, b) => write!(f, "cannot compute {a:?} pow {b:?}"),
|
Exponent(a, b) => write!(f, "cannot compute {a:?} pow {b:?}"),
|
||||||
Compare(a, b) => write!(f, "cannot compare {a:?} and {b:?}"),
|
Compare(a, b) => write!(f, "cannot compare {a:?} and {b:?}"),
|
||||||
IndexOutOfBounds(a, b) => write!(f, "index {a} out of bounds for list of length {b}"),
|
IndexOutOfBounds(a, b) => write!(f, "index {a} out of bounds for list of length {b}"),
|
||||||
Index(a, b) => write!(f, "cannot index {a:?} with {b:?}"),
|
BadIndex(a, b) => write!(f, "cannot index {a:?} with {b:?}"),
|
||||||
|
CannotIndex(a) => write!(f, "cannot index {a:?}"),
|
||||||
Concat(a, b) => write!(f, "cannot concat {a:?} and {b:?}"),
|
Concat(a, b) => write!(f, "cannot concat {a:?} and {b:?}"),
|
||||||
Bitwise(a, b) => write!(f, "cannot bitwise between {a:?} and {b:?}"),
|
Bitwise(a, b) => write!(f, "cannot bitwise between {a:?} and {b:?}"),
|
||||||
DivideByZero => write!(f, "attempted to divide by zero"),
|
DivideByZero => write!(f, "attempted to divide by zero"),
|
||||||
ZeroExpZero => write!(f, "cannot exponent zero with zero"),
|
ZeroExpZero => write!(f, "cannot exponent zero with zero"),
|
||||||
CannotHash(v) => write!(f, "cannot hash {v:?}"),
|
CannotHash(v) => write!(f, "cannot hash {v:?}"),
|
||||||
|
FieldAccess(a) => write!(f, "{a:?} cannot be field accessed"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,8 +88,8 @@ pub enum Value {
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Ratio(Rational64),
|
Ratio(Rational64),
|
||||||
Complex(Complex64),
|
Complex(Complex64),
|
||||||
Regex(Gc<Regex>),
|
Regex(Rc<Regex>),
|
||||||
String(Gc<String>),
|
String(Rc<String>),
|
||||||
List(Gc<List>),
|
List(Gc<List>),
|
||||||
Matrix(Gc<Matrix>),
|
Matrix(Gc<Matrix>),
|
||||||
Table(Gc<Table>),
|
Table(Gc<Table>),
|
||||||
|
@ -153,36 +157,35 @@ 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 = "[[ ".to_string();
|
let mut str = "\n".to_string();
|
||||||
for (i, el) in m.2.iter().enumerate() {
|
for row in m.2.chunks(m.0) {
|
||||||
if i != 0 {
|
|
||||||
if (i % m.1) == 0 {
|
|
||||||
str.push_str(" ; ");
|
|
||||||
} else {
|
|
||||||
str.push_str(" ");
|
str.push_str(" ");
|
||||||
|
for (i, v) in row.iter().enumerate() {
|
||||||
|
if i != 0 {
|
||||||
|
str.push(' ');
|
||||||
}
|
}
|
||||||
|
str.push_str(&v.boring_print());
|
||||||
}
|
}
|
||||||
str.push_str(&el.boring_print());
|
str.push('\n');
|
||||||
}
|
}
|
||||||
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(", ");
|
||||||
|
@ -191,11 +194,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!("[Function: {}]", fun.name)
|
format!("{fun:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,33 +215,32 @@ 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 = "[[ ".to_string();
|
let mut str = "\n".to_string();
|
||||||
for (i, el) in m.2.iter().enumerate() {
|
for row in m.2.chunks(m.0) {
|
||||||
if i != 0 {
|
|
||||||
if (i % m.1) == 0 {
|
|
||||||
str.push_str(" ; ");
|
|
||||||
} else {
|
|
||||||
str.push_str(" ");
|
str.push_str(" ");
|
||||||
|
for (i, v) in row.iter().enumerate() {
|
||||||
|
if i != 0 {
|
||||||
|
str.push(' ');
|
||||||
}
|
}
|
||||||
|
str.push_str(&v.pretty_print());
|
||||||
}
|
}
|
||||||
str.push_str(&el.pretty_print());
|
str.push('\n');
|
||||||
}
|
}
|
||||||
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(", ");
|
||||||
|
@ -247,12 +249,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())
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,10 +297,10 @@ impl Add for Value {
|
||||||
(Float(x), Float(y)) => Ok(Float(x + y)),
|
(Float(x), Float(y)) => Ok(Float(x + y)),
|
||||||
(Ratio(x), Ratio(y)) => Ok(Ratio(x + y)),
|
(Ratio(x), Ratio(y)) => Ok(Ratio(x + y)),
|
||||||
(Complex(x), Complex(y)) => Ok(Complex(x + y)),
|
(Complex(x), Complex(y)) => Ok(Complex(x + y)),
|
||||||
(String(str), value) => Ok(String(Gc::new(
|
(String(str), value) => Ok(String(Rc::new(
|
||||||
format!("{str}{}", value.boring_print())
|
format!("{str}{}", value.boring_print())
|
||||||
))),
|
))),
|
||||||
(value, String(str)) => Ok(String(Gc::new(
|
(value, String(str)) => Ok(String(Rc::new(
|
||||||
format!("{}{str}", value.boring_print())
|
format!("{}{str}", value.boring_print())
|
||||||
))),
|
))),
|
||||||
(List(mut l1), List(l2)) => {
|
(List(mut l1), List(l2)) => {
|
||||||
|
@ -420,28 +422,18 @@ fn ipow(n: i64, d: i64, p: i64) -> Result<(i64, i64)> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
|
||||||
pub fn modulo(self, rhs: Value) -> Result<Self> {
|
pub fn modulo(self, rhs: Value) -> Result<Self> {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
match promote(self, rhs) {
|
match promote(self, rhs) {
|
||||||
(Int(x), Int(y)) => Ok(Int(x.rem_euclid(y))),
|
(Int(x), Int(y)) => Ok(Int(x % y)),
|
||||||
(Float(x), Float(y)) => Ok(Float(x.rem_euclid(y))),
|
(Float(x), Float(y)) => Ok(Float(x % y)),
|
||||||
(Ratio(_x), Ratio(_y)) => todo!("ratio modulo"),
|
(Ratio(x), Ratio(y)) => Ok(Ratio(x % y)),
|
||||||
(Complex(_x), Complex(_y)) => todo!("complex modulo"),
|
(Complex(x), Complex(y)) => Ok(Complex(x % y)),
|
||||||
(l, r) => Err(Error::Modulo(r, l).into())
|
(l, r) => Err(Error::Modulo(r, l).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn int_div(self, rhs: Value) -> Result<Self> {
|
|
||||||
use Value::*;
|
|
||||||
match promote(self, rhs) {
|
|
||||||
(Int(x), Int(y)) => Ok(Int(x.div_euclid(y))),
|
|
||||||
(Float(x), Float(y)) => Ok(Float(x.div_euclid(y))),
|
|
||||||
(Ratio(_x), Ratio(_y)) => todo!("ratio integer division"),
|
|
||||||
(Complex(_x), Complex(_y)) => todo!("complex integer division"),
|
|
||||||
(l, r) => Err(Error::Divide(l, r).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pow(self, rhs: Value) -> Result<Self> {
|
pub fn pow(self, rhs: Value) -> Result<Self> {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
if let (Ratio(x), Int(y)) = (&self, &rhs) {
|
if let (Ratio(x), Int(y)) = (&self, &rhs) {
|
||||||
|
@ -455,6 +447,16 @@ 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 {}
|
||||||
|
@ -518,23 +520,122 @@ impl Value {
|
||||||
.map_or_else(|| Err(Error::Compare(self.clone(), other.clone()).into()), Ok)
|
.map_or_else(|| Err(Error::Compare(self.clone(), other.clone()).into()), Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_index(&self, _other: &Vec<Self>, _value: &Self) -> Result<()> {
|
fn index_single(&self, index: &Value) -> Result<Self> {
|
||||||
todo!()
|
use Value as V;
|
||||||
|
match (self, index) {
|
||||||
|
(V::Table(t), index) => {
|
||||||
|
Ok(t.get(index)?.unwrap_or(&Value::Nil).clone())
|
||||||
|
},
|
||||||
|
(V::List(l), V::Int(i)) => {
|
||||||
|
if *i < 0 || *i as usize >= l.len() {
|
||||||
|
return Err(Error::IndexOutOfBounds(*i as usize, l.len()).into())
|
||||||
|
}
|
||||||
|
Ok(l[*i as usize].clone())
|
||||||
|
},
|
||||||
|
_ => return Err(self::Error::BadIndex(self.clone(), index.clone()).into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index(&self, _other: &Vec<Self>) -> Result<Self> {
|
fn index_multiple(&self, indexes: &Vec<Value>) -> Result<Self> {
|
||||||
todo!()
|
use Value as V;
|
||||||
//use Value::*;
|
match self {
|
||||||
//match (self, other) {
|
V::List(..) => {
|
||||||
// (List(l), Int(i)) => {
|
let mut ret = Vec::new();
|
||||||
// if *i >= 0 && *i < l.len() as i64 {
|
for index in indexes {
|
||||||
// Ok(l[*i as usize].clone())
|
let res = self.index_single(index)?;
|
||||||
// } else {
|
ret.push(res);
|
||||||
// Err(Error::IndexOutOfBounds(*i as usize, l.len()))
|
}
|
||||||
// }
|
Ok(V::List(ret.into()))
|
||||||
// },
|
}
|
||||||
// (l, r) => Err(Error::Index(l.clone(), r.clone()))
|
V::Table(..) => {
|
||||||
//}
|
let mut ret = ValueMap::new();
|
||||||
|
for index in indexes {
|
||||||
|
let res = self.index_single(index)?;
|
||||||
|
ret.insert(index.clone(), res)?;
|
||||||
|
}
|
||||||
|
Ok(V::Table(ret.into()))
|
||||||
|
}
|
||||||
|
_ => return Err(self::Error::CannotIndex(self.clone()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self, index: &Vec<Value>) -> Result<Self> {
|
||||||
|
if index.len() == 0 {
|
||||||
|
Ok(self.clone_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> {
|
||||||
|
@ -557,7 +658,6 @@ impl Value {
|
||||||
LessEquals => Ok(Self::Bool(lhs <= rhs)),
|
LessEquals => Ok(Self::Bool(lhs <= rhs)),
|
||||||
GreaterThan => Ok(Self::Bool(lhs > rhs)),
|
GreaterThan => Ok(Self::Bool(lhs > rhs)),
|
||||||
LessThan => Ok(Self::Bool(lhs < rhs)),
|
LessThan => Ok(Self::Bool(lhs < rhs)),
|
||||||
Range => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
148
matrix/src/vm.rs
148
matrix/src/vm.rs
|
@ -1,5 +1,5 @@
|
||||||
use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap};
|
use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap, cell::RefCell, sync::{atomic::{AtomicUsize, Ordering}, Arc}};
|
||||||
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result};
|
use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction, Chunk, InnerFunction}, Result, compiler::NamesTable};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -7,6 +7,7 @@ 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 {}
|
||||||
|
@ -19,6 +20,7 @@ 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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,26 +90,36 @@ impl<T> Index<usize> for Stack<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StackFrame {
|
struct StackFrame {
|
||||||
fun: Rc<Function>,
|
#[allow(dead_code)]
|
||||||
|
name: Rc<str>,
|
||||||
|
body: Rc<Chunk>,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
bp: usize,
|
bp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackFrame {
|
impl StackFrame {
|
||||||
fn new(vm: &Vm, fun: Rc<Function>) -> Self {
|
fn new(vm: &Vm, name: Rc<str>, body: Rc<Chunk>, arity: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bp: vm.stack.len() - fun.arity,
|
name,
|
||||||
|
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 {
|
||||||
|
@ -120,26 +132,66 @@ 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 = StackFrame::new(&self, fun);
|
let mut frame = self.init_frame(fun)?;
|
||||||
|
self.interupt.store(0, Ordering::SeqCst);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
use Instruction::*;
|
use Instruction::*;
|
||||||
let ins = frame.fun.body.code[frame.ip].clone();
|
let ins = frame.body.code[frame.ip].clone();
|
||||||
frame.ip += 1;
|
frame.ip += 1;
|
||||||
|
|
||||||
match ins {
|
match ins {
|
||||||
NoOp => {},
|
NoOp => {},
|
||||||
CreateLocal => self.locals.push(self.stack.pop()),
|
CreateLocal => self.locals.push(self.stack.pop()),
|
||||||
LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());},
|
LoadLocal(idx) => {self.stack.push(self.locals[idx as usize].clone());},
|
||||||
StoreLocal(idx) => self.stack[frame.bp + idx as usize] = self.pop(),
|
StoreLocal(idx) => self.locals[frame.bp + idx as usize] = self.pop(),
|
||||||
DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
|
DiscardLocals(count) => {self.locals.truncate(self.locals.len() - count as usize)},
|
||||||
LoadGlobal(idx) => {
|
LoadGlobal(idx) => {
|
||||||
let val = self.globals
|
let val = self.globals
|
||||||
|
@ -152,7 +204,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.fun.body.constants[idx as usize].clone()),
|
Const(idx) => self.push(frame.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)),
|
||||||
|
@ -187,25 +239,24 @@ impl Vm {
|
||||||
let domain = list.len() / codomain;
|
let domain = list.len() / codomain;
|
||||||
self.push(Value::Matrix(Gc::new((domain, codomain, list.inner))));
|
self.push(Value::Matrix(Gc::new((domain, codomain, list.inner))));
|
||||||
}
|
}
|
||||||
Index(count) => {
|
Jump(idx) => {
|
||||||
let index = self.stack.split_off(self.stack.len() - count as usize);
|
if self.check_interupt() {
|
||||||
let collection = self.pop();
|
return Ok(Value::Nil)
|
||||||
let value = collection.index(&index.inner)?;
|
}
|
||||||
self.stack.push(value);
|
frame.ip = idx as usize;
|
||||||
},
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -215,14 +266,38 @@ 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())
|
||||||
};
|
};
|
||||||
if fun.arity != arity as usize {
|
let arity = arity as usize;
|
||||||
return Err(Error::InvArity(fun.arity, arity as usize, fun.name.clone()).into())
|
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())
|
||||||
}
|
}
|
||||||
let new_frame = StackFrame::new(&self, fun);
|
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);
|
self.frames.push(frame);
|
||||||
frame = new_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
@ -231,6 +306,29 @@ impl Vm {
|
||||||
self.push(ret);
|
self.push(ret);
|
||||||
frame = prev_frame;
|
frame = prev_frame;
|
||||||
},
|
},
|
||||||
|
Field(name_idx) => {
|
||||||
|
let expr = self.pop();
|
||||||
|
let name = self.names.borrow()[name_idx as usize].clone();
|
||||||
|
self.push(expr.field_access(&name)?);
|
||||||
|
},
|
||||||
|
StoreField(name_idx) => {
|
||||||
|
let mut expr = self.pop();
|
||||||
|
let value = self.pop();
|
||||||
|
let name = self.names.borrow()[name_idx as usize].clone();
|
||||||
|
expr.store_field_access(&name, value)?;
|
||||||
|
},
|
||||||
|
Index(count) => {
|
||||||
|
let index = self.stack.split_off(self.stack.len() - count as usize);
|
||||||
|
let collection = self.pop();
|
||||||
|
let value = collection.index(&index.inner)?;
|
||||||
|
self.stack.push(value);
|
||||||
|
},
|
||||||
|
StoreIndex(count) => {
|
||||||
|
let index = self.stack.split_off(self.stack.len() - count as usize);
|
||||||
|
let mut collection = self.pop();
|
||||||
|
let value = self.pop();
|
||||||
|
collection.store_index(&index.inner, value)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(self.pop())
|
Ok(self.pop())
|
||||||
|
|
Loading…
Reference in a new issue