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 { construct net:http namespace {
Request Request
Response Response
help
} }
construct net:http:Request { construct net:http:Request {
@ -58,22 +59,68 @@ construct net:http:Request {
body stream:write-exact; body stream:write-exact;
stream:flush; 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; 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 { construct net:http:Response {
version
state-num state-msg state-num state-msg
headers headers
body body
; ;
construct { this | with this ; construct { this | with this ;
List:new this:=headers MicroMap:new this:=headers
"" this:=body "" this:=body
this 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 ; join { str | with separator this ;
{ str | with accum item ; { str | with accum item ;
accum _str separator item _str strconcat strconcat accum _str separator item _str concat concat
} this:reduce:calculate } this:reduce:calculate
} }
filter { FilterIter | with filter this ; filter { FilterIter | with filter 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 namespace syn keyword Keyword while if exit eq lt gt neg or and not + - * ++ -- % / with namespace catch use
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

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

View file

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

View file

@ -63,7 +63,7 @@ pub fn start_file_in_runtime(path: &str) -> Result<Stack, Error> {
Ok(stack) 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 { pub fn add_std(stack: &mut Stack) -> OError {
let f = find_in_splpath("std.spl"); let f = find_in_splpath("std.spl");
let words = lex(if let Ok(f) = f { let words = lex(if let Ok(f) = f {
@ -71,10 +71,7 @@ pub fn add_std(stack: &mut Stack) -> OError {
} else { } else {
f.unwrap_err() f.unwrap_err()
}) })
.map_err(|x| Error { .map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?;
kind: ErrorKind::LexError(format!("{x:?}")),
stack: Vec::new(),
})?;
words.exec(stack) words.exec(stack)
} }
@ -94,6 +91,7 @@ nofmt! {
}; };
}; };
} }
#[macro_export] #[macro_export]
macro_rules! require_int_on_stack { macro_rules! require_int_on_stack {
($name:tt, $stack:expr, $fn:literal) => { ($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. /// An SPL runtime.
/// ///
/// This holds: /// This holds:
@ -99,8 +103,8 @@ impl Runtime {
rt rt
} }
pub fn get_type_by_name(&self, name: String) -> Option<AMType> { pub fn get_type_by_name(&self, name: &str) -> Option<AMType> {
self.types_by_name.get(&name).cloned() self.types_by_name.get(name).cloned()
} }
pub fn get_type_by_id(&self, id: u32) -> Option<AMType> { 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. /// A frame's location in SPL code.
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct FrameInfo { pub struct FrameInfo {
pub file: String, pub file: String,
pub function: String, pub function: String,
@ -288,10 +292,7 @@ impl Frame {
if let Some(ref x) = frame.parent { if let Some(ref x) = frame.parent {
frame = x; frame = x;
} else { } else {
return Err(Error { return Err(stack.error(ErrorKind::VariableNotFound(name)));
kind: ErrorKind::VariableNotFound(name),
stack: stack.trace(),
});
} }
} }
} }
@ -305,10 +306,7 @@ impl Frame {
if let Some(ref x) = frame.parent { if let Some(ref x) = frame.parent {
frame = x; frame = x;
} else { } else {
return Err(Error { return Err(stack.error(ErrorKind::VariableNotFound(name)));
kind: ErrorKind::VariableNotFound(name),
stack: stack.trace(),
});
} }
} }
} }
@ -457,10 +455,7 @@ impl Stack {
if let Some(ref x) = frame.parent { if let Some(ref x) = frame.parent {
frame = x; frame = x;
} else { } else {
return Err(Error { return Err(self.error(ErrorKind::FuncNotFound(name)));
kind: ErrorKind::FuncNotFound(name),
stack: self.trace(),
});
} }
} }
} }
@ -553,6 +548,7 @@ impl Stack {
Err(Error { Err(Error {
kind, kind,
stack: self.trace(), stack: self.trace(),
mr_stack: self.mr_trace(),
}) })
} }
@ -560,6 +556,7 @@ impl Stack {
Error { Error {
kind, kind,
stack: self.trace(), stack: self.trace(),
mr_stack: self.mr_trace(),
} }
} }
@ -620,7 +617,7 @@ pub enum Keyword {
/// def <name> /// def <name>
/// ///
/// Defines a variable. /// Defines a variable.
/// equivalent to <name> dyn-def /// equivalent to "<name>" dyn-def
Def(String), Def(String),
/// func <name> { <rem> | <words> } /// func <name> { <rem> | <words> }
/// ///
@ -639,6 +636,10 @@ pub enum Keyword {
/// Adds <typeA> as a parent type of <typeB>. /// Adds <typeA> as a parent type of <typeB>.
/// equivalent to "<typeA>" "<typeB>" dyn-include /// equivalent to "<typeA>" "<typeB>" dyn-include
Include(String, String), Include(String, String),
/// use <path>:<item>
///
/// equivalent to "<path>:<item>" dyn-use
Use(String),
/// while { <wordsA> } { <wordsB> } /// while { <wordsA> } { <wordsB> }
/// ///
/// If wordsA result in a truthy value being on the top of the stack, execute wordsB, and /// 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> /// equivalent to def <...> =<...> def <item> =<item>
/// or "<...>" dyn-def "=<...>" dyn-call "<item>" dyn-def "=<item>" dyn-call /// or "<...>" dyn-def "=<...>" dyn-call "<item>" dyn-def "=<item>" dyn-call
With(Vec<String>), 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. /// 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 { impl From<Value> for Object {
fn from(value: Value) -> Self { fn from(value: Value) -> Self {
Object::new( Object::new(
@ -1105,17 +1140,32 @@ impl Words {
Keyword::Include(ta, tb) => { Keyword::Include(ta, tb) => {
let rstack = &stack; let rstack = &stack;
runtime(move |rt| { runtime(move |rt| {
rt.get_type_by_name(tb.clone()) rt.get_type_by_name(&tb)
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))? .ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))?
.lock() .lock()
.parents .parents
.push( .push(
rt.get_type_by_name(ta.clone()) rt.get_type_by_name(&ta)
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(ta)))?, .ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(ta)))?,
); );
Ok(()) 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 { Keyword::While(cond, blk) => loop {
cond.exec(stack)?; cond.exec(stack)?;
if !stack.pop().lock_ro().is_truthy() { if !stack.pop().lock_ro().is_truthy() {
@ -1123,6 +1173,7 @@ impl Words {
} }
blk.exec(stack)?; blk.exec(stack)?;
if stack.return_accumultor > 0 { if stack.return_accumultor > 0 {
stack.return_accumultor -= 1;
break; break;
} }
}, },
@ -1131,6 +1182,16 @@ impl Words {
blk.exec(stack)?; 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) => { Keyword::With(vars) => {
for var in vars.into_iter().rev() { for var in vars.into_iter().rev() {
stack.define_var(var.clone()); stack.define_var(var.clone());
@ -1186,9 +1247,8 @@ impl Words {
let f0 = o.kind.lock_ro(); let f0 = o.kind.lock_ro();
let f = f0 let f = f0
.get_fn(x.clone()) .get_fn(x.clone())
.ok_or_else(|| Error { .ok_or_else(|| {
kind: ErrorKind::MethodNotFound(f0.name.clone(), x.clone()), stack.error(ErrorKind::MethodNotFound(f0.name.clone(), x.clone()))
stack: stack.trace(),
})? })?
.clone(); .clone();
if option_env!("SPLDEBUG").is_some() { if option_env!("SPLDEBUG").is_some() {
@ -1254,11 +1314,31 @@ pub enum ErrorKind {
CustomObject(AMObject), 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. /// Wrapper for ErrorKind with the stack trace.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub struct Error { pub struct Error {
pub kind: ErrorKind, pub kind: ErrorKind,
pub stack: Vec<String>, pub stack: Vec<String>,
pub mr_stack: Vec<Vec<FrameInfo>>,
} }
impl Debug for Error { impl Debug for Error {
@ -1271,3 +1351,28 @@ impl Debug for Error {
Ok(()) 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, sync::Arc,
}; };
use crate::{ use crate::{dyn_fns, mutex::Mut, runtime::*, *};
dyn_fns,
mutex::Mut,
runtime::*,
*,
};
#[macro_export] #[macro_export]
macro_rules! type_err { macro_rules! type_err {
@ -77,7 +72,7 @@ pub fn settype(stack: &mut Stack) -> OError {
return stack.err(ErrorKind::InvalidCall("settype".to_owned())) return stack.err(ErrorKind::InvalidCall("settype".to_owned()))
}; };
let o = stack.pop(); 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)))?; .ok_or_else(|| stack.error(ErrorKind::TypeNotFound(s)))?;
let mut obj = o.lock(); let mut obj = o.lock();
kind.lock_ro().write_into(&mut obj); 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 { pub fn mr_trace(stack: &mut Stack) -> OError {
let trace = stack.mr_trace(); 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( stack.push(
Value::Array( Value::Array(
trace trace
.into_iter() .into_iter()
.map(|x| { .map(|x| Value::Array(x.into_iter().map(|x| x.spl()).collect()).spl())
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()
})
.collect(), .collect(),
) )
.spl(), .spl(),
@ -784,9 +759,14 @@ pub fn acopy(stack: &mut Stack) -> OError {
Ok(()) 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>) { 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); 49] = [ let fns: [(&str, Fn, u32); 50] = [
("pop", pop, 0), ("pop", pop, 0),
("dup", dup, 2), ("dup", dup, 2),
("clone", clone, 1), ("clone", clone, 1),
@ -836,6 +816,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("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), ("acopy", acopy, 1),
("throw", throw, 0),
]; ];
for f in fns { for f in fns {
r.define_func( r.define_func(

41
std.spl
View file

@ -8,22 +8,57 @@ func println { |
print "\n" print print "\n" print
} }
construct error {
kind
message
object
trace
mr-trace
}
construct FrameInfo {
file
function
}
construct _str_ext { construct _str_ext {
; ;
new { any | with this ; new { any | with this ;
null clone this settype:construct null clone this settype:construct
} }
to-bytes { [int] | str-to-bytes } 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 } include _str_ext in str
construct _mega-ext { construct _mega-ext {
; ;
swap { .. | with this ; swap { .. | with this ;
i mswap this mswap
i -- mswap this -- mswap
} }
mswap { .. | mswap } mswap { .. | mswap }
foreach { | with this ; foreach { | with callable this ;
def i 0 =i def i 0 =i
while { i this lt } { i callable call i ++ =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; "hi\n" _:to-bytes file:write-exact;
file:close null =file file:close null =file
"" println
"testing split" println
{ | println } (" " "hello how are you" _:split):foreach
"" println "" println
use net:http:Request
"testing http" println "testing http" println
def req "tudbut.de" 80 "GET" "/" net:http:Request:new =req def req "tudbut.de" 81 "GET" "/" Request:new =req
req:send req:send:body _str println
"" println "" println
100 100