summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--matrix-bin/src/main.rs90
-rw-r--r--matrix-bin/src/repl.rs16
-rw-r--r--matrix-lang/src/binary/mod.rs6
-rw-r--r--matrix-lang/src/compiler.rs2
-rw-r--r--matrix-lang/src/lex.rs4
-rw-r--r--matrix-lang/src/parse.rs2
-rw-r--r--matrix-lang/src/prelude.rs1
-rw-r--r--matrix-lang/src/value/exception.rs23
-rw-r--r--matrix-lang/src/value/matrix.rs2
-rw-r--r--matrix-lang/src/vm.rs4
-rw-r--r--matrix-macros/src/lib.rs4
-rw-r--r--matrix-std/src/core.rs21
-rw-r--r--matrix-std/src/io.rs6
-rw-r--r--matrix-std/src/iter.rs2
-rw-r--r--matrix-std/src/math.rs4
-rw-r--r--matrix-std/src/sys.rs6
-rw-r--r--test.mat8
-rw-r--r--test.matcbin0 -> 203 bytes
18 files changed, 118 insertions, 83 deletions
diff --git a/matrix-bin/src/main.rs b/matrix-bin/src/main.rs
index 64d1b3f..8321796 100644
--- a/matrix-bin/src/main.rs
+++ b/matrix-bin/src/main.rs
@@ -1,4 +1,4 @@
-use std::{path::PathBuf, io::{self, Read, IsTerminal}, fs, cell::RefCell, rc::Rc};
+use std::{path::PathBuf, io::{self, Read, IsTerminal}, cell::RefCell, rc::Rc};
use clap::{Parser as ArgParser, ColorChoice};
use matrix_lang::prelude::*;
use repl::Repl;
@@ -35,8 +35,8 @@ pub struct Args {
pub enum Mode {
Repl,
- Execute(String),
- Compile(String, PathBuf),
+ Execute(Vec<u8>),
+ Compile(Vec<u8>, PathBuf),
}
pub struct State<'a> {
@@ -46,18 +46,26 @@ pub struct State<'a> {
color: bool,
}
-impl<'a> State<'a> {
- pub fn new (args: Args) -> (Self, Mode) {
+pub fn error(err: Exception, state: &State) {
+ if state.color {
+ println!("\x1b[31mError:\x1b[0m {err}");
+ } else {
+ println!("Error: {err}");
+ }
+}
- let stdin = read_stdin();
+impl<'a> State<'a> {
+ pub fn new (args: Args) -> Result<(Self, Mode)> {
- let file;
+ let mut buffer = Vec::new();
if let Some(path) = &args.file {
- file = Some(fs::read_to_string(path).unwrap());
- } else if stdin.len() > 0 {
- file = Some(stdin);
+ let mut f = File::open(path)?;
+ f.read_to_end(&mut buffer)?;
} else {
- file = None;
+ let mut stdin = io::stdin();
+ if !stdin.is_terminal() {
+ stdin.read_to_end(&mut buffer)?;
+ }
}
let mode;
@@ -74,11 +82,10 @@ impl<'a> State<'a> {
PathBuf::from("matc.out")
}
};
- let file = file.unwrap_or(String::new());
- mode = Mode::Compile(file, path);
+ mode = Mode::Compile(buffer, path);
repl = false;
- } else if let Some(file) = file {
- mode = Mode::Execute(file);
+ } else if buffer.len() > 0 {
+ mode = Mode::Execute(buffer);
repl = false;
} else {
mode = Mode::Repl;
@@ -106,16 +113,16 @@ impl<'a> State<'a> {
Some(ColorChoice::Never) => false,
};
- (Self {
+ Ok((Self {
parser,
vm: Rc::new(RefCell::new(vm)),
compiler,
color,
- }, mode)
+ }, mode))
}
pub fn execute(&mut self, fun: Rc<Function>) -> Result<Value> {
- let val = self.vm.try_borrow_mut().unwrap().run(fun)?;
+ let val = self.vm.borrow_mut().run(fun)?;
Ok(val)
}
@@ -125,47 +132,37 @@ impl<'a> State<'a> {
Ok(fun)
}
- pub fn load_program(&mut self, body: String) -> Result<Rc<Function>> {
- match Program::load(&body)? {
+ pub fn load_program(&mut self, mut buffer: Vec<u8>) -> Result<Rc<Function>> {
+ let res = Program::load(buffer.as_mut_slice())?;
+ match res {
Some(fun) => {
Ok(fun)
},
None => {
+ let body = buffer_to_string(buffer)?;
self.compile(body)
},
}
}
}
-pub fn error(err: Exception, state: &State) {
- if state.color {
- println!("\x1b[31mError:\x1b[0m {err}");
- } else {
- println!("Error: {err}");
- }
-}
-
-fn read_stdin() -> String {
- let mut buffer = String::new();
- let mut stdin = io::stdin();
- if stdin.is_terminal() {
- return String::new();
- }
- stdin.read_to_string(&mut buffer).unwrap();
- buffer
+fn buffer_to_string(buffer: Vec<u8>) -> Result<String> {
+ String::from_utf8(buffer)
+ .map_err(|e| exception!(IO_EXCEPTION, "{e}"))
}
fn handle_mode(state: &mut State, mode: Mode) -> Result<()> {
match mode {
Mode::Repl => {
let mut repl = Repl::new(state);
- repl.run();
+ repl.run()?;
},
- Mode::Execute(body) => {
- let fun = state.load_program(body)?;
+ Mode::Execute(buffer) => {
+ let fun = state.load_program(buffer)?;
state.execute(fun)?;
},
- Mode::Compile(body, path) => {
+ Mode::Compile(buffer, path) => {
+ let body = buffer_to_string(buffer)?;
let fun = state.compile(body)?;
let mut file = File::create(path).map_err(|e|
exception!(IO_EXCEPTION, "{e}")
@@ -176,12 +173,17 @@ fn handle_mode(state: &mut State, mode: Mode) -> Result<()> {
Ok(())
}
-fn main() {
-
+fn load() -> Result<()> {
let args = Args::parse();
- let (mut state, mode) = State::new(args);
-
+ let (mut state, mode) = State::new(args)?;
if let Err(e) = handle_mode(&mut state, mode) {
error(e, &state);
}
+ Ok(())
+}
+
+fn main() {
+ if let Err(e) = load() {
+ println!("\x1b[31mFatal:\x1b[0m {e}");
+ }
}
diff --git a/matrix-bin/src/repl.rs b/matrix-bin/src/repl.rs
index fe9975f..444faef 100644
--- a/matrix-bin/src/repl.rs
+++ b/matrix-bin/src/repl.rs
@@ -20,12 +20,12 @@ impl<'s, 'a> Repl<'s, 'a> {
Ok(val)
}
- pub fn run(&mut self) {
+ pub fn run(&mut self) -> Result<()> {
let interupt = self.state.vm.borrow().interupt();
ctrlc::set_handler(move || {
interupt.store(Interupt::KeyboardInterupt as usize, Ordering::SeqCst);
- }).unwrap();
+ }).exception()?;
let config = Config::builder()
.indent_size(4)
@@ -39,10 +39,10 @@ impl<'s, 'a> Repl<'s, 'a> {
let histfile = std::env::var("MATRIX_HISTORY").ok();
- let mut rl = Editor::with_config(config).unwrap();
+ let mut rl = Editor::with_config(config).exception()?;
rl.set_helper(Some(helper));
if let Some(hf) = &histfile {
- rl.load_history(hf).ok();
+ rl.load_history(hf).exception()?;
}
loop {
@@ -52,7 +52,7 @@ impl<'s, 'a> Repl<'s, 'a> {
Err(_) => continue,
};
- rl.add_history_entry(&line).ok();
+ rl.add_history_entry(&line).exception()?;
match self.execute(line) {
Ok(val) => {
@@ -66,12 +66,14 @@ impl<'s, 'a> Repl<'s, 'a> {
}
Err(err) => crate::error(err, &self.state),
};
- std::io::stdout().flush().ok();
+ std::io::stdout().flush().exception()?;
}
if let Some(hf) = &histfile {
- rl.save_history(hf).ok();
+ rl.save_history(hf).exception()?;
}
+
+ Ok(())
}
}
diff --git a/matrix-lang/src/binary/mod.rs b/matrix-lang/src/binary/mod.rs
index 53b3fe5..780d2a0 100644
--- a/matrix-lang/src/binary/mod.rs
+++ b/matrix-lang/src/binary/mod.rs
@@ -13,8 +13,7 @@ pub struct Program {
const PROGRAM_HEADER: [u8; 5] = [0x00, 0x4d, 0x41, 0x54, 0x0a];
impl Program {
- pub fn load(body: &str) -> Result<Option<Rc<Function>>> {
- let mut bytes = body.as_bytes();
+ pub fn load(bytes: &mut [u8]) -> Result<Option<Rc<Function>>> {
if bytes.len() < 6 {
return Ok(None)
}
@@ -22,7 +21,8 @@ impl Program {
if header != &PROGRAM_HEADER {
return Ok(None)
}
- let mut s = ProgramDeserializer::from(&mut bytes);
+ let mut a = &bytes[..];
+ let mut s = ProgramDeserializer::from(&mut a);
let program = <Self>::deserialize(&mut s)?;
s.finish()?;
Ok(Some(program.fun.clone()))
diff --git a/matrix-lang/src/compiler.rs b/matrix-lang/src/compiler.rs
index 95c6ccf..da1ecf7 100644
--- a/matrix-lang/src/compiler.rs
+++ b/matrix-lang/src/compiler.rs
@@ -142,7 +142,7 @@ impl<'c> Compiler<'c> {
fn collapse_scopes(&mut self, top_scope: usize) {
let mut cutoff = usize::MAX;
while self.scopes.len() > top_scope {
- cutoff = self.scopes.pop().unwrap()
+ cutoff = self.scopes.pop().expect("bypassed compiler scope check")
}
if cutoff < self.locals.len() {
self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16), self.last_pos());
diff --git a/matrix-lang/src/lex.rs b/matrix-lang/src/lex.rs
index b2487ad..82545c4 100644
--- a/matrix-lang/src/lex.rs
+++ b/matrix-lang/src/lex.rs
@@ -286,7 +286,7 @@ impl Lexer {
buf.push(char::from_u32(
n1.to_digit(16).ok_or(error!("invalid digit '{n1}'"))? * 16 +
n2.to_digit(16).ok_or(error!("invalid digit '{n2}'"))?
- ).unwrap());
+ ).expect("bypassed digit check"));
},
'u' => {
self.next_expect('{')?;
@@ -416,7 +416,7 @@ impl Lexer {
}
}
- let last: char = buf.chars().last().unwrap();
+ let last: char = buf.chars().last().unwrap_or('\0');
let is_range = initial != '.' && last == '.' && self.peek() == '.';
if is_range {
diff --git a/matrix-lang/src/parse.rs b/matrix-lang/src/parse.rs
index c476650..04f09ee 100644
--- a/matrix-lang/src/parse.rs
+++ b/matrix-lang/src/parse.rs
@@ -169,7 +169,7 @@ impl Parser {
};
}
if parts.len() == 1 {
- Ok((E::List(parts.pop().unwrap()), pos).into())
+ Ok((E::List(parts.pop().expect("bypassed vec length")), pos).into())
} else {
let codomain = parts.len();
let domain = parts[0].len();
diff --git a/matrix-lang/src/prelude.rs b/matrix-lang/src/prelude.rs
index c5af0c8..cf51a63 100644
--- a/matrix-lang/src/prelude.rs
+++ b/matrix-lang/src/prelude.rs
@@ -2,6 +2,7 @@ pub type Result<T> = std::result::Result<T, Exception>;
pub use crate::value::Value as Value;
pub use crate::value::exception::Exception as Exception;
+pub use crate::value::exception::Except as Except;
pub use crate::value::matrix::Matrix as Matrix;
pub use crate::value::gc::Gc as Gc;
pub use crate::value::hash::ValueMap as ValueMap;
diff --git a/matrix-lang/src/value/exception.rs b/matrix-lang/src/value/exception.rs
index 0df6f5c..c4ae606 100644
--- a/matrix-lang/src/value/exception.rs
+++ b/matrix-lang/src/value/exception.rs
@@ -1,4 +1,4 @@
-use std::{fmt::{Debug, Display}, error::Error};
+use std::{fmt::{Debug, Display}, error::Error, io};
use crate::prelude::*;
#[macro_export]
@@ -76,3 +76,24 @@ impl<T> From<Exception> for Result<T> {
Err(value)
}
}
+
+impl From<io::Error> for Exception {
+ fn from(value: io::Error) -> Self {
+ exception!(IO_EXCEPTION, "{value}")
+ }
+}
+
+pub trait Except {
+ type Output;
+ fn exception(self) -> Result<Self::Output>;
+}
+
+impl<T, E: std::error::Error> Except for std::result::Result<T, E> {
+ type Output = T;
+
+ fn exception(self) -> Result<Self::Output> {
+ self.map_err(|e| {
+ Exception::msg("unknown", format!("{e}").as_str())
+ })
+ }
+}
diff --git a/matrix-lang/src/value/matrix.rs b/matrix-lang/src/value/matrix.rs
index 91e3ec2..1d55210 100644
--- a/matrix-lang/src/value/matrix.rs
+++ b/matrix-lang/src/value/matrix.rs
@@ -184,7 +184,7 @@ impl Matrix {
let values = rows
.into_iter()
.reduce(|mut a,b| {a.extend(b); a})
- .unwrap();
+ .ok_or(error!("matrix row smashed"))?;
Ok(Matrix::new(self.domain + other.domain, self.codomain, values))
}
diff --git a/matrix-lang/src/vm.rs b/matrix-lang/src/vm.rs
index bac6341..b8da01f 100644
--- a/matrix-lang/src/vm.rs
+++ b/matrix-lang/src/vm.rs
@@ -217,7 +217,7 @@ impl Vm {
let val = self.globals
.borrow_mut()
.get(&idx)
- .unwrap()
+ .ok_or(exception!(RUNTIME_EXCEPTION, "undefined global at index {idx}"))?
.clone();
self.stack.push(val);
},
@@ -380,7 +380,7 @@ impl Vm {
self.trystack.push(scope);
},
I::TryEnd => {
- self.trystack.pop().unwrap();
+ self.trystack.pop().ok_or(exception!(RUNTIME_EXCEPTION, "try stack smashed"))?;
},
};
diff --git a/matrix-macros/src/lib.rs b/matrix-macros/src/lib.rs
index a660053..f347956 100644
--- a/matrix-macros/src/lib.rs
+++ b/matrix-macros/src/lib.rs
@@ -17,9 +17,9 @@ impl Parse for NativeFuncParams {
#[proc_macro_attribute]
pub fn native_func(input: TokenStream, annotated_item: TokenStream) -> TokenStream {
- let itemfn: ItemFn = syn::parse(annotated_item).unwrap();
+ let itemfn: ItemFn = syn::parse(annotated_item).expect("invalid rust function");
- let input: NativeFuncParams = syn::parse(input).unwrap();
+ let input: NativeFuncParams = syn::parse(input).expect("invalid native fn annotation");
let arity = input.arity;
let variadic = input.variadic.is_some();
diff --git a/matrix-std/src/core.rs b/matrix-std/src/core.rs
index 69b6d97..5b702d0 100644
--- a/matrix-std/src/core.rs
+++ b/matrix-std/src/core.rs
@@ -4,30 +4,31 @@ use matrix_lang::prelude::*;
use matrix_macros::native_func;
use crate::{VmArgs, next, error, unpack_args, unpack_varargs};
-fn to_radix(r: i64, mut n: i64) -> String {
+fn to_radix(r: i64, mut n: i64) -> Result<String> {
let mut result = String::new();
let mut idx = 0;
if n == 0 {
result.push('0');
- return result
+ return Ok(result)
} else if n < 0 {
n = -n;
idx = 1;
result.push('-');
}
while n != 0 {
- let c = std::char::from_digit((n % r) as u32, r as u32).unwrap();
+ let c = std::char::from_digit((n % r) as u32, r as u32)
+ .ok_or(exception!(RUNTIME_EXCEPTION, "given radix and digit created invalid number"))?;
result.insert(idx, c);
n /= r;
}
- result
+ Ok(result)
}
#[native_func(1)]
fn bin(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
match value {
- Value::Int(n) => Ok(Value::String(to_radix(2, n).into())),
+ Value::Int(n) => Ok(Value::String(to_radix(2, n)?.into())),
_ => error!("bin requires a integer agument")
}
}
@@ -36,7 +37,7 @@ fn bin(_: VmArgs, args: Vec<Value>) -> Result<Value> {
fn sex(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
match value {
- Value::Int(n) => Ok(Value::String(to_radix(6, n).into())),
+ Value::Int(n) => Ok(Value::String(to_radix(6, n)?.into())),
_ => error!("sex requires a integer agument")
}
}
@@ -45,7 +46,7 @@ fn sex(_: VmArgs, args: Vec<Value>) -> Result<Value> {
fn oct(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
match value {
- Value::Int(n) => Ok(Value::String(to_radix(8, n).into())),
+ Value::Int(n) => Ok(Value::String(to_radix(8, n)?.into())),
_ => error!("oct requires a integer agument")
}
}
@@ -54,7 +55,7 @@ fn oct(_: VmArgs, args: Vec<Value>) -> Result<Value> {
fn hex(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
match value {
- Value::Int(n) => Ok(Value::String(to_radix(16, n).into())),
+ Value::Int(n) => Ok(Value::String(to_radix(16, n)?.into())),
_ => error!("hex requires a integer agument")
}
}
@@ -63,7 +64,7 @@ fn hex(_: VmArgs, args: Vec<Value>) -> Result<Value> {
fn radix(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [radix, value] = unpack_args!(args);
match (radix, value) {
- (Value::Int(r), Value::Int(n)) => Ok(Value::String(to_radix(r, n).into())),
+ (Value::Int(r), Value::Int(n)) => Ok(Value::String(to_radix(r, n)?.into())),
_ => error!("radix requires two integer aguments")
}
}
@@ -136,7 +137,7 @@ fn ord(_: VmArgs, args: Vec<Value>) -> Result<Value> {
if str.len() != 1 {
return error!("ord requires a 1 length string")
}
- let char = str.chars().next().unwrap();
+ let char = str.chars().next().unwrap_or('\0');
Ok(Value::Int(char as i64))
}
diff --git a/matrix-std/src/io.rs b/matrix-std/src/io.rs
index 19ff074..829ed28 100644
--- a/matrix-std/src/io.rs
+++ b/matrix-std/src/io.rs
@@ -106,7 +106,7 @@ fn file_read(_: VmArgs, args: Vec<Value>) -> Result<Value> {
return error!("file read requires a file")
};
let mut contents = String::new();
- if let Err(err) = file.try_borrow_mut().unwrap().read_to_string(&mut contents) {
+ if let Err(err) = file.borrow_mut().read_to_string(&mut contents) {
return error!("cannot read file: '{err}'")
};
Ok(Value::String(contents.into()))
@@ -119,7 +119,7 @@ fn file_lines(_: VmArgs, args: Vec<Value>) -> Result<Value> {
return error!("file read requires a file")
};
let mut contents = String::new();
- if let Err(err) = file.try_borrow_mut().unwrap().read_to_string(&mut contents) {
+ if let Err(err) = file.borrow_mut().read_to_string(&mut contents) {
return error!("cannot read file: '{err}'")
};
let lines: Vec<Rc<str>> = contents.split_inclusive("\n").map(|s| Rc::from(s)).collect();
@@ -139,7 +139,7 @@ fn file_write(_: VmArgs, args: Vec<Value>) -> Result<Value> {
return error!("file write requires a file")
};
let content = format!("{content}");
- if let Err(err) = file.try_borrow_mut().unwrap().write_all(content.as_bytes()) {
+ if let Err(err) = file.borrow_mut().write_all(content.as_bytes()) {
return error!("cannot write file: '{err}'")
};
Ok(Value::Nil)
diff --git a/matrix-std/src/iter.rs b/matrix-std/src/iter.rs
index 638755c..c0e0c63 100644
--- a/matrix-std/src/iter.rs
+++ b/matrix-std/src/iter.rs
@@ -365,7 +365,7 @@ fn unzip((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
if vals.len() != 2 {
return error!("unzip only works over a iterator of pairs");
}
- let [l, r] = vals.try_into().unwrap();
+ let [l, r] = vals.try_into().map_err(|_| exception!(RUNTIME_EXCEPTION, "can only unzip over a set of pairs"))?;
ll.push(l);
lr.push(r);
}
diff --git a/matrix-std/src/math.rs b/matrix-std/src/math.rs
index 111544c..503192d 100644
--- a/matrix-std/src/math.rs
+++ b/matrix-std/src/math.rs
@@ -15,7 +15,7 @@ fn trans(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let values = mat
.cols()
.reduce(|mut a, b| {a.extend(b); a})
- .unwrap()
+ .ok_or(exception!(RUNTIME_EXCEPTION, "matrix values smashed"))?
.into_iter()
.map(|e| e.clone())
.collect();
@@ -164,7 +164,7 @@ fn mat_det(mat: Matrix) -> Result<Value> {
.collect::<Vec<Value>>()
)
.reduce(|mut a, b| {a.extend(b); a})
- .unwrap();
+ .ok_or(exception!(RUNTIME_EXCEPTION, "matrix values smashed"))?;
let sub = Matrix::new(mat.domain - 1, mat.domain - 1, sub_values);
let val = mat.get(0, col)?;
let part = (val * mat_det(sub)?)?;
diff --git a/matrix-std/src/sys.rs b/matrix-std/src/sys.rs
index 609e72d..8b54f0f 100644
--- a/matrix-std/src/sys.rs
+++ b/matrix-std/src/sys.rs
@@ -193,7 +193,7 @@ fn basename(_: VmArgs, args: Vec<Value>) -> Result<Value> {
};
let path = PathBuf::from(value.to_string());
match path.file_name() {
- Some(p) => Ok(Value::String(p.to_str().unwrap().into())),
+ Some(p) => Ok(Value::String(p.to_str().unwrap_or("").into())),
None => Ok(Value::String(value.into()))
}
}
@@ -209,7 +209,7 @@ fn dirname(_: VmArgs, args: Vec<Value>) -> Result<Value> {
Some(p) => p,
None => path.as_path()
};
- let str = parent.as_os_str().to_str().unwrap();
+ let str = parent.as_os_str().to_str().unwrap_or("");
match str {
"" => Ok(Value::String(".".into())),
s => Ok(Value::String(s.into()))
@@ -226,7 +226,7 @@ fn realpath(_: VmArgs, args: Vec<Value>) -> Result<Value> {
Ok(p) => p,
Err(e) => return error!("could not get realpath: {e}")
};
- Ok(Value::String(path.to_str().unwrap().into()))
+ Ok(Value::String(path.to_str().unwrap_or("").into()))
}
diff --git a/test.mat b/test.mat
new file mode 100644
index 0000000..71a04dd
--- /dev/null
+++ b/test.mat
@@ -0,0 +1,8 @@
+let a = 3
+{
+ a = 4;
+ const bees = \a => a*2;
+ let j = bees(3);
+ a = j;
+}
+let g = a + 'aaaa';
diff --git a/test.matc b/test.matc
new file mode 100644
index 0000000..19c52ca
--- /dev/null
+++ b/test.matc
Binary files differ