SMBDriverImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
last edit by Satterthwaite, May 26, 1986 1:38:06 pm PDT
DIRECTORY
Atom: TYPE USING [GetPName],
BasicTime: TYPE USING [GMT, Now, Period],
BcdDefs: TYPE USING [
Base, BcdBase, EXPHandle, EXPIndex, FTHandle, IMPHandle, IMPIndex, Link,
ModuleIndex, MTHandle, MTIndex, NullLink, NullModule, ProcLimit],
BcdOps: TYPE USING [ProcessExports, ProcessImports, ProcessModules],
FS: TYPE USING [OpenFile, StreamOpen],
IO: TYPE USING [atom, card, Close, PutF, rope, STREAM],
LoaderOps: TYPE USING [IthLink, LinkSegmentLength],
LoaderOpsExtras: TYPE USING [AcquireFileProc],
Rope: TYPE USING [ROPE, Concat],
SMFI: TYPE USING [BcdFileInfo, SrcFileInfo],
SMBind: TYPE USING [
AllocateIR, AllocateVIR, BuildInterface, BuildFramePtrInterface, ImportLink,
ImportMap, ImportMapSeq, IR, IRSeq, IRSeqRecord, RIR, VIR, BindInfo, BindInfoRecord,
RelocateLink],
SMLDriver: TYPE USING [LoadMod, LoadModRecord],
SMModelBcd: TYPE USING [
Bcd, MTHandle,
BuildBcd, CloseLiterals, DeclareControl, DeclareExport, DeclareImport, DeleteBcd,
FillImport, ImportLiterals, OpenLinks, OpenLiterals, ReadLink, RopeFromNS,
WriteBcd, WriteLink],
SMProj: TYPE USING [Available, Fill, Find, Proj, Read],
SMTree: TYPE Tree USING [
ApplOp, BindOp, Handle, Id, Link, Name, NodeName, null, nullName],
SMTreeOps: TYPE TreeOps USING [
GetExt, GetName, GetNode, NSons, NthSon, OpName, PutExt, Scan, ScanSons, TM],
SMVal: TYPE USING [
Binding, BtoD, BtoG, GetExtFromParse, IdName, IdType, OuterBody, PutExtInParse,
ValOf, ValOfNthSon, VisitNodes],
TimeStamp: TYPE USING [Stamp, Null],
VM: TYPE USING [AddressForPageNumber, Interval];
SMBDriverImpl: CEDAR PROGRAM
IMPORTS
Atom, BasicTime, BcdOps, FS, IO, LoaderOps, Rope,
SMBind, SMModelBcd, SMProj, SMTreeOps, SMVal, VM
EXPORTS SMLDriver~{
OPEN Tree~~SMTree, TreeOps~~SMTreeOps;
BS: TYPE~REF BinderState;
BinderState: TYPE~RECORD[ -- state information for the modeller's loader
z: ZONE←,
tm: TreeOps.TM←,
out: IO.STREAM←,
configBcd: SMModelBcd.Bcd←NIL,
configFormals: SMBind.IRSeq←NIL];
Create: PROC[z: ZONE, tm: TreeOps.TM, out: IO.STREAM] RETURNS[BS] ~ {
RETURN[z.NEW[BinderState ← [z~z, tm~tm, out~out]]]};
BindInfo: TYPE~SMBind.BindInfo;
BindInfoRecord: PUBLIC TYPE~SMBind.BindInfoRecord;
loading modules
Bind: PUBLIC PROC[
name: Rope.ROPE, stamp: BasicTime.GMT, root: Tree.Link,
z: ZONE, tm: TreeOps.TM, out: IO.STREAM, wDir: Rope.ROPE]
RETURNS[errors: BOOLFALSE] ~ {
startTime: BasicTime.GMT ~ BasicTime.Now[];
nBcds: NAT ← 0;
formals, body: Tree.Link;
bs: BS ← Create[z, tm, out];
read the component bcds and build a composite one to simulate a config
LoadBcds: PROC[
root: Tree.Link,
ProcessComponent: PROC[BcdDefs.BcdBase, Rope.ROPE]
RETURNS[BcdDefs.ModuleIndex]
] ~ {
ForEachApply: PROC[node, parent: Tree.Link] ~ {
IF TreeOps.OpName[node] IN Tree.ApplOp THEN {
this is interesting if either an Apply of a source file whose bcd is valid
or an fiBcd for a .bcd mentioned directly in the model
bcd: SMProj.Proj ← NIL;
WITH SMVal.ValOfNthSon[node, 1] SELECT FROM
subNode: Tree.Handle =>
IF TreeOps.OpName[subNode] IN Tree.ApplOp THEN
bcd ← NARROW[TreeOps.GetExt[subNode]];
fiBcd: SMFI.BcdFileInfo => { -- temporary (inefficient)
bcd ← SMProj.Find[fiBcd.stamp];
IF ~bcd.Available THEN bcd.Fill[fiBcd.fName, wDir, FALSE]};
ENDCASE;
IF bcd # NIL AND ~bcd.interface THEN {
loadMod: SMLDriver.LoadMod ← NARROW[SMVal.GetExtFromParse[node]];
IF loadMod = NIL THEN loadMod ← (bs.z).NEW[SMLDriver.LoadModRecord ← []];
IF ~bcd.Available THEN
bs.out.PutF["Error - can't bind %g (bcd not available)\n", IO.rope[bcd.localName]]
ELSE IF loadMod.bindInfo = NIL THEN {
bindInfo: SMBind.BindInfo ~ (bs.z).NEW[SMBind.BindInfoRecord ← []];
loadMod.bindInfo ← bindInfo;
IF loadMod.loadInfo # NIL THEN {
bindInfo.bcdSpace ← loadMod.loadInfo.bcdSpace;
bindInfo.bcd ← loadMod.loadInfo.bcd}
ELSE [bindInfo.bcdSpace, bindInfo.bcd] ← bcd.Read;
[bindInfo.bcdSpace, bindInfo.bcd] ← bcd.Read;
bindInfo.moduleIndex ← ProcessComponent[bindInfo.bcd, bcd.localName];
bindInfo.nModules ← 1; -- **** a fudge for now
nBcds ← nBcds + 1}
ELSE ERROR;
SMVal.PutExtInParse[node, loadMod]};
};
};
SMVal.VisitNodes[bs.tm, root, ForEachApply]};
[formals, body] ← SMVal.OuterBody[root];
bs.configBcd ← SMModelBcd.BuildBcd[name, stamp, body, LoadBcds, NIL];
TRUSTED {
ls.cm ← LoaderOps.AssignControlModules[ls.config];
InputActuals[bs, formals];
CollectExports[bs, body];
ProcessPlusAndThen[bs, body];
ResolveImports[bs, body];
ExportToBcd[bs, body];
AssignControls[bs, body];
}; -- end TRUSTED
IF nBcds = 0 THEN bs.out.PutF["Nothing was bound.\n\n"]
ELSE {
ForEachApply: PROC[node, parent: Tree.Link] ~ {
IF TreeOps.OpName[node] IN Tree.ApplOp THEN {
release binding info and associated structures
loadMod: SMLDriver.LoadMod ← NIL;
WITH SMVal.ValOfNthSon[node, 1] SELECT FROM
subNode: Tree.Handle =>
IF TreeOps.OpName[subNode] IN Tree.ApplOp THEN
loadMod ← NARROW[SMVal.GetExtFromParse[node]];
fiBcd: SMFI.BcdFileInfo => loadMod ← NARROW[SMVal.GetExtFromParse[node]];
ENDCASE;
IF loadMod # NIL THEN {
unmap bcd, etc.
(bs.z).FREE[@loadMod.bindInfo]};
};
};
SMVal.VisitNodes[bs.tm, body, ForEachApply];
{
outName: Rope.ROPE ~ name.Concat[".bcd"];
output: IO.STREAMFS.StreamOpen[
fileName~outName, accessOptions~$create, wDir~wDir];
AcquireFile: LoaderOpsExtras.AcquireFileProc ~ {
bcd: SMProj.Proj ~ SMProj.Find[version];
IF ~bcd.Available THEN bcd.Fill[name, wDir, FALSE];
RETURN[bcd.file]};
bs.configBcd.WriteBcd[output, AcquireFile];
output.Close[];
bs.out.PutF["%d modules bound\n", IO.card[nBcds]];
bs.out.PutF["bcd file written on %g\n", IO.rope[outName]]
};
bs.configBcd.DeleteBcd[];
bs.out.PutF[
"Total time to bind: %d seconds.\n\n", IO.card[startTime.Period[BasicTime.Now[]]]]
};
z.FREE[@bs]};
internal procedures
BaseAddress: PROC[interval: VM.Interval] RETURNS[BcdDefs.BcdBase] ~ TRUSTED {
RETURN[VM.AddressForPageNumber[interval.page]]};
fill in exported interface records from the bcd
CollectExports: PROC[bs: BS, root: Tree.Link] ~ {
ForEachApply: PROC[node, parent: Tree.Link] ~ {
IF TreeOps.OpName[node] IN Tree.ApplOp THEN
WITH SMVal.GetExtFromParse[node] SELECT FROM
loadMod: SMLDriver.LoadMod => {
bindInfo: SMBind.BindInfo ~ loadMod.bindInfo;
IF bindInfo.exports = NIL THEN SetUpExports[bs, bindInfo]}
ENDCASE => NULL;
};
SMVal.VisitNodes[bs.tm, root, ForEachApply]};
SetUpExports: PROC[bs: BS, bindInfo: SMBind.BindInfo] ~ TRUSTED {
bcd: BcdDefs.BcdBase ~ bindInfo.bcd;
n: NAT ← 1;
ForEachExport: PROC[eth: BcdDefs.EXPHandle, eti: BcdDefs.EXPIndex]
RETURNS[stop: BOOLFALSE] ~ CHECKED {
ir: SMBind.IR ~ SMBind.BuildInterface[bindInfo, eth];
bindInfo.exports[n] ← ir;
n ← n+1};
bindInfo.exports ← (bs.z).NEW[SMBind.IRSeqRecord[bcd.nExports+1]];
IF bcd.nModules = 1 THEN
build interface record for a compiler produced module
bindInfo.exports[0] ← SMBind.BuildFramePtrInterface[bindInfo];
[] ← BcdOps.ProcessExports[bcd, ForEachExport]};
merge exported records for import
ProcessPlusAndThen: PROC[bs: BS, root: Tree.Link] ~ {
Eval: PROC[t: Tree.Link] RETURNS[SMBind.IR] ~ {
SELECT TreeOps.OpName[t] FROM
IN Tree.ApplOp => {
this is a coercion not made explicit by the evaluator; simply use the first export
loadMod: SMLDriver.LoadMod ~ NARROW[SMVal.GetExtFromParse[t]];
IF loadMod # NIL THEN {
bindInfo: SMBind.BindInfo ~ loadMod.bindInfo;
RETURN[bindInfo.exports[1]]} -- check size before allowing coercion?
ELSE RETURN[NIL]};
$subscript, $then, $union =>
WITH TreeOps.GetExt[t] SELECT FROM
ir: SMBind.IR => RETURN[ir];
ENDCASE => {
ApplyOp[TreeOps.GetNode[t]]; RETURN[NARROW[TreeOps.GetExt[t]]]};
$nil => RETURN[NIL];
ENDCASE => RETURN[NIL]  -- ERROR?
};
ApplyOp: PROC[node: Tree.Link] ~ {
SELECT TreeOps.OpName[node] FROM
$union, $then => {
left: SMBind.IR ~ Eval[SMVal.ValOfNthSon[node, 1]];
right: SMBind.IR ~ Eval[SMVal.ValOfNthSon[node, 2]];
TreeOps.PutExt[node, BinaryOp[left, right, TreeOps.OpName[node]]]}; -- ****
$subscript => {
gb: Tree.Link ~ TreeOps.NthSon[node, 1];
selector: Tree.Name ~ TreeOps.GetName[TreeOps.NthSon[node, 2]];
left: Tree.Link ~ SMVal.ValOf[gb];
SELECT TreeOps.OpName[left] FROM
IN Tree.ApplOp => {
typeName: Tree.Name ~ IndexToType[gb, selector];
desiredName: Tree.Name ~
(IF typeName # Tree.nullName THEN typeName ELSE selector);
WITH SMVal.GetExtFromParse[left] SELECT FROM
loadMod: SMLDriver.LoadMod => {
exports: SMBind.IRSeq ~ loadMod.bindInfo.exports;
FOR i: NAT IN [0 .. exports.size) DO
IF exports[i] # NIL AND exports[i].name = desiredName THEN
GOTO found;
REPEAT
found => TreeOps.PutExt[node, exports[i]];    -- ****
FINISHED =>
IF typeName # $CONTROL THEN
bs.out.PutF["Error - %g is not exported by %g.\n",
IO.atom[selector], IO.rope[loadMod.proj.localName]];
ENDLOOP;
};
ENDCASE => NULL;
};
ENDCASE => NULL
};
ENDCASE => NULL;
};
BinaryOp: PROC[left, right: SMBind.IR, mode: Tree.NodeName]
RETURNS[result: SMBind.IR] ~ {
IF left = NIL THEN RETURN[right];
IF right = NIL THEN RETURN[left];
IF left.stamp ~= right.stamp THEN {
a TYPE CHECK
bs.out.PutF["Interface mismatch between %g and %g.\n",
IO.atom[left.name], IO.atom[right.name]];
RETURN[left]};
WITH left SELECT FROM
rLeft: SMBind.RIR =>
WITH right SELECT FROM
rRight: SMBind.RIR => {
ir: SMBind.RIR ~ SMBind.AllocateIR[rLeft.stamp, rLeft.name, rLeft.size];
FOR i: NAT IN [0 .. rLeft.size) DO
SELECT mode FROM
$then =>
ir[i] ← (IF EmptyLink[rLeft[i].link] THEN rRight[i] ELSE rLeft[i]);
$union => { -- +
IF ~EmptyLink[rLeft[i].link] AND ~EmptyLink[rRight[i].link] THEN
bs.out.PutF["Multiple exports of item %d in interface %g.\n",
IO.card[i], IO.atom[rLeft.name]];
ir[i] ← (IF EmptyLink[rLeft[i].link] THEN rRight[i] ELSE rLeft[i])};
ENDCASE => ERROR;  -- other operators not yet implemented
ENDLOOP;
result ← ir};
vRight: SMBind.VIR => {
ir: SMBind.RIR ~ SMBind.AllocateIR[rLeft.stamp, rLeft.name, rLeft.size];
FOR i: NAT IN [0 .. rLeft.size) DO
ir[i] ← (IF EmptyLink[rLeft[i].link] THEN
[SMBind.ImportLink[vRight.dummyGfi, i]] ELSE rLeft[i]);
ENDLOOP;
result ← ir};
ENDCASE => result ← left; -- right = NIL
vLeft: SMBind.VIR =>
WITH right SELECT FROM-- can't even approximate this well
rRight: SMBind.RIR => {
bs.out.PutF["Warning: commuting local and formal instances of interface %g.\n",
IO.atom[vLeft.name]];
result ← BinaryOp[left~right, right~left, mode~mode]};
vRight: SMBind.VIR => {
bs.out.PutF["Cannot merge multiple formal instances of interface %g.\n",
IO.atom[vLeft.name]];
result ← left};
ENDCASE => result ← left; -- right = NIL
ENDCASE => result ← right; -- left = NIL
RETURN};
ForEachNode: PROC[node, parent: Tree.Link] ~ {
SELECT TreeOps.OpName[node] FROM
$union, $then, $subscript =>
WITH TreeOps.GetExt[node] SELECT FROM
ir: SMBind.IR => NULL;
ENDCASE => ApplyOp[node];
ENDCASE => NULL;
};
SMVal.VisitNodes[bs.tm, root, ForEachNode]};
IndexToType: PROC[gb: Tree.Link, index: Tree.Name]
RETURNS[typeName: Tree.Name ← Tree.nullName] ~ {
WITH gb SELECT FROM
id: Tree.Id => {
d: Tree.Link ~ SMVal.IdType[id];
FindIndexType: TreeOps.Scan ~ {
elemName: Tree.Name ~ TreeOps.GetName[TreeOps.NthSon[t, 1]];
IF elemName = index THEN {
type: Tree.Link ~ TreeOps.NthSon[t, 2];
WITH type SELECT FROM
typeId: Tree.Id => typeName ← SMVal.IdName[typeId];
ENDCASE => -- temporary
IF TreeOps.OpName[type] = $control THEN typeName ← $CONTROL
ELSE NULL; -- for now
};
};
IF TreeOps.OpName[d] # $decl THEN ERROR;
TreeOps.ScanSons[d, FindIndexType]};
ENDCASE => NULL; -- for now
};
EmptyLink: PROC[link: BcdDefs.Link] RETURNS[BOOL] ~ {
RETURN[link = BcdDefs.NullLink]};
fill in links
InputActuals: PROC[bs: BS, formals: Tree.Link] ~ {
n: NAT ~ TreeOps.NSons[formals];
IF n = 0 THEN bs.configFormals ← NIL
ELSE {
bs.configFormals ← (bs.z).NEW[SMBind.IRSeqRecord[n+1]];
bs.configFormals[0] ← NIL;  -- not used
FOR i: NAT IN [1 .. n] DO
id: Tree.Id ~ NARROW[TreeOps.GetExt[TreeOps.NthSon[formals, i]]];
formalName: Tree.Name ~ SMVal.IdName[id];
type: Tree.Link ~ SMVal.IdType[id];
typeName: Tree.Name ~ (WITH type SELECT FROM
id: Tree.Id => SMVal.IdName[id],
ENDCASE => formalName);
stamp: TimeStamp.Stamp ← TimeStamp.Null;
ir: SMBind.VIR;
examine first son, it is either an apply for a mesa or fiBcd for a bcd in the model
WITH SMVal.ValOf[type] SELECT FROM
node: Tree.Handle =>
WITH SMVal.ValOfNthSon[SMVal.ValOf[node], 1] SELECT FROM
fiSrc: SMFI.SrcFileInfo =>
stamp ← NARROW[TreeOps.GetExt[node], SMProj.Proj].stamp;
subNode: Tree.Handle =>
IF TreeOps.OpName[subNode] IN Tree.ApplOp THEN
stamp ← NARROW[TreeOps.GetExt[subNode], SMProj.Proj].stamp;
fiBcd: SMFI.BcdFileInfo => stamp ← fiBcd.stamp;
ENDCASE;
fiBcd: SMFI.BcdFileInfo => stamp ← fiBcd.stamp;
ENDCASE;
bs.configFormals[i] ← ir ← SMBind.AllocateVIR[stamp, typeName];
ir.index ← (bs.configBcd).DeclareImport[
Atom.GetPName[formalName], Atom.GetPName[typeName], stamp];
ENDLOOP;
};
};
GetInterface: PROC[bs: BS, bcdVersion: TimeStamp.Stamp] RETURNS[ir: SMBind.IR] ~ {
FOR i: NAT IN [1 .. bs.configFormals.size) DO
IF bcdVersion = bs.configFormals[i].stamp THEN RETURN[bs.configFormals[i]];
ENDLOOP;
IF linkerIR = NIL THEN {
this is one of
1) an imported module from the loadstate (done lazily: see LookupFrame)
2) an imported interface that is all inlines
3) an imported interface that has not been exported to the load state (error)
ir ← NIL};
RETURN[NIL]};
ResolveImports: PROC[bs: BS, root: Tree.Link] ~ {
ForEachApply: PROC[node, parent: Tree.Link] ~ {
IF TreeOps.OpName[node] IN Tree.ApplOp THEN
WITH SMVal.GetExtFromParse[node] SELECT FROM
loadMod: SMLDriver.LoadMod =>
IF ~loadMod.bindInfo.linksResolved THEN {
rand: Tree.Link ~ SMVal.ValOfNthSon[node, 2];
args: Tree.Link ~ (IF SMVal.Binding[rand] THEN SMVal.BtoG[rand] ELSE rand);
FillInImports[loadMod, args]};
ENDCASE => NULL;
};
FillInImports: PROC[loadMod: SMLDriver.LoadMod, args: Tree.Link] ~ TRUSTED {
bindInfo: SMBind.BindInfo ~ loadMod.bindInfo;
bcd: BcdDefs.BcdBase ~ bindInfo.bcd;
firstDummy: NAT ~ bcd.firstdummy;
importMap: SMBind.ImportMap ~
(bs.z).NEW[SMBind.ImportMapSeq[bcd.nDummies] ← [bias~firstDummy, map~]];
import: NAT ← 1;
relGfi: NAT ← 0;
ForEachImport: PROC[ith: BcdDefs.IMPHandle, iti: BcdDefs.IMPIndex]
RETURNS[stop: BOOLFALSE] ~ TRUSTED {
fth: BcdDefs.FTHandle ~ @LOOPHOLE[bcd + bcd.ftOffset, BcdDefs.Base][ith.file];
FOR i: NAT IN [0 .. ith.ngfi) DO
importMap[(ith.gfi-firstDummy)+i] ← [index~import, whichOne~i];
ENDLOOP;
bindInfo.imports[import] ← (IF import > TreeOps.NSons[args] THEN
HiddenImport[bs, args, fth.version] ELSE LookupInterface[bs, args, import]);
WITH bindInfo.imports[import] SELECT FROM
formal: SMBind.VIR =>
IF formal.dummyGfi = BcdDefs.NullModule THEN
formal.dummyGfi ← (bs.configBcd).FillImport[formal.index, bcd, iti];
ENDCASE;
IF FALSE AND bindInfo.imports[import] = NIL THEN {
would get spurious warnings for NIL implementations
sym: Rope.ROPE ~ SMModelBcd.RopeFromNS[bcd, ith.name];
bs.out.PutF["Warning - cannot find exporter of %g anywhere.\n", IO.rope[sym]]};
import ← import + 1};
moduleBase: BcdDefs.ModuleIndex ~ bindInfo.moduleIndex;
ForEachModule: PROC[mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex]
RETURNS[stop: BOOLFALSE] ~ TRUSTED {
resolved: BOOLTRUE;
nLinks: NAT ~ LoaderOps.LinkSegmentLength[mth, bcd];
module: SMModelBcd.MTHandle ~ (bs.configBcd).OpenLinks[moduleBase, relGfi, nLinks];
FOR i: CARDINAL IN [0..nLinks) DO
bound: BOOL;
link: BcdDefs.Link;
[link, bound] ← NewLink[
bcdLink~LoaderOps.IthLink[mth, i, bcd],
oldLink~(bs.configBcd).ReadLink[mth~module, offset~i],
bindInfo~loadMod.bindInfo, importMap~importMap];
IF bound THEN (bs.configBcd).WriteLink[mth~module, offset~i, link~link]
ELSE resolved ← FALSE;
ENDLOOP;
IF ~resolved THEN bindInfo.linksResolved ← FALSE;
(bs.configBcd).ImportLiterals[module, bcd, mti];
relGfi ← relGfi + mth.ngfi};
IF bcd.nImports = 0 THEN RETURN; ** Loader crock - can't handle LFNull !!!
bindInfo.imports ← (bs.z).NEW[SMBind.IRSeqRecord[bcd.nImports+1]];
bindInfo.imports[0] ← NIL; -- not used
[] ← BcdOps.ProcessImports[bcd, ForEachImport];
bindInfo.linksResolved ← TRUE;
(bs.configBcd).OpenLiterals[bcd];
[] ← BcdOps.ProcessModules[bcd, ForEachModule];
(bs.configBcd).CloseLiterals[bcd]};
SMVal.VisitNodes[bs.tm, root, ForEachApply]};
PossibleCoercion: PROC[t: Tree.Link] RETURNS[SMBind.IR] ~ {
SELECT TreeOps.OpName[t] FROM
IN Tree.ApplOp => {
this is a coercion not made explicit by the evaluator; simply use the first export
loadMod: SMLDriver.LoadMod ~ NARROW[SMVal.GetExtFromParse[t]];
IF loadMod # NIL THEN {
bindInfo: SMBind.BindInfo ~ loadMod.bindInfo;
RETURN[bindInfo.exports[1]]} -- check size before allowing coercion?
ELSE RETURN[NIL]};
$subscript, $then, $union => RETURN[NARROW[TreeOps.GetExt[t]]];
$nil => RETURN[NIL];
ENDCASE => RETURN[NIL]  -- ERROR?
};
LookupInterface: PROC[bs: BS, args: Tree.Link, import: NAT] RETURNS[SMBind.IR] ~ {
LookupOutside: PROC[id: Tree.Id] RETURNS[ir: SMBind.IR] ~ {
ir ← bs.configFormals[id.p]; -- id must be a formal
IF ir = NIL THEN
bs.out.PutF["Can't import %g from loadstate\n.", IO.atom[SMVal.IdName[id]]];
RETURN};
RETURN [WITH SMVal.ValOfNthSon[args, import] SELECT FROM
node: Tree.Handle => PossibleCoercion[node],
id: Tree.Id => LookupOutside[id],
ENDCASE => ERROR]
};
HiddenImport: PROC[bs: BS, args: Tree.Link, version: TimeStamp.Stamp]
RETURNS[ir: SMBind.IRNIL] ~ {
CheckArg: TreeOps.Scan ~ {
v: Tree.Link ~ SMVal.ValOf[t];
SELECT TreeOps.OpName[v] FROM
IN Tree.ApplOp => {
CheckImport: TreeOps.Scan ~ {
WITH SMVal.ValOf[t] SELECT FROM
node: Tree.Handle => {
argIr: SMBind.IR ~ PossibleCoercion[node];
IF argIr ~= NIL AND argIr.stamp = version THEN {
IF ir ~= NIL AND ir ~= argIr THEN
bs.out.PutF["Ambiguous implicit import of %g\n", IO.atom[ir.name]];
ir ← argIr};
};
ENDCASE;
could be an export too?
};
TreeOps.ScanSons[SMVal.ValOfNthSon[v, 2], CheckImport]};
$subscript => CheckArg[TreeOps.NthSon[v, 1]];
$then, $union => {
CheckArg[TreeOps.NthSon[v, 1]]; CheckArg[TreeOps.NthSon[v, 2]]};
$nil => NULL;
ENDCASE;
};
TreeOps.ScanSons[args, CheckArg];
ir will be NIL here only if implicitly importing instance is a formal
IF ir = NIL THEN ir ← GetInterface[bs, version];
RETURN};
NewLink: PROC[
bcdLink: BcdDefs.Link, oldLink: BcdDefs.Link,
bindInfo: SMBind.BindInfo, importMap: SMBind.ImportMap]
RETURNS[link: BcdDefs.Link, resolved: BOOL] ~ {
FindLink: PROC[bcdLink: BcdDefs.Link]
RETURNS[link: BcdDefs.Link, resolved: BOOL] ~ TRUSTED {
bcdGfi: BcdDefs.ModuleIndex ~ (SELECT bcdLink.vtag FROM
$var => bcdLink.vgfi,
$proc0, $proc1 => bcdLink.gfi,
ENDCASE => ERROR);
IF bcdGfi < importMap.bias THEN {
link ← SMBind.RelocateLink[bindInfo, bcdLink];
resolved ← ~EmptyLink[link]}
ELSE {
relGfi: NAT ~ bcdGfi - importMap.bias;
index: NAT ~ importMap[relGfi].index;
entryNo: CARDINAL ~ bcdLink.ep + (importMap[relGfi].whichOne*BcdDefs.ProcLimit);
WITH bindInfo.imports[index] SELECT FROM
ir: SMBind.RIR => {
resolved ← ~EmptyLink[ir[entryNo].link];
IF resolved THEN link ← ir[entryNo].link};
ir: SMBind.VIR => {
link ← SMBind.ImportLink[ir.dummyGfi, entryNo]; resolved ← TRUE};
ENDCASE => resolved ← FALSE;
IF ~resolved THEN {
**** warning message here?
};
};
RETURN[link, resolved]};
RETURN (SELECT bcdLink.vtag FROM
$proc0, $proc1,
$var =>
IF EmptyLink[oldLink] THEN FindLink[bcdLink] ELSE [oldLink, TRUE],
ENDCASE => [LOOPHOLE[bcdLink.typeID], TRUE])       -- ***
};
ExportToBcd: PROC[bs: BS, body: Tree.Link] ~ {
ForEachItem: PROC[t: Tree.Link] ~ {
WITH PossibleCoercion[SMVal.ValOf[t]] SELECT FROM
ir: SMBind.RIR => {
IthLink: SAFE PROC[i: NAT] RETURNS[BcdDefs.Link] ~ TRUSTED {
RETURN[ir[i].link]};
(bs.configBcd).DeclareExport[
name~Atom.GetPName[ir.name], stamp~ir.stamp, size~ir.size, getLink~IthLink]};
ir: SMBind.VIR =>
NULL -- ****
ENDCASE
};
SELECT TreeOps.OpName[body] FROM
$group => TreeOps.ScanSons[body, ForEachItem];
IN Tree.BindOp => {TreeOps.ScanSons[SMVal.BtoG[body], ForEachItem]};
$let => ExportToBcd[bs, TreeOps.NthSon[body, 2]];
ENDCASE => ForEachItem[body];
};
AssignControls: PROC[bs: BS, body: Tree.Link] ~ {
ForEachNode: PROC[node, parent: Tree.Link] ~ {
IF SMVal.Binding[node] THEN {
d: Tree.Link ~ SMVal.BtoD[node];
g: Tree.Link ~ SMVal.BtoG[node];
p: NAT ← 0;
CheckElem: TreeOps.Scan ~ {
p ← p+1;
IF TreeOps.OpName[SMVal.ValOfNthSon[t, 2]] = $control THEN
AssignControl[SMVal.ValOfNthSon[g, p]]
};
TreeOps.ScanSons[d, CheckElem]};
};
AssignControl: PROC[t: Tree.Link] ~ {
WITH t SELECT FROM
node: Tree.Handle =>
SELECT TreeOps.OpName[node] FROM
IN Tree.ApplOp =>
WITH SMVal.GetExtFromParse[node] SELECT FROM
loadMod: SMLDriver.LoadMod => { -- *** not right for configs
bindInfo: SMBind.BindInfo ~ loadMod.bindInfo;
(bs.configBcd).DeclareControl[bindInfo.moduleIndex]};
ENDCASE;
$subscript => AssignControl[SMVal.ValOfNthSon[node, 1]];
ENDCASE;
ENDCASE => NULL;
};
SMVal.VisitNodes[bs.tm, body, ForEachNode]};
}.