MesaAnalysesImpl.mesa
Mike Spreitzer January 22, 1987 10:06:42 pm PST
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.PutFR["MesaAnalysesImpl, loaded at %g, analysisProp", [time[BasicTime.Now[]]]]];
debug: BOOLFALSE;
Invalidate: PROC [root: TiogaNode] = {
NodeProps.PutProp[root, analysisProp, NIL];
IF debug THEN MessageWindow.Append["Flushing a Mesa Analysis", TRUE];
};
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 => {
ma: MesaAnalysis ← NARROW[NodeProps.GetProp[x.root, analysisProp]];
IF ma # NIL THEN {
startPosition: INT = TextNode.LocOffset[[x.root, 0], [x.text, x.start]];
IF startPosition <= ma.prefixEnd THEN Invalidate[x.root];
};
};
x: REF READONLY ChangingTextForPaste EditNotify.Change => NULL;
x: REF READONLY ChangingSpanForPaste EditNotify.Change => NULL;
x: REF READONLY ChangingFormat EditNotify.Change => NULL;
x: REF READONLY ChangingProp EditNotify.Change => IF x.propAtom = $Comment THEN {
ma: MesaAnalysis ← NARROW[NodeProps.GetProp[x.root, analysisProp]];
IF ma # NIL THEN {
startPosition: INT = TextNode.LocOffset[[x.root, 0], [x.node, 0]];
IF startPosition <= ma.prefixEnd THEN Invalidate[x.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 => {
ma: MesaAnalysis ← NARROW[NodeProps.GetProp[x.root, analysisProp]];
IF ma # NIL THEN {
startPosition: INT = TextNode.LocOffset[[x.root, 0], [x.new, 0]];
IF startPosition <= ma.prefixEnd THEN Invalidate[x.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, discard];
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: BOOLFALSE]--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.