SchemePrinter.mesa
Copyright Ó 1990, 1992 by Xerox Corporation.  All rights reserved.
Last tweaked by Mike Spreitzer on May 12, 1992 9:44 am PDT
 
DIRECTORY Atom, Commander, IO, Process, Rope, Scheme, SchemePrinting, StructuredStreams, UnparserBuffer, UserProfile;
SchemePrinter: 
CEDAR 
PROGRAM
IMPORTS Atom, Commander, IO, Process, Rope, Scheme, StructuredStreams, UnparserBuffer, UserProfile
EXPORTS SchemePrinting
=
 
BEGIN OPEN Scheme, SchemePrinting, SS:StructuredStreams, UB:UnparserBuffer;
PrintStuff: TYPE ~ REF PrintStuffPrivate;
PrintStuffPrivate: 
TYPE ~ 
RECORD [
to: IO.STREAM,
how: How,
quit: REF BOOL,
posns: FormToSource
];
PrettyProc: TYPE ~ PROC [ps: PrintStuff, val: Any, nclose: Nat];
BreakSpec: TYPE ~ RECORD [cond: UB.XBreakCondition, offset: INTEGER, sep: ROPE ¬ " ", double: BOOL ¬ FALSE];
aBrk: BreakSpec ~ [always, 0, NIL, FALSE];
unquoteSplicing: ATOM ~ Atom.MakeAtom["unquote-splicing"];
letStar: ATOM ~ Atom.MakeAtom["let*"];
setBang: ATOM ~ Atom.MakeAtom["set!"];
dynamicBind: ATOM ~ Atom.MakeAtom["dynamic-bind"];
dynamicSetBang: ATOM ~ Atom.MakeAtom["dynamic-set!"];
extendSyntax: ATOM ~ Atom.MakeAtom["extend-syntax"];
deliver: ATOM ~ Atom.MakeAtom["=>"];
PrettyPrint: 
PUBLIC 
PROC [to: 
IO.
STREAM, val: Any, how: How, context: 
ATOM, posns: FormToSource ¬ 
NIL, debugLog: 
IO.
STREAM ¬ 
NIL, quit: 
REF 
BOOL ¬ 
NIL] ~ {
ps: PrintStuff ~ NEW [PrintStuffPrivate ¬ [to, how, quit, posns]];
IF ps.quit=NIL THEN ps.quit ¬ NEW [BOOL ¬ FALSE];
SELECT context 
FROM
$expr => PrintExpr[ps, val, 0];
$data => PrintData[ps, val, 0];
ENDCASE => ERROR Complain[context, "invalid context"];
 
};
 
