bug fixes, improve speed, add basic http support, other minor improvements

This commit is contained in:
Daniella / Tove 2023-03-06 03:45:16 +01:00
parent 25a30a5be6
commit e093c11558
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
11 changed files with 403 additions and 112 deletions

77
http.spl Normal file
View file

@ -0,0 +1,77 @@
"stream.spl" import
construct http namespace {
Request
Response
}
construct http:Request {
host port
method path
headers
body
;
construct { this | with host port method path this ;
host this:=host
port this:=port
method this:=method
path this:=path
List:new this:=headers
"" this:=body
this
}
add-header { this | with header this ;
header this:headers:push
this
}
set-body { this | with body this ;
body this:=body
this
}
send { http:Response | with this ;
def stream this:host this:port StreamTypes:tcp:create =stream
def response http:Response:new =response
this:method:to-bytes stream:write-exact;
" " _:to-bytes stream:write-exact;
this:path:to-bytes stream:write-exact;
" HTTP/1.0\r\n" _:to-bytes stream:write-exact;
"Host: " _:to-bytes stream:write-exact;
this:host:to-bytes stream:write-exact;
"\r\nConnection: Close\r\nUser-Agent: http.spl v0.1 2023-03 (spl@mail.tudbut.de)\r\n"
_:to-bytes stream:write-exact;
{ | with header ;
header:to-bytes stream:write-exact;
"\r\n" stream:write-exact;
} this:headers:foreach
"Content-Length: " _:to-bytes stream:write-exact;
def body this:body:to-bytes =body
body:len _str:to-bytes stream:write-exact;
"\r\n\r\n" _:to-bytes stream:write-exact;
body stream:write-exact;
stream:flush;
1024 stream:read-to-end:to-str println
stream:close;
"todo" panic
}
}
construct http:Response {
state-num state-msg
headers
body
;
construct { this | with this ;
List:new this:=headers
"" this:=body
this
}
}

View file

