more http progress
This commit is contained in:
parent
75a54d3dfd
commit
954f817437
10 changed files with 287 additions and 84 deletions
53
http.spl
53
http.spl
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
2
iter.spl
2
iter.spl
|
@ -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 ;
|
||||||
|
|
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 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_\-]\+\>/
|
||||||
|
|
|
@ -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(
|
||||||
|
|
17
src/lexer.rs
17
src/lexer.rs
|
@ -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;
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
147
src/runtime.rs
147
src/runtime.rs
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
41
std.spl
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
|
8
test.spl
8
test.spl
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue