cli.fun 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #import std
  2. #import nat
  3. #import flo
  4. #import stt
  5. #comment -[
  6. some routines to interface with command line interpreters
  7. Copyright (C) 2007-2010 Dennis Furey]-
  8. #library+
  9. -------------------------------------------------------- constants ---------------------------------------------------------
  10. eof = 4%cOi& # end of file character
  11. ---------------------------------------------------- data structures --------------------------------------------------------
  12. #optimize+
  13. shell :: # interface specification of a command line interpreter
  14. opener %s # command to invoke the shell
  15. login %sLWL # password negotiation protocol, if required
  16. prompt %scLU # shell prompt to expect
  17. settings %sL # commands to be executed when the shell opens
  18. declarer %fOZ ~declarer||0!! # takes an assignment (n: m) to a client that binds the value of m to the symbol n
  19. releaser %fOZ ~releaser||0!! # takes an assignment (n: m) to a client that releases the storage for the symbol n
  20. closers %sL # commands to close the shell
  21. answerer %fOZ ~answerer||~&! # postprocessor for answers returned by the ask function, taking %ssLA
  22. nop %s # shell command that does nothing, used by ask, usually just the empty string
  23. wrapper %fOZ ~wrapper||~&! # postprocessor to the client generated by sh for anything not covered above
  24. ------------------------------------------- functions pertaining to protocols ------------------------------------------------
  25. (# A protocol is represented as a list of pairs of lists of strings <(<command..>,<prompt..>)..>, such that the client sends
  26. the commands and waits for the prompts. If the last list of prompts is <<eof>>, the client will wait until the server closes
  27. the connection. If the last list of prompts is <''>, the client will close the connection upon sending the last command.
  28. Otherwise, the client will close the connection when the last prompt is received. This semantics is a consequence of the
  29. virtual machine's interact combinator calling conventions. #)
  30. handshake = ^|DrlXS(:/''+ ~&iNC,* --<''>+ ~&iNC) # takes a prompt string and a list of command strings to a protocol
  31. completing = ~&i&& ^lrNCT/~&y ~&\<<eof>>+ ~&zl # takes a protocol to one that waits for the server to close the connection
  32. closing = ~&i&& ^lrNCT/~&y ~&\<''>+ ~&zl # takes a protocol to one that ends with the client closing the connection
  33. -------------------------------------------------- functions of clients -----------------------------------------------------
  34. watch = ~&iNHiF+ interact # takes a client to a verbose trace of type %scLULL
  35. exec = ~&Z&&+ !+ ~&NiX\<<eof>>+ ~&iNC # takes a string to a client that executes only one command
  36. expect = # takes a protocol to a client usable as an argument to the interact combinator
  37. %scLULWLMk; ~&i&& (~&?^\!+~&hr ~&l?\0!+ ~&l;+ =:+ ~&t)+ -+
  38. %aaZscLULWXXLMk+ ~&a^& :^\~&fatPR ^/~&ahl ^\~&ahr ~&atihlPB,
  39. %ascLULWXLMk+ ^p\~& %aLMk+ ~&aahPNfatPRXfatPRNXQaaXqS+ ~&xrSPS+ zipp0*+ ~&ziD+ iol+-
  40. (# seq takes a prompt p to a function that takes a list of clients to their sequential composition in a shell with prompt
  41. p. If any client closes the connection, interaction with the next one starts immediately. If any client waits for the server
  42. to close the connection (with <<eof>>), the prompt <'',p> is expected instead (i.e., p preceded by a line break), any
  43. accompanying command from the client has a line break appended, and the interaction of the next client commences when <'',p>
  44. is received. If the initial output of the next client is a single string, a line break is appended to the command, and if its
  45. initial prompt is a single string, a line break is inserted in the prompt. #)
  46. seq =
  47. "p". :-0 ~&l?\~&r ~&r?\~&l ~&lNH?\~&r ~&rNH?\~&l ("f","g"). -!~&Z,~&ll==&l!-?(
  48. "f"+~&ilrPrXB; ~&?(
  49. <<eof>>?=rr(~&/&+ ~&\<'',"p">+ ~&rl,^|\~& ~&/&l),
  50. ! ^|(~&/&r,^|(~&t?/~& --<''>,-!~&ZtY,==<<eof>>!-?/~& ~&NiC)) "g" 0),
  51. &?=l(! ^|(~&/&r,^|(~&t?/~& --<''>,-!~&ZtY,==<<eof>>!-?/~& ~&NiC)) "g" 0,(~&i&& ^|\~& ~&/&r)+ "g"+ ~&lrPrX))
  52. (# When used as a wrapper in a shell, prompt_counter substitutes \n in prompt strings with a count that's incremented each
  53. time starting from 1. #)
  54. prompt_counter =
  55. "f". -+
  56. ~&r&& (~&i&& ~&r; any substring/'\n')?rr\~&lrlPXrrPX -+
  57. %ngXsLWXMk+ ^/~&lrlPX ^/~&rrl ^H\~&rrr '\n'%=*+ ~&h+ %nP+ ~&l,
  58. %ngsLWXXMk+ ^\~&r ~&rrlihtYB?/successor+~&l ~&l+-,
  59. %ngsLWXXMk+ ~&?(^/~&ll "f"+ ~&lrPrX,! ~&NiX "f" 0)+-
  60. ------------------------------------------------------- specific shells ----------------------------------------------------
  61. #optimize-
  62. bash = # system command line interpreter
  63. shell[
  64. opener: 'bash --noediting',
  65. prompt: '$ ',
  66. settings: <'export PS1="$ " PS2="$ "','set +H'>,
  67. declarer: %sI?m(
  68. ("n","m"). exec 'export '--"n"--'="'--"m"--'"',
  69. ("n","m"). seq'$ ' <
  70. exec 'touch '--"n",
  71. (sh shell[opener: 'ed '--"n",settings: <'%d','a'>,closers: <'.','wq'>])/<> ~='.'*~ "m">),
  72. releaser: %sI?m/0! exec+ 'rm '--+ ~&n,
  73. closers: <'exit'>]
  74. psh = shell opener:='psh'! bash
  75. R = # statistical package
  76. shell[
  77. opener: 'R -q',
  78. prompt: '> ',
  79. declarer: expect+ completing+ handshake/'> '+ -?
  80. %eLI+~&m: :^(
  81. ^T/~&n '=rep(0,'--+ --')'+ ~&h+ %nP+ length+ ~&m,
  82. ^D(~&n,num+~&m); * ^T/~&l ~&r; ^T('['--+ --']='+ ~&h+ %nP+ successor+ ~&l,printf/'%0.20e'+ ~&r)),
  83. %eLLI+~&m: :^(
  84. ^T/~&n '=matrix(0,'--+ --')'+ ^T(~&l,:/`,+ ~&r)+ ~&bh+ %nP~~+ length~~+ ~&m; ^/~& ~&z+ leql-<,
  85. ^D(~&n,num+~&m); *= -+
  86. * ^T/~&l ~&r; ^T('['--+ --']'+ ^T/~&l :/`,+ ~&h+ %nP+ successor+ ~&rl,:/`=+ printf/'%0.20e'+ ~&rr),
  87. ^D/~&l ~&r; ^D\num+~&r ~&h+ %nP+ successor+~&l+-),
  88. %eI+~&m: ^TNC/~&n :/`=+ printf/'%0.20e'+ ~&m,
  89. -&~&,%sLI&-+~&m: :^(~&lrhPX; ^|T/~& ' <- '--,~&rt)+ ^lrNCT(~&y,--';'+ ~&z)+ ~&m,
  90. <'unknown R type'>!%?-,
  91. closers: <'q()'>]
  92. octave = # numerical package
  93. shell[
  94. opener: 'octave --q --no-line-editing',
  95. prompt: '> ',
  96. settings: <'PS1=''> ''','PS2='' > ''','split_long_rows=0','format hex','PAGER="cat"'>,
  97. declarer: expect+ completing+ handshake/'> '+ -?
  98. %eLLI+~&m: :^/(^T/~&n '=eye('--+ --');'+ ^|T(~&,:/`,)+ ~&bh+ %nP~~+ length~~+ ~&mmhPX) ^D(~&n,num+~&m); *= -+
  99. * ^T(
  100. ^T/~&l ~&r; '('--+ --')'+ ^T/~&l :/`,+ ~&h+ %nP+ successor+ ~&rl,
  101. ~&r; :/`=+ --';'+ printf/'%0.20e'+ ~&rr),
  102. ^D/~&l ~&r; ^D\num+~&r ~&h+ %nP+ successor+~&l+-,
  103. %eLI+~&m: :^/(^T/~&n '=(1:'--+ --')'';'+ ~&h+ %nP+ length+ ~&m) ^D(~&n,num+~&m); * ^T(
  104. ^|T/~& '('--+ --')'+ ~&h+ %nP+ successor+ ~&l,
  105. :/`=+ --';'+ printf/'%0.20e'+ ~&rr),
  106. %eI+~&m: ^TNC/~&n :/`=+ --';'+ printf/'%0.20e'+ ~&m,
  107. -&~&,%sLI&-+~&m: :^(~&nmhPX; ^|T/~& ' = '--,~&mt),
  108. <'unknown octave type'>!%?-,
  109. closers: <'quit'>,
  110. answerer: ||~& (substring/' ='+ ~&ihB)&& ~&itZBhiQ+ ~&F+ * sep` ; -+
  111. ~&itZBhiQ+ octhex*,
  112. *~ eql/'0000000000000000'&& subset\digits--'abcdef'+-]
  113. gap = # group theory package
  114. shell[
  115. opener: 'gap -b -n',
  116. prompt: 'gap> ',
  117. settings: <'ColorPrompt(false);'>,
  118. declarer: expect+ completing+ handshake/'> '+ -+
  119. ^lrNCT(~&y,--';'+ ~&z)+ '<'%=*'['+ '>'%=*']',
  120. :^(~&lrhPX; ^|T/~& ':='--,~&rt)^/~&n ~&m; -|
  121. -|%nI&& %nP,%nLI&& %nLP,%nLLI&& %nLLP|-,
  122. -&%sLI,any substring/'function',~&i&-,
  123. ''''%=*'"'+ '"'%=*'\"'+ -|%sI&& %sP,%sLI&& %sLP,%sLLI&& %sLLP|-,
  124. ~&l?('/1'%=*''+ ~&r,~&r)+ -?
  125. %qI: ^\%qP ~&rr=='1',
  126. %qLI: ^\%qLP all ~&rr=='1',
  127. %qLLI: ^\%qLLP all all ~&rr=='1',
  128. <'unknown gap type'>!%?-|-+-,
  129. wrapper: //+ ||~& -&
  130. -&~&,~&r,~&rr==<'','gap> '>&-&& ~&rl; -&~&,~&t,~&ttZ,~&thZ&-&& ~&h; -&~&,~&z~=`;&-,
  131. &rlh:= --';'+ ~&rlh&-,
  132. closers: <'quit;'>]
  133. gp = # number theoretic computer algebra system
  134. shell[
  135. opener: 'gp -q',
  136. prompt: '? ',
  137. settings: 'default'--* <'(colors,no)','(output,0)','(readline,0)','(prompt_cont,"? ")','(format,"e0.28")'>,
  138. declarer: expect+ completing+ handshake/''+ ^lrNCT(--'\'*+ ~&y,--';'+ ~&z)^C(^|T/~& ' = '--+ ~&h,~&rt)^/~&n ~&m; -|
  139. -?%nI: %nP,%qI: %qP,%eI: ~&iNC+ printf/'%0.20e',%EI: ~&iNC+ mpfr..mp2str,%sI: ~&iNC,0!?-,
  140. -?%nLI: ~&hS+ %nP*,%qLI: ~&hS+ %qP*,%eLI: printf/*'%0.20e',%ELI: * mpfr..mp2str,-&%sLI,all ~&wZ/`=&-: ~&,0!?-; ~&i&& -+
  141. ^C\~&t '['--+ ~&h,
  142. ^lrNCT(--','*+ ~&y,--']'+ ~&z)+-,
  143. -?%nLLI: ~&hSS+ %nP**,%qLLI: ~&hSS+ %qP**,%eLLI: printf/**'%0.20e',%ELLI: mpfr..mp2str**,%sLLI: ~&,0!?-; ~&i&& -+
  144. ^C('['--+ ~&h,~&t)+ ~&L+ ^lrNCT(~&y; * ^lrNCT/~&y --';'+ ~&z,~&z; ^lrNCT/~&y --']'+ ~&z),
  145. * ^lrNCT(--','*+ ~&y,~&z)+-,
  146. %sLI?/~& <'unknown gp type'>!%|-,
  147. closers: <'\q'>]
  148. maxima = # computer algebra
  149. shell[
  150. opener: 'maxima --quiet --disable-readline',
  151. prompt: '(%i\n) ',
  152. settings: <'display2d: false;'>,
  153. declarer: expect+ completing+ handshake/''+ -+
  154. ^lrNCT(~&y,--'$'+ ~&z)^C\~&rt ^|T/~& ': '--+ ~&h,
  155. ^/~&n ~&m; %sI?/~&iNC %sLI?/~& <'unknown maxima type'>!%+-,
  156. closers: <'quit();'>,
  157. nop: '0$',
  158. wrapper: prompt_counter; //+ ||~& -&
  159. -&~&,~&r,~&rr; -&~&,~&hZ,~&t,~&ttZ,~&t=]'(%i'&-&-&& ~&rl; -&~&,~&t,~&ttZ,~&thZ&-&& ~&h; -&~&,~&z~<';$'&-,
  160. &rlh:= --';'+ ~&rlh&-,
  161. answerer: ~&ihZBtiQ; =]'(%o'?ihB\~& :^\~&t ~&ritB+ ~=` -~+ ~&h]
  162. axiom = # computer algebra
  163. shell[
  164. opener: 'axiom -noht -nogr -nogr -nox',
  165. prompt: '(\n) -> ',
  166. settings: <')set quit unprotected'>,
  167. declarer: expect+ completing+ handshake/''+ ^lrNCT(--'_'*+ ~&y,--';'+ ~&z)^C(^|T/~& ' := '--+ ~&h,~&rt)^/~&n ~&m; -|
  168. -?%nI: %nP,%qI: %qP,%eI: ~&iNC+ printf/'%0.20e',%EI: ~&iNC+ mpfr..mp2str,%sI: ~&iNC,0!?-,
  169. -?%nLI: ~&hS+ %nP*,%qLI: ~&hS+ %qP*,%eLI: printf/*'%0.20e',%ELI: * mpfr..mp2str,-&%sLI,all ~&wZ/`=&-: ~&,0!?-; ~&i&& -+
  170. ^C\~&t '['--+ ~&h,
  171. ^lrNCT(--','*+ ~&y,--']'+ ~&z)+-,
  172. -?%nLLI: ~&hSS+ %nP**,%qLLI: ~&hSS+ %qP**,%eLLI: printf/**'%0.20e',%ELLI: mpfr..mp2str**,%sLLI: ~&,0!?-; ~&i&& -+
  173. ^C('matrix['--+ ~&h,~&t)+ ~&L+ ^lrNCT(~&y; * ^lrNCT/~&y --','+ ~&z,~&z; ^lrNCT/~&y --']'+ ~&z),
  174. * ^C('['--+ ~&h,~&t)^lrNCT(--','*+ ~&y,--']'+ ~&z)+-,
  175. %sLI?/~& <'unknown axiom type'>!%|-,
  176. closers: <')quit'>,
  177. wrapper: "f". -+
  178. ~&r&& (~&i&& ~&r; any substring/'\n')?rr\~&lrlPXrrPX -+
  179. %ngXscLULWXMk+ ^/~&lrlPX ^/~&rrl ^H\~&rrr '\n'%=*+ ~&h+ %nP+ ~&l,
  180. %ngscLULWXXMk+ -!~&lZ,~&rrlihtihBPYB&& ~&rrlh; not -!=]')',=]'--',=]'++'!-!-?(
  181. ^/successor+~&l ~&r,
  182. ^/~&l ~&r; ^/~&l ~&r; ^/~&l ~&r; ~&i&& :^/~&h ~&t; ~&i&& ^llTrC\~&t :/13%cOi&+ ~&h)+-,
  183. %ngscLULWXXMk+ ~&?(^/~&ll "f"+ ~&lrPrX,! ~&NiX "f" 0)+-,
  184. answerer: -+
  185. ~&a^& =]' Loading'?ah\~&a `.?=ahz/~&fatPR ~&fatitB2R,
  186. ~=13%cOi&*~*+ ~&rihZtiQB+ -~ ~&+-]
  187. scilab = # numerical package
  188. shell[
  189. opener: 'scilab -nb -nw -nwni -nogui',
  190. prompt: '-->',
  191. declarer: expect+ completing+ handshake/'-->'+ ^C(^|T/~& ' = '--+ ~&h,~&rt)^/~&n ~&m; -|
  192. -?
  193. %nI: %nP,
  194. %qI: %qP,
  195. %eI: ~&iNC+ printf/'%0.20e',
  196. %EI: ~&iNC+ mpfr..mp2str,
  197. %bI: ~&?/<'%t'>! <'%f'>!,
  198. %sI: ~&iNC+ :/`'+ --'''',
  199. 0!?-,
  200. (~&i&& :/'['+ --<']'>)+ -?
  201. %nLI: ~&hS+ %nP*,
  202. %qLI: ~&hS+ %qP*,
  203. %eLI: printf/*'%0.20e',
  204. %ELI: * mpfr..mp2str,
  205. %bLI: * ~&?/'%t'! '%f'!,
  206. -&%sLI,all ~&wZ/`=&-: * :/`'+ --'''',
  207. 0!?-,
  208. (~&i&& ~&K7; :/'[['+ --<']]'>+ mat'][')+ -?
  209. %nLLI: ~&hSS+ %nP**,
  210. %qLLI: ~&hSS+ %qP**,
  211. %eLLI: printf/**'%0.20e',
  212. %ELLI: mpfr..mp2str**,
  213. %bLLI: * * ~&?/'%t'! '%f'!,
  214. %sLLI: * * :/`'+ --'''',
  215. 0!?-,
  216. %sLI?/~& <'unknown scilab type'>!%|-,
  217. answerer: ~=' '*~; `=?=ihBz\~& ~&t,
  218. closers: <'quit'>]
  219. ---------------------------------------------- functions operating on shells ------------------------------------------------
  220. #optimize+
  221. ssh = sh++ hop
  222. sask = ask++ hop
  223. sopen = open++ hop
  224. multihop = -++-+ hop*
  225. su = ("u","p"). shell$i[opener: ! 'su'-- (~&i&& :/` ) "u",login: ! <(<''>,<'word: '>),(<"p",''>,<' '>)>] bash
  226. hop = # takes a hostname ho and password p to a nestable function that makes a shell remote
  227. ("ho","p"). shell$i[
  228. opener: ! 'ssh'-- (~&i&& :/` ) "ho",
  229. login: -+
  230. //~&T <(<''>,<'word: '>),(<"p",''>,<=]'root@'?(':~# '!,':~$ '!) "ho">)>,
  231. "s". :/(<~opener "s",''>,<''>) ~login "s"+-]
  232. sh = # takes a shell specification to a function that takes an environment and a list of command strings to a client
  233. "s". ("e","c"). (~&?(~&,~&!) ~wrapper "s") (seq ~prompt "s") <
  234. expect :\~login"s" ^biNC(~opener,~login.&Z&& ~prompt) "s",
  235. expect completing handshake ~(prompt,settings) "s",
  236. (seq ~prompt "s") ~declarer"s"* "e",
  237. expect completing handshake (~prompt "s","c"),
  238. (seq ~prompt "s") ~releaser"s"* "e",
  239. expect closing handshake ~(prompt,closers) "s">
  240. open = # takes a shell specification to a function taking an environment and a list of clients to a client
  241. "s". ("e","c"). (~&?(~&,~&!) ~wrapper "s") (seq ~prompt "s") <
  242. expect :\~login"s" ^biNC(~opener,~login.&Z&& ~prompt) "s",
  243. expect completing handshake ~(prompt,settings) "s",
  244. (seq ~prompt "s") ~&L <~declarer"s"* "e","c",~releaser"s"* "e">,
  245. expect closing handshake ~(prompt,closers) "s">
  246. ask = # takes a shell to a function that takes an environment and a list of command strings to a result of type %sLm
  247. "s". -+
  248. ^p(~&nS,~answerer"s"*+ ~&mS)+ ~&mF+ rlc~&rititZBPBZ; %sLLLMk; * %sLLCk ~&hihBPtihiyBPBPX; ^A/~&l ~&lrihBPEritBPrQ,
  249. %sLLMk+ ~&ritBitB+ ~=<~nop "s",''>-~+ ~&liyB+ ~=<~nop "s",''>~-+ watch+ sh"s"^|/~& :/~nop"s"+ --<~nop "s">+-
  250. ------------------------------------------------- functions using shells ----------------------------------------------------
  251. (# now ignores its argument, octhex takes a hexadecimal string to a floating point number, choleski takes a positive
  252. definite matrix to a matrix, and eigen takes a symmetric matrix to a list of vectors and values. #)
  253. now = ~&hmh+ (ask bash)/<>+ <'date -R'>!
  254. octhex = block2; ~&x+ * -$characters ~&iiK0lrNCCS '0123456789abcdef'
  255. eigen = ~&itBthm2hmPpBx+ (ask octave)\<'[v,d]=eig(a);','diag(d)','v'>+ ~&ANC/'a'
  256. choleski = -|~&ihimitBiK7BPBPB,~&ihmPB&& ~&hm%|-+ (ask octave)\<'chol(a)'>+ ~&ANC/'a'
  257. stdmvnorm = # takes (<lower..>,<upper..>,<<sigma..>..>) to a standard multivariate normal probability using R
  258. -&~&,~&r,eql+~&lrlPX,eql+~&lrrPX,~&rr,eql+~&lrrh2X,~&rr; all_same length&-?\<'abnormal'>!% -+
  259. math..strtod+ (~&i&& ~&z; substring/'Normal Completion')?/~&httt <'abnormal completion'>!%,
  260. =]'[1]'*~+ ~&zm+ (ask R)^/<.'lower':+ ~&l,'upper':+ ~&rl,'sigma':+ ~&rr> -+
  261. :/'library(mvtnorm)'+ ~&iNC+ 'print(digits=16,pmvnorm(mean=rep(0,'--+ --'),lower,upper,sigma))',
  262. ~&h+ %nP+ length+ ~&l+-+-
  263. mvnorm = # takes (<lower..>,<upper..>,<mean..>,<<sigma..>..>) to a multivariate normal probability using R
  264. -&~&,~&r,eql+~&lrlPX,eql+~&lrrl2X,~&rrr,eql+~&lrrrh3X,~&rrr; all_same length&-?\<'abnormal'>!% -+
  265. math..strtod+ (~&i&& ~&z; substring/'Normal Completion')?/~&httt <'abnormal completion'>!%,
  266. =]'[1]'*~+ ~&zm+ -+
  267. (ask R)\<'library(mvtnorm)','print(digits=16,pmvnorm(mean=means,lower,upper,sigma))'>,
  268. <.'lower':+ ~&l,'upper':+ ~&rl,'means':+ ~&rrl,'sigma':+ ~&rrr>+-+-
  269. axparse = # parses a list of strings returned by an axiom command of the form expression::InputForm to a tree of strings
  270. -&~&r==<'Type:','InputForm'>,~&l&-+ -+
  271. ~&a^?\<'bad S-exp'>!% ')'?=ah/~&NaX '('?=ah\~&ahNVtX ~&NfatPJX; ~&rah~=')'->lxhdPtV2rat2X ~&lrffaRJPX; ~&ral2lCrfarPJPX,
  272. ~&itB+ ~&itB+ ~&itB+ ~&L; sep` ; *= rlc neither -='()'+-