% util.jam
% last changed by Doug Wyatt,  5-Oct-81 19:13:54

($help) .dup .where {.pop .pop} {100 .dict .def} .ifelse .cvx .exec

(/def)
{3 .copy .exch .pop .def .pop $help 3 1 .roll .put} .cvx .def

(/xdef)
{3 .copy .exch .pop .cvx .def .pop $help 3 1 .roll .put} .cvx .def

(/def)
("/def" accepts three entries on the stack: a key, string, and value.
	the string is stored under the key in the $help dictionary, and
	the value is stored as a noun under the key in the current dictionary.)
(/def).load /def

(/xdef)
("/xdef" accepts three entries on the stack: a key, string, and value.
	the string is stored under the key in the $help dictionary, and
	the value is stored as a verb under the key in the current dictionary.)
(/xdef).load /xdef

(?)
("?"	prints the explanation of the given key from the $help dictionary)
{$help .exch .get =}/xdef

(??)
("??" 	prints the names of all the utility commands found in the $help 
dictionary.)
{$help /kdir}/xdef

(/print)
("/print"	prints the top of the stack)
{(                    ).cvis .print}/xdef

(/lp)
("/lp"	prints a left parenthesis)
{(())0 1 .substring .print}/xdef

(/rp)
("/rp"	prints a right parenthesis)
{(())1 1 .substring .print}/xdef

(/cr)
("/cr"	prints a carriage return)
{(
).print}/xdef

(=)
("="	prints the top of the stack and a carriage return)
{/print /cr}/xdef

% (/pause) not implemented

(/stk)
("/stk"	prints (without destroying) the contents of the operand stack.)
{.cntstk .dup 1 .add .copy
 {.dup .type /print (	).print =}.cvx .rept .pop}/xdef

(/pstk)
("/pstk"	pretty prints (without destroying) the contents of the operand stack.)
{.cntstk .dup 1 .add .copy
 (:tab)(:indent).lvknown {:indent}{0}/ifelse .lv {pprint} .cvx .rept .pop}/xdef

(/clr)
("/clr"	clears the operand stack  (same as .clrstk))
{.clrstk} /xdef

(/dir)
("/dir"	prints the contents of the dictionary on top of the operand stack.)
{{.exch /print (		).print .dup .type .print
 (	).print =}.cvx .dictforall}/xdef

(/kdir)
("/kdir" prints the keys found in the dictionary on the top of the operand
stack.)
((.exch = .pop) .cvx .dictforall)/xdef

(/if)
("/if" is equivalent to ".cvx .if")
{.cvx .if}/xdef

(/ifelse)
("/ifelse" is equivalent to ".ifelse .cvx .exec")
{.ifelse .cvx .exec}/xdef

([)
("[" is a command that marks the operand stack for use by the command "]".
This pair of commands is use to create arrays.  For example:
[ 1 2 (hello) ] 
will create an array containing two integers (1 and 2) and the string
"hello".)
{.mark}/xdef

(])
("]" is a command that counts the elements after the mark on the stack and 
puts these elements into an array which is left on the stack. 
The pair of commands ( "[" and "]" ) is use to create arrays.  For example:
[ 1 2 (hello) ] 
will create an array containing two integers (1 and 2) and the string
"hello".)
{.cnttomrk .array .astore .exch .pop}/xdef

% (/altfile) not implemented

(==)
(== is used to print all types of objects in a manner which can easily be 
read. The object to be printed is expected on the operand stack.
	<x> == => -- )
{(:tab) 0 .lv pprint}/xdef

(pprint)
(pprint supports == and does all the printing)
{tabprint .dup .type .dup /print (	)/print $ptypes .exch .get .exec}/xdef

($ptypes) .dup .where {.pop .pop} {15 .dict .def} /ifelse

$ptypes .begin
(.nulltype)   {.pop /cr}.cvx .def
(.integertype){=}.cvx .def
(.realtype)   {=}.cvx .def
(.booleantype){=}.cvx .def
(.nametype)   {=}.cvx .def
(.stringtype) {/lp .print /rp /cr}.cvx .def
(.streamtype) {.pop /cr}.cvx .def
(.commandtype){.commandname =}.cvx .def
(.dicttype)   {(length )/print .dup .length /print (, maxlength )/print .maxlength =}.cvx .def
(.arraytype)  {(length )/print .dup .length = tabinc {pprint}.cvx .arrayforall tabdec}.cvx .def
(.marktype)   {.pop /cr}.cvx .def
(.exectype)   {.pop /cr}.cvx .def
(.looptype)   {.pop /cr}.cvx .def
(.scopetype)  {.scopename =}.cvx .def
.end

(tabinc){(:tab) :tab 1 .add .lvstore}.cvx .def
(tabprint){:tab {(	)/print}.cvx .rept}.cvx .def
(tabdec){(:tab) :tab 1 .sub .lvstore}.cvx .def