summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-02-23 11:32:47 -0500
committerFreya Murphy <freya@freyacat.org>2024-02-23 11:32:47 -0500
commita888c09bd54de77fb2004754a0e14ce14a906232 (patch)
treec5b20b4be32feec7a3430f1191e1f735ea51ca57
parentindexing and field access (diff)
downloadmatrix-a888c09bd54de77fb2004754a0e14ce14a906232.tar.gz
matrix-a888c09bd54de77fb2004754a0e14ce14a906232.tar.bz2
matrix-a888c09bd54de77fb2004754a0e14ce14a906232.zip
more changes
Diffstat (limited to '')
-rw-r--r--Cargo.lock27
-rw-r--r--Cargo.toml2
-rw-r--r--a.mat5
-rw-r--r--matrix-bin/Cargo.toml2
-rw-r--r--matrix-bin/src/main.rs14
-rw-r--r--matrix-bin/src/repl.rs26
-rw-r--r--matrix-macros/Cargo.toml12
-rw-r--r--matrix-macros/src/lib.rs52
-rw-r--r--matrix-stdlib/Cargo.toml2
-rw-r--r--matrix-stdlib/src/io.rs36
-rw-r--r--matrix-stdlib/src/lib.rs15
-rw-r--r--matrix/src/ast.rs11
-rw-r--r--matrix/src/chunk.rs25
-rw-r--r--matrix/src/compiler.rs40
-rw-r--r--matrix/src/gc.rs4
-rw-r--r--matrix/src/lex.rs12
-rw-r--r--matrix/src/parse.rs57
-rw-r--r--matrix/src/value.rs52
-rw-r--r--matrix/src/vm.rs80
-rw-r--r--syntax_thing63
20 files changed, 377 insertions, 160 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 45a0c7e..8a03761 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -114,7 +114,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.48",
]
[[package]]
@@ -220,12 +220,26 @@ version = "0.1.0"
dependencies = [
"clap",
"matrix",
+ "matrix-stdlib",
"rustyline",
]
[[package]]
+name = "matrix-macros"
+version = "0.1.0"
+dependencies = [
+ "matrix",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
name = "matrix-stdlib"
version = "0.1.0"
+dependencies = [
+ "matrix",
+ "matrix-macros",
+]
[[package]]
name = "memchr"
@@ -409,6 +423,17 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]]
name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
version = "2.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
diff --git a/Cargo.toml b/Cargo.toml
index d1bda86..7e1bcac 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,3 +1,3 @@
[workspace]
resolver = "2"
-members = [ "matrix", "matrix-bin" , "matrix-stdlib"]
+members = [ "matrix", "matrix-bin" , "matrix-macros", "matrix-stdlib"]
diff --git a/a.mat b/a.mat
deleted file mode 100644
index e689317..0000000
--- a/a.mat
+++ /dev/null
@@ -1,5 +0,0 @@
-a = 0;
-
-while a < 1000000000 { a = a + 1 };
-
-
diff --git a/matrix-bin/Cargo.toml b/matrix-bin/Cargo.toml
index 029923b..c4b4d5a 100644
--- a/matrix-bin/Cargo.toml
+++ b/matrix-bin/Cargo.toml
@@ -9,5 +9,7 @@ path = "src/main.rs"
[dependencies]
clap = { version = "4", features = [ "derive" ] }
+ctrlc = "3"
matrix = { path = "../matrix" }
+matrix-stdlib = { path = "../matrix-stdlib" }
rustyline = "13"
diff --git a/matrix-bin/src/main.rs b/matrix-bin/src/main.rs
index 72972c6..909ee77 100644
--- a/matrix-bin/src/main.rs
+++ b/matrix-bin/src/main.rs
@@ -1,6 +1,6 @@
use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs};
use clap::Parser as ArgParser;
-use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}};
+use matrix::{compiler::{Compiler, CompilerBuilder}, vm::Vm, parse::{Parser, ParserBuilder}, value::Value};
use repl::Repl;
mod repl;
@@ -50,24 +50,24 @@ impl<'a> State<'a> {
let parser = ParserBuilder::new()
.optimize(!args.disable_optimizations)
.build();
- let vm = Vm::new();
+ let mut vm = Vm::new();
let compiler = CompilerBuilder::new()
.repl(repl)
.debug(args.debug)
.names(vm.names())
+ .globals(vm.global_names())
.build();
+ matrix_stdlib::load(&mut vm);
+
(Self { parser, vm, compiler, repl }, file)
}
- pub fn execute(&mut self, code: String) -> matrix::Result<()> {
+ pub fn execute(&mut self, code: String) -> matrix::Result<Value> {
let ast = self.parser.parse(code)?;
let fun = self.compiler.compile(&ast)?;
let val = self.vm.run(fun)?;
- if self.repl {
- println!("{val}");
- }
- Ok(())
+ Ok(val)
}
}
diff --git a/matrix-bin/src/repl.rs b/matrix-bin/src/repl.rs
index 81fd289..1b5addc 100644
--- a/matrix-bin/src/repl.rs
+++ b/matrix-bin/src/repl.rs
@@ -1,3 +1,8 @@
+use std::{io::Write, sync::atomic::Ordering};
+
+use matrix::{value::Value, vm::Interupt};
+use rustyline::Config;
+
use crate::State;
pub struct Repl<'a> {
@@ -11,14 +16,29 @@ impl<'a> Repl<'a> {
}
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 {
let Ok(line) = rl.readline(">> ") else {
break;
};
- if let Err(err) = self.state.execute(line) {
- crate::error(err);
+ match self.state.execute(line) {
+ Err(err) => crate::error(err),
+ Ok(val) => {
+ if val != Value::Nil {
+ println!("{val}");
+ }
+ }
}
+ let _ = std::io::stdout().flush();
}
}
diff --git a/matrix-macros/Cargo.toml b/matrix-macros/Cargo.toml
new file mode 100644
index 0000000..df84237
--- /dev/null
+++ b/matrix-macros/Cargo.toml
@@ -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" }
diff --git a/matrix-macros/src/lib.rs b/matrix-macros/src/lib.rs
new file mode 100644
index 0000000..8099fd6
--- /dev/null
+++ b/matrix-macros/src/lib.rs
@@ -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)
+}
diff --git a/matrix-stdlib/Cargo.toml b/matrix-stdlib/Cargo.toml
index 5140bfa..a892c04 100644
--- a/matrix-stdlib/Cargo.toml
+++ b/matrix-stdlib/Cargo.toml
@@ -6,3 +6,5 @@ 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" }
diff --git a/matrix-stdlib/src/io.rs b/matrix-stdlib/src/io.rs
new file mode 100644
index 0000000..288e99e
--- /dev/null
+++ b/matrix-stdlib/src/io.rs
@@ -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());
+}
diff --git a/matrix-stdlib/src/lib.rs b/matrix-stdlib/src/lib.rs
index 7d12d9a..312d397 100644
--- a/matrix-stdlib/src/lib.rs
+++ b/matrix-stdlib/src/lib.rs
@@ -1,14 +1,7 @@
-pub fn add(left: usize, right: usize) -> usize {
- left + right
-}
+use matrix::vm::Vm;
-#[cfg(test)]
-mod tests {
- use super::*;
+mod io;
- #[test]
- fn it_works() {
- let result = add(2, 2);
- assert_eq!(result, 4);
- }
+pub fn load(compiler: &mut Vm) {
+ io::load(compiler);
}
diff --git a/matrix/src/ast.rs b/matrix/src/ast.rs
index 19a4d04..68e325e 100644
--- a/matrix/src/ast.rs
+++ b/matrix/src/ast.rs
@@ -57,7 +57,8 @@ pub enum Expr {
Assign(Box<Expr>, Box<Expr>),
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
- Function(Rc<str>, Vec<Rc<str>>, Box<Expr>),
+ Function(Rc<str>, Vec<Rc<str>>, Box<Expr>, bool),
+ Lambda(Vec<Rc<str>>, Box<Expr>, bool),
Loop(Box<Expr>),
While(Box<Expr>, Box<Expr>),
@@ -279,10 +280,14 @@ pub fn optimize(expr: Expr) -> Result<Expr> {
let block = Box::new(optimize(*block)?);
E::Loop(block)
},
- E::Function(ident, params, stmt) => {
+ E::Function(ident, params, stmt, varadic) => {
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, Box::new(optimize(*expr)?))
},
diff --git a/matrix/src/chunk.rs b/matrix/src/chunk.rs
index 276ffe3..19ff8e6 100644
--- a/matrix/src/chunk.rs
+++ b/matrix/src/chunk.rs
@@ -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};
#[derive(Clone)]
@@ -36,11 +36,30 @@ impl Display for Chunk {
}
}
-#[derive(Debug, Clone)]
pub struct Function {
pub name: Rc<str>,
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)]
diff --git a/matrix/src/compiler.rs b/matrix/src/compiler.rs
index 5531d7e..f573437 100644
--- a/matrix/src/compiler.rs
+++ b/matrix/src/compiler.rs
@@ -1,13 +1,15 @@
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 Value as V;
use Expr as E;
+pub type NamesTable = Rc<RefCell<Vec<Rc<str>>>>;
+
pub struct CompilerBuilder<'c> {
- globals: Rc<RefCell<Vec<Rc<str>>>>,
- names: Rc<RefCell<Vec<Rc<str>>>>,
+ globals: NamesTable,
+ names: NamesTable,
repl: bool,
debug: bool,
name: Rc<str>,
@@ -37,12 +39,12 @@ impl<'c> CompilerBuilder<'c> {
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
}
- pub fn names(mut self, names: Rc<RefCell<Vec<Rc<str>>>>) -> Self {
+ pub fn names(mut self, names: NamesTable) -> Self {
self.names = names;
self
}
@@ -133,6 +135,8 @@ impl<'c> Compiler<'c> {
CompilerBuilder::new()
.name(name)
.debug(self.debug)
+ .globals(self.globals.clone())
+ .names(self.names.clone())
.repl(false)
.parent(self)
.build()
@@ -269,13 +273,14 @@ impl<'c> Compiler<'c> {
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 fun = Value::Function(Rc::new(
chunk::Function {
name: name.clone(),
arity: params.len(),
- body: chunk
+ fun: InnerFunction::Compiled(chunk.into()),
+ variadic: *varadic
}
));
self.emit_const(fun);
@@ -288,6 +293,19 @@ impl<'c> Compiler<'c> {
self.emit(I::CreateLocal);
}
},
+ E::Lambda(params, body, varadic) => {
+ let name: Rc<str> = Rc::from("<lambda>");
+ let chunk = self.compile_function(name.clone(), params, body)?;
+ let fun = Value::Function(Rc::new(
+ chunk::Function {
+ name: name.clone(),
+ arity: params.len(),
+ fun: InnerFunction::Compiled(chunk.into()),
+ variadic: *varadic
+ }
+ ));
+ self.emit_const(fun);
+ },
E::Loop(expr) => {
let idx = self.cur();
self.loop_top.push((idx as usize, self.scopes.len()));
@@ -365,7 +383,9 @@ impl<'c> Compiler<'c> {
},
E::Literal(val) => self.compile_value(val),
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));
} else if let Some(global) = self.find_global(name) {
self.emit(I::LoadGlobal(global as u16));
@@ -377,7 +397,7 @@ impl<'c> Compiler<'c> {
self.compile_expr(rhs)?;
self.emit(I::Dup);
match lhs.as_ref() {
- E::Ident(name) => {
+ E::Ident(name) if name.as_ref() != "_" => {
if let Some(local) = self.find_local(&name) {
self.emit(I::StoreLocal(local.idx as u16));
} else if let Some(global) = self.find_global(&name) {
@@ -540,7 +560,7 @@ impl<'c> Compiler<'c> {
self.chunk = Chunk::new();
self.compile_expr(body)?;
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))
}
}
diff --git a/matrix/src/gc.rs b/matrix/src/gc.rs
index 98d3228..0f31aea 100644
--- a/matrix/src/gc.rs
+++ b/matrix/src/gc.rs
@@ -24,9 +24,9 @@ impl<T> Gc<T> {
}
impl <T: Clone> Gc<T> {
- pub fn clone_inside(&mut self) -> Self {
+ pub fn clone_inside(&self) -> Self {
unsafe {
- let data = self.ptr.as_mut().data.clone();
+ let data = self.ptr.as_ref().data.clone();
Self::new(data)
}
}
diff --git a/matrix/src/lex.rs b/matrix/src/lex.rs
index ab0359b..16032f9 100644
--- a/matrix/src/lex.rs
+++ b/matrix/src/lex.rs
@@ -47,6 +47,8 @@ pub enum Token {
Comma,
Range,
Colon,
+ Backslash,
+ Varadic,
// math
Regex(RegexToken),
@@ -443,6 +445,7 @@ impl Lexer {
'{' => LeftBrace,
'}' => RightBrace,
':' => Colon,
+ '\\' => Backslash,
';' => SemiColon,
'+' => {
match next {
@@ -627,7 +630,14 @@ impl Lexer {
},
'.' => {
if next == '.' {
- Range
+ self.next();
+ match self.peek() {
+ '.' => {
+ self.next();
+ Varadic
+ },
+ _ => Range
+ }
} else if next.is_digit(10) {
self.lex_number(char)?
} else {
diff --git a/matrix/src/parse.rs b/matrix/src/parse.rs
index 4e1de2c..b505415 100644
--- a/matrix/src/parse.rs
+++ b/matrix/src/parse.rs
@@ -40,7 +40,7 @@ pub enum Error {
UnexpectedToken(Token),
ExpectedToken(Token),
ExpectedTokenName(&'static str),
- MatrixCoDomainError(usize, usize, usize),
+ MatrixInvDomain(usize, usize, usize),
NotAssignable(Expr),
ValueError(value::Error),
}
@@ -53,7 +53,7 @@ impl Display for Error {
UnexpectedToken(tok) => write!(f, "Unexpected token: '{tok:?}'"),
ExpectedToken(tok) => write!(f, "Expected token: '{tok:?}'"),
ExpectedTokenName(name) => write!(f, "Expected {name} token"),
- 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"),
ValueError(err) => write!(f, "{err}"),
}
@@ -199,11 +199,11 @@ impl Parser {
if parts.len() == 1 {
Ok(E::List(parts.pop().unwrap()))
} else {
- let codomain = parts[0].len();
- let domain = parts.len();
+ let codomain = parts.len();
+ let domain = parts[0].len();
for (i, part) in parts.iter().enumerate() {
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();
@@ -259,20 +259,29 @@ impl Parser {
Ok(expr)
}
- fn parse_params(&mut self) -> Result<Vec<Rc<str>>> {
+ fn parse_params(&mut self) -> Result<(Vec<Rc<str>>, bool)> {
use T::*;
let tok = self.lexer.next_token()?;
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 => (),
_ => return Err(Error::UnexpectedToken(tok).into()),
}
let mut params = Vec::new();
+ let mut varadic = false;
if self.lexer.peek_token()? == T::RightParen {
self.lexer.next_token()?;
- return Ok(params);
+ return Ok((params, varadic));
}
loop {
@@ -280,13 +289,18 @@ impl Parser {
params.push(ident);
let next = self.lexer.next_token()?;
match next {
+ Varadic => {
+ varadic = true;
+ self.force_token(T::RightParen)?;
+ break;
+ }
Comma => continue,
RightParen => break,
_ => return Err(Error::UnexpectedToken(next).into()),
}
}
- Ok(params)
+ Ok((params, varadic))
}
fn parse_ident(&mut self) -> Result<Rc<str>> {
@@ -308,12 +322,23 @@ impl Parser {
fn parse_function(&mut self) -> Result<Expr> {
self.force_token(T::Function)?;
let ident = self.parse_ident()?;
- let params = match self.lexer.peek_token()? {
- T::LeftBrace => vec![],
+ let (params, varadic) = match self.lexer.peek_token()? {
+ T::LeftBrace => (vec![], false),
+ _ => self.parse_params()?,
+ };
+ let expr = self.parse_expr()?;
+ Ok(E::Function(ident, params, Box::new(expr), varadic))
+ }
+
+ fn parse_lambda(&mut self) -> Result<Expr> {
+ self.force_token(T::Backslash)?;
+ let (params, varadic) = match self.lexer.peek_token()? {
+ T::Arrow => (vec![], false),
_ => self.parse_params()?,
};
+ self.force_token(T::Arrow)?;
let expr = self.parse_expr()?;
- Ok(E::Function(ident, params, Box::new(expr)))
+ Ok(E::Lambda(params, Box::new(expr), varadic))
}
fn parse_do_while(&mut self) -> Result<Expr> {
@@ -387,7 +412,7 @@ impl Parser {
match next {
T::SemiColon => continue,
T::RightBrace => break,
- _ => return Err(Error::UnexpectedToken(next).into())
+ _ => return Err(Error::ExpectedToken(T::SemiColon).into())
}
}
if self.lexer.peek_token()? == T::RightBrace {
@@ -416,6 +441,7 @@ impl Parser {
use T::*;
match self.lexer.peek_token()? {
Function => self.parse_function(),
+ Backslash => self.parse_lambda(),
Do => self.parse_do_while(),
While => self.parse_while(),
Let => self.parse_let(),
@@ -641,6 +667,11 @@ impl Parser {
};
let expr = self.parse_expr()?;
block.push(expr);
+ match self.lexer.next_token()? {
+ T::Eof => break,
+ T::SemiColon => continue,
+ _ => return Err(Error::ExpectedToken(T::SemiColon).into())
+ };
}
Ok(E::Block(block))
}
diff --git a/matrix/src/value.rs b/matrix/src/value.rs
index b7a8218..1e75902 100644
--- a/matrix/src/value.rs
+++ b/matrix/src/value.rs
@@ -171,18 +171,17 @@ impl Value {
str
},
Matrix(m) => {
- let mut str = "[[".to_string();
- for (i, el) in m.2.iter().enumerate() {
- if i != 0 {
- if (i % m.1) == 0 {
- str.push_str(" ; ");
- } else {
- str.push_str(" ");
+ let mut str = "\n".to_string();
+ for row in m.2.chunks(m.0) {
+ str.push_str(" ");
+ for (i, v) in row.iter().enumerate() {
+ if i != 0 {
+ str.push(' ');
}
+ str.push_str(&v.boring_print());
}
- str.push_str(&el.boring_print());
+ str.push('\n');
}
- str.push_str("]]");
str
},
Table(t) => {
@@ -199,7 +198,7 @@ impl Value {
str
},
Function(fun) => {
- format!("[Function: {}]", fun.name)
+ format!("{fun:?}")
}
}
}
@@ -227,18 +226,17 @@ impl Value {
str
},
Matrix(m) => {
- let mut str = "[[".to_string();
- for (i, el) in m.2.iter().enumerate() {
- if i != 0 {
- if (i % m.1) == 0 {
- str.push_str(" ; ");
- } else {
- str.push_str(" ");
+ let mut str = "\n".to_string();
+ for row in m.2.chunks(m.0) {
+ str.push_str(" ");
+ for (i, v) in row.iter().enumerate() {
+ if i != 0 {
+ str.push(' ');
}
+ str.push_str(&v.pretty_print());
}
- str.push_str(&el.pretty_print());
+ str.push('\n');
}
- str.push_str("]]");
str
},
Table(t) => {
@@ -256,7 +254,7 @@ impl Value {
},
Function(_) => {
format!("\x1b[36m{}\x1b[0m", self.boring_print())
- }
+ },
}
}
}
@@ -449,6 +447,16 @@ impl Value {
(l, r) => Err(Error::Exponent(l, r).into())
}
}
+
+ pub fn clone_inside(&self) -> Self {
+ use Value as V;
+ match self {
+ V::List(l) => V::List(l.clone_inside()),
+ V::Table(t) => V::Table(t.clone_inside()),
+ V::Matrix(m) => V::Matrix(m.clone_inside()),
+ _ => self.clone()
+ }
+ }
}
impl Eq for Value {}
@@ -523,7 +531,7 @@ impl Value {
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())
}
}
@@ -553,7 +561,7 @@ impl Value {
pub fn index(&self, index: &Vec<Value>) -> Result<Self> {
if index.len() == 0 {
- Ok(self.clone())
+ Ok(self.clone_inside())
} else if index.len() == 1 {
self.index_single(&index[0])
} else {
diff --git a/matrix/src/vm.rs b/matrix/src/vm.rs
index d0729eb..4c6618d 100644
--- a/matrix/src/vm.rs
+++ b/matrix/src/vm.rs
@@ -1,5 +1,5 @@
use std::{rc::Rc, fmt::{Debug, Display}, usize, ops::{Index, IndexMut}, collections::HashMap, cell::RefCell};
-use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction}, Result};
+use crate::{value::{Value, self, ValueMap}, gc::Gc, chunk::{Function, Instruction, Chunk, InnerFunction}, Result, compiler::NamesTable};
#[derive(Debug)]
pub enum Error {
@@ -7,6 +7,7 @@ pub enum Error {
NotFunction(Value),
InvArity(usize, usize, Rc<str>),
UndefinedGlobal(Rc<str>),
+ ExecNative,
}
impl std::error::Error for Error {}
@@ -19,6 +20,7 @@ impl Display for Error {
NotFunction(v) => write!(f, "{v:?} is not a function"),
InvArity(wanted, had, name) => write!(f, "function {name} takes {wanted} params but was given {had}"),
UndefinedGlobal(name) => write!(f, "{name} is not defined"),
+ ExecNative => write!(f, "cannot execute a native function"),
}
}
}
@@ -88,17 +90,20 @@ impl<T> Index<usize> for Stack<T> {
}
struct StackFrame {
- fun: Rc<Function>,
+ #[allow(dead_code)]
+ name: Rc<str>,
+ body: Rc<Chunk>,
ip: usize,
bp: usize,
}
impl StackFrame {
- fn new(vm: &Vm, fun: Rc<Function>) -> Self {
+ fn new(vm: &Vm, name: Rc<str>, body: Rc<Chunk>, arity: usize) -> Self {
Self {
- bp: vm.stack.len() - fun.arity,
+ name,
+ body,
+ bp: vm.stack.len() - arity,
ip: 0,
- fun,
}
}
}
@@ -108,7 +113,8 @@ pub struct Vm {
locals: Stack<Value>,
frames: Vec<StackFrame>,
globals: HashMap<u16, Value>,
- names: Rc<RefCell<Vec<Rc<str>>>>,
+ names: NamesTable,
+ global_names: NamesTable,
}
impl Vm {
@@ -121,10 +127,14 @@ impl Vm {
self.stack.pop()
}
- pub fn names(&self) -> Rc<RefCell<Vec<Rc<str>>>> {
+ pub fn names(&self) -> NamesTable {
self.names.clone()
}
+ pub fn global_names(&self) -> NamesTable {
+ self.global_names.clone()
+ }
+
pub fn new() -> Self {
Self {
stack: Stack::new(),
@@ -132,14 +142,33 @@ impl Vm {
frames: Vec::new(),
globals: HashMap::new(),
names: Rc::new(RefCell::new(Vec::new())),
+ global_names: Rc::new(RefCell::new(Vec::new()))
}
}
+ 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
+ ))
+ }
+
pub fn run(&mut self, fun: Rc<Function>) -> Result<Value> {
- let mut frame = StackFrame::new(&self, fun);
+ let mut frame = self.init_frame(fun)?;
loop {
use Instruction::*;
- let ins = frame.fun.body.code[frame.ip].clone();
+ let ins = frame.body.code[frame.ip].clone();
frame.ip += 1;
match ins {
@@ -159,7 +188,7 @@ impl Vm {
let val = self.pop();
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)),
True => self.push(Value::Bool(true)),
False => self.push(Value::Bool(false)),
@@ -210,12 +239,33 @@ impl Vm {
let Value::Function(fun) = fun else {
return Err(Error::NotFunction(fun).into())
};
- if fun.arity != arity as usize {
- return Err(Error::InvArity(fun.arity, arity as usize, fun.name.clone()).into())
+ let arity = arity as usize;
+ let normal_args = if fun.variadic { fun.arity - 1 } else { fun.arity };
+ if (fun.variadic && arity < normal_args) || (!fun.variadic && arity != normal_args) {
+ return Err(Error::InvArity(normal_args, arity as usize, fun.name.clone()).into())
+ }
+ if fun.variadic {
+ if arity == normal_args {
+ self.push(Value::List(vec![].into()));
+ } else if arity > normal_args {
+ let count = arity - normal_args;
+ let varadic_params = self.stack.split_off(self.stack.len() - count).inner;
+ self.push(Value::List(varadic_params.into()));
+ }
+ }
+ let name = fun.name.clone();
+ match &fun.fun {
+ InnerFunction::Compiled(body) => {
+ let new_frame = StackFrame::new(self, name, body.clone(), fun.arity);
+ self.frames.push(frame);
+ frame = new_frame;
+ },
+ InnerFunction::Native(native_fun) => {
+ let params = self.stack.split_off(self.stack.len() - fun.arity).inner;
+ let res = native_fun(self, params)?;
+ self.stack.push(res);
+ }
}
- let new_frame = StackFrame::new(&self, fun);
- self.frames.push(frame);
- frame = new_frame;
},
Return => {
let Some(prev_frame) = self.frames.pop() else {
diff --git a/syntax_thing b/syntax_thing
deleted file mode 100644
index 8f48af7..0000000
--- a/syntax_thing
+++ /dev/null
@@ -1,63 +0,0 @@
-root => root_expr*
-root_expr => function
-root_expr => expr
-function => FUNCTION IDENT params block
-params => IDENT
-params => OP CP
-params => OP params_impl
-params_impl => IDENT COMMA params_impl
-params_impl => IDENT CP
-block => expr*
-expr => if_expr
-if_expr => IF math_expr block ELSE if_expr
-if_expr => IF math_expr block ELSE block
-if_expr => IF math_expr block
-expr => DO block WHILE math_expr
-expr => WHILE math_expr block
-expr => LET IDENT EQ math_expr END
-expr => LET IDENT END
-expr => IDENT EQ math_expr END
-expr => block
-expr => RETURN math_expr END
-expr => BREAK
-expr => CONTINUE
-expr => math_expr END
-math_expr => (math_expr_and OR)* math_expr_and
-math_expr_and => math_expr_and AND math_expr_and
-math_expr_and => math_expr_compare
-math_expr_compare => math_expr_compare <COMPARE> math_expr_compare
-
-power_term => power_term POWER power_term
-power_term => power_term BIT_AND power_term
-power_term => power_term BIT_OR power_term
-power_term => power_term SHIFT_LEFT power_term
-power_term => power_term SHIFT_RIGHT power_term
-power_term => term
-term => value
-term => tuple
-term => list
-term => table
-term => IDENT
-value => INT DIVIDE INT
-value => INT
-value => FLOAT
-value => COMPLEX
-value => STRING
-value => REGEX
-value => TRUE
-value => FALSE
-tuple => OP CP
-tuple => OP tuple_impl
-tuple_impl => math_expr COMMA tuple_impl
-tuple_impl => math_expr CP
-list => LBRK RBRK
-list => LBRK list_impl
-list_impl => math_expr COMMA tuple_impl
-list_impl => math_expr RBRK
-table => LBRC RBRC
-table => LBRC table_impl
-table_impl => table_key EQ math_expr COMMA table_impl
-table_impl => table_key EQ math_expr RBRC
-table_key => LBRK math_expr RBRK
-table_key => IDENT
-table_key => STRING