more http progress

This commit is contained in:
Daniella / Tove 2023-03-06 14:56:49 +01:00
parent 75a54d3dfd
commit 954f817437
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
10 changed files with 287 additions and 84 deletions

View file

@ -6,6 +6,7 @@
construct net:http namespace {
Request
Response
help
}
construct net:http:Request {
@ -58,22 +59,68 @@ construct net:http:Request {
body stream:write-exact;
stream:flush;
1024 stream:read-to-end:to-str println
def response 1024 stream:read-to-end =response
response net:http:Response:new:read-from-bytes
stream:close;
}
}
"todo" panic
construct net:http:help namespace {
;
assert-str { | with expected iter _ ;
[ { | pop iter:next } (expected _array):len:foreach ] _str
expected _str
eq not if {
"Expected " expected concat throw
}
}
until-str { str | with expected iter _ ;
def match 0 =match
def bytes expected:to-bytes =bytes
[
while { match bytes:len eq not } {
iter:next dup (match bytes:get) eq dup if {
match ++ =match
} not if {
0 =match
}
}
{ | pop pop } match:foreach
] _str
}
}
construct net:http:Response {
version
state-num state-msg
headers
body
;
construct { this | with this ;
List:new this:=headers
MicroMap:new this:=headers
"" this:=body
this
}
read-from-bytes { this | with bytes this ;
use net:http:help
bytes:iter =bytes
"HTTP/" bytes help:assert-str
" " bytes help:until-str this:=version
" " bytes help:until-str _mega this:=state-num
"\r\n" bytes help:until-str this:=state-msg
while { "\r\n" bytes help:until-str dup "" eq not } {
def iter ": " swap:split:iter =iter
(
iter:next ": "
iter:join
) this:headers:set;
} pop
0 ("Content-Length" this:headers:get _mega) bytes:collect:sub this:=body
this
}
content-type { str | with this ;
"Content-Type" this:headers:get
}
}

View file

