add some documentation
This commit is contained in:
parent
c9f9ba9979
commit
25a30a5be6
10 changed files with 212 additions and 93 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -16,7 +16,7 @@ checksum = "b03f7fbd470aa8b3ad163c85cce8bccfc11cc9c44ef12da0a4eddd98bd307352"
|
|||
|
||||
[[package]]
|
||||
name = "spl"
|
||||
version = "0.0.2"
|
||||
version = "0.0.3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"readformat",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "spl"
|
||||
version = "0.0.2"
|
||||
version = "0.0.3"
|
||||
edition = "2021"
|
||||
description = "Stack Pogramming Language: A simple, concise scripting language."
|
||||
license = "MIT"
|
||||
|
|
|
@ -197,7 +197,7 @@ pub fn dyn_read(stack: &mut Stack) -> OError {
|
|||
kind: ErrorKind::LexError(format!("{x:?}")),
|
||||
stack: stack.trace(),
|
||||
})?),
|
||||
run_at_base: false,
|
||||
run_as_base: false,
|
||||
origin: stack.get_frame(),
|
||||
fname: None,
|
||||
name: "(dyn-read)".to_owned(),
|
||||
|
@ -224,7 +224,7 @@ pub fn dyn_readf(stack: &mut Stack) -> OError {
|
|||
kind: ErrorKind::LexError(format!("{x:?}")),
|
||||
stack: stack.trace(),
|
||||
})?),
|
||||
run_at_base: true,
|
||||
run_as_base: true,
|
||||
origin: stack.get_frame(),
|
||||
fname: Some(n),
|
||||
name: "root".to_owned(),
|
||||
|
@ -267,7 +267,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
|||
AFunc::new(Func {
|
||||
ret_count: f.2,
|
||||
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(wrap(f.1)))),
|
||||
run_at_base: false,
|
||||
run_as_base: false,
|
||||
origin: o.clone(),
|
||||
fname: None,
|
||||
name: f.0.to_owned(),
|
||||
|
|
|
@ -56,7 +56,7 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
|||
words.push(Word::Const(Value::Func(AFunc::new(Func {
|
||||
ret_count: block.0.ok_or(LexerError::FunctionBlockExpected)?,
|
||||
to_call: FuncImpl::SPL(block.1),
|
||||
run_at_base: false,
|
||||
run_as_base: false,
|
||||
origin: Arc::new(Frame::dummy()),
|
||||
fname: None,
|
||||
name: "dyn".to_owned(),
|
||||
|
|
126
src/lib.rs
126
src/lib.rs
|
@ -1,97 +1,135 @@
|
|||
//! # Using SPL as a crate
|
||||
//!
|
||||
//! SPL has a complete API for use in applications and libraries.
|
||||
//! To start a file, use `start_file` with the path, which is relatively straightforward, just like
|
||||
//! `start_file_in_runtime`, which is the same as `start_file` but doesn't create and set a
|
||||
//! runtime.
|
||||
//!
|
||||
//! To start code more customizably, you will have to create a stack and a runtime yourself, then
|
||||
//! call `add_std` to include the standard library.
|
||||
//!
|
||||
//! Example:
|
||||
//! ```
|
||||
//! use spl::*;
|
||||
//! fn main() -> OError {
|
||||
//! Runtime::new().set();
|
||||
//! let mut stack = Stack::new();
|
||||
//! add_std(&mut stack)?;
|
||||
//! Words::new(vec![
|
||||
//! Word::Const(Value::Str("Hello, World!".to_owned())),
|
||||
//! Word::Call("println".to_owned(), /*pop result:*/ false, /*reference:*/ 0)
|
||||
//! ]).exec(&mut stack);
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![allow(clippy::type_complexity)]
|
||||
#![allow(clippy::len_without_is_empty)]
|
||||
|
||||
pub mod stdlib;
|
||||
pub mod dyn_fns;
|
||||
pub mod lexer;
|
||||
pub mod mutex;
|
||||
pub mod runtime;
|
||||
pub mod std_fns;
|
||||
pub mod stdlib;
|
||||
pub mod stream;
|
||||
|
||||
pub use lexer::*;
|
||||
pub use runtime::*;
|
||||
|
||||
use std::fs;
|
||||
|
||||
use lexer::lex;
|
||||
use runtime::*;
|
||||
|
||||
/// Creates a runtime, lexes and executes some SPL code from a file, returning the stack that was
|
||||
/// used for the operations, which should be empty in most cases.
|
||||
pub fn start_file(path: &str) -> Result<Stack, Error> {
|
||||
Runtime::new().set();
|
||||
(start_file_in_runtime(path), Runtime::reset()).0
|
||||
}
|
||||
|
||||
/// TO START A STANDALONE PIECE OF CODE, USE start_file!!
|
||||
/// Lexes and starts some SPL code from a file, returning the stack.
|
||||
pub fn start_file_in_runtime(path: &str) -> Result<Stack, Error> {
|
||||
let mut stack = Stack::new_in(FrameInfo {
|
||||
file: "std.spl".to_owned(),
|
||||
function: "root".to_owned(),
|
||||
});
|
||||
let mut stack = Stack::new();
|
||||
// import stdlib
|
||||
let f = find_in_splpath("std.spl");
|
||||
let words =
|
||||
lex(if let Ok(f) = f { fs::read_to_string(f).unwrap() } else { f.unwrap_err() }).map_err(|x| Error {
|
||||
kind: ErrorKind::LexError(format!("{x:?}")),
|
||||
stack: Vec::new(),
|
||||
})?;
|
||||
words.exec(&mut stack)?;
|
||||
add_std(&mut stack)?;
|
||||
|
||||
// run file
|
||||
Words {
|
||||
words: vec![
|
||||
Words::new(vec![
|
||||
Word::Const(Value::Str(path.to_owned())),
|
||||
Word::Call("call-main-on-file".to_owned(), false, 0),
|
||||
],
|
||||
}
|
||||
])
|
||||
.exec(&mut stack)?;
|
||||
|
||||
Ok(stack)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! require_on_stack {
|
||||
/// Inćlude the standard library in a runtime-stack-pair, where the runtime has been .set().
|
||||
pub fn add_std(stack: &mut Stack) -> OError {
|
||||
let f = find_in_splpath("std.spl");
|
||||
let words = lex(if let Ok(f) = f {
|
||||
fs::read_to_string(f).unwrap()
|
||||
} else {
|
||||
f.unwrap_err()
|
||||
})
|
||||
.map_err(|x| Error {
|
||||
kind: ErrorKind::LexError(format!("{x:?}")),
|
||||
stack: Vec::new(),
|
||||
})?;
|
||||
words.exec(stack)
|
||||
}
|
||||
|
||||
macro_rules! nofmt {
|
||||
{$($code:tt)*} => {
|
||||
$($code)*
|
||||
};
|
||||
}
|
||||
|
||||
// rustfmt adds infinite indentation to this, incrementing every time it is run.
|
||||
nofmt! {
|
||||
#[macro_export]
|
||||
macro_rules! require_on_stack {
|
||||
($name:tt, $type:tt, $stack:expr, $fn:literal) => {
|
||||
let Value::$type($name)
|
||||
= $stack.pop().lock_ro().native.clone() else {
|
||||
let Value::$type($name) = $stack.pop().lock_ro().native.clone() else {
|
||||
return $stack.err(ErrorKind::InvalidCall($fn.to_owned()))
|
||||
};
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_int_on_stack {
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_int_on_stack {
|
||||
($name:tt, $stack:expr, $fn:literal) => {
|
||||
let Value::Int($name)
|
||||
= $stack.pop().lock_ro().native.clone().try_mega_to_int() else {
|
||||
let Value::Int($name) = $stack.pop().lock_ro().native.clone().try_mega_to_int() else {
|
||||
return $stack.err(ErrorKind::InvalidCall($fn.to_owned()))
|
||||
};
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_array {
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_array {
|
||||
($name:tt, $array:expr, $stack:expr, $fn:literal) => {
|
||||
let Value::Array(ref $name)
|
||||
= $array.lock_ro().native else {
|
||||
let Value::Array(ref $name) = $array.lock_ro().native else {
|
||||
return $stack.err(ErrorKind::InvalidCall($fn.to_owned()))
|
||||
};
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_mut_array {
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_mut_array {
|
||||
($name:tt, $array:expr, $stack:expr, $fn:literal) => {
|
||||
let Value::Array(ref mut $name)
|
||||
= $array.lock().native else {
|
||||
let Value::Array(ref mut $name) = $array.lock().native else {
|
||||
return $stack.err(ErrorKind::InvalidCall($fn.to_owned()))
|
||||
};
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_array_on_stack {
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_array_on_stack {
|
||||
($name:tt, $stack:expr, $fn:literal) => {
|
||||
let binding = $stack.pop();
|
||||
require_array!($name, binding, $stack, $fn)
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_mut_array_on_stack {
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! require_mut_array_on_stack {
|
||||
($name:tt, $stack:expr, $fn:literal) => {
|
||||
let binding = $stack.pop();
|
||||
require_mut_array!($name, binding, $stack, $fn)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use spl::{start_file};
|
||||
use spl::start_file;
|
||||
|
||||
use std::env::args;
|
||||
|
||||
|
|
100
src/runtime.rs
100
src/runtime.rs
|
@ -1,8 +1,8 @@
|
|||
use crate::{
|
||||
dyn_fns,
|
||||
mutex::*,
|
||||
std_fns,
|
||||
stream::{self, *}, stdlib,
|
||||
std_fns, stdlib,
|
||||
stream::{self, *},
|
||||
};
|
||||
|
||||
use core::panic;
|
||||
|
@ -26,6 +26,7 @@ thread_local! {
|
|||
static RUNTIME: RefCell<Option<Arc<Mut<Runtime>>>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
/// Obtains a reference to the runtime.
|
||||
pub fn runtime<T>(f: impl FnOnce(RwLockReadGuard<Runtime>) -> T) -> T {
|
||||
RUNTIME.with(|rt| {
|
||||
f(rt.borrow_mut()
|
||||
|
@ -35,6 +36,7 @@ pub fn runtime<T>(f: impl FnOnce(RwLockReadGuard<Runtime>) -> T) -> T {
|
|||
})
|
||||
}
|
||||
|
||||
/// Obtains a mutable reference to the runtime.
|
||||
pub fn runtime_mut<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
|
||||
RUNTIME.with(|rt| {
|
||||
f(rt.borrow_mut()
|
||||
|
@ -44,6 +46,12 @@ pub fn runtime_mut<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
|
|||
})
|
||||
}
|
||||
|
||||
/// An SPL runtime.
|
||||
///
|
||||
/// This holds:
|
||||
/// - types
|
||||
/// - type refs
|
||||
/// - streams
|
||||
#[derive(Clone)]
|
||||
pub struct Runtime {
|
||||
next_type_id: u32,
|
||||
|
@ -139,6 +147,8 @@ impl Runtime {
|
|||
}
|
||||
}
|
||||
|
||||
/// Anything that can be .set() and result in the runtime being set.
|
||||
/// Implemented for Arc<Mut<Runtime>> and Runtime.
|
||||
pub trait SetRuntime {
|
||||
fn set(self);
|
||||
}
|
||||
|
@ -155,12 +165,21 @@ impl SetRuntime for Arc<Mut<Runtime>> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A frame's location in SPL code.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FrameInfo {
|
||||
pub file: String,
|
||||
pub function: String,
|
||||
}
|
||||
|
||||
/// An SPL stack frame.
|
||||
///
|
||||
/// This holds:
|
||||
/// - its parent
|
||||
/// - variables
|
||||
/// - functions
|
||||
/// - its origin ([FrameInfo])
|
||||
/// - whether all functions in it should be made global.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Frame {
|
||||
parent: Option<Arc<Frame>>,
|
||||
|
@ -211,7 +230,7 @@ impl Frame {
|
|||
variables: Mut::new(HashMap::new()),
|
||||
functions: Mut::new(HashMap::new()),
|
||||
origin: FrameInfo {
|
||||
file: "RUNTIME".to_owned(),
|
||||
file: "std.spl".to_owned(),
|
||||
function: "root".to_owned(),
|
||||
},
|
||||
redirect_to_base: false,
|
||||
|
@ -331,6 +350,12 @@ impl Frame {
|
|||
}
|
||||
}
|
||||
|
||||
/// An SPL stack.
|
||||
///
|
||||
/// This holds:
|
||||
/// - a stack of frames
|
||||
/// - the main stack of objects
|
||||
/// - a return accumultor: how many blocks to return directly from
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Stack {
|
||||
frames: Vec<Arc<Frame>>,
|
||||
|
@ -408,7 +433,7 @@ impl Stack {
|
|||
func.origin.clone(),
|
||||
cname.clone(),
|
||||
func.name.clone(),
|
||||
func.run_at_base,
|
||||
func.run_as_base,
|
||||
)
|
||||
} else {
|
||||
Frame::new(func.origin.clone(), func.name.clone())
|
||||
|
@ -453,7 +478,7 @@ impl Stack {
|
|||
stack.push(tmpframe.get_var(tmpname.clone(), stack)?);
|
||||
Ok(())
|
||||
}))),
|
||||
run_at_base: false,
|
||||
run_as_base: false,
|
||||
fname: Some("RUNTIME".to_owned()),
|
||||
name: name.clone(),
|
||||
}),
|
||||
|
@ -469,7 +494,7 @@ impl Stack {
|
|||
let v = stack.pop();
|
||||
tmpframe.set_var(tmpname.clone(), v, stack)
|
||||
}))),
|
||||
run_at_base: false,
|
||||
run_as_base: false,
|
||||
fname: Some("RUNTIME".to_owned()),
|
||||
name: "=".to_owned() + &name,
|
||||
}),
|
||||
|
@ -568,6 +593,9 @@ impl Stack {
|
|||
}
|
||||
}
|
||||
|
||||
/// An SPL keyword. Used to deviate from normal linear code structure.
|
||||
///
|
||||
/// This is different from a [Word], which are any SPL code.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Keyword {
|
||||
/// <none>
|
||||
|
@ -618,6 +646,9 @@ pub enum Keyword {
|
|||
With(Vec<String>),
|
||||
}
|
||||
|
||||
/// Any SPL value that is not a construct.
|
||||
///
|
||||
/// Holds its rust representation.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Value {
|
||||
Null,
|
||||
|
@ -660,19 +691,32 @@ impl PartialOrd for Value {
|
|||
}
|
||||
}
|
||||
|
||||
/// The smallest fragment of SPL code.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Word {
|
||||
/// A keyword, used to deviate from normal code structure.
|
||||
Key(Keyword),
|
||||
/// A constant to push to the stack when encountered.
|
||||
Const(Value),
|
||||
/// A function call.
|
||||
Call(String, bool, u32),
|
||||
/// A method call.
|
||||
ObjCall(String, bool, u32),
|
||||
}
|
||||
|
||||
/// A collection of executable words.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Words {
|
||||
pub words: Vec<Word>,
|
||||
}
|
||||
|
||||
impl Words {
|
||||
pub fn new(words: Vec<Word>) -> Self {
|
||||
Words { words }
|
||||
}
|
||||
}
|
||||
|
||||
/// Any kind of SPL-executable code.
|
||||
#[derive(Clone)]
|
||||
pub enum FuncImpl {
|
||||
Native(fn(&mut Stack) -> OError),
|
||||
|
@ -690,14 +734,24 @@ impl FuncImpl {
|
|||
}
|
||||
}
|
||||
|
||||
/// Any kind of SPL-executable code with metadata surrounding it.
|
||||
///
|
||||
/// This holds:
|
||||
/// - the amount of values returned when called
|
||||
/// - the actual executable code ([FuncImpl])
|
||||
/// - the frame that defined it
|
||||
/// - the name of the file it was defined in, if this is different form the definition frame
|
||||
/// - the name of the function.
|
||||
/// - wether it should be run as the root layer (= wether functions it defines should be made
|
||||
/// global)
|
||||
#[derive(Clone)]
|
||||
pub struct Func {
|
||||
pub ret_count: u32,
|
||||
pub to_call: FuncImpl,
|
||||
pub run_at_base: bool,
|
||||
pub origin: Arc<Frame>,
|
||||
pub fname: Option<String>,
|
||||
pub name: String,
|
||||
pub run_as_base: bool,
|
||||
}
|
||||
|
||||
impl PartialEq for Func {
|
||||
|
@ -713,6 +767,14 @@ impl Debug for Func {
|
|||
}
|
||||
}
|
||||
|
||||
/// Any SPL type.
|
||||
///
|
||||
/// This holds:
|
||||
/// - the name
|
||||
/// - the numeric ID
|
||||
/// - its parent types
|
||||
/// - its methods
|
||||
/// - its fields
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Type {
|
||||
name: String,
|
||||
|
@ -785,8 +847,8 @@ impl Type {
|
|||
);
|
||||
Ok(())
|
||||
}))),
|
||||
run_at_base: false,
|
||||
origin: origin.clone(),
|
||||
run_as_base: false,
|
||||
fname: Some("RUNTIME".to_owned()),
|
||||
name: name.clone(),
|
||||
}),
|
||||
|
@ -802,8 +864,8 @@ impl Type {
|
|||
o.lock().property_map.insert(tmpname.clone(), v);
|
||||
Ok(())
|
||||
}))),
|
||||
run_at_base: false,
|
||||
origin,
|
||||
run_as_base: false,
|
||||
fname: Some("RUNTIME".to_owned()),
|
||||
name: "=".to_owned() + &name,
|
||||
}),
|
||||
|
@ -813,6 +875,12 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
/// Any kind of SPL object, no matter if it is a construct or not.
|
||||
///
|
||||
/// This holds:
|
||||
/// - the type of the object
|
||||
/// - the fields mandated by the type
|
||||
/// - the native value ([Value]), null for constructs unless set manually.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Object {
|
||||
pub kind: AMType,
|
||||
|
@ -905,6 +973,7 @@ impl From<Value> for Object {
|
|||
}
|
||||
}
|
||||
|
||||
/// Trait for converting things to SPL Objects.
|
||||
pub trait SPL {
|
||||
fn spl(self) -> AMObject;
|
||||
}
|
||||
|
@ -918,6 +987,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Finds a file in the SPL_PATH, or returns the internal [stdlib] version of it.
|
||||
pub fn find_in_splpath(path: &str) -> Result<String, String> {
|
||||
if Path::new(path).exists() {
|
||||
return Ok(path.to_owned());
|
||||
|
@ -936,6 +1006,8 @@ pub fn find_in_splpath(path: &str) -> Result<String, String> {
|
|||
}
|
||||
|
||||
impl Words {
|
||||
/// Executes the words. This does *not* create a new frame on the stack. Use [Stack::call] to
|
||||
/// call and create a new frame.
|
||||
pub fn exec(&self, stack: &mut Stack) -> OError {
|
||||
for word in self.words.clone() {
|
||||
match word {
|
||||
|
@ -947,8 +1019,8 @@ impl Words {
|
|||
Arc::new(Func {
|
||||
ret_count: rem,
|
||||
to_call: FuncImpl::SPL(words),
|
||||
run_at_base: false,
|
||||
origin: stack.get_frame(),
|
||||
run_as_base: false,
|
||||
fname: None,
|
||||
name,
|
||||
}),
|
||||
|
@ -970,8 +1042,8 @@ impl Words {
|
|||
Arc::new(Func {
|
||||
ret_count: v.0,
|
||||
to_call: FuncImpl::SPL(v.1),
|
||||
run_at_base: false,
|
||||
origin: origin.clone(),
|
||||
run_as_base: false,
|
||||
fname: None,
|
||||
name: name.clone() + ":" + &k,
|
||||
}),
|
||||
|
@ -1048,8 +1120,8 @@ impl Words {
|
|||
stack.push(ftmp.clone().spl());
|
||||
Ok(())
|
||||
}))),
|
||||
run_at_base: false,
|
||||
origin: stack.get_frame(),
|
||||
run_as_base: false,
|
||||
fname: None,
|
||||
name: s + &x,
|
||||
}));
|
||||
|
@ -1094,8 +1166,8 @@ impl Words {
|
|||
stack.push(ftmp.clone().spl());
|
||||
Ok(())
|
||||
}))),
|
||||
run_at_base: false,
|
||||
origin: stack.get_frame(),
|
||||
run_as_base: false,
|
||||
fname: None,
|
||||
name: s + &x,
|
||||
}));
|
||||
|
@ -1121,6 +1193,7 @@ impl Words {
|
|||
}
|
||||
}
|
||||
|
||||
/// Any error SPL can handle and throw.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ErrorKind {
|
||||
Parse(String, String),
|
||||
|
@ -1137,6 +1210,7 @@ pub enum ErrorKind {
|
|||
CustomObject(AMObject),
|
||||
}
|
||||
|
||||
/// Wrapper for ErrorKind with the stack trace.
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Error {
|
||||
pub kind: ErrorKind,
|
||||
|
|
|
@ -562,7 +562,12 @@ pub fn import(stack: &mut Stack) -> OError {
|
|||
let Value::Str(mut s) = stack.pop().lock_ro().native.clone() else {
|
||||
return stack.err(ErrorKind::InvalidCall("import".to_owned()))
|
||||
};
|
||||
let fallback = match s.as_str().rsplit_once(|x| x == '/' || x == '#').map(|(.., x)| x).unwrap_or(s.as_str()) {
|
||||
let fallback = match s
|
||||
.as_str()
|
||||
.rsplit_once(|x| x == '/' || x == '#')
|
||||
.map(|(.., x)| x)
|
||||
.unwrap_or(s.as_str())
|
||||
{
|
||||
"std.spl" => Some(stdlib::STD),
|
||||
"iter.spl" => Some(stdlib::ITER),
|
||||
"stream.spl" => Some(stdlib::STREAM),
|
||||
|
@ -763,7 +768,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
|||
AFunc::new(Func {
|
||||
ret_count: f.2,
|
||||
to_call: FuncImpl::Native(f.1),
|
||||
run_at_base: false,
|
||||
run_as_base: false,
|
||||
origin: o.clone(),
|
||||
fname: None,
|
||||
name: f.0.to_owned(),
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
pub const STD: &str = include_str!("../std.spl");
|
||||
pub const ITER: &str = include_str!("../iter.spl");
|
||||
pub const STREAM: &str = include_str!("../stream.spl");
|
||||
|
|
|
@ -16,6 +16,7 @@ static STREAM_TYPES: Lazy<Arc<Mut<HashMap<String, StreamType>>>> =
|
|||
Lazy::new(|| Arc::new(Mut::new(HashMap::new())));
|
||||
static IS_INITIALIZED: Lazy<Arc<Mut<bool>>> = Lazy::new(|| Arc::new(Mut::new(false)));
|
||||
|
||||
/// Registers a custom stream type.
|
||||
pub fn register_stream_type(
|
||||
name: &str,
|
||||
supplier: impl Fn(&mut Stack) -> Result<Stream, Error> + Sync + Send + 'static,
|
||||
|
@ -25,10 +26,12 @@ pub fn register_stream_type(
|
|||
.insert(name.to_owned(), StreamType::from(supplier));
|
||||
}
|
||||
|
||||
/// Gets a stream type by name.
|
||||
pub fn get_stream_type(name: String) -> Option<StreamType> {
|
||||
STREAM_TYPES.lock_ro().get(&name).cloned()
|
||||
}
|
||||
|
||||
/// An SPL stream type.
|
||||
#[derive(Clone)]
|
||||
pub struct StreamType {
|
||||
func: Arc<Box<dyn Fn(&mut Stack) -> Result<Stream, Error> + Sync + Send + 'static>>,
|
||||
|
@ -40,6 +43,7 @@ impl StreamType {
|
|||
}
|
||||
}
|
||||
|
||||
/// An SPL stream, holding a reader and a writer, and a function to close it.
|
||||
pub struct Stream {
|
||||
reader: Box<dyn Read + 'static>,
|
||||
writer: Box<dyn Write + 'static>,
|
||||
|
@ -303,7 +307,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
|||
AFunc::new(Func {
|
||||
ret_count: f.2,
|
||||
to_call: FuncImpl::Native(f.1),
|
||||
run_at_base: false,
|
||||
run_as_base: false,
|
||||
origin: o.clone(),
|
||||
fname: None,
|
||||
name: f.0.to_owned(),
|
||||
|
|
Loading…
Add table
Reference in a new issue