bug fixes, improve speed, add basic http support, other minor improvements
This commit is contained in:
parent
25a30a5be6
commit
e093c11558
11 changed files with 403 additions and 112 deletions
77
http.spl
Normal file
77
http.spl
Normal 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
|
||||
}
|
||||
}
|
||||
|
4
iter.spl
4
iter.spl
|
@ -101,7 +101,7 @@ construct ReduceIter {
|
|||
} =itm
|
||||
this:accumulator null eq if {
|
||||
itm dup this:=accumulator
|
||||
null 2 stop
|
||||
2 stop
|
||||
}
|
||||
this:accumulator itm this:reduce-function call dup this:=accumulator
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ construct ChainIter {
|
|||
next-iters
|
||||
;
|
||||
construct { this | with other origin this ;
|
||||
[ other ] List:new this:=next-iters
|
||||
[ other ] List:new:from this:=next-iters
|
||||
origin this:=current
|
||||
this
|
||||
}
|
||||
|
|
2
spl.vim
2
spl.vim
|
@ -6,7 +6,7 @@ endif
|
|||
syn match Comment /".*?";/
|
||||
syn match Number /\<[0-9._]*\>/
|
||||
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 keyword Type pop dup swap
|
||||
syn match Type /=[a-zA-Z0-9_\-]\+\|\<_[a-zA-Z0-9_\-]\+\>/
|
||||
|
|
|
@ -39,7 +39,28 @@ pub fn dyn_construct(stack: &mut Stack) -> OError {
|
|||
return stack.err(ErrorKind::InvalidCall("dyn-construct".to_owned()))
|
||||
};
|
||||
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)?;
|
||||
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>) {
|
||||
type Fn = fn(&mut Stack) -> OError;
|
||||
let fns: [(&str, Fn, u32); 14] = [
|
||||
let fns: [(&str, Fn, u32); 15] = [
|
||||
("dyn-__dump", dyn_dump, 0),
|
||||
("dyn-def", dyn_def, 0),
|
||||
("dyn-func", dyn_func, 0),
|
||||
("dyn-construct", dyn_construct, 0),
|
||||
("dyn-namespace", dyn_namespace, 0),
|
||||
("dyn-def-field", dyn_def_field, 0),
|
||||
("dyn-def-method", dyn_def_method, 0),
|
||||
("dyn-include", dyn_include, 0),
|
||||
|
|
15
src/lexer.rs
15
src/lexer.rs
|
@ -64,6 +64,12 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
|||
}
|
||||
"construct" => {
|
||||
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] != "{" {
|
||||
return Err(LexerError::InvalidConstructBlock);
|
||||
}
|
||||
|
@ -91,10 +97,15 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
|||
i += 1;
|
||||
}
|
||||
}
|
||||
if !has_construct {
|
||||
if !has_construct && !is_namespace {
|
||||
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" => {
|
||||
if let Some(x) = readf(
|
||||
|
|
106
src/runtime.rs
106
src/runtime.rs
|
@ -360,6 +360,7 @@ impl Frame {
|
|||
pub struct Stack {
|
||||
frames: Vec<Arc<Frame>>,
|
||||
object_stack: Vec<AMObject>,
|
||||
files: Vec<String>,
|
||||
pub return_accumultor: u32,
|
||||
}
|
||||
|
||||
|
@ -394,6 +395,7 @@ impl Stack {
|
|||
let mut r = Stack {
|
||||
frames: vec![o.clone()],
|
||||
object_stack: Vec::new(),
|
||||
files: Vec::new(),
|
||||
return_accumultor: 0,
|
||||
};
|
||||
|
||||
|
@ -409,6 +411,7 @@ impl Stack {
|
|||
let mut r = Stack {
|
||||
frames: vec![o.clone()],
|
||||
object_stack: Vec::new(),
|
||||
files: Vec::new(),
|
||||
return_accumultor: 0,
|
||||
};
|
||||
|
||||
|
@ -591,6 +594,15 @@ impl Stack {
|
|||
pub unsafe fn push_frame(&mut self, frame: Arc<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.
|
||||
|
@ -621,7 +633,7 @@ pub enum Keyword {
|
|||
/// equivalent to
|
||||
/// "<name>" dyn-construct; "<field>" "<name>" dyn-def-field { <rem> | <words> } "<fn-name>"
|
||||
/// "<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>
|
||||
///
|
||||
/// Adds <typeA> as a parent type of <typeB>.
|
||||
|
@ -949,6 +961,19 @@ impl Object {
|
|||
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 {
|
||||
|
@ -1025,38 +1050,55 @@ impl Words {
|
|||
name,
|
||||
}),
|
||||
),
|
||||
Keyword::Construct(name, fields, methods) => {
|
||||
Keyword::Construct(name, fields, methods, is_namespace) => {
|
||||
let origin = stack.get_frame();
|
||||
stack.define_var(name.clone());
|
||||
stack.set_var(
|
||||
name.clone(),
|
||||
Value::Str(
|
||||
runtime_mut(move |mut rt| {
|
||||
rt.make_type(name.clone(), move |mut t| {
|
||||
for field in fields {
|
||||
t.add_property(field, origin.clone())?;
|
||||
}
|
||||
t.functions.extend(methods.into_iter().map(|(k, v)| {
|
||||
(
|
||||
k.clone(),
|
||||
Arc::new(Func {
|
||||
ret_count: v.0,
|
||||
to_call: FuncImpl::SPL(v.1),
|
||||
origin: origin.clone(),
|
||||
run_as_base: false,
|
||||
fname: None,
|
||||
name: name.clone() + ":" + &k,
|
||||
}),
|
||||
)
|
||||
}));
|
||||
Ok(t)
|
||||
})
|
||||
})?
|
||||
.lock_ro()
|
||||
.get_name(),
|
||||
)
|
||||
.spl(),
|
||||
)?;
|
||||
if !name.contains(':') {
|
||||
stack.define_var(name.clone());
|
||||
}
|
||||
let t = runtime_mut(|mut rt| {
|
||||
rt.make_type(name.clone(), |mut t| {
|
||||
for field in fields {
|
||||
t.add_property(field, origin.clone())?;
|
||||
}
|
||||
t.functions.extend(methods.into_iter().map(|(k, v)| {
|
||||
(
|
||||
k.clone(),
|
||||
Arc::new(Func {
|
||||
ret_count: v.0,
|
||||
to_call: FuncImpl::SPL(v.1),
|
||||
origin: origin.clone(),
|
||||
run_as_base: false,
|
||||
fname: None,
|
||||
name: name.clone() + ":" + &k,
|
||||
}),
|
||||
)
|
||||
}));
|
||||
Ok(t)
|
||||
})
|
||||
})?;
|
||||
|
||||
let to_set: Object = if is_namespace {
|
||||
let mut obj: Object = Value::Null.into();
|
||||
obj.kind = t.clone();
|
||||
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) => {
|
||||
let rstack = &stack;
|
||||
|
|
143
src/std_fns.rs
143
src/std_fns.rs
|
@ -4,11 +4,17 @@ use std::{
|
|||
fs,
|
||||
io::{stdin, stdout, Write},
|
||||
mem,
|
||||
ops::{Add, Div, Mul, Rem, Sub},
|
||||
process::{self, Stdio},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{dyn_fns, mutex::Mut, runtime::*, *};
|
||||
use crate::{
|
||||
dyn_fns,
|
||||
mutex::Mut,
|
||||
runtime::*,
|
||||
*,
|
||||
};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! type_err {
|
||||
|
@ -185,14 +191,30 @@ pub fn or(stack: &mut Stack) -> OError {
|
|||
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 {
|
||||
let b = stack.pop().lock_ro().native.clone();
|
||||
let a = stack.pop().lock_ro().native.clone();
|
||||
stack.push(
|
||||
match (a, b) {
|
||||
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a + b),
|
||||
_x => stack.err(ErrorKind::InvalidCall("plus".to_owned()))?,
|
||||
}
|
||||
impl_op!(
|
||||
a,
|
||||
b,
|
||||
add,
|
||||
stack.err(ErrorKind::InvalidCall("plus".to_owned())),
|
||||
Mega,
|
||||
Long,
|
||||
Int,
|
||||
)
|
||||
.spl(),
|
||||
);
|
||||
Ok(())
|
||||
|
@ -202,10 +224,15 @@ pub fn minus(stack: &mut Stack) -> OError {
|
|||
let b = stack.pop().lock_ro().native.clone();
|
||||
let a = stack.pop().lock_ro().native.clone();
|
||||
stack.push(
|
||||
match (a, b) {
|
||||
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a - b),
|
||||
_ => todo!(),
|
||||
}
|
||||
impl_op!(
|
||||
a,
|
||||
b,
|
||||
sub,
|
||||
stack.err(ErrorKind::InvalidCall("minus".to_owned())),
|
||||
Mega,
|
||||
Long,
|
||||
Int,
|
||||
)
|
||||
.spl(),
|
||||
);
|
||||
Ok(())
|
||||
|
@ -215,10 +242,15 @@ pub fn slash(stack: &mut Stack) -> OError {
|
|||
let b = stack.pop().lock_ro().native.clone();
|
||||
let a = stack.pop().lock_ro().native.clone();
|
||||
stack.push(
|
||||
match (a, b) {
|
||||
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a / b),
|
||||
_ => todo!(),
|
||||
}
|
||||
impl_op!(
|
||||
a,
|
||||
b,
|
||||
div,
|
||||
stack.err(ErrorKind::InvalidCall("slash".to_owned())),
|
||||
Mega,
|
||||
Long,
|
||||
Int,
|
||||
)
|
||||
.spl(),
|
||||
);
|
||||
Ok(())
|
||||
|
@ -228,10 +260,15 @@ pub fn star(stack: &mut Stack) -> OError {
|
|||
let b = stack.pop().lock_ro().native.clone();
|
||||
let a = stack.pop().lock_ro().native.clone();
|
||||
stack.push(
|
||||
match (a, b) {
|
||||
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a * b),
|
||||
_ => todo!(),
|
||||
}
|
||||
impl_op!(
|
||||
a,
|
||||
b,
|
||||
mul,
|
||||
stack.err(ErrorKind::InvalidCall("star".to_owned())),
|
||||
Mega,
|
||||
Long,
|
||||
Int,
|
||||
)
|
||||
.spl(),
|
||||
);
|
||||
Ok(())
|
||||
|
@ -241,10 +278,15 @@ pub fn percent(stack: &mut Stack) -> OError {
|
|||
let b = stack.pop().lock_ro().native.clone();
|
||||
let a = stack.pop().lock_ro().native.clone();
|
||||
stack.push(
|
||||
match (a, b) {
|
||||
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a % b),
|
||||
_ => todo!(),
|
||||
}
|
||||
impl_op!(
|
||||
a,
|
||||
b,
|
||||
rem,
|
||||
stack.err(ErrorKind::InvalidCall("star".to_owned())),
|
||||
Mega,
|
||||
Long,
|
||||
Int,
|
||||
)
|
||||
.spl(),
|
||||
);
|
||||
Ok(())
|
||||
|
@ -589,18 +631,26 @@ pub fn import(stack: &mut Stack) -> OError {
|
|||
+ "/"
|
||||
+ &s;
|
||||
}
|
||||
stack.push(Value::Str(s).spl());
|
||||
dup(stack)?;
|
||||
read_file(stack).or_else(|x| {
|
||||
if let Some(fallback) = fallback {
|
||||
stack.push(Value::Str(fallback.to_owned()).spl());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(x)
|
||||
}
|
||||
})?;
|
||||
dyn_fns::wrap(dyn_fns::dyn_readf)(stack)?;
|
||||
call(stack)?;
|
||||
if stack.include_file(
|
||||
&(*fs::canonicalize(s.clone())
|
||||
.map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?
|
||||
.as_os_str()
|
||||
.to_string_lossy())
|
||||
.to_owned(),
|
||||
) {
|
||||
stack.push(Value::Str(s).spl());
|
||||
dup(stack)?;
|
||||
read_file(stack).or_else(|x| {
|
||||
if let Some(fallback) = fallback {
|
||||
stack.push(Value::Str(fallback.to_owned()).spl());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(x)
|
||||
}
|
||||
})?;
|
||||
dyn_fns::wrap(dyn_fns::dyn_readf)(stack)?;
|
||||
call(stack)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -710,9 +760,33 @@ pub fn bytes_to_str(stack: &mut Stack) -> OError {
|
|||
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>) {
|
||||
type Fn = fn(&mut Stack) -> OError;
|
||||
let fns: [(&str, Fn, u32); 48] = [
|
||||
let fns: [(&str, Fn, u32); 49] = [
|
||||
("pop", pop, 0),
|
||||
("dup", dup, 2),
|
||||
("clone", clone, 1),
|
||||
|
@ -761,6 +835,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
|||
("command-wait", command_wait, 1),
|
||||
("str-to-bytes", str_to_bytes, 1),
|
||||
("bytes-to-str", bytes_to_str, 1),
|
||||
("acopy", acopy, 1),
|
||||
];
|
||||
for f in fns {
|
||||
r.define_func(
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::{
|
|||
io::Read,
|
||||
io::Write,
|
||||
mem,
|
||||
net::{Shutdown, TcpStream},
|
||||
net::{Shutdown, TcpStream, UdpSocket},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
@ -187,6 +187,19 @@ pub fn write_all_stream(stack: &mut Stack) -> OError {
|
|||
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 {
|
||||
require_on_stack!(id, Mega, stack, "read-stream");
|
||||
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>) {
|
||||
if !*IS_INITIALIZED.lock_ro() {
|
||||
register_stream_type("file", stream_file);
|
||||
register_stream_type("tcp", stream_tcp);
|
||||
register_stream_type("udp", stream_udp);
|
||||
*IS_INITIALIZED.lock() = true;
|
||||
}
|
||||
|
||||
type Fn = fn(&mut Stack) -> OError;
|
||||
let fns: [(&str, Fn, u32); 6] = [
|
||||
let fns: [(&str, Fn, u32); 7] = [
|
||||
("new-stream", new_stream, 1),
|
||||
("write-stream", write_stream, 1),
|
||||
("write-all-stream", write_all_stream, 0),
|
||||
("flush-stream", flush_stream, 0),
|
||||
("read-stream", read_stream, 1),
|
||||
("read-all-stream", read_all_stream, 0),
|
||||
("close-stream", close_stream, 0),
|
||||
|
|
53
std.spl
53
std.spl
|
@ -11,7 +11,7 @@ func println { |
|
|||
construct _str_ext {
|
||||
;
|
||||
new { any | with this ;
|
||||
null clone this settype "construct" dyn-objcall
|
||||
null clone this settype:construct
|
||||
}
|
||||
to-bytes { [int] | str-to-bytes }
|
||||
} include _str_ext in str
|
||||
|
@ -56,6 +56,9 @@ construct _array-ext {
|
|||
while { i this:len lt } { i this:get callable call i ++ =i }
|
||||
}
|
||||
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 this:get
|
||||
}
|
||||
|
@ -78,14 +81,22 @@ construct _array-ext {
|
|||
construct List {
|
||||
array
|
||||
;
|
||||
construct { this | with array this ;
|
||||
construct { this | with this ;
|
||||
0 anew this:=array
|
||||
this
|
||||
}
|
||||
from { this | with array this ;
|
||||
array this:=array
|
||||
this
|
||||
}
|
||||
foreach { | _:array:foreach }
|
||||
get { any | _:array:get }
|
||||
sget { any|null | _:array:sget }
|
||||
len { mega | _:array:len }
|
||||
set { any | _:array:set }
|
||||
to-stack { .. | _:array:to-stack }
|
||||
to-str { str | _:array:to-str }
|
||||
sub { [any] | _:array:sub }
|
||||
}
|
||||
construct _GrowingArray {
|
||||
;
|
||||
|
@ -159,11 +170,12 @@ include _IterableArray in array
|
|||
construct MicroMap {
|
||||
pairs
|
||||
;
|
||||
construct { this | with pairs this ;
|
||||
pairs null eq if {
|
||||
0 anew List:new =pairs
|
||||
}
|
||||
pairs:unwrap this:=pairs
|
||||
construct { this | with this ;
|
||||
List:new this:=pairs
|
||||
this
|
||||
}
|
||||
from { this | with pairs this ;
|
||||
pairs this:=pairs
|
||||
this
|
||||
}
|
||||
get-entry { [any,any]|null | with key this ;
|
||||
|
@ -189,12 +201,15 @@ construct MicroMap {
|
|||
this:pairs:iter
|
||||
{ mega | 0 swap:get key eq not } swap:filter
|
||||
_:collect
|
||||
List:new
|
||||
List:new:from
|
||||
=pairs
|
||||
}
|
||||
iter { ArrayIter | with this ;
|
||||
this:pairs:iter
|
||||
}
|
||||
foreach { | with callable this ;
|
||||
callable this:pairs:foreach
|
||||
}
|
||||
}
|
||||
|
||||
construct Range {
|
||||
|
@ -246,24 +261,12 @@ include _Iter in RangeIter
|
|||
|
||||
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 ;
|
||||
|
||||
def newarr arr1:len arr2:len + anew =newarr
|
||||
|
||||
arr1 newarr 0 0 arr1:len acopy =newarr
|
||||
arr2 newarr 0 arr1:len arr2:len acopy =newarr
|
||||
arr1 newarr 0 0 arr1:len acopy;
|
||||
arr2 newarr 0 arr1:len arr2:len acopy;
|
||||
|
||||
newarr
|
||||
}
|
||||
|
@ -281,8 +284,8 @@ func panic { | with msg ;
|
|||
{ | with it ;
|
||||
it println
|
||||
} trace:foreach
|
||||
"Panic message:" println
|
||||
" " print msg println
|
||||
"\nPanic message:" println
|
||||
" " print msg println
|
||||
def map env =map
|
||||
"SPL_PANIC_DUMP" env:get dup if {
|
||||
"Dumping because SPL_PANIC_DUMP is set." println
|
||||
|
@ -332,7 +335,7 @@ func ] { array |
|
|||
}
|
||||
|
||||
func env { MicroMap |
|
||||
get-env List:new MicroMap:new
|
||||
get-env List:new:from MicroMap:new:from
|
||||
}
|
||||
|
||||
func ++ { mega |
|
||||
|
|
17
stream.spl
17
stream.spl
|
@ -21,20 +21,32 @@ construct Stream {
|
|||
}
|
||||
"the buffer is written to in-place.";
|
||||
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
|
||||
}
|
||||
"the buffer is written to in-place.";
|
||||
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
|
||||
}
|
||||
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 ;
|
||||
buf this:id write-stream
|
||||
}
|
||||
write-exact { | with buf this ;
|
||||
buf this:id write-all-stream
|
||||
}
|
||||
flush { | with this ;
|
||||
this:id flush-stream
|
||||
}
|
||||
close { | with this ;
|
||||
this:id close-stream
|
||||
}
|
||||
|
@ -71,6 +83,7 @@ func register-stream-type { | with id ;
|
|||
}
|
||||
|
||||
"tcp" register-stream-type
|
||||
"udp" register-stream-type
|
||||
"file" register-stream-type
|
||||
|
||||
func StreamTypes { _StreamType |
|
||||
|
|
25
test.spl
25
test.spl
|
@ -1,5 +1,6 @@
|
|||
|
||||
"stream.spl" import
|
||||
"http.spl" import
|
||||
|
||||
func main { int | with args ;
|
||||
def thing
|
||||
|
@ -8,7 +9,7 @@ func main { int | with args ;
|
|||
|
||||
"hi" 0 thing:unwrap:set;
|
||||
|
||||
def thing2 thing:unwrap List:new =thing2
|
||||
def thing2 thing:unwrap List:new:from =thing2
|
||||
|
||||
"world" thing2:unwrap:push
|
||||
"hello" 0 thing2:unwrap:insert
|
||||
|
@ -80,18 +81,17 @@ func main { int | with args ;
|
|||
"" println
|
||||
"testing MicroMap" println
|
||||
|
||||
def map null MicroMap:new =map
|
||||
def map MicroMap:new =map
|
||||
"hey" "hello" map:set;
|
||||
"helloworld" "Hello, World" map:set;
|
||||
"{ " print
|
||||
map:iter
|
||||
{ | with item ;
|
||||
"'" print
|
||||
0 item:get print
|
||||
"': '" print
|
||||
1 item:get print
|
||||
"', " print
|
||||
} swap:foreach
|
||||
{ | with item ;
|
||||
"'" print
|
||||
0 item:get print
|
||||
"': '" print
|
||||
1 item:get print
|
||||
"', " print
|
||||
} map:foreach
|
||||
"}" println
|
||||
|
||||
"" println
|
||||
|
@ -109,5 +109,10 @@ func main { int | with args ;
|
|||
|
||||
"" println
|
||||
|
||||
"testing http" println
|
||||
def req "tudbut.de" 80 "GET" "/" http:Request:new =req
|
||||
req:send
|
||||
"" println
|
||||
|
||||
100
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue