~
BEGIN
ROPE: TYPE ~ Rope.ROPE;
ConfigDependencies:
TYPE ~ MakoDependency.ConfigDependencies;
CDependsCommand: Commander.CommandProc ~ {
ENABLE PFS.Error => { IF error.group=user THEN CommanderOps.Failed[error.explanation] };
arg: ROPE ~ CommanderOps.NextArgument[cmd];
IF arg = NIL OR CommanderOps.NextArgument[cmd] # NIL THEN CommanderOps.Failed[cmd.procData.doc];
FOR tail:
LIST
OF
ROPE ¬ ParseCDependency[arg], tail.rest
UNTIL tail =
NIL
DO
IO.PutRope[cmd.out, tail.first];
IO.PutRope[cmd.out, " "];
ENDLOOP;
IO.PutRope[cmd.out, "\n"];
};
ParseCDependency:
PUBLIC
PROC [fileName:
ROPE]
RETURNS [list:
LIST
OF
ROPE ¬
NIL] ~ {
BUG: assumes UX directory. We get to let cpp do most of the work for us...
path: PFS.PATH ~ PFS.PathFromRope[IF Rope.Match["*.*", fileName] THEN fileName ELSE Rope.Concat[fileName, ".c"]];
uxname: ROPE ~ PFS.PFSNameToUnixName[path];
pos: INT ¬ 0;
size: INT ¬ 0;
lines: ROPE;
result: REF;
cmd: Commander.Handle ~ NARROW[ProcessProps.GetProp[$CommanderHandle]];
[out: lines, result: result] ¬ CommanderOps.DoCommandRope[commandLine: Rope.Concat["cc-M ", uxname], parent: cmd];
IF result = $Failure THEN CommanderOps.Failed["failed to derive dependency for c module"];
size ¬ Rope.Size[lines];
WHILE pos < size
DO
next: INT ¬ Rope.SkipTo[lines, pos, ": \n"];
IF Rope.Fetch[lines, next] # ':
AND Rope.Run[uxname, 0, lines, pos] # Rope.Size[uxname]
THEN {
list ¬ CONS[Rope.Substr[lines, pos, next-pos], list];
};
pos ¬ Rope.SkipOver[lines, next, ": \n"];
ENDLOOP;
};
MesaDependsCommand: Commander.CommandProc ~ {
ENABLE PFS.Error => { IF error.group=user THEN CommanderOps.Failed[error.explanation] };
arg: ROPE ~ CommanderOps.NextArgument[cmd];
IF arg = NIL OR CommanderOps.NextArgument[cmd] # NIL THEN CommanderOps.Failed[cmd.procData.doc];
FOR tail:
LIST
OF
ROPE ¬ ParseMesaDirectory[arg], tail.rest
UNTIL tail =
NIL
DO
IO.PutRope[cmd.out, tail.first];
IO.PutRope[cmd.out, " "];
ENDLOOP;
IO.PutRope[cmd.out, "\n"];
};
ParseMesaDirectory:
PUBLIC
PROC [fileName:
ROPE]
RETURNS [
LIST
OF
ROPE] ~ {
head: LIST OF ROPE ~ LIST[NIL];
last: LIST OF ROPE ¬ head;
stream: IO.STREAM ~ PFS.StreamOpen[fileName: PFS.PathFromRope[IF Rope.Match["*.*", fileName] THEN fileName ELSE Rope.Concat[fileName, ".mesa"]], accessOptions: $read];
Token: TYPE ~ {null, definitions, program, monitor, directory, from, type, using, cedar, unsafe, safe, semicolon, comma, colon, bracketleft, bracketright, id, string};
token: Token ¬ null;
text: REF TEXT ¬ RefText.ObtainScratch[100];
pos: INT ¬ 0;
Get:
PROC ~ {
tokenKind: IO.TokenKind; charsSkipped: INT; error: IO.TokenError;
pos ¬ pos + text.length;
token ¬ null;
[tokenKind: tokenKind, token: text, charsSkipped: charsSkipped, error: error] ¬ IO.GetCedarToken[stream: stream, buffer: text, flushComments: TRUE];
pos ¬ pos + charsSkipped;
IO.PutBlock[bug, text];
IO.PutBlock[bug, " "];
SELECT tokenKind
FROM
tokenID => {
SELECT
TRUE
FROM
RefText.Equal[text, "DEFINITIONS"] => {token ¬ definitions};
RefText.Equal[text, "PROGRAM"] => {token ¬ program};
RefText.Equal[text, "MONITOR"] => {token ¬ monitor};
RefText.Equal[text, "DIRECTORY"] => {token ¬ directory};
RefText.Equal[text, "FROM"] => {token ¬ from};
RefText.Equal[text, "TYPE"] => {token ¬ type};
RefText.Equal[text, "USING"] => {token ¬ using};
RefText.Equal[text, "CEDAR"] => {token ¬ cedar};
RefText.Equal[text, "UNSAFE"] => {token ¬ unsafe};
RefText.Equal[text, "SAFE"] => {token ¬ safe};
ENDCASE => {token ¬ id};
};
tokenSINGLE => {
SELECT text[0]
FROM
'; => token ¬ semicolon;
', => token ¬ comma;
': => token ¬ colon;
'[ => token ¬ bracketleft;
'] => token ¬ bracketright;
ENDCASE;
};
tokenROPE => {
token ¬ string;
};
ENDCASE;
};
Module:
PROC ~ {
Directory[];
IdentList[];
Cedar[];
IF token = definitions THEN Definitions[] ELSE ProgHead[];
};
Directory:
PROC ~ {
IF token = directory
THEN {
Get[];
IF token # semicolon THEN IncludeList[];
IF token = semicolon THEN Get[] ELSE Syntax[];
};
};
IncludeList:
PROC ~ {
IncludeItem[];
WHILE token = comma
DO
Get[];
IncludeItem[];
ENDLOOP;
};
IncludeItem:
PROC ~ {
IF token # id
THEN Syntax[]
ELSE {
name: ROPE ¬ Rope.FromRefText[text];
Get[];
SELECT token
FROM
using => Using[];
colon => {
Get[];
SELECT token
FROM
from => {
Get[];
IF token#string THEN Syntax[];
Get[];
Using[];
};
type => {
Get[];
IF token = id THEN { Get[]; };
Using[];
};
ENDCASE => Syntax[];
};
ENDCASE;
last ¬ last.rest ¬ LIST[name];
};
};
Using:
PROC ~ {
IF token = using
THEN {
Get[];
IF token#bracketleft THEN Syntax[];
Get[];
IF token#bracketright THEN IdList[];
IF token=bracketright THEN Get[] ELSE Syntax[];
};
};
IdList:
PROC ~ {
IdItem[];
WHILE token = comma
DO
Get[];
IdItem[];
ENDLOOP;
};
IdItem:
PROC ~ {
IF token # id THEN Syntax[];
Get[];
};
IdentList:
PROC ~ {
IdList[];
IF token = colon THEN Get[] ELSE Syntax[];
};
Cedar:
PROC ~ {
IF token = cedar THEN Get[];
};
Definitions:
PROC ~ {
IF token = definitions THEN Get[] ELSE Syntax[];
};
ProgHead:
PROC ~ {
IF token = safe OR token = unsafe THEN Get[];
IF token = program OR token = monitor THEN Get[] ELSE Syntax[];
};
Syntax:
PROC ~ {
CommanderOps.Failed[IO.PutFR["Mesa syntax error (%g|%g)", [rope[PFS.RopeFromPath[PFS.GetName[PFS.OpenFileFromStream[stream]].fullFName]]], [integer[pos]]]];
};
Get[];
Module[];
RefText.ReleaseScratch[text];
IO.Close[stream];
RETURN [head.rest];
};
CMesaDependsCommand: Commander.CommandProc ~ {
ENABLE PFS.Error => { IF error.group=user THEN CommanderOps.Failed[error.explanation] };
arg: ROPE ~ CommanderOps.NextArgument[cmd];
IF arg =
NIL
OR CommanderOps.NextArgument[cmd] #
NIL
THEN CommanderOps.Failed[cmd.procData.doc]
ELSE {
d: MakoDependency.ConfigDependencies ¬ ParseCMesaDirectory[arg];
FOR tail:
LIST
OF
ROPE ¬ d.interfaces, tail.rest
UNTIL tail =
NIL
DO
IO.PutRope[cmd.out, tail.first];
IO.PutRope[cmd.out, " "];
ENDLOOP;
FOR tail:
LIST
OF
ROPE ¬ d.implementations, tail.rest
UNTIL tail =
NIL
DO
IO.PutRope[cmd.out, tail.first];
IO.PutRope[cmd.out, " "];
ENDLOOP;
};
IO.PutRope[cmd.out, "\n"];
};
ParseCMesaDirectory:
PUBLIC
PROC [fileName:
ROPE]
RETURNS [ConfigDependencies] ~ {
head: LIST OF ROPE ~ LIST[NIL];
last: LIST OF ROPE ¬ head;
dhead: LIST OF ROPE ~ LIST[NIL];
dlast: LIST OF ROPE ¬ dhead;
stream: IO.STREAM ~ PFS.StreamOpen[fileName: PFS.PathFromRope[IF Rope.Match["*.*", fileName] THEN fileName ELSE Rope.Concat[fileName, ".config"]], accessOptions: $read];
Token: TYPE ~ {null, id, string, comma, semicolon, colon, gets, tilde, bracketleft, bracketright, braceleft, braceright, period, directory, from, pack, configuration, imports, exports, control, begin, requests, static, dynamic, end, plus, then, links, code, frame, all};
token: Token ¬ null;
text: REF TEXT ¬ RefText.ObtainScratch[100];
pos: INT ¬ 0;
locals: LIST OF ROPE ¬ NIL;
NoteName:
PROC [name:
ROPE] ~ {
last ¬ last.rest ¬ LIST[name];
};
Note:
PROC ~ {
NoteName[SaveName[]];
};
SaveName:
PROC
RETURNS [
ROPE] ~ {
RETURN [
SELECT token
FROM
id => Rope.FromRefText[text],
string => Convert.RopeFromLiteral[RefText.TrustTextAsRope[text]],
ENDCASE => NIL]
};
Get:
PROC ~ {
tokenKind: IO.TokenKind; charsSkipped: INT; error: IO.TokenError;
pos ¬ pos + text.length;
token ¬ null;
[tokenKind: tokenKind, token: text, charsSkipped: charsSkipped, error: error] ¬ IO.GetCedarToken[stream: stream, buffer: text, flushComments: TRUE];
pos ¬ pos + charsSkipped;
IO.PutBlock[bug, text];
IO.PutBlock[bug, " "];
SELECT tokenKind
FROM
tokenID => {
IF text.length > 1
AND text[1]
IN ['a..'z]
THEN {token ¬ id}
ELSE {
SELECT
TRUE
FROM
RefText.Equal[text, "DIRECTORY"] => {token ¬ directory};
RefText.Equal[text, "FROM"] => {token ¬ from};
RefText.Equal[text, "PACK"] => {token ¬ pack};
RefText.Equal[text, "CONFIGURATION"] => {token ¬ configuration};
RefText.Equal[text, "CONFIG"] => {token ¬ configuration};
RefText.Equal[text, "IMPORTS"] => {token ¬ imports};
RefText.Equal[text, "EXPORTS"] => {token ¬ exports};
RefText.Equal[text, "CONTROL"] => {token ¬ control};
RefText.Equal[text, "BEGIN"] => {token ¬ begin};
RefText.Equal[text, "REQUESTS"] => {token ¬ requests};
RefText.Equal[text, "STATIC"] => {token ¬ static};
RefText.Equal[text, "DYNAMIC"] => {token ¬ dynamic};
RefText.Equal[text, "END"] => {token ¬ end};
RefText.Equal[text, "PLUS"] => {token ¬ plus};
RefText.Equal[text, "THEN"] => {token ¬ then};
RefText.Equal[text, "LINKS"] => {token ¬ links};
RefText.Equal[text, "CODE"] => {token ¬ code};
RefText.Equal[text, "FRAME"] => {token ¬ frame};
RefText.Equal[text, "ALL"] => {token ¬ all};
ENDCASE => {token ¬ id};
};
};
tokenSINGLE => {
SELECT text[0]
FROM
'; => token ¬ semicolon;
', => token ¬ comma;
': => token ¬ colon;
'[ => token ¬ bracketleft;
'] => token ¬ bracketright;
'{ => token ¬ braceleft;
'} => token ¬ braceright;
'= => token ¬ tilde;
'~ => token ¬ tilde;
ENDCASE;
};
tokenROPE => {
token ¬ string;
};
ENDCASE;
};
Source:
PROC ~ {
Directory[];
Packing[];
Config[];
};
Directory:
PROC ~ {
IF token = directory
THEN {
Get[];
IF token # semicolon THEN IncludeList[];
IF token = semicolon THEN Get[] ELSE Syntax[];
};
};
IncludeList:
PROC ~ {
IncludeItem[];
WHILE token = comma
DO
Get[];
IncludeItem[];
ENDLOOP;
};
IncludeItem:
PROC ~ {
IF token # id
THEN Syntax[]
ELSE {
name: ROPE ¬ SaveName[];
Get[];
SELECT token
FROM
colon => {
Get[];
SELECT token
FROM
from => {
Get[];
name ¬ SaveName[];
String[];
};
ENDCASE => Syntax[];
};
ENDCASE => Syntax[];
dlast ¬ dlast.rest ¬ LIST[name];
};
};
Packing:
PROC ~ {
WHILE token = pack
DO
Get[];
IdentList[];
ENDLOOP;
};
IdList:
PROC ~ {
IdItem[];
WHILE token = comma
DO
Get[];
IdItem[];
ENDLOOP;
};
IdItem:
PROC ~ {
IF token # id THEN Syntax[];
Get[];
};
IdentList:
PROC ~ {
IdList[];
IF token = colon THEN Get[] ELSE Syntax[];
};
Config:
PROC ~ {
IF token = id THEN { locals ¬ CONS[SaveName[], locals]; Get[] } ELSE Syntax[];
IF token = colon THEN Get[] ELSE Syntax[];
ConfigTail[];
};
ConfigTail:
PROC ~ {
save: LIST OF ROPE ~ locals;
start: LIST OF ROPE ~ last;
dstart: LIST OF ROPE ~ dlast;
IF token = configuration THEN Get[] ELSE Syntax[];
Links[];
Imports[];
Exports[];
Statics[];
Dynamics[];
Control[];
IF token = tilde THEN Get[] ELSE Syntax[];
Body[];
UNTIL locals = save
DO
hide: ROPE ~ locals.first;
FOR tail:
LIST
OF
ROPE ¬ start.rest, tail.rest
UNTIL tail =
NIL
DO
IF Rope.Equal[tail.first, hide] THEN { tail.first ¬ NIL };
ENDLOOP;
FOR tail:
LIST
OF
ROPE ¬ dstart.rest, tail.rest
UNTIL tail =
NIL
DO
IF Rope.Equal[tail.first, hide] THEN { tail.first ¬ NIL };
ENDLOOP;
locals ¬ locals.rest;
ENDLOOP;
};
Links:
PROC ~ {
IF token = links
THEN {
Get[];
IF token = colon THEN Get[] ELSE Syntax[];
IF token = code OR token = frame THEN Get[] ELSE Syntax[];
};
};
Imports:
PROC ~ {
IF token = imports
THEN {
Get[];
ItemList[];
};
};
Exports:
PROC ~ {
IF token = exports
THEN {
Get[];
ExportItemList[];
};
};
ItemList:
PROC ~ {
Item[];
WHILE token = comma
DO
Get[];
Item[];
ENDLOOP;
};
Item:
PROC ~ {
name: ROPE ¬ SaveName[];
IF token # id THEN Syntax[];
Get[];
IF token = colon
THEN {
Get[];
IF token = id THEN {name ¬ SaveName[]; Get[]} ELSE Syntax[];
};
dlast ¬ dlast.rest ¬ LIST[name];
};
ExportItemList:
PROC ~ {
ExportItem[];
WHILE token = comma
DO
Get[];
ExportItem[];
ENDLOOP;
};
ExportItem:
PROC ~ {
IF token = all THEN Get[] ELSE Item[];
};
Statics:
PROC ~ {
IF token = static THEN {Get[]; Requests[note: TRUE]};
};
Dynamics:
PROC ~ {
IF token = dynamic THEN {Get[]; Requests[note: FALSE]};
};
Requests:
PROC [note:
BOOL] ~ {
IF token = requests THEN Get[] ELSE Syntax[];
IF note THEN Note[];
String[];
WHILE token = comma
DO
Get[];
IF note THEN Note[];
String[];
ENDLOOP;
};
String:
PROC ~ {
IF token = string THEN Get[] ELSE Syntax[]
};
Control:
PROC ~ {
IF token = control THEN { Get[]; IdList[] };
};
Body:
PROC ~ {
SELECT token
FROM
begin => { Get[]; StatementList[]; IF token = end THEN Get[] ELSE Syntax[] };
braceleft => { Get[]; StatementList[]; IF token = braceright THEN Get[] ELSE Syntax[] };
ENDCASE => Syntax[];
};
StatementList:
PROC ~ {
Statement[];
WHILE token = semicolon
DO
WHILE token = semicolon DO Get[] ENDLOOP;
IF token = bracketleft OR token = id THEN Statement[];
ENDLOOP;
};
Statement:
PROC ~ {
name: ROPE ¬ NIL;
IF token = bracketleft
THEN {
Get[];
ItemList[];
IF token = bracketright THEN Get[] ELSE Syntax[];
IF token = gets THEN Get[] ELSE Syntax[];
name ¬ InterfaceOrModule[];
}
ELSE {
name ¬ SaveName[];
IF token # id THEN Syntax[];
Get[];
IF token = colon
THEN {
Get[];
IF token = id
THEN {name ¬ SaveName[]; Get[]}
ELSE { locals ¬ CONS[name, locals]; ConfigTail[]; RETURN };
};
SELECT token
FROM
gets => { Get[]; name ¬ InterfaceOrModule[] };
bracketright => { name ¬ NIL; ModuleTail[] };
links => { Links[] };
ENDCASE;
};
IF name # NIL THEN NoteName[name];
};
ModuleTail:
PROC ~ {
IF token # bracketright THEN Syntax[];
Get[];
IF token # bracketleft THEN IdList[];
IF token = bracketleft THEN Get[] ELSE Syntax[];
Links[];
};
InterfaceOrModule:
PROC
RETURNS [name:
ROPE ¬
NIL] ~ {
IF token # id THEN Syntax[];
name ¬ SaveName[];
Get[];
SELECT token
FROM
colon => {Get[]; IF token = id THEN {name ¬ SaveName[]; Get[]} ELSE Syntax[]; ModuleTail[] };
bracketright => { ModuleTail[] };
then, plus => { InterfaceTail[] };
ENDCASE;
};
InterfaceTail:
PROC ~ {
WHILE token = then
OR token = plus
DO
Get[];
IF token # id THEN Syntax[];
Note[];
Get[];
ENDLOOP;
};
Syntax:
PROC ~ {
CommanderOps.Failed[IO.PutFR["Configuration syntax error (%g|%g)", [rope[PFS.RopeFromPath[PFS.GetName[PFS.OpenFileFromStream[stream]].fullFName]]], [integer[pos]]]];
};
Get[];
Source[];
RefText.ReleaseScratch[text];
IO.Close[stream];
RETURN [[RopeList.Remove[dhead.rest, NIL], RopeList.Remove[head.rest, NIL]]];
};
MakeItDependsCommand: Commander.CommandProc ~ {
ENABLE PFS.Error => { IF error.group=user THEN CommanderOps.Failed[error.explanation] };
arg: ROPE ~ CommanderOps.NextArgument[cmd];
IF arg =
NIL
OR CommanderOps.NextArgument[cmd] #
NIL
THEN CommanderOps.Failed[cmd.procData.doc]
ELSE {
FOR tail:
LIST
OF
ROPE ¬ ParseMakeItDependency[arg], tail.rest
UNTIL tail =
NIL
DO
IO.PutRope[cmd.out, tail.first];
IO.PutRope[cmd.out, " "];
ENDLOOP;
};
IO.PutRope[cmd.out, "\n"];
};
GetLine:
PROC [stream:
IO.
STREAM]
RETURNS [
ROPE ¬
NIL] ~ {
ENABLE IO.EndOfStream => CONTINUE;
RETURN [IO.GetLineRope[stream]]
};
ParseMakeItDependency:
PUBLIC
PROC [fileName:
ROPE]
RETURNS [
LIST
OF
ROPE] ~ {
head: LIST OF ROPE ~ LIST[NIL];
last: LIST OF ROPE ¬ head;
stream: IO.STREAM ~ PFS.StreamOpen[PFS.PathFromRope[fileName]];
FOR line:
ROPE ¬ GetLine[stream], GetLine[stream]
DO
IF line = NIL THEN EXIT;
IF Rope.Match[pattern: "--*{*}*", object: line]
THEN {
start: INT ~ Rope.Index[line, 0, "{"]+1;
end: INT ~ Rope.Index[line, start, "}"];
s: IO.STREAM ~ IO.RIS[Rope.Substr[line, start, end-start]];
FOR tok:
ROPE ¬ CommanderOps.GetCmdToken[s].value, CommanderOps.GetCmdToken[s].value
UNTIL tok =
NIL
DO
last ¬ last.rest ¬ LIST[tok];
ENDLOOP;
};
ENDLOOP;
IO.Close[stream];
RETURN [head.rest]
};
MOrderCommand: Commander.CommandProc ~ {
arg0: ROPE = CommanderOps.NextArgument[cmd];
PutPair:
PROC [a, b:
ROPE] ~ {
IO.PutRope[cmd.out, a];
IO.PutRope[cmd.out, " "];
IO.PutRope[cmd.out, b];
IO.PutRope[cmd.out, "\n"];
};
IF arg0 =
NIL
THEN CommanderOps.Failed[cmd.procData.doc]
ELSE {
FOR arg:
ROPE ¬ arg0, CommanderOps.NextArgument[cmd]
UNTIL arg =
NIL
DO
notMesa: BOOL ¬ FALSE;
notMesaOrConfig: BOOL ¬ FALSE;
x: LIST OF ROPE ¬ NIL;
x ¬ ParseMesaDirectory[arg ! PFS.Error => { IF error.group=user THEN {notMesa ¬ TRUE; CONTINUE} }];
IF notMesa
THEN {
ENABLE PFS.Error => { IF error.group=user THEN {notMesaOrConfig ¬ TRUE; CONTINUE}};
c: ConfigDependencies ~ ParseCMesaDirectory[arg];
x ¬ RopeList.DAppend[c.interfaces, c.implementations];
};
IF notMesaOrConfig
THEN {
result ¬ $Failure;
msg ¬ Rope.Cat[msg, arg, " not found\n"];
};
IF x =
NIL
THEN { PutPair[arg, arg] }
ELSE {
FOR tail:
LIST
OF
ROPE ¬ x, tail.rest
UNTIL tail =
NIL
DO
PutPair[tail.first, arg];
ENDLOOP;
};
ENDLOOP;
};
};
Commander.Register["Mesa-Depends", MesaDependsCommand, "List direct dependencies of a Mesa module"];
Commander.Register["Config-Depends", CMesaDependsCommand, "List direct dependencies of a Configuration (CMesa) module"];
Commander.Register["C-Depends", CDependsCommand, "List dependencies of a c-language module"];
Commander.Register["MakeIt-Depends", MakeItDependsCommand, "List dependencies of a MakeIt file"];
Commander.Register["MOrder", MOrderCommand, "Make a list of dependency pairs (suitable for processing by tsort) for a collection of mesa and config files\nargs: basename ..."];