MesaAnalysesImpl.mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Mike Spreitzer May 15, 1992 2:57 pm PDT
DIRECTORY Atom, BasicTime, Convert, EditNotify, SymTab, IO, MesaAnalyses, MessageWindow, NodeProps, Rope, TDLexing, TextNode, TiogaStreams;
MesaAnalysesImpl: CEDAR PROGRAM
IMPORTS Atom, BasicTime, Convert, EditNotify, SymTab, IO, MessageWindow, NodeProps, Rope, TDLexing, TextNode, TiogaStreams
EXPORTS MesaAnalyses
=
BEGIN OPEN MesaAnalyses;
analysisProp: ATOM ¬ Atom.MakeAtom[IO.PutFR1["MesaAnalysesImpl, loaded at %g, analysisProp", [time[BasicTime.Now[]]]]];
debug: BOOL ¬ FALSE;
Invalidate: PROC [root: TiogaNode] = {
NodeProps.PutProp[root, analysisProp, NIL];
IF debug THEN MessageWindow.Append["Flushing a Mesa Analysis", TRUE];
};
AnalysisFromRoot: PROC [root: TiogaNode] RETURNS [MesaAnalysis] ~ {
IF root=NIL THEN RETURN [NIL];
RETURN [NARROW[NodeProps.GetProp[root, analysisProp]]]};
EventWatcher: PROC [change: REF READONLY EditNotify.Change] --EditNotify.EditNotifyProc-- = {
WITH change SELECT FROM
x: REF READONLY ChangingView EditNotify.Change => NULL;
x: REF READONLY ChangingText EditNotify.Change => {
root: TiogaNode ~ TextNode.Root[x.text];
ma: MesaAnalysis ¬ AnalysisFromRoot[root];
IF ma # NIL THEN {
startPosition: INT = TextNode.LocOffset[[root, 0], [x.text, x.start]];
IF startPosition <= ma.prefixEnd THEN Invalidate[root];
};
};
x: REF READONLY ChangingSpanForPaste EditNotify.Change => NULL;
x: REF READONLY ChangingProp EditNotify.Change => IF x.name = NodeProps.nameComment THEN {
root: TiogaNode ~ TextNode.Root[x.node];
ma: MesaAnalysis ¬ AnalysisFromRoot[root];
IF ma # NIL THEN {
startPosition: INT = TextNode.LocOffset[[root, 0], [x.node, 0]];
IF startPosition <= ma.prefixEnd THEN Invalidate[root];
};
};
x: REF READONLY MovingNodes EditNotify.Change => NULL--wrong, but I don't understand this kind, and it probably won't happen anyway--;
x: REF READONLY NodeNesting EditNotify.Change => NULL;
x: REF READONLY InsertingNode EditNotify.Change => {
root: TiogaNode ~ TextNode.Root[x.dest];
ma: MesaAnalysis ¬ AnalysisFromRoot[root];
IF ma # NIL THEN {
startPosition: INT = TextNode.LocOffset[[root, 0], [x.new, 0]];
IF startPosition <= ma.prefixEnd THEN Invalidate[root];
};
};
ENDCASE => ERROR;
};
GetAnalysis: PUBLIC PROC [doc: TiogaNode, docName: ROPE, verbose: BOOL] RETURNS [ma: MesaAnalysis] = {
ma ¬ NARROW[NodeProps.GetProp[doc, analysisProp]];
IF ma # NIL THEN RETURN;
IF verbose THEN MessageWindow.Append[Rope.Cat["Analyzing ", docName, " ..."], TRUE];
ma ¬ Analyze[doc, docName];
IF verbose THEN MessageWindow.Append[" done", FALSE];
NodeProps.PutProp[doc, analysisProp, ma];
};
SyntaxError: ERROR = TDLexing.SyntaxError;
Token: TYPE = TDLexing.Token;
Analyze: PROC [doc: TiogaNode, docName: ROPE] RETURNS [ma: MesaAnalysis] = {
in: IO.STREAM = TiogaStreams.CreateInput[doc, [FALSE[]] ];
l: TDLexing.Lexer = TDLexing.MakeLexer[in, GetSourcePosition];
AddIT: PROC [namePos: PositionRange, name, typeClass, fileHint: ROPE, usingList: SymbolTable] RETURNS [it: InterfaceType] = {
it ¬ NEW [InterfaceTypePrivate ¬ [namePos, name, typeClass, fileHint, usingList]];
[] ¬ ma.interfaceTypes.Store[it.name, it];
[] ¬ ma.globalDefs.Store[it.name, it];
};
AddIR: PROC [namePos: PositionRange, name: ROPE, it: InterfaceType] RETURNS [ir: InterfaceRecord] = {
ir ¬ NEW [InterfaceRecordPrivate ¬ [namePos, name, it]];
[] ¬ ma.interfaceRecords.Store[ir.name, ir];
[] ¬ ma.globalDefs.Store[ir.name, ir];
};
EnsureIT: PROC [namePos: PositionRange, itName: ROPE] RETURNS [it: InterfaceType] = {
it ¬ NARROW[ma.interfaceTypes.Fetch[itName].val];
IF it = NIL THEN it ¬ AddIT[namePos, itName, itName, itName.Concat[".mesa"], NIL];
};
EnsureIR: PROC [namePos: PositionRange, irName: ROPE] RETURNS [ir: InterfaceRecord] = {
ir ¬ NARROW[ma.interfaceRecords.Fetch[irName].val];
IF ir = NIL THEN {
it: InterfaceType = EnsureIT[namePos, irName];
ir ¬ AddIR[namePos, irName, it];
};
};
ParseDirectory: PROC = {
toke: Token = l.GetToken[];
IF NOT toke.rope.Equal["DIRECTORY"] THEN {l.ReturnToken[toke]; RETURN};
DO
name, class, fileHint: ROPE;
usingList: SymbolTable ¬ NIL;
namePos: PositionRange ¬ [l.GetPosition[beforeNext], 0];
name ¬ class ¬ l.GetRope[tokenID];
namePos.after ¬ l.GetPosition[afterLast];
fileHint ¬ name.Concat[".mesa"];
IF l.NextIs[":"] THEN SELECT l.GetKwd[] FROM
$TYPE => {
toke2: Token = l.GetToken[];
IF toke2.kind = tokenID AND NOT TDLexing.ReservedWord[toke2.rope]
THEN class ¬ toke2.rope
ELSE l.ReturnToken[toke2];
};
$FROM => fileHint ¬ Convert.RopeFromLiteral[l.GetRope[tokenROPE]];
ENDCASE => SyntaxError[];
IF l.NextIs["USING"] THEN {
usingList ¬ CreateSymbolTable[];
IF NOT l.NextIs["["] THEN SyntaxError[];
IF NOT l.NextIs["]"] THEN {
DO
eltName: ROPE = l.GetRope[tokenID];
[] ¬ usingList.Insert[eltName, $T];
IF NOT l.NextIs[","] THEN EXIT;
ENDLOOP;
IF NOT l.NextIs["]"] THEN SyntaxError[];
};
};
{it: InterfaceType = AddIT[namePos, name, class, fileHint, usingList];
ir: InterfaceRecord = AddIR[namePos, name, it];
IF NOT l.NextIs[","] THEN EXIT;
}ENDLOOP;
IF NOT l.NextIs[";"] THEN SyntaxError[];
};
ParseModuleType: PROC RETURNS [mt: ModuleType] = {
IF l.NextIs["DEFINITIONS"] THEN RETURN [defs];
IF l.NextIsA[LIST["SAFE", "UNSAFE"]] THEN NULL;
IF l.NextIs["PROGRAM"] THEN mt ¬ prog
ELSE IF l.NextIs["MONITOR"] THEN mt ¬ monitor
ELSE SyntaxError[];
};
ParseImports: PROC = {
IF NOT l.NextIs["IMPORTS"] THEN RETURN;
DO
irName: ROPE;
namePos: PositionRange ¬ [l.GetPosition[beforeNext], 0];
irName ¬ l.GetRope[tokenID];
namePos.after ¬ l.GetPosition[afterLast];
IF l.NextIs[":"] THEN {
itName: ROPE;
itNamePos: PositionRange ¬ [l.GetPosition[beforeNext], 0];
itName ¬ l.GetRope[tokenID];
itNamePos.after ¬ l.GetPosition[afterLast];
{it: InterfaceType = EnsureIT[itNamePos, itName];
[] ¬ AddIR[namePos, irName, it];
}};
IF NOT l.NextIs[","] THEN EXIT;
ENDLOOP;
};
ParseOpen: PROC = {
IF NOT l.NextIs["OPEN"] THEN {
ma.bodyStart ¬ l.GetPosition[afterLast];
[] ¬ l.GetToken[];
ma.prefixEnd ¬ l.GetPosition[afterLast]+1;
RETURN;
};
DO
n1: ROPE;
namePos: PositionRange ¬ [l.GetPosition[beforeNext], 0];
n1 ¬ l.GetRope[tokenID];
namePos.after ¬ l.GetPosition[afterLast];
IF l.NextIsA[LIST[":", "~~"]] THEN {
n2: Token = l.GetToken[];
IF n2.kind # tokenID THEN SyntaxError;
{it: InterfaceType = EnsureIT[[n2.before, n2.after], n2.rope];
[] ¬ AddIR[namePos, n1, it];
}}
ELSE {
ir: InterfaceRecord = EnsureIR[namePos, n1];
IF ir.type.usingList # NIL THEN {
AddElt: PROC [key, val: REF ANY] RETURNS [quit: BOOL ¬ FALSE]--SymTab.EachPairAction-- = {
eltName: ROPE = NARROW[key];
ie: InterfaceElement = NEW [InterfaceElementPrivate ¬ [eltName, ir]];
[] ¬ ma.interfaceElements.Store[eltName, ie];
[] ¬ ma.globalDefs.Store[eltName, ie];
};
[] ¬ ir.type.usingList.Pairs[AddElt];
}
ELSE {
ma.openedWithoutUsingList ¬ CONS[ir, ma.openedWithoutUsingList];
};
};
IF NOT l.NextIs[","] THEN EXIT;
ENDLOOP;
IF NOT l.NextIs[";"] THEN SyntaxError[];
ma.bodyStart ¬ ma.prefixEnd ¬ l.GetPosition[afterLast];
};
ma ¬ NEW [MesaAnalysisPrivate ¬ [
moduleType: defs,
globalDefs: CreateSymbolTable[],
interfaceRecords: CreateSymbolTable[],
interfaceTypes: CreateSymbolTable[],
interfaceElements: CreateSymbolTable[],
bodyStart: 0, prefixEnd: 0
]];
{ENABLE SyntaxError => {
MessageWindow.Append[
message: IO.PutFR["Syntax error in %g before %g", [rope[docName]], [integer[l.GetPosition[afterLast]]]],
clearFirst: TRUE];
ma.bodyStart ¬ ma.prefixEnd ¬ l.GetPosition[beforeNext];
CONTINUE;
};
ParseDirectory[];
ma.moduleName ¬ l.GetRope[tokenID];
IF NOT l.NextIs[":"] THEN SyntaxError[];
IF l.NextIs["CEDAR"] THEN NULL;
ma.moduleType ¬ ParseModuleType[];
l.SkipTo[LIST["IMPORTS", "SHARES", "~", "="]];
ParseImports[];
l.SkipTo[LIST["~", "="]];
IF NOT l.NextIsA[LIST["~", "="]] THEN ERROR;
IF l.NextIsA[LIST["PUBLIC", "PRIVATE"]] THEN NULL;
IF ma.moduleType # defs AND l.NextIsA[LIST["CHECKED", "TRUSTED", "UNCHECKED"]] THEN NULL;
IF NOT l.NextIsA[LIST["BEGIN", "{"]] THEN SyntaxError[];
ParseOpen[];
};
};
GetSourcePosition: PROC [in: IO.STREAM] RETURNS [index: INT]--TDLexing.IndexGetter-- = {
loc: TextNode.Location = TiogaStreams.CurInLoc[in];
index ¬ TextNode.LocNumber[loc];
};
CreateSymbolTable: PROC RETURNS [st: SymbolTable] = {
st ¬ SymTab.Create[case: TRUE]};
EditNotify.AddNotifyProc[EventWatcher, after, low];
END.