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
|
} =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
|
||||||
}
|
}
|
||||||
|
|
2
spl.vim
2
spl.vim
|
@ -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_\-]\+\>/
|
||||||
|
|
|
@ -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),
|
||||||
|
|
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" => {
|
"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(
|
||||||
|
|
106
src/runtime.rs
106
src/runtime.rs
|
@ -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;
|
||||||
|
|
143
src/std_fns.rs
143
src/std_fns.rs
|
@ -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(
|
||||||
|
|
|
@ -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
53
std.spl
|
@ -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 |
|
||||||
|
|
17
stream.spl
17
stream.spl
|
@ -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 |
|
||||||
|
|
25
test.spl
25
test.spl
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue