My ultimate goal here is to making binding work easier for SDL programmers by using a file motif, like, eg, rm below.
Suggested Code with testing
// run via // // vmake -results // // testing string to binding // and related funcs // (setq indent-tabs-mode nil) { // functions like these should probaby eventually wind up in generics // . ++= generics(); // from /vesta/beta.vestasys.org/bridges/make_compat/latest/build.ves // latest -> 6/ // // split like perl /**nocache**/ split_text(sep:text, intext:text) { pos = _find(intext, sep); return if pos == -1 then <intext> else { start = _sub(intext, 0, pos); rest = _sub(intext, pos+1); value <start>+split_text(sep, rest); }; }; // with default sep, and trim meaning dont return "" for leading or trailing sep /**nocache**/ split(intext:text, sep:text = "/", trim = FALSE, err = "error in split") { rtn = split_text(sep, intext); rtn = if trim then { rtn_trimmed = < >; foreach elem in rtn do { rtn_trimmed += if elem == "" then < > else <elem>; }; return rtn_trimmed; } else rtn; return rtn; }; // john's code // turns "a/b/c" into [ a = [ b = [ c = 1 ] ] /**nocache**/ string_to_binding(intext:text, sep:text = "/") : binding { pos = _find(intext, sep); res = if pos == -1 then [ $intext = 1 ] else { elem = _sub(intext, 0, pos); rest = _sub(intext, pos+1); value [ $elem = string_to_binding(rest, sep) ]; }; return res; }; // from /vesta/beta.vestasys.org/bridges/make_compat/latest/build.ves // latest -> 6/ // // given list of strings, recursively look up that binding /**nocache**/ lookup_path_l(b: binding, l: list(text), err: any = []): any { res = if _length(l) == 0 then b else { n = _head(l); value if (_is_binding(b) && b!$n) then lookup_path_l(b/$n, _tail(l), err) else err; }; return res; }; // from /vesta/beta.vestasys.org/bridges/make_compat/latest/build.ves // latest -> 6/ // // given "a/b/c" look that up in root (by using split text then calling path-value) /**nocache**/ lookup_path_t(b : binding, path : text, err : any = [ ]) : binding { arc_list = split_text("/", path); return lookup_path_l(b, arc_list, err); }; // from : /vesta/vestasys.org/vesta/repos/latest/src/progs.ves // latest -> 57/ // // Extract a value on a path from a binding, if present, or return // "err" if not. // orig /**nocache**/ lookup_path_b_orig(b: binding, p: any, err: any = []): any { res = if !_is_binding(p) then b else { n = _n(_head(p)); value if (_is_binding(b) && b!$n) then lookup_path_b(b/$n, _v(_head(p)), err) else err; }; return res; }; // jvk modified /**nocache**/ lookup_path_b(b: binding, p: any, err: any = []): any { res = if !_is_binding(p) then b else if _length(p) != 1 then err else { n = _n(_head(p)); value if (b!$n) // dont have to redundantly check whether b _is_binding then lookup_path_b(b/$n, _v(_head(p)), err) else err; }; return res; }; // john's combo /**nocache**/ lookup_path(b: binding, query: any, err : any = [ ]) : binding { return if _is_binding(query) then lookup_path_b(b, query, err) else if _is_list(query) then lookup_path_l(b, query, err) else if _is_text(query) then lookup_path_t(b, query, err) else err; }; // adapted from lookup_path_l /**nocache**/ rm_l(b: binding, path: list(text), err: any = []): binding { _=_assert(_length(path) >= 1, "list got to zero in rm_l"); n = _head(path); rtn = [ ]; foreach [ nam = val ] in b do { rtn += if nam == n then if _length(path) == 1 then [ ] else [ $nam = rm_l (val, _tail(path), err) ] else [ $nam = val ]; }; return rtn; }; /**nocache**/ rm(b: binding, path: text, err: any = []): bool { return rm_l(b, split(path, "/", TRUE), err); }; // return a function that calls f1 and f2 /**nocache**/ append_func(f1_in, f2_in) { appf() { return f1_in() ++ f2_in() ; }; return appf; }; /**nocache**/ append_func_nocache(f1_in, f2_in) { /**nocache**/ appf_nc() { return f1_in() ++ f2_in() ; }; return appf_nc; }; //////////////////////////////////////////// // results and test chk (a, b, msg = "error") { return if a == b then TRUE else { _=_print("error: "); _=_print(msg); _=_print("a != b:"); _=_print([a]); _=_print([b]); return FALSE; } }; cume = [ ]; /**nocache**/ f1(){ _=_print("f1"); return [ f1 = 1 ]; }; /**nocache**/ f2(){ _=_print("f2"); return [ f2 = 2 ]; }; /**nocache**/ f1_for_nc(){ _=_print("f1_nc"); return [ f1_nc = 3 ]; }; /**nocache**/ f2_for_nc(){ _=_print("f2_nc"); return [ f2_nc = 4 ]; }; bnd = [ a = [ 1 = [ i = 1, ii = 2, ], 2 = [ i = 3, ii = 4, iii = 5, ], 3 = [ i = 6, ], 4 = [ ], ], b = [ 1 = [ i = 7, ii = 8, iii = 9, iv = 10, ], 2 = [ i = 11, ], 3 = [ i = 12, ii = 14, ], ], ]; // // test rm // b2 = [ dir0/dir1/file1 = "c" ] ++ [ dir0/dir1/file2 = "c" ] ++ [ dir0/dir2/file3 = "c" ] ++ [ dir0/dir2/file4 = "c" ] ++ [ dir0/dir3/file5 = "c" ] ++ [ dir0/dir3/file6 = "c" ] ; str = "dir0/dir1/file2"; res = [ $str = rm (b2, str) ]; _=chk(res, [ $str = [ dir0/dir1/file1 = "c" ] ++ [ dir0/dir2/file3 = "c" ] ++ [ dir0/dir2/file4 = "c" ] ++ [ dir0/dir3/file5 = "c" ] ++ [ dir0/dir3/file6 = "c" ] ], "wrong value"); cume ++= res; str = "dir0/dir3"; res = [ $str = rm (b2, str) ]; _=chk(res, [ $str = [ dir0/dir1/file1 = "c" ] ++ [ dir0/dir1/file2 = "c" ] ++ [ dir0/dir2/file3 = "c" ] ++ [ dir0/dir2/file4 = "c" ] ], "wrong value"); cume ++= res; // leading slash str = "/dir0/dir1/file2"; res = [ $str = rm (b2, str) ]; _=chk(res, [ $str = [ dir0/dir1/file1 = "c" ] ++ [ dir0/dir2/file3 = "c" ] ++ [ dir0/dir2/file4 = "c" ] ++ [ dir0/dir3/file5 = "c" ] ++ [ dir0/dir3/file6 = "c" ] ], "wrong value"); cume ++= res; str = "/dir0/dir3"; res = [ $str = rm (b2, str) ]; _=chk(res, [ $str = [ dir0/dir1/file1 = "c" ] ++ [ dir0/dir1/file2 = "c" ] ++ [ dir0/dir2/file3 = "c" ] ++ [ dir0/dir2/file4 = "c" ] ], "wrong value"); cume ++= res; // trailing slash str = "/dir0/dir1/file2/"; res = [ $str = rm (b2, str) ]; _=chk(res, [ $str = [ dir0/dir1/file1 = "c" ] ++ [ dir0/dir2/file3 = "c" ] ++ [ dir0/dir2/file4 = "c" ] ++ [ dir0/dir3/file5 = "c" ] ++ [ dir0/dir3/file6 = "c" ] ], "wrong value"); cume ++= res; str = "/dir0/dir3/"; res = [ $str = rm (b2, str) ]; _=chk(res, [ $str = [ dir0/dir1/file1 = "c" ] ++ [ dir0/dir1/file2 = "c" ] ++ [ dir0/dir2/file3 = "c" ] ++ [ dir0/dir2/file4 = "c" ] ], "wrong value"); cume ++= res; // // test append_func // test_appf = append_func(f1, f2); res = [ append_f1_f2 = test_appf ]; // can't chk cume ++= res; res = [ append_f1_f2_rtn = test_appf() ]; _=chk(res, [ append_f1_f2_rtn = [ f1 = 1, f2 = 2 ] ], "append_func check error"); cume ++= res; // this commnent is a trivial change to cache miss model file test_appf_nc = append_func_nocache(f1_for_nc, f2_for_nc); res = [ append_f1_f2_nc = test_appf_nc ]; // can't chk cume ++= res; res = [ append_f1_f2_nc_rtn = test_appf_nc() ]; _=chk(res, [ append_f1_f2_nc_rtn = [ f1_nc = 3, f2_nc = 4 ] ], "append_func_nocache check error"); cume ++= res; // // test split // str = "a/b/c"; res = [ $str = split (str)]; _=chk(res, [ $str = <"a", "b", "c"> ], "wrong value"); cume ++= res; str = "a/b/c/"; res = [ $str = split (str)]; _=chk(res, [ $str = <"a", "b", "c", ""> ], "wrong value"); cume ++= res; str = "/a/b/c"; res = [ $str = split (str)]; _=chk(res, [ $str = <"", "a", "b", "c"> ], "wrong value"); cume ++= res; str = "a/b/c"; res = [ $(str + " trimmed") = split (str, "/", TRUE)]; _=chk(res, [ $(str + " trimmed") = <"a", "b", "c"> ], "wrong value"); cume ++= res; str = "a/b/c/"; res = [ $(str + " trimmed") = split (str, "/", TRUE)]; _=chk(res, [ $(str + " trimmed") = <"a", "b", "c"> ], "wrong value"); cume ++= res; str = "/a/b/c"; res = [ $(str + " trimmed") = split (str, "/", TRUE)]; _=chk(res, [ $(str + " trimmed") = <"a", "b", "c"> ], "wrong value"); cume ++= res; // // test lookup_path // func = lookup_path; str = "a/1/i"; res = [ $str = func(bnd, str) ]; _=chk(res, [ $str = 1 ], "wrong value"); cume ++= res; str = [ a/1/ii = 1 ]; res = [ a_1_ii_binding = func(bnd, str) ]; _=chk(res, [ a_1_ii_binding = 2 ], "wrong value"); cume ++= res; str = < "b", "1", "iv" >; res = [ b_1_iv_list = func(bnd, str) ]; _=chk(res, [ b_1_iv_list = 10 ], "wrong value"); cume ++= res; str = "b/3/ii"; res = [ $str = func(bnd, str) ]; _=chk(res, [ $str = 14 ], "wrong value"); cume ++= res; str = "/b/3/ii"; res = [ $str = func(bnd, str) ]; _=chk(res, [ $str = 14 ], "wrong value"); cume ++= res; str = "b/2"; res = [ $str = func(bnd, str) ]; _=chk(res, [ $str = [ i = 11 ] ], "wrong value"); cume ++= res; str = [ a/3 = 1 ]; res = [ a_3_binding = func(bnd, str) ]; _=chk(res, [ a_3_binding = [ i =6 ] ], "wrong value"); cume ++= res; str = <"b","1">; res = [ b_1_list = func(bnd, str) ]; _=chk(res, [ b_1_list = [ i = 7 , ii = 8, iii = 9, iv = 10 ] ], "wrong value"); cume ++= res; str = "blah"; res = [ $str = func(bnd, str, "blah_error") ]; cume ++= res; _=chk(res, [ $str = "blah_error" ], "wrong value"); str = "b/blah"; res = [ $str = func(bnd, str, "didnt work") ]; _=chk(res, [ $str = "didnt work" ], "wrong value"); cume ++= res; str = "a/2/blah"; res = [ $str = func(bnd, str, "9999") ]; _=chk(res, [ $str = "9999" ], "wrong value"); cume ++= res; str = "b/blah/3"; res = [ $str = func(bnd, str, [result = "error"]) ]; _=chk(res, [ $str = [result = "error"] ], "wrong value"); cume ++= res; str = [ oops = 1 ]; res = [ oops_binding = func(bnd, str, "oops") ]; _=chk(res, [ oops_binding = "oops" ], "wrong value"); cume ++= res; str = <"b", "nonex">; res = [ nonex_list = func(bnd, str, "didnt work nonex") ]; _=chk(res, [ nonex_list = "didnt work nonex" ], "wrong value"); cume ++= res; stb = string_to_binding("string/to/bindg"); res = [ stb ]; _=chk(res, [ stb = [ string = [ to = [ bindg = 1 ] ] ] ], "wrong value"); cume ++= res; return cume; }
Results
My running of this returned
% vesta -result /vesta/twd1.shr.intel.com/play/jvkumpf/test/jvkumpf_test_pkg/checkout/19/56/build.12.string_to_binding.and.lookup_path.johns.versions.ves Vesta evaluator, version eval/72 "f1_nc" "f2_nc" Return value of `/vesta/twd1.shr.intel.com/play/jvkumpf/test/jvkumpf_test_pkg/checkout/19/56/build.12.string_to_binding.and.lookup_path.johns.versions.ves': [ "dir0/dir1/file2"= [ dir0= [ dir1= [ file1="c" ], dir2= [ file3="c", file4="c" ], dir3= [ file5="c", file6="c" ] ] ], "dir0/dir3"= [ dir0= [ dir1= [ file1="c", file2="c" ], dir2= [ file3="c", file4="c" ] ] ], "/dir0/dir1/file2"= [ dir0= [ dir1= [ file1="c" ], dir2= [ file3="c", file4="c" ], dir3= [ file5="c", file6="c" ] ] ], "/dir0/dir3"= [ dir0= [ dir1= [ file1="c", file2="c" ], dir2= [ file3="c", file4="c" ] ] ], "/dir0/dir1/file2/"= [ dir0= [ dir1= [ file1="c" ], dir2= [ file3="c", file4="c" ], dir3= [ file5="c", file6="c" ] ] ], "/dir0/dir3/"= [ dir0= [ dir1= [ file1="c", file2="c" ], dir2= [ file3="c", file4="c" ] ] ], append_f1_f2=<Closure>, append_f1_f2_rtn= [ f1=1, f2=2 ], append_f1_f2_nc=<Closure>, append_f1_f2_nc_rtn= [ f1_nc=3, f2_nc=4 ], "a/b/c"= < "a", "b", "c" >, "a/b/c/"= < "a", "b", "c", "" >, "/a/b/c"= < "", "a", "b", "c" >, "a/b/c trimmed"= < "a", "b", "c" >, "a/b/c/ trimmed"= < "a", "b", "c" >, "/a/b/c trimmed"= < "a", "b", "c" >, "a/1/i"=1, a_1_ii_binding=2, b_1_iv_list=10, "b/3/ii"=14, "/b/3/ii"= [ ], "b/2"= [ i=11 ], a_3_binding= [ i=6 ], b_1_list= [ i=7, ii=8, iii=9, iv=10 ], blah="blah_error", "b/blah"="didnt work", "a/2/blah"="9999", "b/blah/3"= [ result="error" ], oops_binding="oops", nonex_list="didnt work nonex", stb= [ string= [ to= [ bindg=1 ] ] ] ]