PrintExpr: 
PROC [ps: PrintStuff, val: Any, nclose: Nat] ~ {
Process.CheckForAbort[];
IF ps.quit THEN ERROR ABORTED;
WITH val 
SELECT 
FROM
v: SimpleVector => PrintVector[ps, v, nclose, PrintExpr];
v: Vector => PrintVector[ps, v, nclose, PrintExpr];
p: Pair => {
IF p.cdr=
NIL 
THEN {
ps.to.PutChar['(];
PrintExpr[ps, p.car, nclose.SUCC];
RETURN};
 
WITH p.car 
SELECT 
FROM
a: 
ATOM => 
SELECT a 
FROM
$quote => PrintQuote[ps, "'", a, p.cdr, nclose];
$quasiquote => PrintQuote[ps, "`", a, p.cdr, nclose];
$unquote => PrintUnquote[ps, ",", a, p.cdr, nclose];
unquoteSplicing => PrintUnquote[ps, ",@", a, p.cdr, nclose];
$define, setBang, dynamicSetBang => PrintDef[ps, a, p.cdr, nclose];
$lambda => PrintLambda[ps, a, p.cdr, nclose];
$if => PrintIf[ps, a, p.cdr, nclose];
$when, $unless => PrintWhen[ps, a, p.cdr, nclose];
$cond => PrintCond[ps, a, p.cdr, FALSE, nclose];
$case => PrintCond[ps, a, p.cdr, TRUE, nclose];
$let => PrintLet[ps, a, p.cdr, TRUE, nclose];
$letrec, letStar, dynamicBind, $with => PrintLet[ps, a, p.cdr, FALSE, nclose];
$begin => PrintBegin[ps, a, p.cdr, nclose];
$do => PrintDo[ps, a, p.cdr, nclose];
extendSyntax => PrintExtSyn[ps, a, p.cdr, nclose];
$export => PrintExport[ps, a, p.cdr, nclose];
ENDCASE => PrintComb[ps, a, p.cdr, TRUE, TRUE, nclose];
ENDCASE => PrintComb[ps, p.car, p.cdr, FALSE, Simple[p.car, ps.how], nclose]};
 
ENDCASE => {Print[val, ps.to]; Multiply[ps, '), nclose]};
 
RETURN};
 
PrintData: 
PROC [ps: PrintStuff, val: Any, nclose: Nat] ~ {
Process.CheckForAbort[];
IF ps.quit THEN ERROR ABORTED;
WITH val 
SELECT 
FROM
v: SimpleVector => PrintVector[ps, v, nclose, PrintData];
v: Vector => PrintVector[ps, v, nclose, PrintData];
p: Pair => {
WITH p.car 
SELECT 
FROM
a: 
ATOM => 
SELECT a 
FROM
$unquote => PrintUnquote[ps, ",", a, p.cdr, nclose];
unquoteSplicing => PrintUnquote[ps, ",@", a, p.cdr, nclose];
ENDCASE => PrintListForm[ps, p, [lookLeft, ps.how.sia], PrintData, nclose];
ENDCASE => PrintListForm[ps, p, [lookLeft, ps.how.sia], PrintData, nclose]};
 
ENDCASE => {Print[val, ps.to]; Multiply[ps, '), nclose]};
 
RETURN};
 
PrintVector: 
PROC [ps: PrintStuff, v: Any, nclose: Nat, 
Inner: PrettyProc] ~ {
len: INT ~ VectorLength[v];
ps.to.PutRope["#("];
IF len=0 THEN {Multiply[ps, '), nclose.SUCC]; RETURN};
SS.Begin[ps.to];
FOR i: 
INT 
IN [0 .. len) 
DO
elt: Any ~ VectorRef[v, i];
IF i>0 THEN SS.XBp[ps.to, lookLeft, 0, " "];
Inner[ps, elt, IF i.SUCC=len THEN nclose.SUCC ELSE 0];
ENDLOOP;
 
SS.End[ps.to];
RETURN};
 
PrintQuote: 
PROC [ps: PrintStuff, intro: 
ROPE, head: 
ATOM, rest: Any, nclose: Nat] ~ {
WITH rest 
SELECT 
FROM
p: Pair => 
IF p.cdr=
NIL 
THEN {
ps.to.PutRope[intro];
PrintData[ps, p.car, nclose];
RETURN};
ENDCASE => NULL;
 
PrintComb[ps, head, rest, TRUE, TRUE, nclose];
RETURN};
 
PrintUnquote: 
PROC [ps: PrintStuff, intro: 
ROPE, head: 
ATOM, rest: Any, nclose: Nat] ~ {
WITH rest 
SELECT 
FROM
p: Pair => 
IF p.cdr=
NIL 
THEN {
ps.to.PutRope[intro];
PrintExpr[ps, p.car, nclose];
RETURN};
ENDCASE => NULL;
 
PrintComb[ps, head, rest, TRUE, TRUE, nclose];
RETURN};
 
PrintDef: 
PROC [ps: PrintStuff, head: 
ATOM, rest: Any, nclose: Nat] ~ {
WITH rest 
SELECT 
FROM
p: Pair => {
sep: BreakSpec ~ 
IF Atomic[p.car, ps.how]
THEN 
WITH p.cdr 
SELECT 
FROM
q: Pair => IF q.cdr=NIL AND Simple[q.car, ps.how] THEN [lookLeft, ps.how.sia] ELSE [always, ps.how.sia],
ENDCASE => [always, ps.how.sia]
 
ELSE [always, ps.how.sia];
SS.Begin[ps.to];
ps.to.PutChar['(];
ps.to.PutRope[Atom.GetPName[head]];
ps.to.PutChar[' ];
PrintFormals[ps, p.car, IF p.cdr=NIL THEN nclose.SUCC ELSE 0];
PrintSeries[ps, p.cdr, FALSE, sep, PrintExpr, nclose.SUCC]};
ENDCASE => PrintComb[ps, head, rest, TRUE, TRUE, nclose]};
 
 
PrintLambda: 
PROC [ps: PrintStuff, head: 
ATOM, rest: Any, nclose: Nat] ~ {
WITH rest 
SELECT 
FROM
formalsTail: Pair => 
WITH formalsTail.cdr 
SELECT 
FROM
bodyTail: Pair => {
simple: BOOL ~ bodyTail.cdr=NIL AND Simple[bodyTail.car, ps.how];
SS.Begin[ps.to];
ps.to.PutChar['(];
ps.to.PutRope[Atom.GetPName[head]];
ps.to.PutChar[' ];
PrintFormals[ps, formalsTail.car, 0];
PrintSeries[ps, bodyTail, FALSE, [IF simple THEN lookLeft ELSE always, ps.how.sia], PrintExpr, nclose.SUCC];
RETURN};
ENDCASE => NULL;
ENDCASE => --what??--NULL;
 
PrintComb[ps, head, rest, TRUE, TRUE, nclose];
RETURN};
 
PrintFormals: 
PROC [ps: PrintStuff, formals: Any, nclose: Nat] ~ {
PrintListForm[ps, formals, [lookLeft, 1], PrintExpr, nclose]};
 
PrintIf: 
PROC [ps: PrintStuff, head: 
ATOM, args: Any, nclose: Nat] ~ {
WITH args 
SELECT 
FROM
testTail: Pair => 
--(test cons alt) or (test cons)
WITH testTail.cdr 
SELECT 
FROM
consTail: Pair => {
--(cons alt) or (cons)
testSimple: BOOL ~ Simple[testTail.car, ps.how];
consSimple, consAtomic, special: BOOL ¬ FALSE;
consSep: BreakSpec;
SELECT Classify[consTail.car, ps.how] 
FROM
atomic => consSimple ¬ consAtomic ¬ TRUE;
simple => consSimple ¬ TRUE;
complex => consSimple ¬ FALSE;
ENDCASE => ERROR;
 
IF consTail.cdr=NIL THEN NULL
ELSE 
IF consSimple 
THEN 
WITH consTail.cdr 
SELECT 
FROM
altTail: Pair => 
SELECT Classify[altTail.car, ps.how] 
FROM
atomic => NULL;
simple => consAtomic ¬ FALSE;
complex => consSimple ¬ consAtomic ¬ FALSE;
ENDCASE => ERROR;
ENDCASE => consSimple ¬ consAtomic ¬ FALSE;
 
SS.Begin[ps.to];
ps.to.PutRope["(if "];
PrintExpr[ps, testTail.car, 0];
SS.XBp[ps.to, IF testSimple AND consSimple THEN lookLeft ELSE always, ps.how.sia, " "];
special ¬ testSimple AND consAtomic;
consSep ¬ [IF consAtomic THEN lookLeft ELSE united, IF special THEN 0 ELSE ps.how.sia];
IF special THEN SS.Begin[ps.to];
PrintSeries[ps, consTail, TRUE, consSep, PrintExpr, nclose.SUCC];
IF special THEN SS.End[ps.to];
RETURN};
ENDCASE => NULL;
 
ENDCASE => NULL;
 
PrintComb[ps, head, args, TRUE, TRUE, nclose];
RETURN};
 
PrintWhen: 
PROC [ps: PrintStuff, head: 
ATOM, rest: Any, nclose: Nat] ~ {
WITH rest 
SELECT 
FROM
predTail: Pair => {
SS.Begin[ps.to];
ps.to.PutChar['(];
ps.to.PutRope[Atom.GetPName[head]];
ps.to.PutChar[' ];
PrintExpr[ps, predTail.car, IF predTail.cdr=NIL THEN nclose.SUCC ELSE 0];
PrintSeries[ps, predTail.cdr, FALSE, [always, ps.how.sia], PrintExpr, nclose.SUCC];
RETURN};
ENDCASE => PrintComb[ps, head, rest, TRUE, TRUE, nclose]};
 
 
PrintCond: 
PROC [ps: PrintStuff, head: 
ATOM, args: Any, case: 
BOOL, nclose: Nat] ~ {
expr: Any ¬ NIL;
arms: Any ¬ args;
first: BOOL ¬ TRUE;
IF case 
THEN 
WITH args 
SELECT 
FROM
p: Pair => {expr ¬ p.car; arms ¬ p.cdr};
ENDCASE => {PrintComb[ps, head, args, TRUE, TRUE, nclose]; RETURN};
 
SS.Begin[ps.to];
ps.to.PutChar['(];
ps.to.PutRope[Atom.GetPName[head]];
IF case 
THEN {
ps.to.PutChar[' ];
PrintExpr[ps, expr, IF arms=NIL THEN nclose.SUCC ELSE 0];
SS.XBp[ps.to, always, ps.how.sia, " "];
}
 
ELSE {
IF arms=NIL THEN {Multiply[ps, '), nclose.SUCC]; SS.End[ps.to]; RETURN};
SS.XBp[ps.to, miser, ps.how.sia, " "]};
 
SS.Begin[ps.to];
PrintSeries[ps, arms, TRUE, [always, 0], PrintCondClause, nclose.SUCC];
SS.End[ps.to];
RETURN};
 
PrintCondClause: 
PROC [ps: PrintStuff, val: Any, nclose: Nat] ~ {
WITH val 
SELECT 
FROM
c0: Pair => {
predSimple: BOOL ~ Simple[c0.car, ps.how];
Finish: 
PROC [rest: Any, del, long, exprSimple: 
BOOL] ~ {
sep: BreakSpec ~ [IF long OR NOT (predSimple AND exprSimple) THEN always ELSE lookLeft, 0];
IF del THEN {ApplyBS[ps, sep]; ps.to.PutRope["=> "]};
PrintSeries[ps, rest, del, sep, PrintExpr, nclose.SUCC];
};
 
ps.to.PutChar['(];
SS.Begin[ps.to];
PrintExpr[ps, c0.car, IF c0.cdr=NIL THEN nclose.SUCC ELSE 0];
IF c0.cdr=NIL THEN {SS.End[ps.to]; RETURN};
WITH c0.cdr 
SELECT 
FROM
c1: Pair => 
SELECT c1.car 
FROM
deliver => 
WITH c1.cdr 
SELECT 
FROM
c2: Pair => Finish[c1.cdr, TRUE, c2.cdr#NIL, Simple[c2.car, ps.how]];
ENDCASE => 
IF c1.cdr#
NIL
THEN Finish[c1.cdr, TRUE, TRUE, FALSE]
ELSE Finish[c0.cdr, FALSE, FALSE, FALSE];
 
ENDCASE => Finish[c0.cdr, FALSE, c1.cdr#NIL, Simple[c1.car, ps.how]];
ENDCASE => Finish[c0.cdr, FALSE, TRUE, FALSE];
 
};
ENDCASE => PrintExpr[ps, val, nclose];
 
RETURN};
 
PrintLet: 
PROC [ps: PrintStuff, head: 
ATOM, rest: Any, mayName: 
BOOL, nclose: Nat] ~ {
named: BOOL ¬ FALSE;
name: ATOM ¬ NIL;
tail: Any ¬ rest;
IF mayName 
THEN 
WITH rest 
SELECT 
FROM
p: Pair => 
WITH p.car 
SELECT 
FROM
a: ATOM => {named ¬ TRUE; name ¬ a; tail ¬ p.cdr};
ENDCASE => NULL;
ENDCASE => NULL;
 
WITH tail 
SELECT 
FROM
bindTail: Pair => {
--(bindings . body)
SS.Begin[ps.to];
ps.to.PutChar['(];
ps.to.PutRope[Atom.GetPName[head]];
ps.to.PutChar[' ];
IF named 
THEN {
SS.Begin[ps.to];
ps.to.PutRope[Atom.GetPName[name]];
SS.XBp[ps.to, miser, 0, " "]};
 
PrintListForm[ps, bindTail.car, [always, 1], PrintBinding, IF bindTail.cdr=NIL THEN nclose.SUCC ELSE 0];
IF named THEN SS.End[ps.to];
PrintSeries[ps, bindTail.cdr, FALSE, [always, ps.how.sia], PrintExpr, nclose.SUCC];
};
ENDCASE => PrintComb[ps, head, rest, TRUE, TRUE, nclose];
 
RETURN};
 
PrintBinding: 
PROC [ps: PrintStuff, val: Any, nclose: Nat] ~ {
WITH val 
SELECT 
FROM
vTail: Pair => 
--(v e)-- 
WITH vTail.car 
SELECT 
FROM
v: 
ATOM => 
WITH vTail.cdr 
SELECT 
FROM
eTail: Pair => 
--(e)-- 
IF eTail.cdr=
NIL 
THEN {
PrintListForm[ps, val, [miser, ps.how.sia], PrintExpr, nclose];
RETURN};
ENDCASE => NULL;
ENDCASE => NULL;
ENDCASE => NULL;
 
PrintListForm[ps, val, [lookLeft, ps.how.sia], PrintExpr, nclose];
RETURN};
 
PrintBegin: 
PROC [ps: PrintStuff, head: 
ATOM, args: Any, nclose: Nat] ~ {
SS.Begin[ps.to];
ps.to.PutRope["(begin"];
IF args=NIL THEN {Multiply[ps, '), nclose.SUCC]; SS.End[ps.to]; RETURN};
SS.XBp[ps.to, miser, ps.how.sia, " "];
SS.Begin[ps.to];
PrintSeries[ps, args, TRUE, [always, 0], PrintExpr, nclose.SUCC];
SS.End[ps.to];
RETURN};
 
PrintDo: 
PROC [ps: PrintStuff, head: 
ATOM, args: Any, nclose: Nat] ~ {
WITH args 
SELECT 
FROM
bindTail: Pair => 
--(bindings test . body)-- 
WITH bindTail.cdr 
SELECT 
FROM
testTail: Pair => {
--(test . body)
bindings: Any ¬ bindTail.car;
SS.Begin[ps.to];
ps.to.PutRope["(do "];
SS.Begin[ps.to];
PrintListForm[ps, bindTail.car, [always, 1], PrintAnyComb, 0];
SS.XBp[ps.to, always, 0, " "];
PrintCondClause[ps, testTail.car, IF testTail.cdr=NIL THEN nclose.SUCC ELSE 0];
SS.End[ps.to];
PrintSeries[ps, testTail.cdr, FALSE, [always, ps.how.sia], PrintExpr, nclose.SUCC];
RETURN};
ENDCASE => NULL;
ENDCASE => NULL;
 
PrintComb[ps, head, args, TRUE, TRUE, nclose];
RETURN};
 
PrintExtSyn: 
PROC [ps: PrintStuff, head: 
ATOM, rest: Any, nclose: Nat] ~ {
WITH rest 
SELECT 
FROM
keyTail: Pair => {
--(keylist . stmts)
SS.Begin[ps.to];
ps.to.PutChar['(];
ps.to.PutRope[Atom.GetPName[head]];
ps.to.PutChar[' ];
PrintListForm[ps, keyTail.car, [width, 1], PrintExpr, IF keyTail.cdr=NIL THEN nclose.SUCC ELSE 0];
PrintSeries[ps, keyTail.cdr, FALSE, [always, ps.how.sia], PrintSyntaxStmt, nclose.SUCC];
RETURN};
ENDCASE => PrintComb[ps, head, rest, TRUE, TRUE, nclose];
 
RETURN};
 
PrintSyntaxStmt: 
PROC [ps: PrintStuff, val: Any, nclose: Nat] ~ {
PrintListForm[ps, val, [always, 1], PrintExpr, nclose]};
 
PrintExport: 
PROC [ps: PrintStuff, head: 
ATOM, rest: Any, nclose: Nat] ~ {
wasDefine: BOOL ¬ FALSE;
ExportEltSep: 
PROC [elt: Any, first, last: 
BOOL, how: How] 
RETURNS [BreakSpec] ~ {
prevDefine: BOOL ~ wasDefine;
isDefine: 
BOOL ~ 
WITH elt 
SELECT 
FROM
p: Pair => p.car=$define,
ENDCASE => FALSE;
wasDefine ¬ isDefine;
RETURN [[always, how.sia, " ", prevDefine OR isDefine]]};
 
WITH rest 
SELECT 
FROM
formalTail: Pair => {
SS.Begin[ps.to];
ps.to.PutChar['(];
ps.to.PutRope[Atom.GetPName[head]];
ps.to.PutChar[' ];
PrintFormals[ps, formalTail.car, 0];
IF formalTail.cdr#NIL THEN PrintEngine[ps, formalTail.cdr, FALSE, ExportEltSep, AlwaysSia, PrintExpr, nclose.SUCC]
ELSE {
SS.XBp[ps.to, always, ps.how.sia, NIL];
Multiply[ps, '), nclose.SUCC];
SS.End[ps.to]};
 
};
ENDCASE => PrintComb[ps, head, rest, TRUE, TRUE, nclose]};
 
 
PrintAnyComb: 
PROC [ps: PrintStuff, val: Any, nclose: Nat] ~ {
WITH val 
SELECT 
FROM
p: Pair => 
WITH p.car 
SELECT 
FROM
a: ATOM => PrintComb[ps, a, p.cdr, TRUE, TRUE, nclose];
ENDCASE => PrintComb[ps, p.car, p.cdr, FALSE, Simple[p.car, ps.how], nclose];
ENDCASE => PrintExpr[ps, val, nclose]};
 
 
PrintComb: 
PROC [ps: PrintStuff, head: Any, args: Any, procAtomic, procSimple: 
BOOL, nclose: Nat] ~ {
wasSimple: BOOL ¬ TRUE;
EltBrk: 
PROC [elt: Any, first, last: 
BOOL, how: How] 
RETURNS [BreakSpec] ~ {
prevSimple: BOOL ~ wasSimple;
isSimple: BOOL ~ last OR Simple[elt, how];
wasSimple ¬ isSimple;
IF first THEN RETURN [[never, 0, NIL]]
ELSE RETURN[[IF prevSimple AND isSimple THEN lookLeft ELSE always, 0]]};
 
SS.Begin[ps.to];
ps.to.PutChar['(];
PrintExpr[ps, head, IF args=NIL THEN nclose.SUCC ELSE 0];
IF procAtomic THEN SS.XBp[ps.to, miser, ps.how.sia, " "]
ELSE IF procSimple THEN SS.XBp[ps.to, lookLeft, ps.how.sia, " "]
ELSE SS.XBp[ps.to, always, 1, " "];
SS.Begin[ps.to];
PrintEngine[ps, args, TRUE, EltBrk, NeverBreak, PrintExpr, nclose.SUCC];
SS.End[ps.to];
RETURN};
 
PrintSeries: 
PROC [ps: PrintStuff, rest: Any, first: 
BOOL, sep: BreakSpec, 
Inner: PrettyProc, nclose: Nat] ~ {
EltBrk: 
PROC [elt: Any, first, last: 
BOOL, how: How] 
RETURNS [BreakSpec]
~ {RETURN [IF first THEN [never, 0, NIL] ELSE sep]};
 
PrintEngine[ps, rest, first, EltBrk, NeverBreak, Inner, nclose]};
 
PrintListForm: 
PROC [ps: PrintStuff, list: Any, sep: BreakSpec, 
Inner: PrettyProc, nclose: Nat] ~ {
EltBrk: 
PROC [elt: Any, first, last: 
BOOL, how: How] 
RETURNS [BreakSpec]
~ {RETURN [IF first THEN [never, 0, NIL] ELSE sep]};
 
IF list=NIL THEN {ps.to.PutChar['(]; Multiply[ps, '), nclose.SUCC]; RETURN};
WITH list 
SELECT 
FROM
p: Pair => {
SS.Begin[ps.to];
ps.to.PutChar['(];
PrintEngine[ps, list, TRUE, EltBrk, NeverBreak, Inner, nclose.SUCC]};
ENDCASE => PrintExpr[ps, list, nclose];
 
RETURN};
 
Breaker: TYPE ~ PROC [elt: Any, first, last: BOOL, how: How] RETURNS [BreakSpec];
PrintEngine: 
PROC [ps: PrintStuff, tail: Any, first: 
BOOL, EltBrk, 
EndBrk: Breaker, 
Inner: PrettyProc, nclose: Nat] ~ {
IF tail#
NIL 
THEN 
DO
WITH tail 
SELECT 
FROM
p: Pair => {last: 
BOOL ~ (tail ¬ p.cdr)=
NIL;
sep: BreakSpec ~ EltBrk[p.car, first, last, ps.how];
final: BreakSpec ~ IF last THEN EndBrk[NIL, FALSE, TRUE, ps.how] ELSE aBrk;
first ¬ FALSE;
ApplyBS[ps, sep];
Inner[ps, p.car, IF final.cond#never THEN 0 ELSE nclose];
IF last 
THEN {
ApplyBS[ps, final];
IF final.cond#never THEN Multiply[ps, '), nclose];
EXIT}};
 
ENDCASE => {
sep: BreakSpec ~ EltBrk[tail, first, TRUE, ps.how];
final: BreakSpec ~ EndBrk[NIL, FALSE, TRUE, ps.how];
ApplyBS[ps, sep];
ps.to.PutRope[". "];
Inner[ps, tail, IF final.cond#never THEN 0 ELSE nclose];
ApplyBS[ps, final];
IF final.cond#never THEN Multiply[ps, '), nclose];
EXIT};
 
 
ENDLOOP;
 
SS.End[ps.to];
RETURN};
 
NeverBreak: Breaker ~ {RETURN [[never, 0, NIL]]};
AlwaysSia: Breaker ~ {RETURN [[always, how.sia]]};
Atomic: 
PROC [val: Any, how: How] 
RETURNS [
BOOL] ~ {
WITH val 
SELECT 
FROM
p: Pair => 
IF how.simpleQuote 
AND (p.car=$quote 
OR p.car=$quasiquote)
THEN 
WITH p.cdr 
SELECT 
FROM
q: Pair => RETURN [q.cdr=NIL AND Atomic[q.car, how]];
ENDCASE => RETURN [FALSE]
 
ELSE RETURN [FALSE]
ENDCASE => RETURN [TRUE]};
 
 
Simple: 
PROC [val: Any, how: How] 
RETURNS [
BOOL]
~ INLINE {RETURN [Classify[val, how] < complex]};
 
Classification: TYPE ~ {atomic, simple, complex};
Classify: 
PROC [val: Any, how: How] 
RETURNS [Classification] ~ {
WITH val 
SELECT 
FROM
p: Pair => {
len: Nat ¬ 1;
car: Any ¬ p.car;
rest: Any ¬ p.cdr;
IF how.simpleQuote 
AND (car=$quote 
OR car=$quasiquote)
THEN 
WITH rest 
SELECT 
FROM
q: Pair => 
IF q.cdr=
NIL
THEN RETURN Classify[q.car, how]
ELSE RETURN [complex]
ENDCASE => RETURN [complex];
 
 
DO
IF len>how.simpleLen THEN RETURN [complex];
WITH car 
SELECT 
FROM
q: Pair => RETURN [complex];
ENDCASE => NULL;
 
IF rest=NIL THEN RETURN [simple];
WITH rest 
SELECT 
FROM
q: Pair => {car ¬ q.car; rest ¬ q.cdr; len ¬ len.SUCC};
ENDCASE => RETURN [IF len < how.simpleLen THEN simple ELSE complex];
 
ENDLOOP};
 
ENDCASE => RETURN [atomic]};
 
 
ApplyBS: 
PROC [ps: PrintStuff, bs: BreakSpec] ~ 
INLINE {
SS.XBp[ps.to, bs.cond, bs.offset, bs.sep];
IF bs.double THEN SS.XBp[ps.to, bs.cond, bs.offset, bs.sep];
RETURN};
 
Multiply: 
PROC [ps: PrintStuff, c: 
CHAR, n: 
NAT]
~ {THROUGH [1..n] DO ps.to.PutChar[c] ENDLOOP};
 
Cmd: 
PROC [cmd: Commander.Handle] 
RETURNS [result: 
REF 
ANY ¬ 
NIL, msg: 
ROPE ¬ 
NIL] 
--Commander.CommandProc-- ~ {
specIn: IO.STREAM ~ IO.RIS[cmd.commandLine];
how: How ¬ defaultHow;
margin: INT ¬ defaultMargin;
barfum: ROPE ¬ NIL;
msg ¬ NIL;
DO
ENABLE Complain => {
barfum ¬ Rope.Concat["Scheme err on command line: ", msg];
GOTO Abort};
 
spec: Any ¬ Read[specIn];
Car: 
PROC [a: Any] 
RETURNS [Any] ~ {
WITH a 
SELECT 
FROM
p: Pair => RETURN[p.car];
ENDCASE => Complain[a, "spec must be of form (name val)"]};
 
 
IF spec=endOfFile THEN EXIT;
WITH spec 
SELECT 
FROM
p: Pair => 
SELECT p.car 
FROM
$margin => margin ¬ TheINT[Car[p.cdr]];
$sia => how.sia ¬ TheINT[Car[p.cdr]];
$simplelen => how.simpleLen ¬ TheINT[Car[p.cdr]];
$simplequote => how.simpleQuote ¬ True[Car[p.cdr]];
ENDCASE => RETURN [$Failure, Rope.Concat["unrecognized spec: ", Fmt[spec]]];
ENDCASE => RETURN [$Failure, Rope.Concat["unrecognized spec: ", Fmt[spec]]];
 
REPEAT
Abort => RETURN [$Failure, msg.Cat["; ", barfum].Substr[2]];
 
ENDLOOP;
 
{h: UB.Handle ~ UB.Create[[margin: margin, output: [stream[cmd.out]] ]];
out: IO.STREAM ~ SS.Create[h];
cmd.out.PutF1["%l", [rope["f"]]];
DO
{arg: Any ~ Read[cmd.in];
IF arg=endOfFile THEN EXIT;
out.PutRope["\n"];
PrettyPrint[out, arg, how, NARROW[cmd.procData.clientData]];
out.PutRope["\n"];
}ENDLOOP;
 
cmd.out.PutF1["%l", [rope[" "]]];
IF msg#NIL THEN msg ¬ msg.Substr[2];
RETURN}};
defaultHow: How ¬ [];
defaultMargin: INT ¬ 80;
 
Fmt: 
PROC [a: Any] 
RETURNS [
ROPE] ~ {
buf: IO.STREAM ~ IO.ROS[];
Print[a, buf];
RETURN buf.RopeFromROS[]};
 
NoteProfile: 
PROC [reason: UserProfile.ProfileChangeReason] 
--UserProfile.ProfileChangedProc--~ {
defaultHow ¬ [
sia: UserProfile.Number["SchemePretty.sia", 2],
simpleLen: UserProfile.Number["SchemePretty.simpleLen", 2],
simpleQuote: UserProfile.Boolean["SchemePretty.simpleQuote", TRUE]
];
};
 
UserProfile.CallWhenProfileChanges[NoteProfile];
Commander.Register[key: "SchemePrettyPrintExpr", proc: Cmd, doc: "Pretty prints stdin to stdout", clientData: $expr];
Commander.Register[key: "SchemePrettyPrintData", proc: Cmd, doc: "Pretty prints stdin to stdout", clientData: $data];
END.