@ -31,7 +31,7 @@ construct _Iter {
}
join { str | with separator this ;
{ str | with accum item ;
accum _str separator item _str strconcat strconcat
accum _str separator item _str concat concat
} this:reduce:calculate
}
filter { FilterIter | with filter this ;

View file

@ -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 namespace
syn keyword Keyword while if exit eq lt gt neg or and not + - * ++ -- % / with namespace catch use
syn match Keyword /;/
syn keyword Type pop dup swap
syn match Type /=[a-zA-Z0-9_\-]\+\|\<_[a-zA-Z0-9_\-]\+\>/

View file

@ -1,6 +1,7 @@
use std::sync::Arc;
use crate::{lexer, runtime::*};
use crate::*;
pub fn dyn_dump(stack: &mut Stack) -> OError {
Words {
@ -76,11 +77,8 @@ pub fn dyn_def_field(stack: &mut Stack) -> OError {
) else {
return stack.err(ErrorKind::InvalidCall("dyn-def-field".to_owned()))
};
runtime(|rt| rt.get_type_by_name(s.to_owned()))
.ok_or_else(|| Error {
kind: ErrorKind::TypeNotFound(s),
stack: stack.trace(),
})?
runtime(|rt| rt.get_type_by_name(&s))
.ok_or_else(|| stack.error(ErrorKind::TypeNotFound(s)))?
.lock()
.add_property(name, stack.get_frame())?;
Ok(())
@ -98,11 +96,8 @@ pub fn dyn_def_method(stack: &mut Stack) -> OError {
) else {
return stack.err(ErrorKind::InvalidCall("dyn-def-method".to_owned()))
};
runtime(|rt| rt.get_type_by_name(s.to_owned()))
.ok_or_else(|| Error {
kind: ErrorKind::TypeNotFound(s),
stack: stack.trace(),
})?
runtime(|rt| rt.get_type_by_name(&s))
.ok_or_else(|| stack.error(ErrorKind::TypeNotFound(s)))?
.lock()
.functions
.insert(name, f);
@ -214,10 +209,9 @@ pub fn dyn_read(stack: &mut Stack) -> OError {
stack.push(
Value::Func(AFunc::new(Func {
ret_count: 0,
to_call: FuncImpl::SPL(lexer::lex(s).map_err(|x| Error {
kind: ErrorKind::LexError(format!("{x:?}")),
stack: stack.trace(),
})?),
to_call: FuncImpl::SPL(
lexer::lex(s).map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
),
run_as_base: false,
origin: stack.get_frame(),
fname: None,
@ -241,10 +235,9 @@ pub fn dyn_readf(stack: &mut Stack) -> OError {
stack.push(
Value::Func(AFunc::new(Func {
ret_count: 0,
to_call: FuncImpl::SPL(lexer::lex(s).map_err(|x| Error {
kind: ErrorKind::LexError(format!("{x:?}")),
stack: stack.trace(),
})?),
to_call: FuncImpl::SPL(
lexer::lex(s).map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
),
run_as_base: true,
origin: stack.get_frame(),
fname: Some(n),
@ -255,6 +248,27 @@ pub fn dyn_readf(stack: &mut Stack) -> OError {
Ok(())
}
pub fn dyn_catch(stack: &mut Stack) -> OError {
require_on_stack!(ctch, Func, stack, "dyn-catch");
require_on_stack!(blk, Func, stack, "dyn-catch");
require_on_stack!(types, Array, stack, "dyn-catch");
if let Err(e) = blk.to_call.call(stack) {
if types.is_empty() || types.contains(&e.kind.to_string().spl()) {
stack.push(e.spl());
ctch.to_call.call(stack)
} else {
Err(e)
}
} else {
Ok(())
}
}
pub fn dyn_use(stack: &mut Stack) -> OError {
require_on_stack!(item, Str, stack, "dyn-use");
Words::new(vec![Word::Key(Keyword::Use(item))]).exec(stack)
}
pub(crate) fn wrap(f: fn(&mut Stack) -> OError) -> impl Fn(&mut Stack) -> OError {
move |stack| unsafe {
let frame = stack.pop_frame(0);
@ -266,7 +280,7 @@ 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); 15] = [
let fns: [(&str, Fn, u32); 17] = [
("dyn-__dump", dyn_dump, 0),
("dyn-def", dyn_def, 0),
("dyn-func", dyn_func, 0),
@ -282,6 +296,8 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("dyn-all-types", dyn_all_types, 1),
("dyn-read", dyn_read, 1),
("dyn-readf", dyn_readf, 1),
("dyn-catch", dyn_catch, 0),
("dyn-use", dyn_use, 0),
];
for f in fns {
r.define_func(

View file

@ -121,6 +121,11 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
}
i += 3;
}
"use" => {
let item = str_words[i + 1].to_owned();
i += 1;
words.push(Word::Key(Keyword::Use(item)));
}
"while" => {
let cond = read_block(&str_words[i + 2..], false)?;
i += 2 + cond.2;
@ -133,6 +138,18 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
i += 2 + blk.2;
words.push(Word::Key(Keyword::If(blk.1)));
}
"catch" => {
let mut types = Vec::new();
i += 1;
while &str_words[i] != "{" {
types.push(str_words[i].to_owned());
i += 1;
}
let blk = read_block(&str_words[i..], false)?;
i += 2 + blk.2;
let ctch = read_block(&str_words[i..], false)?;
words.push(Word::Key(Keyword::Catch(types, blk.1, ctch.1)))
}
"with" => {
let mut vars = Vec::new();
i += 1;

View file

@ -63,7 +63,7 @@ pub fn start_file_in_runtime(path: &str) -> Result<Stack, Error> {
Ok(stack)
}
/// Inćlude the standard library in a runtime-stack-pair, where the runtime has been .set().
/// Include the standard library in a runtime-stack-pair, where the runtime has been .set().
pub fn add_std(stack: &mut Stack) -> OError {
let f = find_in_splpath("std.spl");
let words = lex(if let Ok(f) = f {
@ -71,10 +71,7 @@ pub fn add_std(stack: &mut Stack) -> OError {
} else {
f.unwrap_err()
})
.map_err(|x| Error {
kind: ErrorKind::LexError(format!("{x:?}")),
stack: Vec::new(),
})?;
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?;
words.exec(stack)
}
@ -94,6 +91,7 @@ nofmt! {
};
};
}
#[macro_export]
macro_rules! require_int_on_stack {
($name:tt, $stack:expr, $fn:literal) => {

View file

@ -46,6 +46,10 @@ pub fn runtime_mut<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
})
}
pub fn get_type(name: &str) -> Option<AMType> {
runtime(|rt| rt.get_type_by_name(name))
}
/// An SPL runtime.
///
/// This holds:
@ -99,8 +103,8 @@ impl Runtime {
rt
}
pub fn get_type_by_name(&self, name: String) -> Option<AMType> {
self.types_by_name.get(&name).cloned()
pub fn get_type_by_name(&self, name: &str) -> Option<AMType> {
self.types_by_name.get(name).cloned()
}
pub fn get_type_by_id(&self, id: u32) -> Option<AMType> {
@ -166,7 +170,7 @@ impl SetRuntime for Arc<Mut<Runtime>> {
}
/// A frame's location in SPL code.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FrameInfo {
pub file: String,
pub function: String,
@ -288,10 +292,7 @@ impl Frame {
if let Some(ref x) = frame.parent {
frame = x;
} else {
return Err(Error {
kind: ErrorKind::VariableNotFound(name),
stack: stack.trace(),
});
return Err(stack.error(ErrorKind::VariableNotFound(name)));
}
}
}
@ -305,10 +306,7 @@ impl Frame {
if let Some(ref x) = frame.parent {
frame = x;
} else {
return Err(Error {
kind: ErrorKind::VariableNotFound(name),
stack: stack.trace(),
});
return Err(stack.error(ErrorKind::VariableNotFound(name)));
}
}
}
@ -457,10 +455,7 @@ impl Stack {
if let Some(ref x) = frame.parent {
frame = x;
} else {
return Err(Error {
kind: ErrorKind::FuncNotFound(name),
stack: self.trace(),
});
return Err(self.error(ErrorKind::FuncNotFound(name)));
}
}
}
@ -553,6 +548,7 @@ impl Stack {
Err(Error {
kind,
stack: self.trace(),
mr_stack: self.mr_trace(),
})
}
@ -560,6 +556,7 @@ impl Stack {
Error {
kind,
stack: self.trace(),
mr_stack: self.mr_trace(),
}
}
@ -620,7 +617,7 @@ pub enum Keyword {
/// def <name>
///
/// Defines a variable.
/// equivalent to <name> dyn-def
/// equivalent to "<name>" dyn-def
Def(String),
/// func <name> { <rem> | <words> }
///
@ -639,6 +636,10 @@ pub enum Keyword {
/// Adds <typeA> as a parent type of <typeB>.
/// equivalent to "<typeA>" "<typeB>" dyn-include
Include(String, String),
/// use <path>:<item>
///
/// equivalent to "<path>:<item>" dyn-use
Use(String),
/// while { <wordsA> } { <wordsB> }
///
/// If wordsA result in a truthy value being on the top of the stack, execute wordsB, and
@ -656,6 +657,12 @@ pub enum Keyword {
/// equivalent to def <...> =<...> def <item> =<item>
/// or "<...>" dyn-def "=<...>" dyn-call "<item>" dyn-def "=<item>" dyn-call
With(Vec<String>),
/// catch [<type> <...>] { <code> } with { <wordsOnCatch> }
///
/// Catches errors that happen within <code>, running <wordsOnCatch> when an error is
/// encountered and the error is of <type> (or, if no type is specified, any error).
/// equivalent to \[ ["<type>" <...>] \] { | <code> } { | <wordsOnCatch> } dyn-catch
Catch(Vec<String>, Words, Words),
}
/// Any SPL value that is not a construct.
@ -978,6 +985,34 @@ impl Object {
}
}
impl From<String> for Object {
fn from(value: String) -> Self {
Value::Str(value).into()
}
}
impl From<FrameInfo> for Object {
fn from(value: FrameInfo) -> Self {
let mut obj = Object::new(
get_type("FrameInfo").expect("FrameInfo type must exist"),
Value::Null,
);
obj.property_map.insert("file".to_owned(), value.file.spl());
obj.property_map
.insert("function".to_owned(), value.function.spl());
obj
}
}
impl<T> From<Vec<T>> for Object
where
T: Into<Object>,
{
fn from(value: Vec<T>) -> Self {
Value::Array(value.into_iter().map(|x| x.spl()).collect()).into()
}
}
impl From<Value> for Object {
fn from(value: Value) -> Self {
Object::new(
@ -1105,17 +1140,32 @@ impl Words {
Keyword::Include(ta, tb) => {
let rstack = &stack;
runtime(move |rt| {
rt.get_type_by_name(tb.clone())
rt.get_type_by_name(&tb)
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))?
.lock()
.parents
.push(
rt.get_type_by_name(ta.clone())
rt.get_type_by_name(&ta)
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(ta)))?,
);
Ok(())
})?;
}
Keyword::Use(item) => {
if let Some((a, mut name)) = item.split_once(':') {
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;
}
stack.define_var(name.to_owned());
let o = f.lock_ro().field(name, stack)?.clone();
stack.set_var(name.to_owned(), o)?;
}
}
Keyword::While(cond, blk) => loop {
cond.exec(stack)?;
if !stack.pop().lock_ro().is_truthy() {
@ -1123,6 +1173,7 @@ impl Words {
}
blk.exec(stack)?;
if stack.return_accumultor > 0 {
stack.return_accumultor -= 1;
break;
}
},
@ -1131,6 +1182,16 @@ impl Words {
blk.exec(stack)?;
}
}
Keyword::Catch(types, blk, ctch) => {
if let Err(e) = blk.exec(stack) {
if types.is_empty() || types.contains(&e.kind.to_string()) {
stack.push(e.spl());
ctch.exec(stack)?;
} else {
return Err(e);
}
}
}
Keyword::With(vars) => {
for var in vars.into_iter().rev() {
stack.define_var(var.clone());
@ -1186,9 +1247,8 @@ impl Words {
let f0 = o.kind.lock_ro();
let f = f0
.get_fn(x.clone())
.ok_or_else(|| Error {
kind: ErrorKind::MethodNotFound(f0.name.clone(), x.clone()),
stack: stack.trace(),
.ok_or_else(|| {
stack.error(ErrorKind::MethodNotFound(f0.name.clone(), x.clone()))
})?
.clone();
if option_env!("SPLDEBUG").is_some() {
@ -1254,11 +1314,31 @@ pub enum ErrorKind {
CustomObject(AMObject),
}
impl Display for ErrorKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ErrorKind::Parse(_, _) => f.write_str("Parse"),
ErrorKind::InvalidCall(_) => f.write_str("InvalidCall"),
ErrorKind::InvalidType(_, _) => f.write_str("InvalidType"),
ErrorKind::VariableNotFound(_) => f.write_str("VariableNotFound"),
ErrorKind::FuncNotFound(_) => f.write_str("FuncNotFound"),
ErrorKind::MethodNotFound(_, _) => f.write_str("MethodNotFound"),
ErrorKind::PropertyNotFound(_, _) => f.write_str("PropertyNotFound"),
ErrorKind::TypeNotFound(_) => f.write_str("TypeNotFound"),
ErrorKind::LexError(_) => f.write_str("LexError"),
ErrorKind::IO(_) => f.write_str("IO"),
ErrorKind::Custom(_) => f.write_str("Custom"),
ErrorKind::CustomObject(_) => f.write_str("CustomObject"),
}
}
}
/// Wrapper for ErrorKind with the stack trace.
#[derive(PartialEq, Eq)]
pub struct Error {
pub kind: ErrorKind,
pub stack: Vec<String>,
pub mr_stack: Vec<Vec<FrameInfo>>,
}
impl Debug for Error {
@ -1271,3 +1351,28 @@ impl Debug for Error {
Ok(())
}
}
impl From<Error> for Object {
fn from(value: Error) -> Self {
let mut obj = Object::new(
get_type("error").expect("error type must exist"),
Value::Null,
);
obj.property_map
.insert("kind".to_owned(), value.kind.to_string().spl());
obj.property_map
.insert("message".to_owned(), format!("{:?}", value.kind).spl());
if let ErrorKind::CustomObject(ref o) = value.kind {
obj.property_map.insert("object".to_owned(), o.clone());
}
if let ErrorKind::Custom(ref s) = value.kind {
obj.property_map
.insert("message".to_owned(), s.clone().spl());
}
obj.property_map
.insert("trace".to_owned(), value.stack.spl());
obj.property_map
.insert("mr-trace".to_owned(), value.mr_stack.spl());
obj
}
}

View file

@ -9,12 +9,7 @@ use std::{
sync::Arc,
};
use crate::{
dyn_fns,
mutex::Mut,
runtime::*,
*,
};
use crate::{dyn_fns, mutex::Mut, runtime::*, *};
#[macro_export]
macro_rules! type_err {
@ -77,7 +72,7 @@ pub fn settype(stack: &mut Stack) -> OError {
return stack.err(ErrorKind::InvalidCall("settype".to_owned()))
};
let o = stack.pop();
let kind = runtime(|rt| rt.get_type_by_name(s.clone()))
let kind = runtime(|rt| rt.get_type_by_name(&s))
.ok_or_else(|| stack.error(ErrorKind::TypeNotFound(s)))?;
let mut obj = o.lock();
kind.lock_ro().write_into(&mut obj);
@ -485,31 +480,11 @@ pub fn trace(stack: &mut Stack) -> OError {
pub fn mr_trace(stack: &mut Stack) -> OError {
let trace = stack.mr_trace();
let kind = runtime(|rt| rt.get_type_by_name("TraceElement".to_owned()))
.ok_or_else(|| stack.error(ErrorKind::TypeNotFound("TraceElement".to_owned())))?;
stack.push(
Value::Array(
trace
.into_iter()
.map(|x| {
Value::Array(
x.into_iter()
.map(|x| {
let item = Value::Null.spl();
let mut obj = item.lock();
kind.lock_ro().write_into(&mut obj);
obj.kind = kind.clone();
obj.property_map
.insert("file".to_owned(), Value::Str(x.file).spl());
obj.property_map
.insert("function".to_owned(), Value::Str(x.function).spl());
mem::drop(obj);
item
})
.collect(),
)
.spl()
})
.map(|x| Value::Array(x.into_iter().map(|x| x.spl()).collect()).spl())
.collect(),
)
.spl(),
@ -784,9 +759,14 @@ pub fn acopy(stack: &mut Stack) -> OError {
Ok(())
}
pub fn throw(stack: &mut Stack) -> OError {
let kind = ErrorKind::CustomObject(stack.pop());
stack.err(kind)
}
pub fn register(r: &mut Stack, o: Arc<Frame>) {
type Fn = fn(&mut Stack) -> OError;
let fns: [(&str, Fn, u32); 49] = [
let fns: [(&str, Fn, u32); 50] = [
("pop", pop, 0),
("dup", dup, 2),
("clone", clone, 1),
@ -836,6 +816,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("str-to-bytes", str_to_bytes, 1),
("bytes-to-str", bytes_to_str, 1),
("acopy", acopy, 1),
("throw", throw, 0),
];
for f in fns {
r.define_func(

41
std.spl
View file

@ -8,22 +8,57 @@ func println { |
print "\n" print
}
construct error {
kind
message
object
trace
mr-trace
}
construct FrameInfo {
file
function
}
construct _str_ext {
;
new { any | with this ;
null clone this settype:construct
}
to-bytes { [int] | str-to-bytes }
split { str | with splitter this ;
def bytes splitter:to-bytes =bytes
def iter this:to-bytes:iter =iter
def item 0 =item
[ while { item null eq not } {
def match 0 =match
[
while { match bytes:len eq not } {
iter:next =item
item null eq if {
3 stop
}
item dup (match bytes:get) eq dup if {
match ++ =match
} not if {
0 =match
}
}
{ | pop pop } match:foreach
] _str
} ]
}
} include _str_ext in str
construct _mega-ext {
;
swap { .. | with this ;
i mswap
i -- mswap
this mswap
this -- mswap
}
mswap { .. | mswap }
foreach { | with this ;
foreach { | with callable this ;
def i 0 =i
while { i this lt } { i callable call i ++ =i }
}

View file

@ -107,11 +107,15 @@ func main { int | with args ;
"hi\n" _:to-bytes file:write-exact;
file:close null =file
"" println
"testing split" println
{ | println } (" " "hello how are you" _:split):foreach
"" println
use net:http:Request
"testing http" println
def req "tudbut.de" 80 "GET" "/" net:http:Request:new =req
req:send
def req "tudbut.de" 81 "GET" "/" Request:new =req
req:send:body _str println
"" println
100