summaryrefslogtreecommitdiff
path: root/appl/cmd/sh/sexprs.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/sh/sexprs.b')
-rw-r--r--appl/cmd/sh/sexprs.b271
1 files changed, 271 insertions, 0 deletions
diff --git a/appl/cmd/sh/sexprs.b b/appl/cmd/sh/sexprs.b
new file mode 100644
index 00000000..1908078a
--- /dev/null
+++ b/appl/cmd/sh/sexprs.b
@@ -0,0 +1,271 @@
+implement Shellbuiltin;
+
+# parse/generate sexprs.
+
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+ sh: Sh;
+ Listnode, Context: import sh;
+ myself: Shellbuiltin;
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+include "sexprs.m";
+ sexprs: Sexprs;
+ Sexp: import sexprs;
+
+# getsexprs cmd
+# islist val
+# ${els se}
+# ${text se}
+# ${textels se}
+
+# ${mktext val}
+# ${mklist [val...]}
+# ${mktextlist [val...]}
+
+Maxerrs: con 10;
+
+initbuiltin(ctxt: ref Context, shmod: Sh): string
+{
+ sys = load Sys Sys->PATH;
+ sh = shmod;
+ myself = load Shellbuiltin "$self";
+ if (myself == nil)
+ ctxt.fail("bad module", sys->sprint("sexpr: cannot load self: %r"));
+ bufio = load Bufio Bufio->PATH;
+ if (bufio == nil)
+ ctxt.fail("bad module", sys->sprint("sexpr: cannot load: %s: %r", Bufio->PATH));
+ sexprs = load Sexprs Sexprs->PATH;
+ if(sexprs == nil)
+ ctxt.fail("bad module", sys->sprint("sexpr: cannot load: %s: %r", Sexprs->PATH));
+ sexprs->init();
+ ctxt.addbuiltin("getsexprs", myself);
+ ctxt.addbuiltin("islist", myself);
+ ctxt.addsbuiltin("els", myself);
+ ctxt.addsbuiltin("text", myself);
+ ctxt.addsbuiltin("b64", myself);
+ ctxt.addsbuiltin("textels", myself);
+ ctxt.addsbuiltin("mktext", myself);
+ ctxt.addsbuiltin("mklist", myself);
+ ctxt.addsbuiltin("mktextlist", myself);
+
+ return nil;
+}
+
+whatis(nil: ref Sh->Context, nil: Sh, nil: string, nil: int): string
+{
+ return nil;
+}
+
+getself(): Shellbuiltin
+{
+ return myself;
+}
+
+runbuiltin(c: ref Sh->Context, nil: Sh,
+ cmd: list of ref Sh->Listnode, nil: int): string
+{
+ case (hd cmd).word {
+ "getsexprs" =>
+ return builtin_getsexprs(c, tl cmd);
+ "islist" =>
+ return builtin_islist(c, tl cmd);
+ }
+ return nil;
+}
+
+runsbuiltin(c: ref Sh->Context, nil: Sh,
+ cmd: list of ref Sh->Listnode): list of ref Listnode
+{
+ case (hd cmd).word {
+ "els" =>
+ return sbuiltin_els(c, tl cmd);
+ "text" =>
+ return sbuiltin_text(c, tl cmd);
+ "b64" =>
+ return sbuiltin_b64(c, tl cmd);
+ "textels" =>
+ return sbuiltin_textels(c, tl cmd);
+ "mktext" =>
+ return sbuiltin_mktext(c, tl cmd);
+ "mklist" =>
+ return sbuiltin_mklist(c, tl cmd);
+ "mktextlist" =>
+ return sbuiltin_mktextlist(c, tl cmd);
+ }
+ return nil;
+}
+
+builtin_getsexprs(ctxt: ref Context, argv: list of ref Listnode): string
+{
+ n := len argv;
+ if (n != 1 || !iscmd(hd argv))
+ builtinusage(ctxt, "getsexprs {cmd}");
+ cmd := hd argv :: ctxt.get("*");
+ stdin := bufio->fopen(sys->fildes(0), Sys->OREAD);
+ if (stdin == nil)
+ ctxt.fail("bad input", sys->sprint("getsexprs: cannot open stdin: %r"));
+ status := "";
+ nerrs := 0;
+ ctxt.push();
+ for(;;){
+ {
+ for (;;) {
+ (se, err) := Sexp.read(stdin);
+ if(err != nil){
+ sys->fprint(sys->fildes(2), "getsexprs: error on read: %s\n", err);
+ if(++nerrs > Maxerrs)
+ raise "fail:too many errors";
+ continue;
+ }
+ if(se == nil)
+ break;
+ nerrs = 0;
+ ctxt.setlocal("sexp", ref Listnode(nil, se.text()) :: nil);
+ status = setstatus(ctxt, ctxt.run(cmd, 0));
+ }
+ ctxt.pop();
+ return status;
+ }exception e{
+ "fail:*" =>
+ ctxt.pop();
+ if (loopexcept(e) == BREAK)
+ return status;
+ ctxt.push();
+ }
+ }
+}
+
+builtin_islist(ctxt: ref Context, argv: list of ref Listnode): string
+{
+ if(argv == nil || tl argv != nil)
+ builtinusage(ctxt, "islist sexp");
+ w := word(hd argv);
+ if(w != nil && w[0] =='(')
+ return nil;
+ if(parse(ctxt, hd argv).islist())
+ return nil;
+ return "not a list";
+}
+
+CONTINUE, BREAK: con iota;
+loopexcept(ename: string): int
+{
+ case ename[5:] {
+ "break" =>
+ return BREAK;
+ "continue" =>
+ return CONTINUE;
+ * =>
+ raise ename;
+ }
+ return 0;
+}
+
+iscmd(n: ref Listnode): int
+{
+ return n.cmd != nil || (n.word != nil && n.word[0] == '{');
+}
+
+builtinusage(ctxt: ref Context, s: string)
+{
+ ctxt.fail("usage", "usage: " + s);
+}
+
+setstatus(ctxt: ref Context, val: string): string
+{
+ ctxt.setlocal("status", ref Listnode(nil, val) :: nil);
+ return val;
+}
+
+sbuiltin_els(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode
+{
+ if (val == nil || tl val != nil)
+ builtinusage(ctxt, "els sexp");
+ r, rr: list of ref Listnode;
+ for(els := parse(ctxt, hd val).els(); els != nil; els = tl els)
+ r = ref Listnode(nil, (hd els).text()) :: r;
+ for(; r != nil; r = tl r)
+ rr = hd r :: rr;
+ return rr;
+}
+
+sbuiltin_text(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode
+{
+ if(val == nil || tl val != nil)
+ builtinusage(ctxt, "text sexp");
+ return ref Listnode(nil, parse(ctxt, hd val).astext()) :: nil;
+}
+
+sbuiltin_b64(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode
+{
+ if(val == nil || tl val != nil)
+ builtinusage(ctxt, "b64 sexp");
+ return ref Listnode(nil, parse(ctxt, hd val).b64text()) :: nil;
+}
+
+sbuiltin_textels(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode
+{
+ if (val == nil || tl val != nil)
+ builtinusage(ctxt, "textels sexp");
+ r, rr: list of ref Listnode;
+ for(els := parse(ctxt, hd val).els(); els != nil; els = tl els)
+ r = ref Listnode(nil, (hd els).astext()) :: r;
+ for(; r != nil; r = tl r)
+ rr = hd r :: rr;
+ return rr;
+}
+
+sbuiltin_mktext(ctxt: ref Context, val: list of ref Listnode): list of ref Listnode
+{
+ if (val == nil || tl val != nil)
+ builtinusage(ctxt, "mktext sexp");
+ return ref Listnode(nil, (ref Sexp.String(word(hd val), nil)).text()) :: nil;
+}
+
+sbuiltin_mklist(nil: ref Context, val: list of ref Listnode): list of ref Listnode
+{
+ if(val == nil)
+ return ref Listnode(nil, "()") :: nil;
+ s := "(" + word(hd val);
+ for(val = tl val; val != nil; val = tl val)
+ s += " " + word(hd val);
+ s[len s] = ')';
+ return ref Listnode(nil, s) :: nil;
+}
+
+sbuiltin_mktextlist(nil: ref Context, val: list of ref Listnode): list of ref Listnode
+{
+ if(val == nil)
+ return ref Listnode(nil, "()") :: nil;
+ s := "(" + (ref Sexp.String(word(hd val), nil)).text();
+ for(val = tl val; val != nil; val = tl val)
+ s += " " + (ref Sexp.String(word(hd val), nil)).text();
+ s[len s] = ')';
+ return ref Listnode(nil, s) :: nil;
+}
+
+parse(ctxt: ref Context, val: ref Listnode): ref Sexp
+{
+ (se, rest, err) := Sexp.parse(word(val));
+ if(rest != nil){
+ for(i := 0; i < len rest; i++)
+ if(rest[i] != ' ' && rest[i] != '\t' && rest[i] != '\n')
+ ctxt.fail("bad sexp", sys->sprint("extra text found at end of s-expression %#q", word(val)));
+ }
+ if(err != nil)
+ ctxt.fail("bad sexp", err);
+ return se;
+}
+
+word(n: ref Listnode): string
+{
+ if (n.word != nil)
+ return n.word;
+ if (n.cmd != nil)
+ n.word = sh->cmd2string(n.cmd);
+ return n.word;
+}