PrintTypeStringImpl.mesa
Copyright Ó 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Last tweaked by Mike Spreitzer on March 3, 1992 9:56 am PST
Michael Plass, May 21, 1992 1:12 am PDT
Russ Atkinson (RRA) November 21, 1991 3:46 pm PST
DIRECTORY Card2Tab, Commander, CommanderOps, Convert, ConvertUnsafe, IO, MesaLoadState, MesaLoadStateBackdoor, MobDefs, PFSNames, PrintTypeString, Rope, SafeStorage, StructuredStreams, SymTab, TypeStrings, UnparserBuffer, VersionMap2, VersionMap2Binding;
PrintTypeStringImpl: CEDAR PROGRAM
IMPORTS Card2Tab, Commander, CommanderOps, Convert, ConvertUnsafe, IO, MesaLoadState, MesaLoadStateBackdoor, PFSNames, Rope, StructuredStreams, SymTab, UnparserBuffer, VersionMap2, VersionMap2Binding
EXPORTS PrintTypeString
SHARES Rope
= BEGIN OPEN PrintTypeString, SS:StructuredStreams, TS:TypeStrings, UB:UnparserBuffer, VM2:VersionMap2;
Defs: TYPE ~ REF DefsPrivate;
DefsPrivate: TYPE ~ ARRAY CHAR OF INT;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Malformed: PUBLIC ERROR [i: INT, why: ROPE] ~ CODE;
vsToName: Card2Tab.Ref ~ Card2Tab.Create[];
ToRope: PUBLIC PROC [ts: ROPE] RETURNS [ROPE] ~ {
buff: STREAM ~ IO.ROS[];
ToStream[buff, ts];
RETURN IO.RopeFromROS[buff]};
ToStream: PUBLIC PROC [to: STREAM, ts: ROPE] ~ {
defs: Defs = NEW [DefsPrivate ¬ ALL[INT.FIRST]];
Work: PROC ~ {
after: INT ¬ PrintType[to, defs, ts, 0];
IF after # ts.Length[] THEN Malformed[after, "didn't consume whole string"];
FOR name: CHAR IN CHAR DO
IF defs[name] # INT.FIRST THEN {
to.PutRope[";"];
SS.Bp[to, united, 0, " "];
to.PutF1["T%g: TYPE = ", [cardinal[name.ORD]] ];
[] ¬ PrintType[to, defs, ts, defs[name]];
}
ENDLOOP;
RETURN};
PrintObj[to, Work];
};
GetChar: PROC [ts: ROPE, i: INT] RETURNS [c: CHAR] ~ {
WITH ts SELECT FROM
text: Rope.Text => IF i IN [0..text.length) THEN RETURN [text[i]];
ENDCASE => IF i IN [0..Rope.Length[ts]) THEN RETURN [Rope.Fetch[ts, i]];
ERROR Malformed[i, "ran off end"];
};
PrintObj: PROC [to: STREAM, obj: PROC] ~ {
SS.Begin[to];
obj[!UNWIND => SS.End[to]];
SS.End[to];
};
PrintType: PROC [to: STREAM, defs: Defs, ts: ROPE, i: INT] RETURNS [INT] ~ {
byte: NAT ~ GetChar[ts, i].ORD;
code: TS.Code ¬ definition;
SELECT byte FROM
< TS.Code.FIRST.ORD => Malformed[i, "too-small code"];
300B => {to.PutRope["SX-Val"]; RETURN [i.SUCC]};
> TS.Code.LAST.ORD => Malformed[i, "too-large code"];
ENDCASE => code ¬ VAL[byte];
SELECT code FROM
definition => {
name: CHAR ~ GetChar[ts, i.SUCC];
IF defs[name] # INT.FIRST THEN Malformed[i, "double def"];
defs[name] ¬ i+2;
to.PutF1["T%g", [cardinal[name.ORD]] ];
RETURN PrintType[IO.noWhereStream, defs, ts, i+2]};
name => {
name: CHAR ~ GetChar[ts, i.SUCC];
IF defs[name] = INT.FIRST THEN Malformed[i, "undefined name"];
to.PutF1["T%g", [cardinal[name.ORD]] ];
RETURN [i+2]};
boolean => {to.PutRope["BOOL"]; RETURN [i.SUCC]};
enumerated => {
j: INT ¬ i+2; first: BOOL ¬ TRUE;
PrintEnum: PROC ~ {
to.PutRope["{"];
UNTIL GetChar[ts, j].ORD = TS.Code.rightParen.ORD DO
name: ROPE; j2, j3: INT; rep: CARD;
[name, j2] ¬ GetName[ts, j];
[rep, j3] ¬ GetCard[ts, j2];
IF first THEN first ¬ FALSE ELSE {to.PutChar[',]; SS.Bp[to, lookLeft, 3, " "]};
to.PutF["%g(%g)", [rope[name]], [cardinal[rep]] ];
j ¬ j3; ENDLOOP;
to.PutRope["}"]};
IF GetChar[ts, i.SUCC].ORD # TS.Code.leftParen.ORD THEN
ERROR Malformed[i, "enumerated not followed by leftParen"];
PrintObj[to, PrintEnum];
RETURN [j.SUCC];
};
paint => RETURN PrintPaint[to, ts, i.SUCC, FALSE];
text => {to.PutRope["TEXT"]; RETURN [i.SUCC]};
stringBody => {to.PutRope["StringBody"]; RETURN [i.SUCC]};
leftParen => {
PrintRecord: PROC ~ {first: BOOL ¬ TRUE;
i ¬ i.SUCC;
UNTIL GetChar[ts, i].ORD = TS.Code.rightParen.ORD DO
IF first THEN first ¬ FALSE ELSE {to.PutChar[',]; SS.Bp[to, united, 0, " "]};
i ¬ PrintField[to, defs, ts, i];
ENDLOOP;
to.PutRope["]"]};
to.PutRope["["];
PrintObj[to, PrintRecord];
RETURN [i.SUCC];
};
union => RETURN PrintPaint[to, ts, i.SUCC, FALSE];
packed => {to.PutRope["PACKED "]; RETURN PrintType[to, defs, ts, i.SUCC]};
array => RETURN PrintBinary[to, defs, ts, i.SUCC, "ARRAY ", "OF ", FALSE];
sequence => {
i2, i3: INT ¬ 0;
SeqObj: PROC ~ {
to.PutRope["SEQUENCE "];
i2 ¬ PrintField[to, defs, ts, i.SUCC];
SS.Bp[to, united, 2, " "];
to.PutRope["OF "];
i3 ¬ PrintType[to, defs, ts, i2]};
PrintObj[to, SeqObj];
RETURN [i3];
};
subrange => {
SubObj: PROC ~ {
first, last: CARD ¬ 0;
i2: INT ¬ i.SUCC;
next: BYTE = GetChar[ts, i2].ORD;
signed: BOOL ¬ FALSE;
maybeByte: BOOL ¬ FALSE;
integerCode: BYTE = TS.Code[integer].ORD;
cardinalCode: BYTE = TS.Code[cardinal].ORD;
SELECT next FROM
integerCode, cardinalCode => i ¬ i2.SUCC;
ENDCASE => i ¬ PrintType[to, defs, ts, i2];
[first, i] ¬ GetCard[ts, i];
[last, i] ¬ GetCard[ts, i];
IF next = cardinalCode THEN {
IF first = 0 THEN SELECT last FROM
BYTE.LAST => {IO.PutRope[to, "BYTE"]; RETURN};
NAT15.LAST => {IO.PutRope[to, "NAT15"]; RETURN};
CARD16.LAST => {IO.PutRope[to, "CARD16"]; RETURN};
ENDCASE;
IO.PutRope[to, "CARDINAL"];
RETURN;
};
IF next = integerCode
AND LOOPHOLE[first, INTEGER] = INT16.FIRST
AND LOOPHOLE[last, INTEGER] = INT16.LAST THEN {
IO.PutRope[to, "INT16"];
RETURN;
};
IF next = integerCode
THEN IO.PutF1[to, "[%g", [integer[LOOPHOLE[first, INTEGER]]]]
ELSE IO.PutF1[to, "[%g", [cardinal[first]]];
IF next = integerCode
THEN IO.PutF1[to, "..%g]", [integer[LOOPHOLE[last, INTEGER]]]]
ELSE IO.PutF1[to, "..%g]", [cardinal[last]]];
};
PrintObj[to, SubObj];
RETURN [i];
};
atomRec => {to.PutRope["AtomRec"]; RETURN [i.SUCC]};
opaque => RETURN PrintPaint[to, ts, i.SUCC, TRUE];
mds => RETURN PrintUnary[to, defs, ts, i.SUCC, "MDS"];
countedZone => {to.PutRope["CountedZone"]; RETURN [i.SUCC]};
uncountedZone => {to.PutRope["UncountedZone"]; RETURN [i.SUCC]};
ordered => RETURN PrintUnary[to, defs, ts, i.SUCC, "ORDERED"];
readOnly => RETURN PrintUnary[to, defs, ts, i.SUCC, "READONLY"];
list => RETURN PrintUnary[to, defs, ts, i.SUCC, "LIST OF"];
relativeRef => RETURN PrintBinary[to, defs, ts, i.SUCC, NIL, "RELATIVE"];
refAny => {to.PutRope["REF"]; RETURN [i.SUCC]};
ref => RETURN PrintUnary[to, defs, ts, i.SUCC, "REF"];
var => RETURN PrintUnary[to, defs, ts, i.SUCC, "VAR"];
pointer => RETURN PrintUnary[to, defs, ts, i.SUCC, "POINTER TO"];
longPointer => RETURN PrintUnary[to, defs, ts, i.SUCC, "LONG POINTER TO"];
descriptor => RETURN PrintUnary[to, defs, ts, i.SUCC, "DESCRIPTOR FOR"];
longDescriptor => RETURN PrintUnary[to, defs, ts, i.SUCC, "LONG DESCRIPTOR FOR"];
procedure => RETURN PrintTransfer[to, defs, ts, i.SUCC, "UNSAFE PROC "];
safeProc => RETURN PrintTransfer[to, defs, ts, i.SUCC, "SAFE PROC "];
safe => RETURN PrintUnary[to, defs, ts, i.SUCC, "SAFE"];
port => RETURN PrintTransfer[to, defs, ts, i.SUCC, "PORT "];
program => RETURN PrintTransfer[to, defs, ts, i.SUCC, "PROGRAM "];
signal => RETURN PrintTransfer[to, defs, ts, i.SUCC, "SIGNAL "];
error => RETURN PrintTransfer[to, defs, ts, i.SUCC, "ERROR "];
process => RETURN PrintUnary[to, defs, ts, i.SUCC, "PROCESS RETURNS"];
cardinal => {to.PutRope["CARDINAL"]; RETURN [i.SUCC]};
integer => {to.PutRope["INTEGER"]; RETURN [i.SUCC]};
character => {to.PutRope["CHAR"]; RETURN [i.SUCC]};
longInteger => {to.PutRope["INT"]; RETURN [i.SUCC]};
longCardinal => {to.PutRope["CARD"]; RETURN [i.SUCC]};
real => {to.PutRope["REAL"]; RETURN [i.SUCC]};
type => {to.PutRope["TYPE"]; RETURN [i.SUCC]};
any => {to.PutRope["ANY"]; RETURN [i.SUCC]};
unspecified => {to.PutRope["UNSPECIFIED"]; RETURN [i.SUCC]};
longUnspecified => {to.PutRope["LONG UNSPECIFIED"]; RETURN [i.SUCC]};
dcard => {to.PutRope["DCARD"]; RETURN [i.SUCC]};
dint => {to.PutRope["DINT"]; RETURN [i.SUCC]};
dreal => {to.PutRope["DREAL"]; RETURN [i.SUCC]};
globalFrame, localFrame => Malformed[i, "got a frame"];
ENDCASE => Malformed[i, "unrecognized code"]};
PrintTransfer: PROC
[to: STREAM, defs: Defs, ts: ROPE, i: INT, head: ROPE] RETURNS [INT] ~ {
RETURN PrintBinary[to, defs, ts, i, head, "RETURNS"];
};
PrintUnary: PROC [to: STREAM, defs: Defs, ts: ROPE, i: INT, head: ROPE] RETURNS [INT] ~ {
i2: INT ¬ 0;
Objer: PROC ~ {
to.PutRope[head];
SS.Bp[to, united, 2, " "];
i2 ¬ PrintType[to, defs, ts, i];
RETURN};
PrintObj[to, Objer];
RETURN [i2];
};
PrintBinary: PROC
[to: STREAM, defs: Defs, ts: ROPE, i: INT, head, mid: ROPE, b2: BOOL ¬ TRUE]
RETURNS [INT] ~ {
i2, i3: INT ¬ 0;
Objer: PROC ~ {
to.PutRope[head];
i2 ¬ PrintType[to, defs, ts, i];
SS.Bp[to, united, 1, " "];
to.PutRope[mid];
IF b2 THEN SS.Bp[to, united, 2, " "];
i3 ¬ PrintType[to, defs, ts, i2];
};
PrintObj[to, Objer];
RETURN [i3];
};
PrintField: PROC [to: STREAM, defs: Defs, ts: ROPE, i: INT] RETURNS [INT] ~ {
name: ROPE;
i2, i3: INT ¬ 0;
FieldObj: PROC ~ {
to.PutRope[name];
to.PutRope[":"];
SS.Bp[to, united, 2, " "];
i3 ¬ PrintType[to, defs, ts, i2];
};
[name, i2] ¬ GetName[ts, i];
PrintObj[to, FieldObj];
RETURN [i3];
};
PrintPaint: PROC [to: STREAM, ts: ROPE, i: INT, isOpaque: BOOL] RETURNS [INT] ~ {
vs: MobDefs.VersionStamp;
i2, i3, i4: INT;
IF isOpaque THEN {mod, name: ROPE;
[name, i2] ¬ GetName[ts, i];
[vs[0], i3] ¬ GetCard[ts, i2];
[vs[1], i4] ¬ GetCard[ts, i3];
mod ¬ DescribeModule[vs];
to.PutF["%g.%g", [rope[mod]], [rope[name]] ];
RETURN [i4]}
ELSE {mod: ROPE; ctx: CARD;
[vs[0], i2] ¬ GetCard[ts, i];
[vs[1], i3] ¬ GetCard[ts, i2];
mod ¬ DescribeModule[vs];
[ctx, i4] ¬ GetCard[ts, i3];
to.PutF["%g.%g", [rope[mod]], [cardinal[ctx]] ];
RETURN [i4]}};
DescribeModule: PROC [vs: MobDefs.VersionStamp] RETURNS [ROPE] ~ {
ans: ROPE;
Update: PROC [found: BOOL, val: REF ANY] RETURNS [op: Card2Tab.UpdateOperation, new: REF ANY] ~ {
IF found THEN {
ans ¬ NARROW[val];
RETURN [none, NIL]}
ELSE {
ints: VM2.Map ~ VersionMap2Binding.GetMap["Intermediate"];
syms: SymTab.Ref ~ SymTab.Create[case: FALSE];
PerMatch: PROC [vt: VM2.VersionTuple] RETURNS [BOOL] ~ {
lc: PFSNames.Component ~ vt.name.ShortName[];
snr: ROPE ~ lc.ComponentRope[--no version part wanted or expected--];
dp: INT ~ snr.Index[s2: "."];
base: ROPE ~ snr.Substr[len: dp];
[] ¬ syms.Insert[ans ¬ base, $T];
RETURN [syms.GetSize[] > 1]};
[] ¬ ints.ScanMatches[PerMatch, FALSE, [stamp: vs]];
SELECT syms.GetSize[] FROM
1 => ans ¬ ans;
ENDCASE => ans ¬ IO.PutFR["%08x%08x", [cardinal[vs[0]]], [cardinal[vs[1]]] ];
RETURN [store, ans]};
};
vsToName.Update[vs, Update];
RETURN [ans]};
GetName: PROC [ts: ROPE, i: INT] RETURNS [name: ROPE, j: INT] ~ {
len: INT ~ GetChar[ts, i].ORD;
GenChar: PROC RETURNS [CHAR] ~ {j ¬ j.SUCC; RETURN [GetChar[ts, j]]};
IF len=0 THEN RETURN ["null name", i.SUCC];
IF len >= 200B THEN Malformed[i, "implausible name"];
j ¬ i;
name ¬ Rope.FromProc[len, GenChar];
j ¬ j.SUCC;
IF name.Fetch[0].ORD = len-1 THEN name ¬ name.Substr[start: 1];
};
b8: CARD = 256;
GetCard: PROC [ts: ROPE, i: INT] RETURNS [card: CARD, j: INT] ~ {
encodeMod: NAT = 64;
c1: NAT ~ GetChar[ts, i].ORD;
SELECT c1 FROM
< encodeMod*1 => RETURN [c1, i+1];
< encodeMod*2 => RETURN [256*(c1-encodeMod*1) + GetChar[ts, i+1].ORD, i+2];
< encodeMod*3 => RETURN [65536*(c1-encodeMod*2) + b8*GetChar[ts, i+1].ORD + GetChar[ts, i+2].ORD, i+3];
> encodeMod*3 => RETURN [CARD.LAST-(c1-encodeMod*3-1), i+1];
ENDCASE => RETURN [GetChar[ts, i+4].ORD + b8 * (
GetChar[ts, i+3].ORD + b8 * (
GetChar[ts, i+2].ORD + b8 * (
GetChar[ts, i+1].ORD))), i+5]};
FlushCommand: Commander.CommandProc ~ {vsToName.Erase[]; RETURN};
PrintTypeStringCommand: PROC [cmd: Commander.Handle] RETURNS [result: REF ANY ¬ NIL, msg: ROPE ¬ NIL] --Commander.CommandProc-- ~ {
buff: UB.Handle ~ UB.NewInittedHandle[[margin: 60, output: [stream[cmd.out]] ]];
sout: STREAM ~ SS.Create[buff];
argv: CommanderOps.ArgumentVector;
argv ¬ CommanderOps.Parse[cmd];
IF argv.argc < 2 THEN CommanderOps.Failed[cmd.procData.doc];
FOR i: NAT IN (0 .. argv.argc) DO
ts: ROPE ~ argv[i];
sout.PutF1["\"%q\" <->", [rope[ts]] ];
SS.Bp[sout, width, 0, " "];
ToStream[sout, ts !Malformed => {
cmd.err.PutF["!Malformed (%g) at %g", [rope[why]], [integer[i]] ];
CONTINUE}];
sout.PutRope[".\n"];
ENDLOOP;
RETURN
};
PrintTypeCodeCommand: Commander.CommandProc ~ {
ENABLE Convert.Error => CommanderOps.Failed[cmd.procData.doc];
arg0: ROPE ~ CommanderOps.NextArgument[cmd];
IF arg0 = NIL THEN CommanderOps.Failed[cmd.procData.doc];
FOR arg: ROPE ¬ arg0, CommanderOps.NextArgument[cmd] UNTIL arg = NIL DO
tc: CARD ~ Convert.CardFromRope[arg];
typeString: STRING ~ MesaLoadState.TypeStringFromType[VAL[MIN[tc, SafeStorage.TypeIndex.LAST]]];
IF typeString = NIL
THEN { IO.PutF1[cmd.err, "Bad typecode %g\n", [cardinal[tc]]] }
ELSE { ToStream[cmd.out, ConvertUnsafe.ToRope[typeString]] };
IO.PutChar[cmd.out, '\n];
ENDLOOP;
};
TypeStringFromTypeCmd: Commander.CommandProc ~ {
ENABLE Convert.Error => CommanderOps.Failed[cmd.procData.doc];
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
IF argv.argc # 2 THEN CommanderOps.Failed["Usage: MLS.TypeStringFromType typecode"];
{tc: CARD ~ Convert.CardFromRope[argv[1]];
ts: STRING ¬ MesaLoadState.TypeStringFromType[VAL[tc]];
cmd.out.PutF1["\"%q\"\n", [rope[ConvertUnsafe.ToRope[ts]]] ];
RETURN}};
TypeFromTypeStringCmd: Commander.CommandProc ~ {
ENABLE Convert.Error => CommanderOps.Failed[cmd.procData.doc];
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
IF argv.argc # 2 THEN CommanderOps.Failed["Usage: MLS.TypeFromTypeString typestring"];
{trt: REF TEXT ~ Rope.ToRefText[argv[1]];
sst: SafeStorage.Type;
sst ¬ MesaLoadState.TypeFromTypeString[LOOPHOLE[trt]];
cmd.out.PutF1["%g\n", [cardinal[sst.ORD]] ];
RETURN}};
ConcreteTypeFromAbstractTypeCmd: Commander.CommandProc ~ {
ENABLE Convert.Error => CommanderOps.Failed[cmd.procData.doc];
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
IF argv.argc # 2 THEN CommanderOps.Failed["Usage: MLS.ConcreteTypeFromAbstractType typecode"];
{atc: CARD ~ Convert.CardFromRope[argv[1]];
csst: SafeStorage.Type ~ MesaLoadState.ConcreteTypeFromAbstractType[VAL[atc]];
cmd.out.PutF1["%g\n", [cardinal[csst.ORD]] ];
RETURN}};
BTypeStringFromTypeCmd: Commander.CommandProc ~ {
ENABLE Convert.Error => CommanderOps.Failed[cmd.procData.doc];
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
IF argv.argc # 2 THEN CommanderOps.Failed["Usage: MLSB.TypeStringFromType typecode"];
{tc: CARD ~ Convert.CardFromRope[argv[1]];
ts: STRING ¬ MesaLoadStateBackdoor .UnmonitoredTypeStringFromType[VAL[tc]];
cmd.out.PutF1["\"%q\"\n", [rope[ConvertUnsafe.ToRope[ts]]] ];
RETURN}};
BTypeFromTypeStringCmd: Commander.CommandProc ~ {
ENABLE Convert.Error => CommanderOps.Failed[cmd.procData.doc];
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
IF argv.argc # 2 THEN CommanderOps.Failed["Usage: MLSB.TypeFromTypeString typestring"];
{trt: REF TEXT ~ Rope.ToRefText[argv[1]];
found: BOOL;
sst: SafeStorage.Type;
[found, sst] ¬ MesaLoadStateBackdoor .UnmonitoredFindTypeFromTypeString[ LOOPHOLE[trt]];
IF found
THEN cmd.out.PutF1["%g\n", [cardinal[sst.ORD]] ]
ELSE cmd.out.PutRope["not found\n"];
RETURN}};
Commander.Register["FlushTypeStringModuleCache", FlushCommand, "Flushes the cache for PrintTypeString/PrintTypeCode"];
Commander.Register["PrintTypeString", PrintTypeStringCommand, "Decodes a type string"];
Commander.Register["PrintTypeCode", PrintTypeCodeCommand, "Decodes SafeStorage.Type values"];
Commander.Register["MLS.TypeStringFromType", TypeStringFromTypeCmd, "typecode --- prints type string"];
Commander.Register["MLS.TypeFromTypeString", TypeFromTypeStringCmd, "string --- prints typecode"];
Commander.Register["MLS.ConcreteTypeFromAbstractType", ConcreteTypeFromAbstractTypeCmd, "abstract-typecode --- prints concrete-typecode"];
Commander.Register["MLSB.TypeStringFromType", BTypeStringFromTypeCmd, "typecode --- prints type string"];
Commander.Register["MLSB.TypeFromTypeString", BTypeFromTypeStringCmd, "string --- prints typecode"];
END.