@ -101,7 +101,7 @@ construct ReduceIter {
} =itm } =itm
this:accumulator null eq if { this:accumulator null eq if {
itm dup this:=accumulator itm dup this:=accumulator
null 2 stop 2 stop
} }
this:accumulator itm this:reduce-function call dup this:=accumulator this:accumulator itm this:reduce-function call dup this:=accumulator
} }
@ -165,7 +165,7 @@ construct ChainIter {
next-iters next-iters
; ;
construct { this | with other origin this ; construct { this | with other origin this ;
[ other ] List:new this:=next-iters [ other ] List:new:from this:=next-iters
origin this:=current origin this:=current
this this
} }

View file

@ -6,7 +6,7 @@ endif
syn match Comment /".*?";/ syn match Comment /".*?";/
syn match Number /\<[0-9._]*\>/ syn match Number /\<[0-9._]*\>/
syn match Function /\<func[ \n]\+[^ ]\+[ \n]\+{ .*[ ]*|\|{ .*[ ]*|\|{\|}/ syn match Function /\<func[ \n]\+[^ ]\+[ \n]\+{ .*[ ]*|\|{ .*[ ]*|\|{\|}/
syn keyword Keyword while if exit eq lt gt neg or and not + - * ++ -- % / with syn keyword Keyword while if exit eq lt gt neg or and not + - * ++ -- % / with namespace
syn match Keyword /;/ syn match Keyword /;/
syn keyword Type pop dup swap syn keyword Type pop dup swap
syn match Type /=[a-zA-Z0-9_\-]\+\|\<_[a-zA-Z0-9_\-]\+\>/ syn match Type /=[a-zA-Z0-9_\-]\+\|\<_[a-zA-Z0-9_\-]\+\>/

View file

@ -39,7 +39,28 @@ pub fn dyn_construct(stack: &mut Stack) -> OError {
return stack.err(ErrorKind::InvalidCall("dyn-construct".to_owned())) return stack.err(ErrorKind::InvalidCall("dyn-construct".to_owned()))
}; };
Words { Words {
words: vec![Word::Key(Keyword::Construct(s, Vec::new(), Vec::new()))], words: vec![Word::Key(Keyword::Construct(
s,
Vec::new(),
Vec::new(),
false,
))],
}
.exec(stack)?;
Ok(())
}
pub fn dyn_namespace(stack: &mut Stack) -> OError {
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
return stack.err(ErrorKind::InvalidCall("dyn-construct".to_owned()))
};
Words {
words: vec![Word::Key(Keyword::Construct(
s,
Vec::new(),
Vec::new(),
true,
))],
} }
.exec(stack)?; .exec(stack)?;
Ok(()) Ok(())
@ -245,11 +266,12 @@ pub(crate) fn wrap(f: fn(&mut Stack) -> OError) -> impl Fn(&mut Stack) -> OError
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); 15] = [
("dyn-__dump", dyn_dump, 0), ("dyn-__dump", dyn_dump, 0),
("dyn-def", dyn_def, 0), ("dyn-def", dyn_def, 0),
("dyn-func", dyn_func, 0), ("dyn-func", dyn_func, 0),
("dyn-construct", dyn_construct, 0), ("dyn-construct", dyn_construct, 0),
("dyn-namespace", dyn_namespace, 0),
("dyn-def-field", dyn_def_field, 0), ("dyn-def-field", dyn_def_field, 0),
("dyn-def-method", dyn_def_method, 0), ("dyn-def-method", dyn_def_method, 0),
("dyn-include", dyn_include, 0), ("dyn-include", dyn_include, 0),

View file

@ -64,6 +64,12 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
} }
"construct" => { "construct" => {
let name = str_words[i + 1].to_owned(); let name = str_words[i + 1].to_owned();
let is_namespace = if str_words[i + 2] == "namespace" {
i += 1;
true
} else {
false
};
if str_words[i + 2] != "{" { if str_words[i + 2] != "{" {
return Err(LexerError::InvalidConstructBlock); return Err(LexerError::InvalidConstructBlock);
} }
@ -91,10 +97,15 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
i += 1; i += 1;
} }
} }
if !has_construct { if !has_construct && !is_namespace {
methods.push(("construct".to_string(), (1, Words { words: vec![] }))); methods.push(("construct".to_string(), (1, Words { words: vec![] })));
} }
words.push(Word::Key(Keyword::Construct(name, fields, methods))); words.push(Word::Key(Keyword::Construct(
name,
fields,
methods,
is_namespace,
)));
} }
"include" => { "include" => {
if let Some(x) = readf( if let Some(x) = readf(

View file

@ -360,6 +360,7 @@ impl Frame {
pub struct Stack { pub struct Stack {
frames: Vec<Arc<Frame>>, frames: Vec<Arc<Frame>>,
object_stack: Vec<AMObject>, object_stack: Vec<AMObject>,
files: Vec<String>,
pub return_accumultor: u32, pub return_accumultor: u32,
} }
@ -394,6 +395,7 @@ impl Stack {
let mut r = Stack { let mut r = Stack {
frames: vec![o.clone()], frames: vec![o.clone()],
object_stack: Vec::new(), object_stack: Vec::new(),
files: Vec::new(),
return_accumultor: 0, return_accumultor: 0,
}; };
@ -409,6 +411,7 @@ impl Stack {
let mut r = Stack { let mut r = Stack {
frames: vec![o.clone()], frames: vec![o.clone()],
object_stack: Vec::new(), object_stack: Vec::new(),
files: Vec::new(),
return_accumultor: 0, return_accumultor: 0,
}; };
@ -591,6 +594,15 @@ impl Stack {
pub unsafe fn push_frame(&mut self, frame: Arc<Frame>) { pub unsafe fn push_frame(&mut self, frame: Arc<Frame>) {
self.frames.push(frame); self.frames.push(frame);
} }
pub(crate) fn include_file(&mut self, s: &String) -> bool {
if self.files.contains(s) {
false
} else {
self.files.push(s.to_owned());
true
}
}
} }
/// An SPL keyword. Used to deviate from normal linear code structure. /// An SPL keyword. Used to deviate from normal linear code structure.
@ -621,7 +633,7 @@ pub enum Keyword {
/// equivalent to /// equivalent to
/// "<name>" dyn-construct; "<field>" "<name>" dyn-def-field { <rem> | <words> } "<fn-name>" /// "<name>" dyn-construct; "<field>" "<name>" dyn-def-field { <rem> | <words> } "<fn-name>"
/// "<name>" dyn-def-method /// "<name>" dyn-def-method
Construct(String, Vec<String>, Vec<(String, (u32, Words))>), Construct(String, Vec<String>, Vec<(String, (u32, Words))>, bool),
/// include <typeA> in <typeB> /// include <typeA> in <typeB>
/// ///
/// Adds <typeA> as a parent type of <typeB>. /// Adds <typeA> as a parent type of <typeB>.
@ -949,6 +961,19 @@ impl Object {
Value::Str(x) => !x.is_empty(), Value::Str(x) => !x.is_empty(),
} }
} }
pub fn field(&self, name: &str, stack: &mut Stack) -> Result<AMObject, Error> {
Ok(self
.property_map
.get(name)
.ok_or_else(|| {
stack.error(ErrorKind::PropertyNotFound(
self.kind.lock_ro().name.to_owned(),
name.to_owned(),
))
})?
.clone())
}
} }
impl From<Value> for Object { impl From<Value> for Object {
@ -1025,38 +1050,55 @@ impl Words {
name, name,
}), }),
), ),
Keyword::Construct(name, fields, methods) => { Keyword::Construct(name, fields, methods, is_namespace) => {
let origin = stack.get_frame(); let origin = stack.get_frame();
stack.define_var(name.clone()); if !name.contains(':') {
stack.set_var( stack.define_var(name.clone());
name.clone(), }
Value::Str( let t = runtime_mut(|mut rt| {
runtime_mut(move |mut rt| { rt.make_type(name.clone(), |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())?; }
} t.functions.extend(methods.into_iter().map(|(k, v)| {
t.functions.extend(methods.into_iter().map(|(k, v)| { (
( k.clone(),
k.clone(), Arc::new(Func {
Arc::new(Func { ret_count: v.0,
ret_count: v.0, to_call: FuncImpl::SPL(v.1),
to_call: FuncImpl::SPL(v.1), origin: origin.clone(),
origin: origin.clone(), run_as_base: false,
run_as_base: false, fname: None,
fname: None, name: name.clone() + ":" + &k,
name: name.clone() + ":" + &k, }),
}), )
) }));
})); Ok(t)
Ok(t) })
}) })?;
})?
.lock_ro() let to_set: Object = if is_namespace {
.get_name(), let mut obj: Object = Value::Null.into();
) obj.kind = t.clone();
.spl(), t.lock_ro().write_into(&mut obj);
)?; obj
} else {
Value::Str(t.lock_ro().get_name()).into()
};
if name.contains(':') {
let Some((a, mut name)) = name.split_once(':') else { unreachable!() };
let mut f = stack.get_var(a.to_owned())?;
while let Some((a, b)) = name.split_once(':') {
name = b;
let o = f.lock_ro();
let nf = o.field(a, stack)?;
mem::drop(o);
f = nf;
}
*f.lock_ro().field(name, stack)?.lock() = to_set;
} else {
stack.set_var(name.clone(), to_set.spl())?;
}
} }
Keyword::Include(ta, tb) => { Keyword::Include(ta, tb) => {
let rstack = &stack; let rstack = &stack;

View file

@ -4,11 +4,17 @@ use std::{
fs, fs,
io::{stdin, stdout, Write}, io::{stdin, stdout, Write},
mem, mem,
ops::{Add, Div, Mul, Rem, Sub},
process::{self, Stdio}, process::{self, Stdio},
sync::Arc, sync::Arc,
}; };
use crate::{dyn_fns, mutex::Mut, runtime::*, *}; use crate::{
dyn_fns,
mutex::Mut,
runtime::*,
*,
};
#[macro_export] #[macro_export]
macro_rules! type_err { macro_rules! type_err {
@ -185,14 +191,30 @@ pub fn or(stack: &mut Stack) -> OError {
Ok(()) Ok(())
} }
macro_rules! impl_op {
($a:expr, $b:expr, $op:tt, $err:expr, $($kind:tt,)*) => {
match ($a, $b) {
$(
(Value::$kind(a), Value::$kind(b)) => Value::$kind(a.$op(b)),
)*
_ => $err?,
}
};
}
pub fn plus(stack: &mut Stack) -> OError { pub fn plus(stack: &mut Stack) -> OError {
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { impl_op!(
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a + b), a,
_x => stack.err(ErrorKind::InvalidCall("plus".to_owned()))?, b,
} add,
stack.err(ErrorKind::InvalidCall("plus".to_owned())),
Mega,
Long,
Int,
)
.spl(), .spl(),
); );
Ok(()) Ok(())
@ -202,10 +224,15 @@ pub fn minus(stack: &mut Stack) -> OError {
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { impl_op!(
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a - b), a,
_ => todo!(), b,
} sub,
stack.err(ErrorKind::InvalidCall("minus".to_owned())),
Mega,
Long,
Int,
)
.spl(), .spl(),
); );
Ok(()) Ok(())
@ -215,10 +242,15 @@ pub fn slash(stack: &mut Stack) -> OError {
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { impl_op!(
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a / b), a,
_ => todo!(), b,
} div,
stack.err(ErrorKind::InvalidCall("slash".to_owned())),
Mega,
Long,
Int,
)
.spl(), .spl(),
); );
Ok(()) Ok(())
@ -228,10 +260,15 @@ pub fn star(stack: &mut Stack) -> OError {
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { impl_op!(
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a * b), a,
_ => todo!(), b,
} mul,
stack.err(ErrorKind::InvalidCall("star".to_owned())),
Mega,
Long,
Int,
)
.spl(), .spl(),
); );
Ok(()) Ok(())
@ -241,10 +278,15 @@ pub fn percent(stack: &mut Stack) -> OError {
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { impl_op!(
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a % b), a,
_ => todo!(), b,
} rem,
stack.err(ErrorKind::InvalidCall("star".to_owned())),
Mega,
Long,
Int,
)
.spl(), .spl(),
); );
Ok(()) Ok(())
@ -589,18 +631,26 @@ pub fn import(stack: &mut Stack) -> OError {
+ "/" + "/"
+ &s; + &s;
} }
stack.push(Value::Str(s).spl()); if stack.include_file(
dup(stack)?; &(*fs::canonicalize(s.clone())
read_file(stack).or_else(|x| { .map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?
if let Some(fallback) = fallback { .as_os_str()
stack.push(Value::Str(fallback.to_owned()).spl()); .to_string_lossy())
Ok(()) .to_owned(),
} else { ) {
Err(x) stack.push(Value::Str(s).spl());
} dup(stack)?;
})?; read_file(stack).or_else(|x| {
dyn_fns::wrap(dyn_fns::dyn_readf)(stack)?; if let Some(fallback) = fallback {
call(stack)?; stack.push(Value::Str(fallback.to_owned()).spl());
Ok(())
} else {
Err(x)
}
})?;
dyn_fns::wrap(dyn_fns::dyn_readf)(stack)?;
call(stack)?;
}
Ok(()) Ok(())
} }
@ -710,9 +760,33 @@ pub fn bytes_to_str(stack: &mut Stack) -> OError {
Ok(()) Ok(())
} }
pub fn acopy(stack: &mut Stack) -> OError {
require_on_stack!(len, Mega, stack, "acopy");
require_on_stack!(idx_dest, Mega, stack, "acopy");
require_on_stack!(idx_src, Mega, stack, "acopy");
let dest_array = stack.pop();
{
require_mut_array!(dest, dest_array, stack, "acopy");
require_array_on_stack!(src, stack, "acopy");
let offset = idx_dest - idx_src;
if (src.len() as i128) < idx_src + len
|| idx_src < 0
|| (dest.len() as i128) < idx_dest + len
|| idx_dest < 0
{
stack.err(ErrorKind::InvalidCall("acopy".to_owned()))?;
}
for i in idx_src..idx_src + len {
*dest.get_mut((i + offset) as usize).unwrap() = src.get(i as usize).unwrap().clone();
}
}
stack.push(dest_array);
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); 48] = [ let fns: [(&str, Fn, u32); 49] = [
("pop", pop, 0), ("pop", pop, 0),
("dup", dup, 2), ("dup", dup, 2),
("clone", clone, 1), ("clone", clone, 1),
@ -761,6 +835,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("command-wait", command_wait, 1), ("command-wait", command_wait, 1),
("str-to-bytes", str_to_bytes, 1), ("str-to-bytes", str_to_bytes, 1),
("bytes-to-str", bytes_to_str, 1), ("bytes-to-str", bytes_to_str, 1),
("acopy", acopy, 1),
]; ];
for f in fns { for f in fns {
r.define_func( r.define_func(

View file

@ -4,7 +4,7 @@ use std::{
io::Read, io::Read,
io::Write, io::Write,
mem, mem,
net::{Shutdown, TcpStream}, net::{Shutdown, TcpStream, UdpSocket},
sync::Arc, sync::Arc,
}; };
@ -187,6 +187,19 @@ pub fn write_all_stream(stack: &mut Stack) -> OError {
Ok(()) Ok(())
} }
pub fn flush_stream(stack: &mut Stack) -> OError {
require_on_stack!(id, Mega, stack, "flush-stream");
let stream = runtime(|rt| {
rt.get_stream(id as u128)
.ok_or_else(|| stack.error(ErrorKind::VariableNotFound(format!("__stream-{id}"))))
})?;
stream
.lock()
.flush()
.map_err(|x| stack.error(ErrorKind::IO(format!("{x:?}"))))?;
Ok(())
}
pub fn read_stream(stack: &mut Stack) -> OError { pub fn read_stream(stack: &mut Stack) -> OError {
require_on_stack!(id, Mega, stack, "read-stream"); require_on_stack!(id, Mega, stack, "read-stream");
let array = stack.pop(); let array = stack.pop();
@ -285,18 +298,48 @@ fn stream_tcp(stack: &mut Stack) -> Result<Stream, Error> {
)) ))
} }
fn stream_udp(stack: &mut Stack) -> Result<Stream, Error> {
require_int_on_stack!(port, stack, "UDP new-stream");
require_on_stack!(ip, Str, stack, "UDP new-stream");
require_int_on_stack!(self_port, stack, "UDP new-stream");
require_on_stack!(self_ip, Str, stack, "UDP new-stream");
fn close_udp(_stream: &mut Stream) {}
let sock = UdpSocket::bind((self_ip, self_port as u16))
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?;
sock.connect((ip, port as u16))
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?;
struct UdpRW(UdpSocket);
impl Write for UdpRW {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.0.send(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl Read for UdpRW {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.0.recv(buf)
}
}
Ok(Stream::new(UdpRW(sock), close_udp))
}
pub fn register(r: &mut Stack, o: Arc<Frame>) { pub fn register(r: &mut Stack, o: Arc<Frame>) {
if !*IS_INITIALIZED.lock_ro() { if !*IS_INITIALIZED.lock_ro() {
register_stream_type("file", stream_file); register_stream_type("file", stream_file);
register_stream_type("tcp", stream_tcp); register_stream_type("tcp", stream_tcp);
register_stream_type("udp", stream_udp);
*IS_INITIALIZED.lock() = true; *IS_INITIALIZED.lock() = true;
} }
type Fn = fn(&mut Stack) -> OError; type Fn = fn(&mut Stack) -> OError;
let fns: [(&str, Fn, u32); 6] = [ let fns: [(&str, Fn, u32); 7] = [
("new-stream", new_stream, 1), ("new-stream", new_stream, 1),
("write-stream", write_stream, 1), ("write-stream", write_stream, 1),
("write-all-stream", write_all_stream, 0), ("write-all-stream", write_all_stream, 0),
("flush-stream", flush_stream, 0),
("read-stream", read_stream, 1), ("read-stream", read_stream, 1),
("read-all-stream", read_all_stream, 0), ("read-all-stream", read_all_stream, 0),
("close-stream", close_stream, 0), ("close-stream", close_stream, 0),

53
std.spl
View file

@ -11,7 +11,7 @@ func println { |
construct _str_ext { construct _str_ext {
; ;
new { any | with this ; new { any | with this ;
null clone this settype "construct" dyn-objcall null clone this settype:construct
} }
to-bytes { [int] | str-to-bytes } to-bytes { [int] | str-to-bytes }
} include _str_ext in str } include _str_ext in str
@ -56,6 +56,9 @@ construct _array-ext {
while { i this:len lt } { i this:get callable call i ++ =i } while { i this:len lt } { i this:get callable call i ++ =i }
} }
to-str { str | bytes-to-str } to-str { str | bytes-to-str }
sub { [any] | with begin end this ;
this (end begin - anew) begin 0 (end begin -) acopy
}
0 { any | with this ; 0 { any | with this ;
0 this:get 0 this:get
} }
@ -78,14 +81,22 @@ construct _array-ext {
construct List { construct List {
array array
; ;
construct { this | with array this ; construct { this | with this ;
0 anew this:=array
this
}
from { this | with array this ;
array this:=array array this:=array
this this
} }
foreach { | _:array:foreach }
get { any | _:array:get } get { any | _:array:get }
sget { any|null | _:array:sget } sget { any|null | _:array:sget }
len { mega | _:array:len } len { mega | _:array:len }
set { any | _:array:set } set { any | _:array:set }
to-stack { .. | _:array:to-stack }
to-str { str | _:array:to-str }
sub { [any] | _:array:sub }
} }
construct _GrowingArray { construct _GrowingArray {
; ;
@ -159,11 +170,12 @@ include _IterableArray in array
construct MicroMap { construct MicroMap {
pairs pairs
; ;
construct { this | with pairs this ; construct { this | with this ;
pairs null eq if { List:new this:=pairs
0 anew List:new =pairs this
} }
pairs:unwrap this:=pairs from { this | with pairs this ;
pairs this:=pairs
this this
} }
get-entry { [any,any]|null | with key this ; get-entry { [any,any]|null | with key this ;
@ -189,12 +201,15 @@ construct MicroMap {
this:pairs:iter this:pairs:iter
{ mega | 0 swap:get key eq not } swap:filter { mega | 0 swap:get key eq not } swap:filter
_:collect _:collect
List:new List:new:from
=pairs =pairs
} }
iter { ArrayIter | with this ; iter { ArrayIter | with this ;
this:pairs:iter this:pairs:iter
} }
foreach { | with callable this ;
callable this:pairs:foreach
}
} }
construct Range { construct Range {
@ -246,24 +261,12 @@ include _Iter in RangeIter
construct shadow { } construct shadow { }
"Copy array";
func acopy { array | with arr1 arr2 idx1 idx2 len ;
def i 0 =i
while { i len lt } {
(( i idx1 + ) arr1:get) (i idx2 +) arr2:set;
i ++ =i
}
arr2
}
func aadd { array | with arr1 arr2 ; func aadd { array | with arr1 arr2 ;
def newarr arr1:len arr2:len + anew =newarr def newarr arr1:len arr2:len + anew =newarr
arr1 newarr 0 0 arr1:len acopy =newarr arr1 newarr 0 0 arr1:len acopy;
arr2 newarr 0 arr1:len arr2:len acopy =newarr arr2 newarr 0 arr1:len arr2:len acopy;
newarr newarr
} }
@ -281,8 +284,8 @@ func panic { | with msg ;
{ | with it ; { | with it ;
it println it println
} trace:foreach } trace:foreach
"Panic message:" println "\nPanic message:" println
" " print msg println " " print msg println
def map env =map def map env =map
"SPL_PANIC_DUMP" env:get dup if { "SPL_PANIC_DUMP" env:get dup if {
"Dumping because SPL_PANIC_DUMP is set." println "Dumping because SPL_PANIC_DUMP is set." println
@ -332,7 +335,7 @@ func ] { array |
} }
func env { MicroMap | func env { MicroMap |
get-env List:new MicroMap:new get-env List:new:from MicroMap:new:from
} }
func ++ { mega | func ++ { mega |

View file

@ -21,20 +21,32 @@ construct Stream {
} }
"the buffer is written to in-place."; "the buffer is written to in-place.";
read { mega [int] | with buf this ; read { mega [int] | with buf this ;
buf gettype "int" eq if { buf anew =buf } buf gettype "mega" eq if { buf anew =buf }
buf this:id read-stream buf buf this:id read-stream buf
} }
"the buffer is written to in-place."; "the buffer is written to in-place.";
read-exact { [int] | with buf this ; read-exact { [int] | with buf this ;
buf gettype "int" eq if { buf anew =buf } buf gettype "mega" eq if { buf anew =buf }
buf this:id read-all-stream buf buf this:id read-all-stream buf
} }
read-to-end { [int] | with buf this ;
def full 0 anew =full
buf gettype "mega" eq if { buf anew =buf }
def read
while { buf this:id read-stream pop _mega dup =read } {
full (0 read buf:sub) aadd =full
}
full
}
write { mega | with buf this ; write { mega | with buf this ;
buf this:id write-stream buf this:id write-stream
} }
write-exact { | with buf this ; write-exact { | with buf this ;
buf this:id write-all-stream buf this:id write-all-stream
} }
flush { | with this ;
this:id flush-stream
}
close { | with this ; close { | with this ;
this:id close-stream this:id close-stream
} }
@ -71,6 +83,7 @@ func register-stream-type { | with id ;
} }
"tcp" register-stream-type "tcp" register-stream-type
"udp" register-stream-type
"file" register-stream-type "file" register-stream-type
func StreamTypes { _StreamType | func StreamTypes { _StreamType |

View file

@ -1,5 +1,6 @@
"stream.spl" import "stream.spl" import
"http.spl" import
func main { int | with args ; func main { int | with args ;
def thing def thing
@ -8,7 +9,7 @@ func main { int | with args ;
"hi" 0 thing:unwrap:set; "hi" 0 thing:unwrap:set;
def thing2 thing:unwrap List:new =thing2 def thing2 thing:unwrap List:new:from =thing2
"world" thing2:unwrap:push "world" thing2:unwrap:push
"hello" 0 thing2:unwrap:insert "hello" 0 thing2:unwrap:insert
@ -80,18 +81,17 @@ func main { int | with args ;
"" println "" println
"testing MicroMap" println "testing MicroMap" println
def map null MicroMap:new =map def map MicroMap:new =map
"hey" "hello" map:set; "hey" "hello" map:set;
"helloworld" "Hello, World" map:set; "helloworld" "Hello, World" map:set;
"{ " print "{ " print
map:iter { | with item ;
{ | with item ; "'" print
"'" print 0 item:get print
0 item:get print "': '" print
"': '" print 1 item:get print
1 item:get print "', " print
"', " print } map:foreach
} swap:foreach
"}" println "}" println
"" println "" println
@ -109,5 +109,10 @@ func main { int | with args ;
"" println "" println
"testing http" println
def req "tudbut.de" 80 "GET" "/" http:Request:new =req
req:send
"" println
100 100
} }