minor fixes, add streams api
This commit is contained in:
parent
00f9db725e
commit
8c30e2fd2f
12 changed files with 702 additions and 214 deletions
15
install.spl
Normal file
15
install.spl
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
"to be run with `cargo run install.spl`.";
|
||||||
|
|
||||||
|
func main { mega |
|
||||||
|
[ "sudo" "mkdir" "/usr/lib/spl" ] command-wait;
|
||||||
|
[ "sh" "-c" "sudo cp *.spl /usr/lib/spl" ] command-wait;
|
||||||
|
[ "cargo" "build" "--release" ] command-wait;
|
||||||
|
[ "sudo" "cp" "target/release/spl" "/bin" ] command-wait;
|
||||||
|
|
||||||
|
"make sure its executable";
|
||||||
|
[ "sudo" "chmod" "a+rx" "/bin/spl" ] command-wait;
|
||||||
|
|
||||||
|
"SPL is now installed!" println
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
205
iter.spl
Normal file
205
iter.spl
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
|
||||||
|
construct _Iter {
|
||||||
|
;
|
||||||
|
foreach { | with callable this ;
|
||||||
|
def itm
|
||||||
|
while { this:next dup =itm null eq not } {
|
||||||
|
itm callable call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collect { array | with this ;
|
||||||
|
[ { any | } this:foreach ]
|
||||||
|
}
|
||||||
|
map { MapIter | with map-function this ;
|
||||||
|
map-function this MapIter:new
|
||||||
|
}
|
||||||
|
reduce { ReduceIter | with reduce-function this ;
|
||||||
|
reduce-function this ReduceIter:new
|
||||||
|
}
|
||||||
|
fold { FoldIter | with accumulator fold-function this ;
|
||||||
|
accumulator fold-function this FoldIter:new
|
||||||
|
}
|
||||||
|
sum { mega | with this ;
|
||||||
|
{ mega | with accum item ;
|
||||||
|
accum item +
|
||||||
|
} this:reduce:calculate
|
||||||
|
}
|
||||||
|
product { mega | with this ;
|
||||||
|
{ mega | with accum item ;
|
||||||
|
accum item *
|
||||||
|
} this:reduce:calculate
|
||||||
|
}
|
||||||
|
join { str | with separator this ;
|
||||||
|
{ str | with accum item ;
|
||||||
|
accum _str separator item _str strconcat strconcat
|
||||||
|
} this:reduce:calculate
|
||||||
|
}
|
||||||
|
filter { FilterIter | with filter this ;
|
||||||
|
filter this FilterIter:new
|
||||||
|
}
|
||||||
|
skip { this | with amount this ;
|
||||||
|
{ |
|
||||||
|
this:next;
|
||||||
|
} amount:foreach
|
||||||
|
}
|
||||||
|
count { mega | with this ;
|
||||||
|
def n 0 =n
|
||||||
|
while { this:next null eq not } {
|
||||||
|
n ++ =n
|
||||||
|
}
|
||||||
|
n
|
||||||
|
}
|
||||||
|
last { any | with this ;
|
||||||
|
def last
|
||||||
|
def cur
|
||||||
|
while { this:next dup =cur null eq not } {
|
||||||
|
cur =last
|
||||||
|
}
|
||||||
|
last
|
||||||
|
}
|
||||||
|
chain { ChainIter | with other this ;
|
||||||
|
other this ChainIter:new
|
||||||
|
}
|
||||||
|
enumerate { EnumerationIter | with this ;
|
||||||
|
this EnumerationIter:new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
construct MapIter {
|
||||||
|
origin
|
||||||
|
map-function
|
||||||
|
;
|
||||||
|
construct { this | with map-function origin this ;
|
||||||
|
origin this:=origin
|
||||||
|
map-function this:=map-function
|
||||||
|
this
|
||||||
|
}
|
||||||
|
next { any | with this ;
|
||||||
|
this:origin:next dup null eq if {
|
||||||
|
2 stop
|
||||||
|
}
|
||||||
|
this:map-function call
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include _Iter in MapIter
|
||||||
|
|
||||||
|
construct ReduceIter {
|
||||||
|
origin
|
||||||
|
accumulator
|
||||||
|
reduce-function
|
||||||
|
;
|
||||||
|
construct { this | with reduce-function origin this ;
|
||||||
|
origin this:=origin
|
||||||
|
reduce-function this:=reduce-function
|
||||||
|
this
|
||||||
|
}
|
||||||
|
next { any | with this ;
|
||||||
|
def itm
|
||||||
|
this:origin:next dup null eq if {
|
||||||
|
2 stop
|
||||||
|
} =itm
|
||||||
|
this:accumulator null eq if {
|
||||||
|
itm dup this:=accumulator
|
||||||
|
null 2 stop
|
||||||
|
}
|
||||||
|
this:accumulator itm this:reduce-function call dup this:=accumulator
|
||||||
|
}
|
||||||
|
calculate { any | with this ;
|
||||||
|
{ | pop } this:foreach
|
||||||
|
this:accumulator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include _Iter in ReduceIter
|
||||||
|
|
||||||
|
construct FoldIter {
|
||||||
|
origin
|
||||||
|
accumulator
|
||||||
|
reduce-function
|
||||||
|
;
|
||||||
|
construct { this | with accumulator fold-function origin this ;
|
||||||
|
accumulator this:=accumulator
|
||||||
|
origin this:=origin
|
||||||
|
fold-function this:=fold-function
|
||||||
|
this
|
||||||
|
}
|
||||||
|
next { any | with this ;
|
||||||
|
def itm
|
||||||
|
this:origin:next dup null eq if {
|
||||||
|
2 stop
|
||||||
|
} =itm
|
||||||
|
this:accumulator itm this:fold-function call dup this:=accumulator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include _Iter in FoldIter
|
||||||
|
|
||||||
|
construct FilterIter {
|
||||||
|
origin
|
||||||
|
filter
|
||||||
|
;
|
||||||
|
construct { this | with filter origin this ;
|
||||||
|
origin this:=origin
|
||||||
|
filter this:=filter
|
||||||
|
this
|
||||||
|
}
|
||||||
|
next { any | with this ;
|
||||||
|
while { 1 } {
|
||||||
|
def next this:origin:next =next
|
||||||
|
next null eq if {
|
||||||
|
null
|
||||||
|
3 stop
|
||||||
|
}
|
||||||
|
next this:filter call if {
|
||||||
|
next 3 stop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include _Iter in FilterIter
|
||||||
|
|
||||||
|
construct ChainIter {
|
||||||
|
current
|
||||||
|
next-iters
|
||||||
|
;
|
||||||
|
construct { this | with other origin this ;
|
||||||
|
[ other ] List:new this:=next-iters
|
||||||
|
origin this:=current
|
||||||
|
this
|
||||||
|
}
|
||||||
|
next { any | with this ;
|
||||||
|
def item this:current:next =item
|
||||||
|
while { item null eq } {
|
||||||
|
this:next-iters:pop-front dup null eq not if {
|
||||||
|
this:=current
|
||||||
|
this:current:next =item
|
||||||
|
} 2 stop
|
||||||
|
}
|
||||||
|
item
|
||||||
|
}
|
||||||
|
chain { this | with other this ;
|
||||||
|
other this:next-iters:push
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include _Iter in ChainIter
|
||||||
|
|
||||||
|
construct EnumerationIter {
|
||||||
|
origin
|
||||||
|
idx
|
||||||
|
;
|
||||||
|
construct { this | with origin this ;
|
||||||
|
origin this:=origin
|
||||||
|
this
|
||||||
|
}
|
||||||
|
next { [mega,any]|null | with this ;
|
||||||
|
this:origin:next dup null eq not if {
|
||||||
|
[ swap this:idx swap ]
|
||||||
|
this:idx ++ this:=idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include _Iter in EnumerationIter
|
|
@ -190,7 +190,6 @@ pub fn dyn_read(stack: &mut Stack) -> OError {
|
||||||
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
|
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
|
||||||
return stack.err(ErrorKind::InvalidCall("dyn-read".to_owned()))
|
return stack.err(ErrorKind::InvalidCall("dyn-read".to_owned()))
|
||||||
};
|
};
|
||||||
let origin = stack.peek_frame(1);
|
|
||||||
stack.push(
|
stack.push(
|
||||||
Value::Func(AFunc::new(Func {
|
Value::Func(AFunc::new(Func {
|
||||||
ret_count: 0,
|
ret_count: 0,
|
||||||
|
@ -199,7 +198,7 @@ pub fn dyn_read(stack: &mut Stack) -> OError {
|
||||||
stack: stack.trace(),
|
stack: stack.trace(),
|
||||||
})?),
|
})?),
|
||||||
run_at_base: false,
|
run_at_base: false,
|
||||||
origin,
|
origin: stack.get_frame(),
|
||||||
fname: None,
|
fname: None,
|
||||||
name: "(dyn-read)".to_owned(),
|
name: "(dyn-read)".to_owned(),
|
||||||
}))
|
}))
|
||||||
|
@ -218,7 +217,6 @@ pub fn dyn_readf(stack: &mut Stack) -> OError {
|
||||||
) else {
|
) else {
|
||||||
return stack.err(ErrorKind::InvalidCall("dyn-readf".to_owned()))
|
return stack.err(ErrorKind::InvalidCall("dyn-readf".to_owned()))
|
||||||
};
|
};
|
||||||
let origin = stack.peek_frame(1);
|
|
||||||
stack.push(
|
stack.push(
|
||||||
Value::Func(AFunc::new(Func {
|
Value::Func(AFunc::new(Func {
|
||||||
ret_count: 0,
|
ret_count: 0,
|
||||||
|
@ -227,15 +225,26 @@ pub fn dyn_readf(stack: &mut Stack) -> OError {
|
||||||
stack: stack.trace(),
|
stack: stack.trace(),
|
||||||
})?),
|
})?),
|
||||||
run_at_base: true,
|
run_at_base: true,
|
||||||
origin,
|
origin: stack.get_frame(),
|
||||||
fname: Some(n),
|
fname: Some(n),
|
||||||
name: "(dyn-read)".to_owned(),
|
name: "root".to_owned(),
|
||||||
}))
|
}))
|
||||||
.spl(),
|
.spl(),
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wrap(f: fn(&mut Stack) -> OError) -> impl Fn(&mut Stack) -> OError {
|
||||||
|
move |stack| {
|
||||||
|
unsafe {
|
||||||
|
let frame = stack.pop_frame(0);
|
||||||
|
let r = f(stack);
|
||||||
|
stack.push_frame(frame);
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
||||||
type Fn = fn(&mut Stack) -> OError;
|
type Fn = fn(&mut Stack) -> OError;
|
||||||
let fns: [(&str, Fn, u32); 14] = [
|
let fns: [(&str, Fn, u32); 14] = [
|
||||||
|
@ -259,7 +268,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
||||||
f.0.to_owned(),
|
f.0.to_owned(),
|
||||||
AFunc::new(Func {
|
AFunc::new(Func {
|
||||||
ret_count: f.2,
|
ret_count: f.2,
|
||||||
to_call: FuncImpl::Native(f.1),
|
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(wrap(f.1)))),
|
||||||
run_at_base: false,
|
run_at_base: false,
|
||||||
origin: o.clone(),
|
origin: o.clone(),
|
||||||
fname: None,
|
fname: None,
|
||||||
|
|
71
src/lib.rs
71
src/lib.rs
|
@ -1,8 +1,79 @@
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
#![allow(clippy::len_without_is_empty)]
|
#![allow(clippy::len_without_is_empty)]
|
||||||
|
|
||||||
pub mod dyn_fns;
|
pub mod dyn_fns;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
pub mod std_fns;
|
pub mod std_fns;
|
||||||
pub mod stream;
|
pub mod stream;
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use lexer::lex;
|
||||||
|
use runtime::*;
|
||||||
|
|
||||||
|
pub fn start_file(path: &str) -> Result<Stack, Error> {
|
||||||
|
Runtime::new().set();
|
||||||
|
(start_file_in_runtime(path), Runtime::reset()).0
|
||||||
|
}
|
||||||
|
|
||||||
|
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(),
|
||||||
|
});
|
||||||
|
// import stdlib
|
||||||
|
let words =
|
||||||
|
lex(fs::read_to_string(find_in_splpath("std.spl")).unwrap()).map_err(|x| Error {
|
||||||
|
kind: ErrorKind::LexError(format!("{x:?}")),
|
||||||
|
stack: Vec::new(),
|
||||||
|
})?;
|
||||||
|
words.exec(&mut stack)?;
|
||||||
|
|
||||||
|
// run file
|
||||||
|
Words {
|
||||||
|
words: 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 {
|
||||||
|
($name:tt, $type:tt, $stack:expr, $fn:literal) => {
|
||||||
|
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 {
|
||||||
|
($name:tt, $stack:expr, $fn:literal) => {
|
||||||
|
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_on_stack {
|
||||||
|
($name:tt, $stack:expr, $fn:literal) => {
|
||||||
|
let _binding = $stack.pop();
|
||||||
|
let Value::Array(ref $name) = _binding.lock_ro().native else {
|
||||||
|
return $stack.err(ErrorKind::InvalidCall($fn.to_owned()))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! require_mut_array_on_stack {
|
||||||
|
($name:tt, $stack:expr, $fn:literal) => {
|
||||||
|
let _binding = $stack.pop();
|
||||||
|
let Value::Array(ref mut $name) = _binding.lock().native else {
|
||||||
|
return $stack.err(ErrorKind::InvalidCall($fn.to_owned()))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -1,19 +1,9 @@
|
||||||
use spl::{lexer::lex, runtime::*};
|
use spl::{runtime::*, start_file};
|
||||||
|
|
||||||
use std::fs;
|
use std::env::args;
|
||||||
|
|
||||||
fn main() -> OError {
|
fn main() {
|
||||||
let rt = Runtime::new();
|
if let Err(x) = start_file(&args().nth(1).expect("no file provided to be started.")) {
|
||||||
rt.set();
|
println!("{x:?}");
|
||||||
let mut stack = Stack::new_in(FrameInfo {
|
}
|
||||||
file: "std.spl".to_owned(),
|
|
||||||
function: "root".to_owned(),
|
|
||||||
});
|
|
||||||
let words = lex(fs::read_to_string("std.spl").unwrap()).map_err(|x| Error {
|
|
||||||
kind: ErrorKind::LexError(format!("{x:?}")),
|
|
||||||
stack: Vec::new(),
|
|
||||||
})?;
|
|
||||||
words.exec(&mut stack)?;
|
|
||||||
Runtime::reset();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::mem;
|
use std::sync::{RwLockWriteGuard, RwLockReadGuard};
|
||||||
use std::sync::RwLockWriteGuard;
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
@ -15,7 +14,8 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
vec,
|
vec,
|
||||||
};
|
};
|
||||||
use std::{collections::VecDeque, thread::panicking};
|
use std::collections::VecDeque;
|
||||||
|
use std::{env::var, mem, path::Path};
|
||||||
|
|
||||||
pub type AMObject = Arc<Mut<Object>>;
|
pub type AMObject = Arc<Mut<Object>>;
|
||||||
pub type AMType = Arc<Mut<Type>>;
|
pub type AMType = Arc<Mut<Type>>;
|
||||||
|
@ -26,7 +26,16 @@ thread_local! {
|
||||||
static RUNTIME: RefCell<Option<Arc<Mut<Runtime>>>> = RefCell::new(None);
|
static RUNTIME: RefCell<Option<Arc<Mut<Runtime>>>> = RefCell::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn runtime<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
|
pub fn runtime<T>(f: impl FnOnce(RwLockReadGuard<Runtime>) -> T) -> T {
|
||||||
|
RUNTIME.with(|rt| {
|
||||||
|
f(rt.borrow_mut()
|
||||||
|
.as_mut()
|
||||||
|
.expect("no runtime (use .set())")
|
||||||
|
.lock_ro())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn runtime_mut<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
|
||||||
RUNTIME.with(|rt| {
|
RUNTIME.with(|rt| {
|
||||||
f(rt.borrow_mut()
|
f(rt.borrow_mut()
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -171,7 +180,13 @@ impl Display for Frame {
|
||||||
std::fmt::Display::fmt(&object.lock_ro(), f)?;
|
std::fmt::Display::fmt(&object.lock_ro(), f)?;
|
||||||
f.write_str("\n")?;
|
f.write_str("\n")?;
|
||||||
}
|
}
|
||||||
f.write_str("\n")?;
|
f.write_str("\nFuncs: \n")?;
|
||||||
|
for (name, ..) in self.functions.lock_ro().iter() {
|
||||||
|
f.write_str(" ")?;
|
||||||
|
f.write_str(name)?;
|
||||||
|
f.write_str("\n")?;
|
||||||
|
}
|
||||||
|
f.write_str("\n\n")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,9 +414,9 @@ impl Stack {
|
||||||
Frame::new(func.origin.clone(), func.name.clone())
|
Frame::new(func.origin.clone(), func.name.clone())
|
||||||
};
|
};
|
||||||
self.frames.push(Arc::new(f));
|
self.frames.push(Arc::new(f));
|
||||||
func.to_call.call(self)?;
|
let r = func.to_call.call(self);
|
||||||
self.frames.pop().unwrap();
|
self.frames.pop().unwrap();
|
||||||
Ok(())
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_func(&self, name: String) -> Result<AFunc, Error> {
|
pub fn get_func(&self, name: String) -> Result<AFunc, Error> {
|
||||||
|
@ -558,9 +573,9 @@ pub enum Keyword {
|
||||||
/// <none>
|
/// <none>
|
||||||
///
|
///
|
||||||
/// Dumps stack. Not available as actual keyword, therefore only obtainable through AST
|
/// Dumps stack. Not available as actual keyword, therefore only obtainable through AST
|
||||||
/// manipulation or modding. When using dyn variant, it must be enabled in the main function.
|
/// manipulation, a dyn call, or modding.
|
||||||
/// equivalent to dyn-__dump
|
/// equivalent to dyn-__dump
|
||||||
/// example: func main { int | dyn-__dump-check "Hello, world!" dyn-__dump 0 }
|
/// example: func main { int | "Hello, world!" dyn-__dump pop 0 }
|
||||||
Dump,
|
Dump,
|
||||||
/// def <name>
|
/// def <name>
|
||||||
///
|
///
|
||||||
|
@ -816,7 +831,7 @@ impl PartialEq for Object {
|
||||||
impl PartialOrd for Object {
|
impl PartialOrd for Object {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
if self.kind != other.kind {
|
if self.kind != other.kind {
|
||||||
panic!();
|
return None;
|
||||||
}
|
}
|
||||||
self.native.partial_cmp(&other.native)
|
self.native.partial_cmp(&other.native)
|
||||||
}
|
}
|
||||||
|
@ -903,6 +918,18 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn find_in_splpath(path: &str) -> String {
|
||||||
|
if Path::new(path).exists() {
|
||||||
|
return path.to_owned();
|
||||||
|
}
|
||||||
|
let s = var("SPL_PATH").unwrap_or("/usr/lib/spl".to_owned()) + "/" + path;
|
||||||
|
if Path::new(&s).exists() {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
path.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Words {
|
impl Words {
|
||||||
pub fn exec(&self, stack: &mut Stack) -> OError {
|
pub fn exec(&self, stack: &mut Stack) -> OError {
|
||||||
for word in self.words.clone() {
|
for word in self.words.clone() {
|
||||||
|
@ -927,7 +954,7 @@ impl Words {
|
||||||
stack.set_var(
|
stack.set_var(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
Value::Str(
|
Value::Str(
|
||||||
runtime(move |mut rt| {
|
runtime_mut(move |mut rt| {
|
||||||
rt.make_type(name.clone(), move |mut t| {
|
rt.make_type(name.clone(), move |mut t| {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
t.add_property(field, origin.clone())?;
|
t.add_property(field, origin.clone())?;
|
||||||
|
@ -1113,18 +1140,11 @@ pub struct Error {
|
||||||
|
|
||||||
impl Debug for Error {
|
impl Debug for Error {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
if panicking() {
|
f.write_str("\n\nSPL PANIC DUE TO UNCAUGHT ERROR:\n")?;
|
||||||
f.write_str("\n\nSPL PANIC DUE TO UNCAUGHT ERROR:\n")?;
|
f.write_str(format!("Error: {:?}", self.kind).as_str())?;
|
||||||
f.write_str(format!("Error: {:?}", self.kind).as_str())?;
|
f.write_str("\n")?;
|
||||||
f.write_str("\n")?;
|
f.write_str(self.stack.join("\n").as_str())?;
|
||||||
f.write_str(self.stack.join("\n").as_str())?;
|
f.write_str("\n\n")?;
|
||||||
f.write_str("\n\n")?;
|
Ok(())
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
f.debug_struct("Error")
|
|
||||||
.field("kind", &self.kind)
|
|
||||||
.field("stack", &self.stack)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
env::{args, var, vars},
|
env::{args, vars},
|
||||||
fs,
|
fs,
|
||||||
io::{stdin, stdout, Write},
|
io::{stdin, stdout, Write},
|
||||||
mem, process,
|
mem,
|
||||||
|
process::{self, Stdio},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -190,7 +191,7 @@ pub fn plus(stack: &mut Stack) -> OError {
|
||||||
stack.push(
|
stack.push(
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a + b),
|
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a + b),
|
||||||
x => todo!("{x:?}"),
|
x => stack.err(ErrorKind::InvalidCall("plus".to_owned()))?,
|
||||||
}
|
}
|
||||||
.spl(),
|
.spl(),
|
||||||
);
|
);
|
||||||
|
@ -430,7 +431,7 @@ pub fn callp(stack: &mut Stack) -> OError {
|
||||||
stack.call(&a)?;
|
stack.call(&a)?;
|
||||||
for _ in 0..a.ret_count {
|
for _ in 0..a.ret_count {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
};
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +488,9 @@ pub fn exec(stack: &mut Stack) -> OError {
|
||||||
};
|
};
|
||||||
unsafe {
|
unsafe {
|
||||||
let f = stack.pop_frame(0);
|
let f = stack.pop_frame(0);
|
||||||
|
let f1 = stack.pop_frame(0);
|
||||||
a.to_call.call(stack)?;
|
a.to_call.call(stack)?;
|
||||||
|
stack.push_frame(f1);
|
||||||
stack.push_frame(f);
|
stack.push_frame(f);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -500,7 +503,9 @@ pub fn exec2(stack: &mut Stack) -> OError {
|
||||||
unsafe {
|
unsafe {
|
||||||
let f = stack.pop_frame(0);
|
let f = stack.pop_frame(0);
|
||||||
let f1 = stack.pop_frame(0);
|
let f1 = stack.pop_frame(0);
|
||||||
|
let f2 = stack.pop_frame(0);
|
||||||
a.to_call.call(stack)?;
|
a.to_call.call(stack)?;
|
||||||
|
stack.push_frame(f2);
|
||||||
stack.push_frame(f1);
|
stack.push_frame(f1);
|
||||||
stack.push_frame(f);
|
stack.push_frame(f);
|
||||||
}
|
}
|
||||||
|
@ -555,15 +560,15 @@ pub fn alit_end(stack: &mut Stack) -> OError {
|
||||||
|
|
||||||
pub fn import(stack: &mut Stack) -> OError {
|
pub fn import(stack: &mut Stack) -> OError {
|
||||||
let Value::Str(mut s) = stack.pop().lock_ro().native.clone() else {
|
let Value::Str(mut s) = stack.pop().lock_ro().native.clone() else {
|
||||||
return stack.err(ErrorKind::InvalidCall("include".to_owned()))
|
return stack.err(ErrorKind::InvalidCall("import".to_owned()))
|
||||||
};
|
};
|
||||||
if let Some(x) = s.strip_prefix('#') {
|
if let Some(x) = s.strip_prefix('#') {
|
||||||
s = var("SPL_PATH").unwrap_or("/usr/lib/spl".to_owned()) + "/" + x;
|
s = find_in_splpath(x);
|
||||||
} else if let Some(x) = s.strip_prefix('@') {
|
} else if let Some(x) = s.strip_prefix('@') {
|
||||||
s = x.to_owned();
|
s = x.to_owned();
|
||||||
} else {
|
} else {
|
||||||
s = stack
|
s = stack
|
||||||
.get_frame()
|
.peek_frame(1)
|
||||||
.origin
|
.origin
|
||||||
.file
|
.file
|
||||||
.rsplit_once('/')
|
.rsplit_once('/')
|
||||||
|
@ -600,9 +605,66 @@ pub fn readln(stack: &mut Stack) -> OError {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn command(stack: &mut Stack) -> OError {
|
||||||
|
let binding = stack.pop();
|
||||||
|
let Value::Array(ref a) = binding.lock_ro().native else {
|
||||||
|
return stack.err(ErrorKind::InvalidCall("command".to_owned()))
|
||||||
|
};
|
||||||
|
let mut args = Vec::new();
|
||||||
|
for item in a.into_iter() {
|
||||||
|
if let Value::Str(ref s) = item.lock_ro().native {
|
||||||
|
args.push(s.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if args.len() < 1 {
|
||||||
|
return stack.err(ErrorKind::InvalidCall("command".to_owned()));
|
||||||
|
}
|
||||||
|
process::Command::new(args[0].to_owned())
|
||||||
|
.args(&args[1..])
|
||||||
|
.stdin(Stdio::inherit())
|
||||||
|
.stdout(Stdio::inherit())
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.spawn()
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn command_wait(stack: &mut Stack) -> OError {
|
||||||
|
let binding = stack.pop();
|
||||||
|
let Value::Array(ref a) = binding.lock_ro().native else {
|
||||||
|
return stack.err(ErrorKind::InvalidCall("command".to_owned()))
|
||||||
|
};
|
||||||
|
let mut args = Vec::new();
|
||||||
|
for item in a.into_iter() {
|
||||||
|
if let Value::Str(ref s) = item.lock_ro().native {
|
||||||
|
args.push(s.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if args.len() < 1 {
|
||||||
|
return stack.err(ErrorKind::InvalidCall("command".to_owned()));
|
||||||
|
}
|
||||||
|
stack.push(
|
||||||
|
Value::Int(
|
||||||
|
process::Command::new(args[0].to_owned())
|
||||||
|
.args(&args[1..])
|
||||||
|
.stdin(Stdio::inherit())
|
||||||
|
.stdout(Stdio::inherit())
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.spawn()
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?
|
||||||
|
.wait()
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?
|
||||||
|
.code()
|
||||||
|
.unwrap_or(-1),
|
||||||
|
)
|
||||||
|
.spl(),
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
||||||
type Fn = fn(&mut Stack) -> OError;
|
type Fn = fn(&mut Stack) -> OError;
|
||||||
let fns: [(&str, Fn, u32); 44] = [
|
let fns: [(&str, Fn, u32); 46] = [
|
||||||
("pop", pop, 0),
|
("pop", pop, 0),
|
||||||
("dup", dup, 2),
|
("dup", dup, 2),
|
||||||
("clone", clone, 1),
|
("clone", clone, 1),
|
||||||
|
@ -647,6 +709,8 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
||||||
("alit-end", alit_end, 1),
|
("alit-end", alit_end, 1),
|
||||||
("import", import, 0),
|
("import", import, 0),
|
||||||
("readln", readln, 1),
|
("readln", readln, 1),
|
||||||
|
("command", command, 0),
|
||||||
|
("command-wait", command_wait, 1),
|
||||||
];
|
];
|
||||||
for f in fns {
|
for f in fns {
|
||||||
r.define_func(
|
r.define_func(
|
||||||
|
|
173
src/stream.rs
173
src/stream.rs
|
@ -1,11 +1,20 @@
|
||||||
use std::{collections::HashMap, io::Read, io::Write, mem, sync::Arc};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs::{OpenOptions, File},
|
||||||
|
io::Read,
|
||||||
|
io::Write,
|
||||||
|
mem,
|
||||||
|
net::{TcpStream, Shutdown},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{mutex::Mut, runtime::*, type_err};
|
use crate::{mutex::Mut, runtime::*, type_err, require_on_stack, require_int_on_stack, require_array_on_stack, require_mut_array_on_stack};
|
||||||
|
|
||||||
static STREAM_TYPES: Lazy<Arc<Mut<HashMap<String, StreamType>>>> =
|
static STREAM_TYPES: Lazy<Arc<Mut<HashMap<String, StreamType>>>> =
|
||||||
Lazy::new(|| Arc::new(Mut::new(HashMap::new())));
|
Lazy::new(|| Arc::new(Mut::new(HashMap::new())));
|
||||||
|
static IS_INITIALIZED: Lazy<Arc<Mut<bool>>> = Lazy::new(|| Arc::new(Mut::new(false)));
|
||||||
|
|
||||||
pub fn register_stream_type(
|
pub fn register_stream_type(
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -34,10 +43,11 @@ impl StreamType {
|
||||||
pub struct Stream {
|
pub struct Stream {
|
||||||
reader: Box<dyn Read + 'static>,
|
reader: Box<dyn Read + 'static>,
|
||||||
writer: Box<dyn Write + 'static>,
|
writer: Box<dyn Write + 'static>,
|
||||||
|
close: fn(&mut Self),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream {
|
impl Stream {
|
||||||
pub fn new<T: Read + Write + 'static>(main: T) -> Self {
|
pub fn new<T: Read + Write + 'static>(main: T, close: fn(&mut Self)) -> Self {
|
||||||
let mut rw = Box::new(main);
|
let mut rw = Box::new(main);
|
||||||
Self {
|
Self {
|
||||||
// SAFETY: Because these are both in private fields on one object, they can not be
|
// SAFETY: Because these are both in private fields on one object, they can not be
|
||||||
|
@ -45,12 +55,14 @@ impl Stream {
|
||||||
// by the borrow checker on the Stream.
|
// by the borrow checker on the Stream.
|
||||||
reader: Box::new(unsafe { mem::transmute::<&mut _, &mut T>(rw.as_mut()) }),
|
reader: Box::new(unsafe { mem::transmute::<&mut _, &mut T>(rw.as_mut()) }),
|
||||||
writer: rw,
|
writer: rw,
|
||||||
|
close,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new_split(reader: impl Read + 'static, writer: impl Write + 'static) -> Self {
|
pub fn new_split(reader: impl Read + 'static, writer: impl Write + 'static, close: fn(&mut Self)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reader: Box::new(reader),
|
reader: Box::new(reader),
|
||||||
writer: Box::new(writer),
|
writer: Box::new(writer),
|
||||||
|
close,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,30 +123,24 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_stream(stack: &mut Stack) -> OError {
|
pub fn new_stream(stack: &mut Stack) -> OError {
|
||||||
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
|
require_on_stack!(s, Str, stack, "write-stream");
|
||||||
return stack.err(ErrorKind::InvalidCall("new-stream".to_owned()))
|
let stream = get_stream_type(s.clone())
|
||||||
};
|
.ok_or_else(|| {
|
||||||
let stream = runtime(|mut rt| {
|
stack.error(ErrorKind::VariableNotFound(format!("__stream-type-{s}")))
|
||||||
|
})?
|
||||||
|
.make_stream(stack)?;
|
||||||
|
let stream = runtime_mut(move |mut rt| {
|
||||||
Ok(rt.register_stream(
|
Ok(rt.register_stream(
|
||||||
get_stream_type(s.clone())
|
stream
|
||||||
.ok_or_else(|| {
|
|
||||||
stack.error(ErrorKind::VariableNotFound(format!("__stream-type-{s}")))
|
|
||||||
})?
|
|
||||||
.make_stream(stack)?,
|
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
stack.push(Value::Mega(stream.0 as i128).spl());
|
stack.push(Value::Mega(stream.0 as i128).spl());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_to_stream(stack: &mut Stack) -> OError {
|
pub fn write_stream(stack: &mut Stack) -> OError {
|
||||||
let binding = stack.pop();
|
require_on_stack!(id, Mega, stack, "write-stream");
|
||||||
let Value::Array(ref a) = binding.lock_ro().native else {
|
require_array_on_stack!(a, stack, "write-stream");
|
||||||
return stack.err(ErrorKind::InvalidCall("write-to-stream".to_owned()))
|
|
||||||
};
|
|
||||||
let Value::Mega(id) = stack.pop().lock_ro().native.clone() else {
|
|
||||||
return stack.err(ErrorKind::InvalidCall("write-to-stream".to_owned()))
|
|
||||||
};
|
|
||||||
let stream = runtime(|rt| {
|
let stream = runtime(|rt| {
|
||||||
rt.get_stream(id as u128)
|
rt.get_stream(id as u128)
|
||||||
.ok_or_else(|| stack.error(ErrorKind::VariableNotFound(format!("__stream-{id}"))))
|
.ok_or_else(|| stack.error(ErrorKind::VariableNotFound(format!("__stream-{id}"))))
|
||||||
|
@ -158,9 +164,132 @@ pub fn write_to_stream(stack: &mut Stack) -> OError {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_all_stream(stack: &mut Stack) -> OError {
|
||||||
|
require_on_stack!(id, Mega, stack, "write-all-stream");
|
||||||
|
require_array_on_stack!(a, stack, "write-all-stream");
|
||||||
|
let stream = runtime(|rt| {
|
||||||
|
rt.get_stream(id as u128)
|
||||||
|
.ok_or_else(|| stack.error(ErrorKind::VariableNotFound(format!("__stream-{id}"))))
|
||||||
|
})?;
|
||||||
|
let mut fixed = Vec::with_capacity(a.len());
|
||||||
|
for item in a.iter() {
|
||||||
|
match item.lock_ro().native {
|
||||||
|
Value::Int(x) => fixed.push(x as u8),
|
||||||
|
_ => type_err!(stack, "!int", "int"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream
|
||||||
|
.lock()
|
||||||
|
.write_all(&fixed[..])
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(format!("{x:?}"))))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_stream(stack: &mut Stack) -> OError {
|
||||||
|
require_on_stack!(id, Mega, stack, "read-stream");
|
||||||
|
require_mut_array_on_stack!(a, stack, "read-stream");
|
||||||
|
let stream = runtime(|rt| {
|
||||||
|
rt.get_stream(id as u128)
|
||||||
|
.ok_or_else(|| stack.error(ErrorKind::VariableNotFound(format!("__stream-{id}"))))
|
||||||
|
})?;
|
||||||
|
let mut vec = vec![0; a.len()];
|
||||||
|
stack.push(
|
||||||
|
Value::Mega(
|
||||||
|
stream
|
||||||
|
.lock()
|
||||||
|
.read(&mut vec[..])
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(format!("{x:?}"))))? as i128,
|
||||||
|
)
|
||||||
|
.spl(),
|
||||||
|
);
|
||||||
|
a.clone_from_slice(
|
||||||
|
&vec.into_iter()
|
||||||
|
.map(|x| Value::Int(x as i32).spl())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_all_stream(stack: &mut Stack) -> OError {
|
||||||
|
require_on_stack!(id, Mega, stack, "read-all-stream");
|
||||||
|
require_mut_array_on_stack!(a, stack, "read-all-stream");
|
||||||
|
let stream = runtime(|rt| {
|
||||||
|
rt.get_stream(id as u128)
|
||||||
|
.ok_or_else(|| stack.error(ErrorKind::VariableNotFound(format!("__stream-{id}"))))
|
||||||
|
})?;
|
||||||
|
let mut vec = vec![0; a.len()];
|
||||||
|
stream
|
||||||
|
.lock()
|
||||||
|
.read_exact(&mut vec[..])
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(format!("{x:?}"))))?;
|
||||||
|
a.clone_from_slice(
|
||||||
|
&vec.into_iter()
|
||||||
|
.map(|x| Value::Int(x as i32).spl())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_stream(stack: &mut Stack) -> OError {
|
||||||
|
require_on_stack!(id, Mega, stack, "close-stream");
|
||||||
|
if let Some(stream) = runtime(|rt| {
|
||||||
|
rt.get_stream(id as u128)
|
||||||
|
}) {
|
||||||
|
let mut stream = stream.lock();
|
||||||
|
(stream.close)(&mut stream);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nop(_stream: &mut Stream) {}
|
||||||
|
|
||||||
|
fn stream_file(stack: &mut Stack) -> Result<Stream, Error> {
|
||||||
|
let truncate = stack.pop().lock_ro().is_truthy();
|
||||||
|
require_on_stack!(path, Str, stack, "FILE new-stream");
|
||||||
|
Ok(Stream::new(
|
||||||
|
OpenOptions::new()
|
||||||
|
.read(!truncate)
|
||||||
|
.write(true)
|
||||||
|
.create(truncate)
|
||||||
|
.truncate(truncate)
|
||||||
|
.open(path)
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?,
|
||||||
|
nop
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stream_tcp(stack: &mut Stack) -> Result<Stream, Error> {
|
||||||
|
require_int_on_stack!(port, stack, "TCP new-stream");
|
||||||
|
require_on_stack!(ip, Str, stack, "TCP new-stream");
|
||||||
|
fn close_tcp(stream: &mut Stream) {
|
||||||
|
unsafe {
|
||||||
|
let f = ((stream.reader.as_mut() as *mut dyn Read).cast() as *mut TcpStream).as_mut().unwrap();
|
||||||
|
let _ = f.shutdown(Shutdown::Both);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Stream::new(
|
||||||
|
TcpStream::connect((ip, port as u16))
|
||||||
|
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?,
|
||||||
|
close_tcp
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
||||||
|
if !*IS_INITIALIZED.lock_ro() {
|
||||||
|
register_stream_type("file", stream_file);
|
||||||
|
register_stream_type("tcp", stream_tcp);
|
||||||
|
*IS_INITIALIZED.lock() = true;
|
||||||
|
}
|
||||||
|
|
||||||
type Fn = fn(&mut Stack) -> OError;
|
type Fn = fn(&mut Stack) -> OError;
|
||||||
let fns: [(&str, Fn, u32); 1] = [("new-stream", new_stream, 1)];
|
let fns: [(&str, Fn, u32); 6] = [
|
||||||
|
("new-stream", new_stream, 1),
|
||||||
|
("write-stream", write_stream, 1),
|
||||||
|
("write-all-stream", write_all_stream, 0),
|
||||||
|
("read-stream", read_stream, 1),
|
||||||
|
("read-all-stream", read_all_stream, 0),
|
||||||
|
("close-stream", close_stream, 0),
|
||||||
|
];
|
||||||
for f in fns {
|
for f in fns {
|
||||||
r.define_func(
|
r.define_func(
|
||||||
f.0.to_owned(),
|
f.0.to_owned(),
|
||||||
|
|
172
std.spl
172
std.spl
|
@ -12,11 +12,6 @@ func println { |
|
||||||
null clone type settype "construct" dyn-objcall
|
null clone type settype "construct" dyn-objcall
|
||||||
} "new" "str" dyn-def-method
|
} "new" "str" dyn-def-method
|
||||||
|
|
||||||
{ | with callable this ;
|
|
||||||
def i 0 =i
|
|
||||||
while { i this:len lt } { i this:get callable call i ++ =i }
|
|
||||||
} "foreach" "array" dyn-def-method
|
|
||||||
|
|
||||||
construct _mega-ext {
|
construct _mega-ext {
|
||||||
;
|
;
|
||||||
swap { .. | with this ;
|
swap { .. | with this ;
|
||||||
|
@ -24,7 +19,12 @@ construct _mega-ext {
|
||||||
i -- mswap
|
i -- mswap
|
||||||
}
|
}
|
||||||
mswap { .. | mswap }
|
mswap { .. | mswap }
|
||||||
|
foreach { | with this ;
|
||||||
|
def i 0 =i
|
||||||
|
while { i this lt } { i callable call i ++ =i }
|
||||||
|
}
|
||||||
} include _mega-ext in mega
|
} include _mega-ext in mega
|
||||||
|
|
||||||
construct _array-ext {
|
construct _array-ext {
|
||||||
;
|
;
|
||||||
get { any | array-get }
|
get { any | array-get }
|
||||||
|
@ -51,138 +51,24 @@ construct _array-ext {
|
||||||
def i 0 =i
|
def i 0 =i
|
||||||
while { i this:len lt } { i this:get callable call i ++ =i }
|
while { i this:len lt } { i this:get callable call i ++ =i }
|
||||||
}
|
}
|
||||||
|
0 { any | with this ;
|
||||||
|
0 this:get
|
||||||
|
}
|
||||||
|
1 { any | with this ;
|
||||||
|
1 this:get
|
||||||
|
}
|
||||||
|
2 { any | with this ;
|
||||||
|
2 this:get
|
||||||
|
}
|
||||||
|
3 { any | with this ;
|
||||||
|
3 this:get
|
||||||
|
}
|
||||||
|
4 { any | with this ;
|
||||||
|
4 this:get
|
||||||
|
}
|
||||||
} include _array-ext in array
|
} include _array-ext in array
|
||||||
|
|
||||||
construct _Iter {
|
"iter.spl" import
|
||||||
;
|
|
||||||
foreach { | with callable this ;
|
|
||||||
def itm
|
|
||||||
while { this:next dup =itm null eq not } {
|
|
||||||
itm callable call
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collect { array | with this ;
|
|
||||||
[ { any | } this:foreach ]
|
|
||||||
}
|
|
||||||
map { MapIter | with map-function this ;
|
|
||||||
map-function this MapIter:new
|
|
||||||
}
|
|
||||||
reduce { ReduceIter | with reduce-function this ;
|
|
||||||
reduce-function this ReduceIter:new
|
|
||||||
}
|
|
||||||
fold { FoldIter | with accumulator fold-function this ;
|
|
||||||
accumulator fold-function this FoldIter:new
|
|
||||||
}
|
|
||||||
sum { mega | with this ;
|
|
||||||
{ mega | with accum item ;
|
|
||||||
accum item +
|
|
||||||
} this:reduce:calculate
|
|
||||||
}
|
|
||||||
product { mega | with this ;
|
|
||||||
{ mega | with accum item ;
|
|
||||||
accum item *
|
|
||||||
} this:reduce:calculate
|
|
||||||
}
|
|
||||||
filter { FilterIter | with filter this ;
|
|
||||||
filter this FilterIter:new
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
construct MapIter {
|
|
||||||
origin
|
|
||||||
map-function
|
|
||||||
;
|
|
||||||
construct { this | with map-function origin this ;
|
|
||||||
origin this:=origin
|
|
||||||
map-function this:=map-function
|
|
||||||
this
|
|
||||||
}
|
|
||||||
next { any | with this ;
|
|
||||||
this:origin:next dup null eq if {
|
|
||||||
2 stop
|
|
||||||
}
|
|
||||||
this:map-function call
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
include _Iter in MapIter
|
|
||||||
|
|
||||||
construct ReduceIter {
|
|
||||||
origin
|
|
||||||
accumulator
|
|
||||||
reduce-function
|
|
||||||
;
|
|
||||||
construct { this | with reduce-function origin this ;
|
|
||||||
origin this:=origin
|
|
||||||
reduce-function this:=reduce-function
|
|
||||||
this
|
|
||||||
}
|
|
||||||
next { any | with this ;
|
|
||||||
def itm
|
|
||||||
this:origin:next dup null eq if {
|
|
||||||
2 stop
|
|
||||||
} =itm
|
|
||||||
this:accumulator null eq if {
|
|
||||||
itm dup this:=accumulator
|
|
||||||
2 stop
|
|
||||||
}
|
|
||||||
this:accumulator itm this:reduce-function call dup this:=accumulator
|
|
||||||
}
|
|
||||||
calculate { any | with this ;
|
|
||||||
{ | pop } this:foreach
|
|
||||||
this:accumulator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
include _Iter in ReduceIter
|
|
||||||
|
|
||||||
construct FoldIter {
|
|
||||||
origin
|
|
||||||
accumulator
|
|
||||||
reduce-function
|
|
||||||
;
|
|
||||||
construct { this | with accumulator fold-function origin this ;
|
|
||||||
accumulator this:=accumulator
|
|
||||||
origin this:=origin
|
|
||||||
fold-function this:=fold-function
|
|
||||||
this
|
|
||||||
}
|
|
||||||
next { any | with this ;
|
|
||||||
def itm
|
|
||||||
this:origin:next dup null eq if {
|
|
||||||
2 stop
|
|
||||||
} =itm
|
|
||||||
this:accumulator itm this:fold-function call dup this:=accumulator
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
include _Iter in FoldIter
|
|
||||||
|
|
||||||
construct FilterIter {
|
|
||||||
origin
|
|
||||||
filter
|
|
||||||
;
|
|
||||||
construct { this | with filter origin this ;
|
|
||||||
origin this:=origin
|
|
||||||
filter this:=filter
|
|
||||||
this
|
|
||||||
}
|
|
||||||
next { any | with this ;
|
|
||||||
while { 1 } {
|
|
||||||
def next this:origin:next =next
|
|
||||||
next null eq if {
|
|
||||||
null
|
|
||||||
3 stop
|
|
||||||
}
|
|
||||||
next this:filter call if {
|
|
||||||
next 3 stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dyn-__dump
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
include _Iter in FilterIter
|
|
||||||
|
|
||||||
construct List {
|
construct List {
|
||||||
array
|
array
|
||||||
|
@ -215,11 +101,17 @@ construct _ShrinkingArray {
|
||||||
0 this:remove
|
0 this:remove
|
||||||
}
|
}
|
||||||
pop { any | with this ;
|
pop { any | with this ;
|
||||||
|
this:array:len not if {
|
||||||
|
null 2 stop
|
||||||
|
}
|
||||||
def item
|
def item
|
||||||
[ this:array:to-stack =item ] this:=array
|
[ this:array:to-stack =item ] this:=array
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
remove { any | with index this ;
|
remove { any | with index this ;
|
||||||
|
this:array:len not if {
|
||||||
|
null 2 stop
|
||||||
|
}
|
||||||
def item
|
def item
|
||||||
this:array:len index - =index
|
this:array:len index - =index
|
||||||
[ this:array:to-stack index:mswap =item (index --):mswap ] this:=array
|
[ this:array:to-stack index:mswap =item (index --):mswap ] this:=array
|
||||||
|
@ -325,6 +217,7 @@ construct Range {
|
||||||
itm
|
itm
|
||||||
2 stop
|
2 stop
|
||||||
} not if {
|
} not if {
|
||||||
|
null
|
||||||
2 stop
|
2 stop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,6 +340,12 @@ func -- { mega |
|
||||||
|
|
||||||
func _ { | }
|
func _ { | }
|
||||||
|
|
||||||
|
func call-main-on-file { | with file ;
|
||||||
|
"@" file concat import
|
||||||
|
update-types
|
||||||
|
argv main exit
|
||||||
|
}
|
||||||
|
|
||||||
func update-types { |
|
func update-types { |
|
||||||
{ | with type ;
|
{ | with type ;
|
||||||
{ self | } "unwrap" type dyn-def-method
|
{ self | } "unwrap" type dyn-def-method
|
||||||
|
@ -461,6 +360,3 @@ func update-types { |
|
||||||
}
|
}
|
||||||
update-types
|
update-types
|
||||||
|
|
||||||
1 argv:sget:unwrap import
|
|
||||||
update-types
|
|
||||||
argv main exit
|
|
||||||
|
|
78
stream.spl
Normal file
78
stream.spl
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
"The SPL stream is an IO construct used to read and write to ";
|
||||||
|
"some external thing, for example a file or a TCP socket.";
|
||||||
|
|
||||||
|
"All functions here are encapsulations of their native counterparts.";
|
||||||
|
|
||||||
|
"Examples:";
|
||||||
|
"def tcp 'localhost' 8080 StreamType:tcp:create =tcp";
|
||||||
|
"def file 'test.txt' 1 StreamType:file:create =file 'hi':to-bytes file:write-exact; file:close null =file";
|
||||||
|
|
||||||
|
construct Stream {
|
||||||
|
id
|
||||||
|
;
|
||||||
|
construct { this | with type this ;
|
||||||
|
type new-stream this:=id
|
||||||
|
this
|
||||||
|
}
|
||||||
|
read-one { mega | with this ;
|
||||||
|
def buf 1 anew =buf
|
||||||
|
while { buf this:id read-stream not } { }
|
||||||
|
0 buf:get _mega
|
||||||
|
}
|
||||||
|
"the buffer is written to in-place.";
|
||||||
|
read { mega [int] | with buf this ;
|
||||||
|
buf gettype "int" eq if { buf anew =buf }
|
||||||
|
buf this:id read-stream buf
|
||||||
|
}
|
||||||
|
"the buffer is written to in-place.";
|
||||||
|
read-exact { [int] | with buf this ;
|
||||||
|
buf gettype "int" eq if { buf anew =buf }
|
||||||
|
buf this:id read-all-stream buf
|
||||||
|
}
|
||||||
|
write { mega | with buf this ;
|
||||||
|
buf this:id write-stream
|
||||||
|
}
|
||||||
|
write-exact { | with buf this ;
|
||||||
|
buf this:id write-all-stream
|
||||||
|
}
|
||||||
|
close { | with this ;
|
||||||
|
this:id close-stream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
construct StreamType {
|
||||||
|
id
|
||||||
|
;
|
||||||
|
construct { this | with id this ;
|
||||||
|
id this:=id
|
||||||
|
this
|
||||||
|
}
|
||||||
|
create { Stream | with this ;
|
||||||
|
this:id Stream:new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def stream-types 0 anew =stream-types
|
||||||
|
|
||||||
|
construct _StreamType {
|
||||||
|
;
|
||||||
|
construct { this | with this ;
|
||||||
|
{ | with type ;
|
||||||
|
"type StreamType:new this:=<type>";
|
||||||
|
(type StreamType:new) (this ("=" type concat)) dyn-objcall
|
||||||
|
} stream-types:foreach
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func register-stream-type { | with id ;
|
||||||
|
[ stream-types:to-stack id ] =stream-types
|
||||||
|
id _StreamType dyn-def-field
|
||||||
|
}
|
||||||
|
|
||||||
|
"tcp" register-stream-type
|
||||||
|
"file" register-stream-type
|
||||||
|
|
||||||
|
func StreamTypes { _StreamType |
|
||||||
|
_StreamType:new
|
||||||
|
}
|
10
test.spl
10
test.spl
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
"stream.spl" import
|
||||||
|
|
||||||
func main { int | with args ;
|
func main { int | with args ;
|
||||||
def thing
|
def thing
|
||||||
|
|
||||||
|
@ -97,6 +99,14 @@ func main { int | with args ;
|
||||||
argv:iter
|
argv:iter
|
||||||
{ str | " " concat } swap:map
|
{ str | " " concat } swap:map
|
||||||
&print swap:foreach
|
&print swap:foreach
|
||||||
|
|
||||||
|
"" println
|
||||||
|
"testing stream" println
|
||||||
|
|
||||||
|
def file "test.txt" 1 StreamTypes:file:create =file
|
||||||
|
"hi" _array file:write-exact;
|
||||||
|
file:close null =file
|
||||||
|
|
||||||
"" println
|
"" println
|
||||||
|
|
||||||
100
|
100
|
||||||
|
|
1
test.txt
Normal file
1
test.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hi
|
Loading…
Add table
Reference in a new issue