diff --git a/.gitignore b/.gitignore index ea8c4bf..6abfe1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/.direnv diff --git a/spl/json.spl b/spl/json.spl index 3159c9a..5271bce 100644 --- a/spl/json.spl +++ b/spl/json.spl @@ -75,61 +75,84 @@ construct json namespace { } null } - parse { [^ok,json:Object]/[^err,error] | with input this ; - input this:parse-stringy-raw =>? [ ^ok def raw ] if { - [ ^ok raw json:Object:new:from ] + parse { [^ok,json:Object/json:Array]/[^err,error] | with input this ; + input this:parse-stringy-raw =>? [ ^ok def mode, raw ] if { + def ty + mode ^obj eq if { json:Object } =ty + mode ^arr eq if { json:Array } =ty + [ + ^ok + raw ty:new:from + ] } } - parse-stringy-raw { [^ok,[[k,v]]/[v]]/[^err,error] | with input this ; + parse-stringy-raw { [^ok,^obj/^arr,[[k,v]]/[v]]/[^err,error] | with input this ; def error [ ^err ^no-object ] def mode + + def cdquot, cbackslash, cn, ct, cr, cspace, ctab, clf, ccol, ccomma, ccbo, ccbc, csbo, csbc + "\"" :_char =cdquot + "\\" :_char =cbackslash + "n" :_char =cn + "t" :_char =ct + "r" :_char =cr + " " :_char =cspace + "\t" :_char =ctab + "\n" :_char =clf + ":" :_char =ccol + "," :_char =ccomma + "{" :_char =ccbo + "}" :_char =ccbc + "[" :_char =csbo + "]" :_char =csbc + input:readf1<"{{}}"> dup if { ^obj =mode } input:readf1<"[{}]"> dup if { ^arr =mode } or => def items if { def in-string, in-escape, exists - mode LinkedList:new dup =mode :push-front - pop [ ^ok [ + pop [ ^ok mode [ + mode LinkedList:new dup =mode :push-front mode:value ^obj eq if { [ } "" items _array :foreach<| with char ; error if { 2 stop } "fail fast"; - in-escape not char "\"" :_char eq and if { + in-escape not char cdquot eq and if { in-string not =in-string 2 stop } in-escape if { - char "\"" :_char eq - char "\\" :_char eq or if { + char cdquot eq + char cbackslash eq or if { char awrap _str concat } - char "n" :_char eq if { + char cn eq if { "\n" concat } - char "t" :_char eq if { + char ct eq if { "\t" concat } - char "r" :_char eq if { + char cr eq if { "\r" concat } 0 =in-escape 2 stop } - in-string char "\\" :_char eq and if { + in-string char cbackslash eq and if { 1 =in-escape 2 stop } in-string not if { - char " " :_char eq - char "\t" :_char eq or - char "\n" :_char eq or if { + char cspace eq + char ctab eq or + char clf eq or if { 3 stop } - char ":" :_char eq if { + char ccol eq if { 1 =exists "" 3 stop } - char "," :_char eq if { + char ccomma eq if { mode:value ^obj eq if { ] [ "" } @@ -139,34 +162,37 @@ construct json namespace { 0 =exists 3 stop } - char "{" :_char eq if { + char ccbo eq if { pop [ [ "" ^obj mode:push-front 3 stop } - char "}" :_char eq if { - exists not dup if { pop pop } "remove the empty KV and string"; - not if { ] } + char ccbc eq if { + exists not if { pop pop } "remove the empty KV and string"; + exists if { ] } "close KV"; ] mode:pop-front; + 1 =exists 3 stop } - char "[" :_char eq if { + char csbo eq if { pop [ "" ^arr mode:push-front 3 stop } - char "]" :_char eq if { + char csbc eq if { exists not if { pop } "remove the empty string"; ] mode:pop-front; + 1 =exists 3 stop } } 1 =exists char awrap _str concat > - mode:value ^obj eq if { ] } + exists not if { pop pop } + exists if { mode:value ^obj eq if { ] } } ] ] } error if { @@ -220,14 +246,14 @@ construct json:Object { get-int { mega/null | with key this ; this:map:get with object ; null - object gettype "string" eq if { + object gettype "str" eq if { pop object _mega } } get-double { double/null | with key this ; this:map:get with object ; null - object gettype "string" eq if { + object gettype "str" eq if { pop object _double } } @@ -265,6 +291,9 @@ construct json:Object { construct json:Array { ; + array { array | with this ; + this:map + } construct { this | with this ; List:new this:=map this @@ -278,6 +307,9 @@ construct json:Array { null this:map:push; this } + len { length | with this ; + this:map:len + } } include json:Object in json:Array diff --git a/spl/std.spl b/spl/std.spl index 81c3fc7..8666c41 100644 --- a/spl/std.spl +++ b/spl/std.spl @@ -603,7 +603,7 @@ func aadd { array | with arr1 arr2 ; } func concat { str | with a b ; - a _array b _array aadd _str + a _barray b _barray aadd _str } func nconcat { str | with amt ; diff --git a/src/runtime.rs b/src/runtime.rs index df1153f..00d213e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -436,8 +436,8 @@ impl Frame { #[derive(Clone, Debug)] pub struct Stack { frames: Vec>, - object_stack: Vec, - objcall_stack: Vec, + object_stack: LinkedList, + objcall_stack: LinkedList, files: Vec, pub return_accumultor: u32, } @@ -472,8 +472,8 @@ impl Stack { let o = Arc::new(Frame::root()); let mut r = Stack { frames: vec![o.clone()], - object_stack: Vec::new(), - objcall_stack: Vec::new(), + object_stack: LinkedList::new(), + objcall_stack: LinkedList::new(), files: Vec::new(), return_accumultor: 0, }; @@ -489,8 +489,8 @@ impl Stack { let o = Arc::new(Frame::root_in(frame_info)); let mut r = Stack { frames: vec![o.clone()], - object_stack: Vec::new(), - objcall_stack: Vec::new(), + object_stack: LinkedList::new(), + objcall_stack: LinkedList::new(), files: Vec::new(), return_accumultor: 0, }; @@ -589,16 +589,14 @@ impl Stack { } pub fn pop_until(&mut self, obj: AMObject) -> Vec { - let Some((idx, ..)) = self - .object_stack - .iter() - .enumerate() - .rfind(|o| *o.1.lock_ro() == *obj.lock_ro()) - else { - return Vec::new(); - }; - let items = self.object_stack[idx + 1..].to_vec(); - self.object_stack = self.object_stack[0..idx].to_vec(); + let mut items = Vec::new(); + while let Some(item) = self.object_stack.pop_back() { + if obj == item { + break; + } + items.push(item); + } + items.reverse(); items } @@ -637,18 +635,18 @@ impl Stack { } pub fn push(&mut self, obj: AMObject) { - self.object_stack.push(obj) + self.object_stack.push_back(obj) } pub fn peek(&mut self) -> AMObject { self.object_stack - .last() + .back() .cloned() .unwrap_or(Value::Null.spl()) } pub fn pop(&mut self) -> AMObject { - self.object_stack.pop().unwrap_or(Value::Null.spl()) + self.object_stack.pop_back().unwrap_or(Value::Null.spl()) } pub fn get_origin(&self) -> FrameInfo { @@ -1475,12 +1473,12 @@ impl Words { } Keyword::ObjPush => { let o = stack.pop(); - stack.objcall_stack.push(o); + stack.objcall_stack.push_back(o); } Keyword::ObjPop => { let o = stack .objcall_stack - .pop() + .pop_back() .expect("invalid word generation. objpop without objpush!"); stack.push(o); } diff --git a/src/std_fns.rs b/src/std_fns.rs index 994f335..ce96605 100644 --- a/src/std_fns.rs +++ b/src/std_fns.rs @@ -1,5 +1,5 @@ use std::{ - collections::{HashMap, VecDeque}, + collections::{HashMap, LinkedList, VecDeque}, env::{self, args, vars}, fs, io::{stdin, stdout, Write}, @@ -10,7 +10,7 @@ use std::{ time::{Duration, SystemTime}, }; -use readformat::readf; +use readformat::{readf, readf1}; use crate::{dyn_fns, mutex::Mut, runtime::*, sasm::sasm_write, *}; @@ -1176,6 +1176,104 @@ pub fn chdir(stack: &mut Stack) -> OError { Ok(()) } +pub fn json_parse(stack: &mut Stack) -> OError { + /* + require_on_stack!(input, Str, stack, "json_parse"); + let objstr = readf1("{{}}", &input); + let arrstr = readf1("[{}]", &input); + enum Mode { + Obj, + Arr, + } + use Mode::*; + let primary_mode = if arrstr.is_some() { Arr } else { Obj }; + let Some(input) = (if arrstr.is_some() { arrstr } else { objstr }) else { + let errarr = vec![ + Value::Str("err".to_owned()).spl(), + Value::Str("no-obj".to_owned()).spl(), + ]; + stack.push(Value::Array(errarr).spl()); + return Ok(()); + }; + let mut mode = LinkedList::new(); + mode.push_back(primary_mode); + let mut values = Vec::new(); + + let mut in_string = false; + let mut in_escape = false; + let mut exists = false; + let mut key = String::new(); + let mut string = String::new(); + let mut object = None; + for c in input.chars() { + if !in_escape && c != '"' { + in_string = !in_string; + continue; + } + if in_escape { + if c == '"' || c == '\\' { + string.push(c); + } + match c { + 'n' => string.push('\n'), + 't' => string.push('\t'), + 'r' => string.push('\r'), + _ => (), + } + in_escape = false; + continue; + } + if in_string && c == '\\' { + in_escape = true; + continue; + } + if !in_string { + if c.is_whitespace() { + continue; + } + if c == ':' { + exists = true; + (key, string) = (string, String::new()); + continue; + } + if c == ',' { + let o = if let Some(o) = object { + o + } else { + Value::Str(string).spl() + }; + match mode.back() { + Some(Obj) => { + values.push( + Value::Array(vec![Value::Str(key).spl(), Value::Str(string).spl()]) + .spl(), + ); + } + Some(Arr) => values.push(), + None => stack.err(ErrorKind::Custom("json-parse"))?, + } + } + } + } + + stack.push( + Value::Array(vec![ + Value::Str("ok".to_owned()).spl(), + Value::Str( + match primary_mode { + Obj => "obj", + Arr => "arr", + } + .to_owned(), + ) + .spl(), + values, + ]) + .spl(), + );*/ + Ok(()) +} + pub fn register(r: &mut Stack, o: Arc) { type Fn = fn(&mut Stack) -> OError; let fns: [(&str, Fn, u32); 71] = [ @@ -1250,6 +1348,7 @@ pub fn register(r: &mut Stack, o: Arc) { ("delete-file", delete_file, 1), ("delete-dir", delete_dir, 1), ("chdir", chdir, 0), + // ("json-parse", json_parse, 1), ]; for f in fns { r.define_func( diff --git a/test.spl b/test.spl index c7273ab..035fb77 100644 --- a/test.spl +++ b/test.spl @@ -446,7 +446,7 @@ func main { int | with args ; object json:stringy<0> dup =object println - object json:parse =>? [ ^ok &=object ] not if { + object json:parse =>? [ ^ok ^obj &=object ] not if { :sjson<0> println }