remove unwraps, fix utf8
This commit is contained in:
parent
e492ad9a4a
commit
ace046624d
18 changed files with 118 additions and 83 deletions
|
@ -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 clap::{Parser as ArgParser, ColorChoice};
|
||||||
use matrix_lang::prelude::*;
|
use matrix_lang::prelude::*;
|
||||||
use repl::Repl;
|
use repl::Repl;
|
||||||
|
@ -35,8 +35,8 @@ pub struct Args {
|
||||||
|
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
Repl,
|
Repl,
|
||||||
Execute(String),
|
Execute(Vec<u8>),
|
||||||
Compile(String, PathBuf),
|
Compile(Vec<u8>, PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
|
@ -46,18 +46,26 @@ pub struct State<'a> {
|
||||||
color: bool,
|
color: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn error(err: Exception, state: &State) {
|
||||||
|
if state.color {
|
||||||
|
println!("\x1b[31mError:\x1b[0m {err}");
|
||||||
|
} else {
|
||||||
|
println!("Error: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
pub fn new (args: Args) -> (Self, Mode) {
|
pub fn new (args: Args) -> Result<(Self, Mode)> {
|
||||||
|
|
||||||
let stdin = read_stdin();
|
let mut buffer = Vec::new();
|
||||||
|
|
||||||
let file;
|
|
||||||
if let Some(path) = &args.file {
|
if let Some(path) = &args.file {
|
||||||
file = Some(fs::read_to_string(path).unwrap());
|
let mut f = File::open(path)?;
|
||||||
} else if stdin.len() > 0 {
|
f.read_to_end(&mut buffer)?;
|
||||||
file = Some(stdin);
|
|
||||||
} else {
|
} else {
|
||||||
file = None;
|
let mut stdin = io::stdin();
|
||||||
|
if !stdin.is_terminal() {
|
||||||
|
stdin.read_to_end(&mut buffer)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mode;
|
let mode;
|
||||||
|
@ -74,11 +82,10 @@ impl<'a> State<'a> {
|
||||||
PathBuf::from("matc.out")
|
PathBuf::from("matc.out")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let file = file.unwrap_or(String::new());
|
mode = Mode::Compile(buffer, path);
|
||||||
mode = Mode::Compile(file, path);
|
|
||||||
repl = false;
|
repl = false;
|
||||||
} else if let Some(file) = file {
|
} else if buffer.len() > 0 {
|
||||||
mode = Mode::Execute(file);
|
mode = Mode::Execute(buffer);
|
||||||
repl = false;
|
repl = false;
|
||||||
} else {
|
} else {
|
||||||
mode = Mode::Repl;
|
mode = Mode::Repl;
|
||||||
|
@ -106,16 +113,16 @@ impl<'a> State<'a> {
|
||||||
Some(ColorChoice::Never) => false,
|
Some(ColorChoice::Never) => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
(Self {
|
Ok((Self {
|
||||||
parser,
|
parser,
|
||||||
vm: Rc::new(RefCell::new(vm)),
|
vm: Rc::new(RefCell::new(vm)),
|
||||||
compiler,
|
compiler,
|
||||||
color,
|
color,
|
||||||
}, mode)
|
}, mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&mut self, fun: Rc<Function>) -> Result<Value> {
|
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)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,47 +132,37 @@ impl<'a> State<'a> {
|
||||||
Ok(fun)
|
Ok(fun)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_program(&mut self, body: String) -> Result<Rc<Function>> {
|
pub fn load_program(&mut self, mut buffer: Vec<u8>) -> Result<Rc<Function>> {
|
||||||
match Program::load(&body)? {
|
let res = Program::load(buffer.as_mut_slice())?;
|
||||||
|
match res {
|
||||||
Some(fun) => {
|
Some(fun) => {
|
||||||
Ok(fun)
|
Ok(fun)
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
|
let body = buffer_to_string(buffer)?;
|
||||||
self.compile(body)
|
self.compile(body)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(err: Exception, state: &State) {
|
fn buffer_to_string(buffer: Vec<u8>) -> Result<String> {
|
||||||
if state.color {
|
String::from_utf8(buffer)
|
||||||
println!("\x1b[31mError:\x1b[0m {err}");
|
.map_err(|e| exception!(IO_EXCEPTION, "{e}"))
|
||||||
} 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 handle_mode(state: &mut State, mode: Mode) -> Result<()> {
|
fn handle_mode(state: &mut State, mode: Mode) -> Result<()> {
|
||||||
match mode {
|
match mode {
|
||||||
Mode::Repl => {
|
Mode::Repl => {
|
||||||
let mut repl = Repl::new(state);
|
let mut repl = Repl::new(state);
|
||||||
repl.run();
|
repl.run()?;
|
||||||
},
|
},
|
||||||
Mode::Execute(body) => {
|
Mode::Execute(buffer) => {
|
||||||
let fun = state.load_program(body)?;
|
let fun = state.load_program(buffer)?;
|
||||||
state.execute(fun)?;
|
state.execute(fun)?;
|
||||||
},
|
},
|
||||||
Mode::Compile(body, path) => {
|
Mode::Compile(buffer, path) => {
|
||||||
|
let body = buffer_to_string(buffer)?;
|
||||||
let fun = state.compile(body)?;
|
let fun = state.compile(body)?;
|
||||||
let mut file = File::create(path).map_err(|e|
|
let mut file = File::create(path).map_err(|e|
|
||||||
exception!(IO_EXCEPTION, "{e}")
|
exception!(IO_EXCEPTION, "{e}")
|
||||||
|
@ -176,12 +173,17 @@ fn handle_mode(state: &mut State, mode: Mode) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn load() -> Result<()> {
|
||||||
|
|
||||||
let args = Args::parse();
|
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) {
|
if let Err(e) = handle_mode(&mut state, mode) {
|
||||||
error(e, &state);
|
error(e, &state);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if let Err(e) = load() {
|
||||||
|
println!("\x1b[31mFatal:\x1b[0m {e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,12 @@ impl<'s, 'a> Repl<'s, 'a> {
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) -> Result<()> {
|
||||||
|
|
||||||
let interupt = self.state.vm.borrow().interupt();
|
let interupt = self.state.vm.borrow().interupt();
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
interupt.store(Interupt::KeyboardInterupt as usize, Ordering::SeqCst);
|
interupt.store(Interupt::KeyboardInterupt as usize, Ordering::SeqCst);
|
||||||
}).unwrap();
|
}).exception()?;
|
||||||
|
|
||||||
let config = Config::builder()
|
let config = Config::builder()
|
||||||
.indent_size(4)
|
.indent_size(4)
|
||||||
|
@ -39,10 +39,10 @@ impl<'s, 'a> Repl<'s, 'a> {
|
||||||
|
|
||||||
let histfile = std::env::var("MATRIX_HISTORY").ok();
|
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));
|
rl.set_helper(Some(helper));
|
||||||
if let Some(hf) = &histfile {
|
if let Some(hf) = &histfile {
|
||||||
rl.load_history(hf).ok();
|
rl.load_history(hf).exception()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -52,7 +52,7 @@ impl<'s, 'a> Repl<'s, 'a> {
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
rl.add_history_entry(&line).ok();
|
rl.add_history_entry(&line).exception()?;
|
||||||
|
|
||||||
match self.execute(line) {
|
match self.execute(line) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
|
@ -66,12 +66,14 @@ impl<'s, 'a> Repl<'s, 'a> {
|
||||||
}
|
}
|
||||||
Err(err) => crate::error(err, &self.state),
|
Err(err) => crate::error(err, &self.state),
|
||||||
};
|
};
|
||||||
std::io::stdout().flush().ok();
|
std::io::stdout().flush().exception()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(hf) = &histfile {
|
if let Some(hf) = &histfile {
|
||||||
rl.save_history(hf).ok();
|
rl.save_history(hf).exception()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,7 @@ pub struct Program {
|
||||||
const PROGRAM_HEADER: [u8; 5] = [0x00, 0x4d, 0x41, 0x54, 0x0a];
|
const PROGRAM_HEADER: [u8; 5] = [0x00, 0x4d, 0x41, 0x54, 0x0a];
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
pub fn load(body: &str) -> Result<Option<Rc<Function>>> {
|
pub fn load(bytes: &mut [u8]) -> Result<Option<Rc<Function>>> {
|
||||||
let mut bytes = body.as_bytes();
|
|
||||||
if bytes.len() < 6 {
|
if bytes.len() < 6 {
|
||||||
return Ok(None)
|
return Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +21,8 @@ impl Program {
|
||||||
if header != &PROGRAM_HEADER {
|
if header != &PROGRAM_HEADER {
|
||||||
return Ok(None)
|
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)?;
|
let program = <Self>::deserialize(&mut s)?;
|
||||||
s.finish()?;
|
s.finish()?;
|
||||||
Ok(Some(program.fun.clone()))
|
Ok(Some(program.fun.clone()))
|
||||||
|
|
|
@ -142,7 +142,7 @@ impl<'c> Compiler<'c> {
|
||||||
fn collapse_scopes(&mut self, top_scope: usize) {
|
fn collapse_scopes(&mut self, top_scope: usize) {
|
||||||
let mut cutoff = usize::MAX;
|
let mut cutoff = usize::MAX;
|
||||||
while self.scopes.len() > top_scope {
|
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() {
|
if cutoff < self.locals.len() {
|
||||||
self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16), self.last_pos());
|
self.emit(Instruction::DiscardLocals((self.locals.len() - cutoff) as u16), self.last_pos());
|
||||||
|
|
|
@ -286,7 +286,7 @@ impl Lexer {
|
||||||
buf.push(char::from_u32(
|
buf.push(char::from_u32(
|
||||||
n1.to_digit(16).ok_or(error!("invalid digit '{n1}'"))? * 16 +
|
n1.to_digit(16).ok_or(error!("invalid digit '{n1}'"))? * 16 +
|
||||||
n2.to_digit(16).ok_or(error!("invalid digit '{n2}'"))?
|
n2.to_digit(16).ok_or(error!("invalid digit '{n2}'"))?
|
||||||
).unwrap());
|
).expect("bypassed digit check"));
|
||||||
},
|
},
|
||||||
'u' => {
|
'u' => {
|
||||||
self.next_expect('{')?;
|
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() == '.';
|
let is_range = initial != '.' && last == '.' && self.peek() == '.';
|
||||||
|
|
||||||
if is_range {
|
if is_range {
|
||||||
|
|
|
@ -169,7 +169,7 @@ impl Parser {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if parts.len() == 1 {
|
if parts.len() == 1 {
|
||||||
Ok((E::List(parts.pop().unwrap()), pos).into())
|
Ok((E::List(parts.pop().expect("bypassed vec length")), pos).into())
|
||||||
} else {
|
} else {
|
||||||
let codomain = parts.len();
|
let codomain = parts.len();
|
||||||
let domain = parts[0].len();
|
let domain = parts[0].len();
|
||||||
|
|
|
@ -2,6 +2,7 @@ pub type Result<T> = std::result::Result<T, Exception>;
|
||||||
|
|
||||||
pub use crate::value::Value as Value;
|
pub use crate::value::Value as Value;
|
||||||
pub use crate::value::exception::Exception as Exception;
|
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::matrix::Matrix as Matrix;
|
||||||
pub use crate::value::gc::Gc as Gc;
|
pub use crate::value::gc::Gc as Gc;
|
||||||
pub use crate::value::hash::ValueMap as ValueMap;
|
pub use crate::value::hash::ValueMap as ValueMap;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{fmt::{Debug, Display}, error::Error};
|
use std::{fmt::{Debug, Display}, error::Error, io};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -76,3 +76,24 @@ impl<T> From<Exception> for Result<T> {
|
||||||
Err(value)
|
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())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ impl Matrix {
|
||||||
let values = rows
|
let values = rows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.reduce(|mut a,b| {a.extend(b); a})
|
.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))
|
Ok(Matrix::new(self.domain + other.domain, self.codomain, values))
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,7 +217,7 @@ impl Vm {
|
||||||
let val = self.globals
|
let val = self.globals
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.get(&idx)
|
.get(&idx)
|
||||||
.unwrap()
|
.ok_or(exception!(RUNTIME_EXCEPTION, "undefined global at index {idx}"))?
|
||||||
.clone();
|
.clone();
|
||||||
self.stack.push(val);
|
self.stack.push(val);
|
||||||
},
|
},
|
||||||
|
@ -380,7 +380,7 @@ impl Vm {
|
||||||
self.trystack.push(scope);
|
self.trystack.push(scope);
|
||||||
},
|
},
|
||||||
I::TryEnd => {
|
I::TryEnd => {
|
||||||
self.trystack.pop().unwrap();
|
self.trystack.pop().ok_or(exception!(RUNTIME_EXCEPTION, "try stack smashed"))?;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@ impl Parse for NativeFuncParams {
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn native_func(input: TokenStream, annotated_item: TokenStream) -> TokenStream {
|
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 arity = input.arity;
|
||||||
let variadic = input.variadic.is_some();
|
let variadic = input.variadic.is_some();
|
||||||
|
|
||||||
|
|
|
@ -4,30 +4,31 @@ use matrix_lang::prelude::*;
|
||||||
use matrix_macros::native_func;
|
use matrix_macros::native_func;
|
||||||
use crate::{VmArgs, next, error, unpack_args, unpack_varargs};
|
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 result = String::new();
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
result.push('0');
|
result.push('0');
|
||||||
return result
|
return Ok(result)
|
||||||
} else if n < 0 {
|
} else if n < 0 {
|
||||||
n = -n;
|
n = -n;
|
||||||
idx = 1;
|
idx = 1;
|
||||||
result.push('-');
|
result.push('-');
|
||||||
}
|
}
|
||||||
while n != 0 {
|
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);
|
result.insert(idx, c);
|
||||||
n /= r;
|
n /= r;
|
||||||
}
|
}
|
||||||
result
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[native_func(1)]
|
#[native_func(1)]
|
||||||
fn bin(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
fn bin(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let [value] = unpack_args!(args);
|
let [value] = unpack_args!(args);
|
||||||
match value {
|
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")
|
_ => 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> {
|
fn sex(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let [value] = unpack_args!(args);
|
let [value] = unpack_args!(args);
|
||||||
match value {
|
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")
|
_ => 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> {
|
fn oct(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let [value] = unpack_args!(args);
|
let [value] = unpack_args!(args);
|
||||||
match value {
|
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")
|
_ => 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> {
|
fn hex(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let [value] = unpack_args!(args);
|
let [value] = unpack_args!(args);
|
||||||
match value {
|
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")
|
_ => 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> {
|
fn radix(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let [radix, value] = unpack_args!(args);
|
let [radix, value] = unpack_args!(args);
|
||||||
match (radix, value) {
|
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")
|
_ => error!("radix requires two integer aguments")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +137,7 @@ fn ord(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
if str.len() != 1 {
|
if str.len() != 1 {
|
||||||
return error!("ord requires a 1 length string")
|
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))
|
Ok(Value::Int(char as i64))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ fn file_read(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
return error!("file read requires a file")
|
return error!("file read requires a file")
|
||||||
};
|
};
|
||||||
let mut contents = String::new();
|
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}'")
|
return error!("cannot read file: '{err}'")
|
||||||
};
|
};
|
||||||
Ok(Value::String(contents.into()))
|
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")
|
return error!("file read requires a file")
|
||||||
};
|
};
|
||||||
let mut contents = String::new();
|
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}'")
|
return error!("cannot read file: '{err}'")
|
||||||
};
|
};
|
||||||
let lines: Vec<Rc<str>> = contents.split_inclusive("\n").map(|s| Rc::from(s)).collect();
|
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")
|
return error!("file write requires a file")
|
||||||
};
|
};
|
||||||
let content = format!("{content}");
|
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}'")
|
return error!("cannot write file: '{err}'")
|
||||||
};
|
};
|
||||||
Ok(Value::Nil)
|
Ok(Value::Nil)
|
||||||
|
|
|
@ -365,7 +365,7 @@ fn unzip((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
if vals.len() != 2 {
|
if vals.len() != 2 {
|
||||||
return error!("unzip only works over a iterator of pairs");
|
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);
|
ll.push(l);
|
||||||
lr.push(r);
|
lr.push(r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn trans(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
let values = mat
|
let values = mat
|
||||||
.cols()
|
.cols()
|
||||||
.reduce(|mut a, b| {a.extend(b); a})
|
.reduce(|mut a, b| {a.extend(b); a})
|
||||||
.unwrap()
|
.ok_or(exception!(RUNTIME_EXCEPTION, "matrix values smashed"))?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|e| e.clone())
|
.map(|e| e.clone())
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -164,7 +164,7 @@ fn mat_det(mat: Matrix) -> Result<Value> {
|
||||||
.collect::<Vec<Value>>()
|
.collect::<Vec<Value>>()
|
||||||
)
|
)
|
||||||
.reduce(|mut a, b| {a.extend(b); a})
|
.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 sub = Matrix::new(mat.domain - 1, mat.domain - 1, sub_values);
|
||||||
let val = mat.get(0, col)?;
|
let val = mat.get(0, col)?;
|
||||||
let part = (val * mat_det(sub)?)?;
|
let part = (val * mat_det(sub)?)?;
|
||||||
|
|
|
@ -193,7 +193,7 @@ fn basename(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
};
|
};
|
||||||
let path = PathBuf::from(value.to_string());
|
let path = PathBuf::from(value.to_string());
|
||||||
match path.file_name() {
|
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()))
|
None => Ok(Value::String(value.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ fn dirname(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => path.as_path()
|
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 {
|
match str {
|
||||||
"" => Ok(Value::String(".".into())),
|
"" => Ok(Value::String(".".into())),
|
||||||
s => Ok(Value::String(s.into()))
|
s => Ok(Value::String(s.into()))
|
||||||
|
@ -226,7 +226,7 @@ fn realpath(_: VmArgs, args: Vec<Value>) -> Result<Value> {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return error!("could not get realpath: {e}")
|
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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
8
test.mat
Normal file
8
test.mat
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
let a = 3
|
||||||
|
{
|
||||||
|
a = 4;
|
||||||
|
const bees = \a => a*2;
|
||||||
|
let j = bees(3);
|
||||||
|
a = j;
|
||||||
|
}
|
||||||
|
let g = a + 'aaaa';
|
BIN
test.matc
Normal file
BIN
test.matc
Normal file
Binary file not shown.
Loading…
Reference in a new issue