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 ] ] ] ]