From 46759ed6fb2896d7bcbcc2f8e0181256281c9809 Mon Sep 17 00:00:00 2001 From: mrodz <79176075+mrodz@users.noreply.github.com> Date: Wed, 5 Apr 2023 00:42:31 -0700 Subject: [PATCH 1/4] make_vector --- src/bytecode/bin/test.mmm | 18 +++ src/bytecode/instruction.rs | 40 +++++-- src/bytecode/variables.rs | 59 +--------- .../variables/primitive_shorthands.rs | 107 ++++++++++++++++++ src/bytecode/variables/variable.rs | 32 +++--- 5 files changed, 175 insertions(+), 81 deletions(-) create mode 100644 src/bytecode/variables/primitive_shorthands.rs diff --git a/src/bytecode/bin/test.mmm b/src/bytecode/bin/test.mmm index b8083c8..3b80d18 100644 --- a/src/bytecode/bin/test.mmm +++ b/src/bytecode/bin/test.mmm @@ -30,6 +30,24 @@ function main printn * + void + + call src/bytecode/bin/test.mmm#test_vecs + + void + ret +end + +function test_vecs + int 5 + int 0 + string "Hello, World!" + float 3.14159 + constexpr 0b101 + make_vector + + printn * + void ret end \ No newline at end of file diff --git a/src/bytecode/instruction.rs b/src/bytecode/instruction.rs index 5447fee..904b23a 100644 --- a/src/bytecode/instruction.rs +++ b/src/bytecode/instruction.rs @@ -64,7 +64,7 @@ mod implementations { use super::*; use crate::bytecode::function::{PrimitiveFunction, ReturnValue}; use crate::bytecode::variables::{buckets, Variable}; - use crate::{bool, function, int}; + use crate::{bool, function, int, vector}; use std::collections::HashMap; instruction! { @@ -196,7 +196,6 @@ mod implementations { make_type!(make_char); make_type!(make_byte); make_type!(make_bigint); - // make_type!(make_function); instruction! { make_function(ctx, args) { @@ -224,12 +223,36 @@ mod implementations { Ok(()) } + + make_vector(ctx, args) { + if args.len() > 1 { + bail!("`make_vector` instruction requires 1 argument (capacity) or none (initializes with contents of local operating stack)") + } + + let Some(arg) = args.first() else { + let vec = ctx.get_local_operating_stack().clone(); + // ^^ new capacity = old length + + ctx.clear_stack(); + ctx.push(vector!(raw vec)); + + return Ok(()) + }; + + let capacity = usize::from_str_radix(arg, 10).context("argument must be of type usize")?; + + let vec = vector!(raw Vec::with_capacity(capacity)); + + ctx.push(vec); + + Ok(()) + } } instruction! { printn(ctx, args) { let Some(arg) = args.first() else { - bail!("expected 1 parameter of type __rust__::usize, or * to print all"); + bail!("expected 1 parameter (index into local operating stack), or * to print all"); }; if arg == "*" { @@ -247,7 +270,7 @@ mod implementations { return Ok(()); } - let arg = usize::from_str_radix(arg, 10)?; + let arg = usize::from_str_radix(arg, 10).context("argument must be of type usize")?; println!("{:?}", ctx.get_nth_op_item(arg)); @@ -295,7 +318,7 @@ mod implementations { bail!("expected one argument") }; - let n = usize::from_str_radix(first, 10)?; + let n = usize::from_str_radix(first, 10).context("argument must be of type usize")?; let Some(nth_arg) = ctx.nth_arg(n) else { bail!("#{n} argument does not exist (range 0..{})", ctx.argc()) @@ -470,6 +493,7 @@ pub fn query(name: &String) -> InstructionSignature { "char" => implementations::make_char, "byte" => implementations::make_byte, "make_function" => implementations::make_function, + "make_vector" => implementations::make_vector, "void" => implementations::void, "breakpoint" => implementations::breakpoint, "ret" => implementations::ret, @@ -491,10 +515,10 @@ pub fn query(name: &String) -> InstructionSignature { } } +#[inline(always)] pub fn run_instruction(ctx: &mut Ctx, instruction: &Instruction) -> Result<()> { - let x = query(&instruction.name); - x(ctx, &instruction.arguments)?; - + let instruction_fn = query(&instruction.name); + instruction_fn(ctx, &instruction.arguments)?; Ok(()) } diff --git a/src/bytecode/variables.rs b/src/bytecode/variables.rs index 91eca5e..65167b1 100644 --- a/src/bytecode/variables.rs +++ b/src/bytecode/variables.rs @@ -1,4 +1,5 @@ mod equality; +mod primitive_shorthands; mod variable; pub use variable::bin_op_from; @@ -6,61 +7,3 @@ pub use variable::bin_op_result; pub use variable::buckets; pub use variable::Primitive; pub use variable::Variable; - -pub mod primitive_shorthands { - #[macro_export] - macro_rules! string { - ($data:expr) => { - Primitive::Str(buckets::Str($data)) - }; - } - - #[macro_export] - macro_rules! bigint { - ($data:expr) => { - Primitive::BigInt(buckets::BigInt($data)) - }; - } - - #[macro_export] - macro_rules! int { - ($data:expr) => { - Primitive::Int(buckets::Int($data)) - }; - } - - #[macro_export] - macro_rules! float { - ($data:expr) => { - Primitive::Float(buckets::Float($data)) - }; - } - - #[macro_export] - macro_rules! bool { - ($data:expr) => { - Primitive::Bool(buckets::Bool($data)) - }; - } - - #[macro_export] - macro_rules! char { - ($data:expr) => { - Primitive::Char(buckets::Char($data)) - }; - } - - #[macro_export] - macro_rules! byte { - ($data:expr) => { - Primitive::Byte(buckets::Byte($data)) - }; - } - - #[macro_export] - macro_rules! function { - ($data:expr) => { - Primitive::Function(buckets::Function($data)) - }; - } -} diff --git a/src/bytecode/variables/primitive_shorthands.rs b/src/bytecode/variables/primitive_shorthands.rs new file mode 100644 index 0000000..1df2263 --- /dev/null +++ b/src/bytecode/variables/primitive_shorthands.rs @@ -0,0 +1,107 @@ +#[macro_export] +macro_rules! string { + ($data:expr) => { + Primitive::Str(buckets::Str($data)) + }; + (raw $data:expr) => {{ + Primitive::Str(buckets::Str(Into::::into($data))) + }}; +} + +#[macro_export] +macro_rules! bigint { + ($data:expr) => { + Primitive::BigInt(buckets::BigInt($data)) + }; +} + +#[macro_export] +macro_rules! int { + ($data:expr) => { + Primitive::Int(buckets::Int($data)) + }; +} + +#[macro_export] +macro_rules! float { + ($data:expr) => { + Primitive::Float(buckets::Float($data)) + }; +} + +#[macro_export] +macro_rules! bool { + ($data:expr) => { + Primitive::Bool(buckets::Bool($data)) + }; +} + +#[macro_export] +macro_rules! char { + ($data:expr) => { + Primitive::Char(buckets::Char($data)) + }; +} + +#[macro_export] +macro_rules! byte { + ($data:expr) => { + Primitive::Byte(buckets::Byte($data)) + }; +} + +#[macro_export] +macro_rules! function { + ($data:expr) => { + Primitive::Function(buckets::Function($data)) + }; +} + +#[macro_export] +macro_rules! vector { + () => { + Primitive::Vector(buckets::Vector(vec![])) + }; + ($elem:expr; $n:expr) => { + Primitive::Vector(buckets::Vector(vec![$elem; $n])) + }; + ($($x:expr),+ $(,)?) => { + { + let mut vector = vec![]; + $( + vector.push($x); + )* + Primitive::Vector(buckets::Vector(vector)) + } + }; + (raw $data:expr) => { + Primitive::Vector(buckets::Vector($data)) + }; +} + +#[cfg(test)] +mod test { + use crate::bytecode::variables::{buckets, Primitive}; + use crate::*; + + #[test] + pub fn ints() { + assert_eq!(int!(5), Primitive::Int(buckets::Int(5))) + } + + #[test] + pub fn vectors() { + let vector = Primitive::Vector(buckets::Vector(vec![ + Primitive::Int(buckets::Int(5)), + Primitive::Str(buckets::Str("Hello".into())), + Primitive::Vector(buckets::Vector(vec![Primitive::Float(buckets::Float( + 3.14159, + ))])), + ])); + + assert_eq!( + vector![int!(5), string!(raw "Hello"), vector![float!(3.14159)]], + vector + ) + } +} diff --git a/src/bytecode/variables/variable.rs b/src/bytecode/variables/variable.rs index 3879c5a..6902b5d 100644 --- a/src/bytecode/variables/variable.rs +++ b/src/bytecode/variables/variable.rs @@ -1,10 +1,9 @@ -use crate::bytecode::function::PrimitiveFunction; use crate::{bigint, bool, byte, char, float, int, string}; use anyhow::{bail, Result}; use std::fmt::{Debug, Display}; macro_rules! primitive { - ($($variant:ident = $type:ty)+) => { + ($($variant:ident($type:ty)),+ $(,)?) => { pub mod buckets { $( #[derive(PartialEq, PartialOrd, Clone)] @@ -12,13 +11,13 @@ macro_rules! primitive { impl std::fmt::Debug for $variant { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - write!(f, "{}", self.0) + write!(f, "{:?}", self.0) } } impl std::fmt::Display for $variant { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { - write!(f, "{}", self.0) + write!(f, "{:?}", self.0) } } @@ -66,14 +65,15 @@ macro_rules! primitive { } primitive! { - Bool = bool - Str = String - Int = i32 - BigInt = i128 - Float = f64 - Char = char - Byte = u8 - Function = crate::bytecode::variables::variable::PrimitiveFunction + Bool(bool), + Str(String), + Int(i32), + BigInt(i128), + Float(f64), + Char(char), + Byte(u8), + Function(crate::bytecode::function::PrimitiveFunction), + Vector(Vec), // 4/4/2023: odd circular import structure } #[derive(Clone)] @@ -154,7 +154,8 @@ impl Primitive { let bytes = string.as_bytes(); if let (Some(b'\"'), Some(b'\"')) = (bytes.first(), bytes.last()) { - return Ok(string!(string[1..string.len() - 1].to_string())); + let sliced = &string[1..string.len() - 1]; + return Ok(string!(raw sliced)); } bail!("not a Str") @@ -235,6 +236,7 @@ impl Display for Primitive { Char(c) => write!(f, "{c}"), Byte(b) => write!(f, "0b{:b}", **b), Function(fun) => write!(f, "{fun}"), + Vector(l) => write!(f, "{l}"), } } } @@ -366,7 +368,7 @@ mod primitives { println!("{}", byte!(0b101)); println!("{}", int!(5)); println!("{}", float!(PI)); - println!("{}", string!("Hello".into())); + println!("{}", string!(raw "Hello")); println!("{}", bool!(false)); println!("{}", char!('@')); } @@ -377,7 +379,7 @@ mod primitives { assert!(int!(5).is_numeric()); assert!(float!(3.0 / 2.0).is_numeric()); assert!(bigint!(2147483648).is_numeric()); - assert!(!string!("Hello".into()).is_numeric()); + assert!(!string!(raw "Hello").is_numeric()); assert!(!bool!(true).is_numeric()); assert!(!char!('@').is_numeric()); } From 3fdf6886b701208ef3b817e7814a334889cd5d37 Mon Sep 17 00:00:00 2001 From: mrodz <79176075+mrodz@users.noreply.github.com> Date: Wed, 5 Apr 2023 16:05:58 -0700 Subject: [PATCH 2/4] indexing into vector (read only) --- src/bytecode/bin/test.mmm | 10 +++++++ src/bytecode/context.rs | 9 ++++++ src/bytecode/function.rs | 20 ++++++------- src/bytecode/instruction.rs | 46 ++++++++++++++++++++++++++---- src/bytecode/variables.rs | 1 + src/bytecode/variables/variable.rs | 28 ++++++++++++++++-- src/bytecode/variables/vector.rs | 1 + 7 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 src/bytecode/variables/vector.rs diff --git a/src/bytecode/bin/test.mmm b/src/bytecode/bin/test.mmm index 3b80d18..b63b61e 100644 --- a/src/bytecode/bin/test.mmm +++ b/src/bytecode/bin/test.mmm @@ -20,6 +20,8 @@ function add_n end function main +bool false +if int 50 call src/bytecode/bin/test.mmm#add_n store add_fifty @@ -31,6 +33,7 @@ function main printn * void +endif call src/bytecode/bin/test.mmm#test_vecs @@ -48,6 +51,13 @@ function test_vecs printn * + vec_op reverse + + printn * + + # vec_op [4] + # printn * + void ret end \ No newline at end of file diff --git a/src/bytecode/context.rs b/src/bytecode/context.rs index 2e5f34f..1f959f1 100644 --- a/src/bytecode/context.rs +++ b/src/bytecode/context.rs @@ -77,6 +77,15 @@ impl<'a> Ctx<'a> { self.stack.get_mut(n) } + pub fn get_last_op_item(&mut self) -> Option<&Primitive> { + self.stack.get(self.stack_size() - 1) + } + + pub fn get_last_op_item_mut(&mut self) -> Option<&mut Primitive> { + let last_idx = self.stack_size() - 1; + self.stack.get_mut(last_idx) + } + pub fn get_call_stack(&self) -> &mut Stack { use std::borrow::BorrowMut; unsafe { (*self.call_stack.as_ptr()).borrow_mut() } diff --git a/src/bytecode/function.rs b/src/bytecode/function.rs index 1645b08..8fd773b 100644 --- a/src/bytecode/function.rs +++ b/src/bytecode/function.rs @@ -235,8 +235,8 @@ impl<'a> Function { .expect("this if has not been mapped."); let IfStatement::If(..) = if_stmt else { - bail!("expected if statment, found {if_stmt:?}"); - }; + bail!("expected if statment, found {if_stmt:?}"); + }; let next = *if_stmt.next_pos(); @@ -296,18 +296,18 @@ pub struct Functions { impl<'a> Functions { pub fn get(&self, signature: &str) -> Result<&Function> { - let Some(result) = self.map.get(signature) else { - bail!("unknown function ({signature})"); - }; - + let result = self + .map + .get(signature) + .with_context(|| format!("unknown function ({signature})"))?; Ok(result) } pub fn get_mut(&'a mut self, signature: &str) -> Result<&'a mut Function> { - let Some(result) = self.map.get_mut(signature) else { - bail!("unknown function ({signature})"); - }; - + let result = self + .map + .get_mut(signature) + .with_context(|| format!("unknown function ({signature})"))?; Ok(result) } } diff --git a/src/bytecode/instruction.rs b/src/bytecode/instruction.rs index 904b23a..933d45e 100644 --- a/src/bytecode/instruction.rs +++ b/src/bytecode/instruction.rs @@ -121,15 +121,12 @@ mod implementations { instruction! { bin_op(ctx, args) { - let symbols = match args.first() { - Some(symbols) => symbols, - None => bail!("Expected an operation [+,-,*,/,%]"), - }.as_bytes(); + let symbols = args.first().context("Expected an operation [+,-,*,/,%]")?.as_bytes(); let symbol = symbols[0] as char; let (Some(right), Some(left)) = (ctx.pop(), ctx.pop()) else { - unreachable!() + bail!("bin_op requires two items on the local operating stack.") }; let (i32_fn, i128_fn, f_fn) = bin_op_from(symbol).context("constructing bin op")?; @@ -141,6 +138,44 @@ mod implementations { Ok(()) } + vec_op(ctx, args) { + let mut arg_iter = args.iter(); + let op_name = arg_iter.next().context("Expected a vector operation")?; + let bytes = op_name.as_bytes(); + + if let (Some(b'['), Some(b']')) = (bytes.first(), bytes.last()) { + let Some(Primitive::Vector(vector)) = ctx.pop() else { + bail!("Cannot perform a vector operation on a non-vector") + }; + + let content = &bytes[1..bytes.len() - 1]; + + // this manual byte slice to usize conversion is more performant + let mut idx: usize = 0; + let mut max = 10_usize.pow(content.len() as u32 - 1); + + for byte in content { + idx += (byte - 48) as usize * max; + max /= 10; + } + + let item = vector.get(idx as usize) + .with_context(|| format!("index {idx} out of bounds (len {})", vector.len()))?; + + ctx.push(item.clone()); + } else { + let Some(Primitive::Vector(buckets::Vector(vector))) = ctx.get_last_op_item_mut() else { + bail!("Cannot perform a vector operation on a non-vector") + }; + + match op_name.as_str() { + "reverse" => vector.reverse(), + not_found => bail!("operation not found: `{not_found}`") + } + } + + Ok(()) + } } instruction! { @@ -485,6 +520,7 @@ pub fn query(name: &String) -> InstructionSignature { "stack_dump" => implementations::stack_dump, "pop" => implementations::pop, "bin_op" => implementations::bin_op, + "vec_op" => implementations::vec_op, "bool" => implementations::make_bool, "string" => implementations::make_str, "bigint" => implementations::make_bigint, diff --git a/src/bytecode/variables.rs b/src/bytecode/variables.rs index 65167b1..64e6bd8 100644 --- a/src/bytecode/variables.rs +++ b/src/bytecode/variables.rs @@ -1,6 +1,7 @@ mod equality; mod primitive_shorthands; mod variable; +mod vector; pub use variable::bin_op_from; pub use variable::bin_op_result; diff --git a/src/bytecode/variables/variable.rs b/src/bytecode/variables/variable.rs index 6902b5d..4db27ea 100644 --- a/src/bytecode/variables/variable.rs +++ b/src/bytecode/variables/variable.rs @@ -1,6 +1,8 @@ -use crate::{bigint, bool, byte, char, float, int, string}; +use crate::{bigint, bool, byte, char, float, int, string, vector}; use anyhow::{bail, Result}; use std::fmt::{Debug, Display}; +// use crate::bytecode::variables::vector::Vector; +// pub struct Vector(Vec); macro_rules! primitive { ($($variant:ident($type:ty)),+ $(,)?) => { @@ -73,7 +75,7 @@ primitive! { Char(char), Byte(u8), Function(crate::bytecode::function::PrimitiveFunction), - Vector(Vec), // 4/4/2023: odd circular import structure + Vector(Vec), } #[derive(Clone)] @@ -335,6 +337,28 @@ pub fn bin_op_result( bail!("could not perform checked integer operation (maybe an overflow, or / by 0)") } } + (Primitive::Str(x), y) => { + let mut x = (*x).clone(); + + if let Primitive::Str(y) = y { + x.push_str(&*y); // slight performance benefit + } else { + x.push_str(&y.to_string()); + } + + string!(x) + } + (Primitive::Vector(x), Primitive::Vector(y)) => { + // if `adding` vectors, the user probably wants a new copy to operate on. + // to extend a vector, use a `vec_op` instruction. + + let mut x_cloned = (*x).clone(); + let mut y_cloned = (*y).clone(); + + x_cloned.append(&mut y_cloned); + + vector!(raw x_cloned) + } (x, y) => bail!("cannot perform binary operation on {x}, {y}"), }) } diff --git a/src/bytecode/variables/vector.rs b/src/bytecode/variables/vector.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/bytecode/variables/vector.rs @@ -0,0 +1 @@ + From b5f468256a702156fa4b8c8990a799e6be58e142 Mon Sep 17 00:00:00 2001 From: mrodz <79176075+mrodz@users.noreply.github.com> Date: Wed, 5 Apr 2023 20:36:07 -0700 Subject: [PATCH 3/4] update item at index --- src/bytecode/bin/test.mmm | 6 ++-- src/bytecode/context.rs | 18 +++++++----- src/bytecode/instruction.rs | 56 ++++++++++++++++++++++++++++--------- src/bytecode/stack.rs | 10 ++++--- 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/bytecode/bin/test.mmm b/src/bytecode/bin/test.mmm index b63b61e..8d3154a 100644 --- a/src/bytecode/bin/test.mmm +++ b/src/bytecode/bin/test.mmm @@ -51,12 +51,12 @@ function test_vecs printn * - vec_op reverse + int 10 + vec_op mut 0 printn * - # vec_op [4] - # printn * + stack_dump void ret diff --git a/src/bytecode/context.rs b/src/bytecode/context.rs index 1f959f1..30b9f64 100644 --- a/src/bytecode/context.rs +++ b/src/bytecode/context.rs @@ -1,4 +1,4 @@ -use std::{cell::Cell, fmt::Debug, sync::Arc}; +use std::{cell::Cell, fmt::Debug, sync::Arc, collections::VecDeque}; use anyhow::{bail, Result}; @@ -12,7 +12,7 @@ use super::{ }; pub struct Ctx<'a> { - stack: Vec, + stack: VecDeque, function: &'a Function, call_stack: Arc>, pub active_if_stmts: Vec<(IfStatement, bool)>, @@ -35,7 +35,7 @@ impl<'a> Ctx<'a> { callback_state: Option>, ) -> Self { Self { - stack: vec![], + stack: VecDeque::new(), active_if_stmts: vec![], function, call_stack, @@ -91,7 +91,7 @@ impl<'a> Ctx<'a> { unsafe { (*self.call_stack.as_ptr()).borrow_mut() } } - pub fn get_local_operating_stack(&self) -> Vec { + pub fn get_local_operating_stack(&self) -> VecDeque { self.stack.clone() } @@ -125,7 +125,7 @@ impl<'a> Ctx<'a> { pub(crate) fn clear_and_set_stack(&mut self, var: Primitive) { self.stack.clear(); - self.stack.push(var); + self.stack.push_back(var); } pub(crate) fn stack_size(&self) -> usize { @@ -133,11 +133,15 @@ impl<'a> Ctx<'a> { } pub(crate) fn push(&mut self, var: Primitive) { - self.stack.push(var); + self.stack.push_back(var); + } + + pub(crate) fn pop_front(&mut self) -> Option { + self.stack.pop_front() } pub(crate) fn pop(&mut self) -> Option { - self.stack.pop() + self.stack.pop_back() } pub(crate) fn register_variable(&self, name: String, var: Primitive) { diff --git a/src/bytecode/instruction.rs b/src/bytecode/instruction.rs index 933d45e..2ec7164 100644 --- a/src/bytecode/instruction.rs +++ b/src/bytecode/instruction.rs @@ -155,21 +155,44 @@ mod implementations { let mut max = 10_usize.pow(content.len() as u32 - 1); for byte in content { - idx += (byte - 48) as usize * max; + if !matches!(byte, b'0'..=b'9') { + bail!("'{}' is not numeric", char::from(*byte)) + } + idx += (byte - b'0') as usize * max; max /= 10; } - let item = vector.get(idx as usize) + let item = vector.get(idx) .with_context(|| format!("index {idx} out of bounds (len {})", vector.len()))?; ctx.push(item.clone()); } else { - let Some(Primitive::Vector(buckets::Vector(vector))) = ctx.get_last_op_item_mut() else { - bail!("Cannot perform a vector operation on a non-vector") - }; - match op_name.as_str() { - "reverse" => vector.reverse(), + "reverse" => { + let Some(Primitive::Vector(buckets::Vector(vector))) = ctx.get_last_op_item_mut() else { + bail!("Cannot perform a vector operation on a non-vector") + }; + + vector.reverse() + }, + "mut" => { + let idx = arg_iter.next().context("mutating an array requires an argument")?; + let idx = usize::from_str_radix(idx, 10)?; + + // let len = ctx.stack_size(); + if ctx.stack_size() != 2 { + bail!("mutating an array requires two items in the local operating stack") + } + + let new_item = ctx.pop().context("could not pop first item")?; + + let Some(Primitive::Vector(buckets::Vector(vector))) = ctx.get_last_op_item_mut() else { + bail!("Cannot perform a vector operation on a non-vector") + }; + + vector[idx] = new_item; + + } not_found => bail!("operation not found: `{not_found}`") } } @@ -265,7 +288,7 @@ mod implementations { } let Some(arg) = args.first() else { - let vec = ctx.get_local_operating_stack().clone(); + let vec = ctx.get_local_operating_stack().clone().into(); // ^^ new capacity = old length ctx.clear_stack(); @@ -296,8 +319,10 @@ mod implementations { }; print!("{first}"); - for var in &ctx.get_local_operating_stack()[1..] { - print!(", {var}"); + let operating_stack = ctx.get_local_operating_stack(); + + for var in operating_stack.iter().skip(1) { + print!(", {var}") } println!(); @@ -307,7 +332,7 @@ mod implementations { let arg = usize::from_str_radix(arg, 10).context("argument must be of type usize")?; - println!("{:?}", ctx.get_nth_op_item(arg)); + println!("{}", ctx.get_nth_op_item(arg).context("nothing at index")?); Ok(()) } @@ -315,6 +340,11 @@ mod implementations { instruction! { call(ctx, args) { + // This never needs to re-allocate, but does need to do O(n) data movement + // if the circular buffer doesn’t happen to be at the beginning of the + // allocation (https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html) + let arguments = ctx.get_local_operating_stack().into(); + let Some(first) = args.first() else { let last = ctx.pop(); @@ -328,7 +358,7 @@ mod implementations { destination_label: f.location.clone(), callback_state: f.callback_state.clone(), stack: ctx.arced_call_stack().clone(), - arguments: ctx.get_local_operating_stack(), + arguments, })); ctx.clear_stack(); @@ -340,7 +370,7 @@ mod implementations { destination_label: first.clone(), callback_state: None, stack: ctx.arced_call_stack().clone(), - arguments: ctx.get_local_operating_stack(), + arguments, })); ctx.clear_stack(); diff --git a/src/bytecode/stack.rs b/src/bytecode/stack.rs index c9fc59f..19226b4 100644 --- a/src/bytecode/stack.rs +++ b/src/bytecode/stack.rs @@ -14,11 +14,13 @@ impl Display for VariableMapping { result.push(format!("{key} = {}", value)); } - write!( - f, - "{}", + let string = if result.len() == 0 { + "None".into() + } else { result.iter().fold("".to_owned(), |x, y| x + "\r\n" + y) - ) + }; + + write!(f, "{string}") } } From d269d2ac46beece95f5b8f54de4eee672bef2e60 Mon Sep 17 00:00:00 2001 From: mrodz <79176075+mrodz@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:02:51 -0700 Subject: [PATCH 4/4] documentation --- src/bytecode/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/bytecode/README.md b/src/bytecode/README.md index de2ff2c..296da0c 100644 --- a/src/bytecode/README.md +++ b/src/bytecode/README.md @@ -91,6 +91,40 @@ Perform fast arithmetic on two loaded items. --- +### `vec_op ! [vector_function, [arguments, ...]?]` +Perform native manipulation on a Vector primitive. Requires a function name, and optionally, arguments. + +Available interfaces: +* `vec_op [idx]` +Will retrieve an element at `idx`. + ``` + int 1 + int 2 + int 3 + make_vec + vec_op [1] + printn * > Outputs 2 + ``` +* `vec_op reverse` +Reverses the vector +* `vec_op mut idx` +Mutate the vector by replacing the `Primitive` at `idx` with the item on top of the local operating stack. + ``` + int 5 + int 10 + make_vec + + int 20 + vec_op mut 0 + printn * > Outputs [20, 10] + ``` + +| ! | Reason | +| - | - | +| 1 | Each vector function can fail uniquely. | + +--- + ### `nop` No operation.