DIRECTORY
AMTypes USING [TV, TVEqual, TVType, UnderClass],
AMBridge USING [SomeRefFromTV, TVForFrame, TVForReferent, TVToRef],
AMModel USING [Context],
AMModelBridge USING [ContextForFrame],
CD, CDBasics, CDCells, CDDirectory, CDImports, CDLayers, CDProperties, CDRects, CDSatellites, CDSequencer, CDSymbolicObjects, CDTexts,
Convert, 
Core, CoreClasses, CoreOps, CoreProperties,
CoreGeometry,
IO,
Interpreter USING [Evaluate],
PrincOpsUtils,
PW, RefTab, Rope, RopeList,
Sinix,
Sisyph,
SymTab, TerminalIO;

SisyphImpl: CEDAR PROGRAM				
IMPORTS AMBridge, AMModelBridge, AMTypes, CDBasics, CDCells, CDDirectory, CDImports, CDLayers, CDProperties, CDRects, CDSatellites, CDSequencer, CDTexts, Convert, CoreClasses, CoreOps, CoreProperties, CoreGeometry, Interpreter, IO, PrincOpsUtils, PW, RefTab, Rope, RopeList, Sinix, SymTab, TerminalIO 
EXPORTS Sisyph
SHARES CDCells, CDImports, CDRects, CDTexts, Sinix = 
BEGIN OPEN Sisyph; 
expressionsProp: PUBLIC ATOM _ PW.RegisterProp[$SisyphExpressions, TRUE];

designRope: PRIVATE ROPE _ "design";
globalNamesRope: PRIVATE ROPE _ "globalNames";
corePropsRope: PUBLIC ROPE _ "coreProps";
coreInstPropsRope: PUBLIC ROPE _ "coreInstProps";
cdObjRope: PRIVATE ROPE _ "cdObj";

localVariablesRopes: ROPES = LIST ["&", "&&", corePropsRope, coreInstPropsRope, cdObjRope, "cI", "wI", "wire"];

parmNamesProp: PUBLIC ATOM _ PW.RegisterProp[$SisyphParmNames, TRUE];
defaultGlobalNames: PUBLIC ROPES _ LIST ["Vdd", "Gnd", "RosemaryLogicTime"];

mode: PUBLIC Sinix.Mode _ NEW [Sinix.ModeRec _ [
extractProcProp: PW.RegisterProp[$SisyphExtractProc, TRUE],
decoration: CoreGeometry.CreateDecoration["Sisyph"],
instanceEqualProc: InstanceEqual,
objectEqualProc: ObjectEqual,
instanceLayer: Sinix.DefaultInstanceLayer,
userData: DefaultUserData,
fusionByName: schematics,
touchProc: Touch,
nameProc: Name
]];
ResultFor: PROC [cx: Context, obj: CD.Object, properties: CD.PropList] RETURNS [result: REF _ NIL] = {
codeFor: ROPE _ NARROW [CDProperties.GetListProp[properties, $CodeFor]];
iconFor: ROPE _ NARROW [CDProperties.GetListProp[properties, $IconFor]];
IF codeFor=NIL THEN codeFor _ NARROW [CDProperties.GetObjectProp[obj, $CodeFor]];
IF iconFor=NIL THEN iconFor _ NARROW [CDProperties.GetObjectProp[obj, $IconFor]];
SELECT TRUE FROM
codeFor#NIL AND iconFor#NIL	=> ERROR; -- that's one two many!
codeFor#NIL							=> {
result _ EvalToRef[cx, codeFor];
IF result#NIL THEN WITH result SELECT FROM
ct: CellType	=> {};
w: Wire		=> {};	
w: Wires		=> {};
ENDCASE					=> ERROR;
};
iconFor#NIL							=> result _ ES[iconFor, cx];
ENDCASE 							=> ERROR; -- one of them at least should be present!
};

ExtractCellIcon: PUBLIC Sinix.ExtractProc = {
cx: Context _ EvaluateParameters[userData, obj, properties];
iconCT: CellType _ NARROW [Sinix.ExtractCell[obj, mode, NIL, cx].result];
iconName: ROPE _ Name[obj, cx];
cellType: CellType; 
name: ROPE;
result _ ResultFor[cx, obj, properties];
IF result=NIL THEN RETURN;
cellType _ NARROW [result];
name _ CoreOps.GetCellTypeName[cellType];
IF name=NIL THEN name _ CDNameToCTName[iconName, ".icon"];
cellType _ Sinix.CreateIcon[cellType: cellType, name: name];
result _ cellType;
CoreGeometry.PutObject[mode.decoration, cellType, obj];
IF NOT CheckAndDecorate[iconName, obj, iconCT.public, cellType.public, GetGlobalNames[cx]] THEN {
TerminalIO.PutF["*** Error: icon public and schematic public for cell icon %g do NOT conform\n", IO.rope[iconName]];
TerminalIO.PutF["Icon public is:"];
CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\nSchematic public is:"];
CoreOps.PrintWire[wire: cellType.public, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\n"];
ERROR
};
cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]];
props _ GetCoreInstProps[cx];
};

ExtractNamedWireIcon: PUBLIC Sinix.ExtractProc = {
cx: Context _ EvaluateParameters[userData, obj, properties];
iconCT: CellType _ NARROW [Sinix.ExtractCell[obj, mode, NIL, cx].result];
iconName: ROPE = Name[obj, cx];
resultWire: WireSeq;
result _ ResultFor[cx, obj, properties];
IF result=NIL 
THEN {result _ resultWire _ iconCT.public; RETURN}
ELSE WITH result SELECT FROM
wires: Wires		=> {
result _ resultWire _ CoreOps.CreateWire[wires]; 
resultWire.properties _ PutCoreProps[resultWire.properties, GetCoreProps[cx]];
};
ww: Wire			=> {result _ ww; resultWire _ CoreOps.CreateWire[LIST [ww]]};
cellType: CellType	=> result _ resultWire _ CoreOps.CopyWire[cellType.public]; 
ENDCASE			=> ERROR;
SELECT TRUE FROM
iconCT.public.size=1 AND resultWire.size=1	=> {
result _ resultWire _ resultWire[0];
CoreGeometry.PutIndirectLazyPins[mode.decoration, resultWire, iconCT.public[0]];
};
CheckAndDecorate[iconName, obj, iconCT.public, resultWire]	=> {};
ENDCASE	=> {
TerminalIO.PutF["*** Error: icon wire and result wire for wire icon %g don't conform\n", IO.rope[iconName]];
TerminalIO.PutF["Icon wire is:"];
CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\nResult wire is:"];
CoreOps.PrintWire[wire: resultWire, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\n"];
ERROR
};
props _ GetCoreInstProps[cx];
};

ExtractUnNamedWireIcon: PUBLIC Sinix.ExtractProc = {
FlushName: CoreOps.EachWireProc = {[] _ CoreOps.SetShortWireName[wire, NIL]};
wire: Wire;
[result, props] _ ExtractNamedWireIcon[obj, mode, properties, userData];
wire _ NARROW [result];
[] _ CoreOps.VisitWire[wire, FlushName];
};

ExtractWire: Sinix.ExtractProc = {
wire: Wire;
cx: Context;
resultVar, resultExpr: ROPE;
IF obj.class#CDRects.bareRectClass THEN ERROR; 
IF obj.layer#CD.commentLayer THEN ERROR; 
[cx, resultVar, resultExpr] _ OldEvaluateParameters[userData, obj, properties, IsResultVar]; 
IF resultVar=NIL 
THEN wire _ CoreOps.CreateWire[] 
ELSE {
EvalExpr[cx, resultVar, resultExpr, FALSE];
wire _ NARROW [GetRef[cx, "wire"]];
TerminalIO.PutF["*** Old Syntax: 'wire _%g'.  Sisyph might not be able to cope with that in near future!\n", IO.rope[resultExpr]];
};
CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]];
wire.properties _ PutCoreProps[wire.properties, GetCoreInstProps[cx]];
result _ wire;
};
ExtractImport: Sinix.ExtractProc = {
cx: Context = NARROW [userData];
design: CD.Design _ GetDesign[cx];
import: CDImports.ImportSpecific = NARROW [obj.specific];
CDSequencer.CheckAborted[design];
IF import.boundOb=NIL OR import.boundDesign=NIL THEN {
IF NOT CDImports.LoadAndBindDesign[into: design, importeeName: import.designName, allowConflicts: interactive, useCache: TRUE] THEN {TerminalIO.PutF["*** Error: Cannot load import %g[%g] which is unbound.\n", IO.rope[import.objectName], IO.rope[import.designName]]; ERROR};
IF import.boundOb=NIL OR import.boundDesign=NIL THEN {TerminalIO.PutF["*** Error: Cannot bind import %g[%g].\n", IO.rope[import.objectName], IO.rope[import.designName]]; ERROR};
};
RETURN Sinix.Extract[obj: import.boundOb, mode: mode, properties: properties, userData: Create[import.boundDesign, cx]];
};

ES, ExtractSchematicByName: PUBLIC PROC [name: ROPE, cx: Context] RETURNS [CellType] = {
design: CD.Design = GetDesign[cx];
obj: CD.Object = CDDirectory.Fetch[design, name].object;
IF obj=NIL THEN {TerminalIO.PutF["*** Error: ES cannot find object '%g' in design '%g'.\n", IO.rope[name], IO.rope[design.name]]; ERROR};
RETURN [NARROW [Sinix.Extract[obj: obj, mode: mode, properties: NIL, userData: cx].result]];
};
Create: PUBLIC PROC [design: CD.Design, previousCx: Context _ NIL] RETURNS [cx: Context] = {
EvalDesignExprs: PROC [exprs: ROPES] = {
WHILE exprs#NIL DO
expr: ROPE _ exprs.first;
tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE;
[tokenKind1, token1, rest] _ ParseRope[expr];
[tokenKind2, token2, rest] _ ParseRope[rest];
SELECT TRUE FROM
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest];
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE];
ENDCASE	=> {
TerminalIO.PutF["*** Old syntax in design satellite or expression: Side effect in '%g'.\n", IO.rope[expr]];
Eval[cx, expr];
};
exprs _ exprs.rest;
ENDLOOP;
};
cx _ IF previousCx=NIL THEN SymTab.Create[11] ELSE Copy[previousCx];
Store[cx, designRope, NEW [CD.Design _ design]];
Insert[cx, globalNamesRope, NEW [ROPES _ defaultGlobalNames]];
EvalDesignExprs[NARROW [CDProperties.GetDesignProp[design, expressionsProp]]];
EvalDesignExprs[CDSatellites.GetSatelliteRopes[design]];
};

Copy: PUBLIC PROC [oldCx: Context] RETURNS [cx: Context] = {
cx _ SymTab.Copy[oldCx]; -- JMF: copy the table, no more necessary to copy TV's
Store[cx, corePropsRope, NEW [Properties _ NIL]]; -- and erase some standard variables
Store[cx, coreInstPropsRope, NEW [Properties _ NIL]];
Store[cx, cdObjRope, NEW [CD.Object _ NIL]];
};

Store: PUBLIC PROC [cx: Context, var: ROPE, value: REF _ NIL] = {
[] _ SymTab.Store[cx, var, TVFromRef[value]];
};

Insert: PUBLIC PROC [cx: Context, var: ROPE, value: REF _ NIL] = {
[] _ SymTab.Insert[cx, var, TVFromRef[value]];
};

FetchInt: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: INT] = {
val: SymTab.Val _ SymTab.Fetch[cx, var].val;
IF val=NIL THEN RETURN;
WITH RefFromTV[val] SELECT FROM
refInt: REF INT	=> RETURN [TRUE, refInt^];
refNat: REF NAT	=> RETURN [TRUE, INT[refNat^]];
ENDCASE	=> ERROR; -- Wrong type
};

FetchAtom: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: ATOM] = {
val: SymTab.Val _ SymTab.Fetch[cx, var].val;
IF val=NIL THEN RETURN;
RETURN [TRUE,  NARROW [RefFromTV[val]]];
};

FetchRope: PUBLIC PROC [cx: Context, var: ROPE] RETURNS [found: BOOL _ FALSE, value: ROPE] = {
val: SymTab.Val _ SymTab.Fetch[cx, var].val;
IF val=NIL THEN RETURN;
WITH RefFromTV[val] SELECT FROM
rope: ROPE		=> RETURN [TRUE, rope];
text: REF TEXT	=> RETURN [TRUE, Rope.FromRefText[text]];
ENDCASE			=> ERROR; -- Wrong type
};

EvalToTV: PROC [cx: Context, expr: ROPE] RETURNS [result: AMTypes.TV, errorRope: ROPE, noResult: BOOL] = TRUSTED {
[result, errorRope, noResult] _ Interpreter.Evaluate[
rope: expr, 
context: AMModelBridge.ContextForFrame[
AMBridge.TVForFrame[PrincOpsUtils.GetReturnFrame[]]
], 
symbolsList: LIST [cx]
];
};

EvalToRef: PUBLIC PROC [cx: Context, expr: ROPE] RETURNS [result: REF] = TRUSTED {
tv: AMTypes.TV; errorRope: ROPE; noResult: BOOL;
[tv, errorRope, noResult] _ EvalToTV[cx, expr];
SELECT TRUE FROM
errorRope#NIL => SIGNAL InterpreterError[cx, NIL, expr, errorRope];
noResult	=> SIGNAL InterpreterError[cx, NIL, expr, "No Result"];
ENDCASE	=> result _ RefFromTV[tv];
};

EvalExpr : PUBLIC PROC [cx: Context, var, expr: ROPE, checkDefined: BOOL _ TRUE] = {
result: AMTypes.TV; errorRope: ROPE; noResult: BOOL;
[result, errorRope, noResult] _ EvalToTV[cx, expr];
SELECT TRUE FROM
errorRope#NIL	=> SIGNAL InterpreterError[cx, var, expr, errorRope];
noResult		=> SIGNAL InterpreterError[cx, var, expr, "No Result"];
Rope.Fetch[var]='& OR NOT checkDefined	=> [] _ SymTab.Store[cx, var, result];
ENDCASE		=> IF SymTab.Store[cx, var, result] THEN SIGNAL InterpreterError[cx, var, expr, "Variable has not been previously declared (with a Sisyph.Store)"];
};

AddProp: PUBLIC PROC [cx: Context, key: ATOM, expr: ROPE, inst: BOOL] = {
AddPropInternal[cx, key, EvalToRef[cx, expr], inst];
};
AddPropInternal: PROC [cx: Context, key: ATOM, value: REF, inst: BOOL] = {
previousProps: Properties _ (IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx];
Store[cx, IF inst THEN coreInstPropsRope ELSE corePropsRope, NEW [Properties _ CoreProperties.PutProp[previousProps, key, value]]];
};

Eval: PRIVATE PROC [cx: Context, expr: ROPE] = {
result: AMTypes.TV; errorRope: ROPE; noResult: BOOL; -- JMF
TRUSTED {[result, errorRope, noResult] _ Interpreter.Evaluate[
rope: expr, 
context: AMModelBridge.ContextForFrame[
AMBridge.TVForFrame[PrincOpsUtils.GetReturnFrame[]]
], 
symbolsList: LIST [cx]
]};
IF errorRope=NIL THEN RETURN;
SIGNAL InterpreterError[cx, NIL, expr, errorRope];
};

ContextEqual: PROC [cx1, cx2: Context, parmNames: ROPES] RETURNS [BOOL] = { -- JMF
IsSubset: PROC [a, b: Context] RETURNS [BOOL] = {
CheckAbsentInb: SymTab.EachPairAction = {
found: BOOL; bVal: SymTab.Val;
IF val=NIL THEN RETURN [FALSE]; -- value is in fact not in a ...
IF RopeList.Memb[localVariablesRopes, key] THEN RETURN [FALSE];
[found, bVal] _ SymTab.Fetch[b, key];
quit _ NOT found OR bVal=NIL OR NOT TVEqual[bVal, val];
};
RETURN [NOT SymTab.Pairs[a, CheckAbsentInb]];
};
SELECT TRUE FROM
cx1=cx2 => RETURN [TRUE]; -- for sure...
parmNames=NIL => RETURN [IsSubset[cx1, cx2] AND IsSubset[cx2, cx1]]; -- most general case
parmNames.rest=NIL AND Rope.Equal[parmNames.first, "0"] => RETURN [TRUE]; -- no parameters
ENDCASE => { -- limited parameter list, compare only those
found1: BOOL; val1: SymTab.Val;
found2: BOOL; val2: SymTab.Val;
FOR keys: ROPES _ parmNames, keys.rest UNTIL keys=NIL DO
[found1, val1] _ SymTab.Fetch[cx1, keys.first];
[found2, val2] _ SymTab.Fetch[cx2, keys.first];
found1 _ found1 AND val1#NIL; -- TV's are not supposed to be NIL ...
found2 _ found2 AND val2#NIL;
IF found1#found2 THEN RETURN[FALSE]; -- present in only one table
IF found1 AND NOT TVEqual[val1, val2] THEN RETURN[FALSE]; --values differ
ENDLOOP;
RETURN [TRUE]; -- all parameters matched
};
};

InstanceEqual: PROC [obj: CD.Object, p1: CD.PropList, ud1: REF, p2: CD.PropList, ud2: REF] RETURNS [BOOL] = {
instArgs1: ROPES _ NARROW [CDProperties.GetListProp[p1, expressionsProp]];
satArgs1: ROPES _ NARROW [CDProperties.GetListProp[p1, Sinix.satellitesProp]];
extract1: ATOM _ NARROW [CDProperties.GetListProp[p1, mode.extractProcProp]];
instArgs2: ROPES _ NARROW [CDProperties.GetListProp[p2, expressionsProp]];
satArgs2: ROPES _ NARROW [CDProperties.GetListProp[p2, Sinix.satellitesProp]];
extract2: ATOM _ NARROW [CDProperties.GetListProp[p2, mode.extractProcProp]];
parmNames: ROPES _ NARROW [CDProperties.GetObjectProp[obj, parmNamesProp]];
IF extract1#extract2 THEN RETURN [FALSE];
IF NOT EqualRopes[instArgs1, instArgs2] OR NOT EqualRopes[satArgs1, satArgs2] THEN RETURN [FALSE];
IF parmNames#NIL AND Rope.Equal[parmNames.first, "0"] THEN RETURN [TRUE];
RETURN [ContextEqual[NARROW [ud1], NARROW [ud2], NIL]];
};

ObjectEqual: PROC [obj: CD.Object, ud1: REF, ud2: REF] RETURNS [BOOL] = {
parmNames: ROPES _ NARROW [CDProperties.GetObjectProp[obj, parmNamesProp]];
IF parmNames#NIL AND Rope.Equal[parmNames.first, "0"] THEN RETURN [TRUE];
RETURN [ContextEqual[NARROW [ud1], NARROW [ud2], parmNames]];
};
EqualRopes: PUBLIC PROC [ropes1, ropes2: ROPES] RETURNS [BOOL] = {
FOR r1: ROPES _ ropes1, r1.rest WHILE r1#NIL DO
IF NOT RopeList.Memb[ropes2, r1.first] THEN RETURN [FALSE];
ENDLOOP; 
FOR r2: ROPES _ ropes2, r2.rest WHILE r2#NIL DO
IF NOT RopeList.Memb[ropes1, r2.first] THEN RETURN [FALSE];
ENDLOOP; 
RETURN [TRUE];
};

Cons: PUBLIC PROC [r: ROPE, lor: ROPES] RETURNS [ROPES] = {
RETURN [CONS [r, lor]];
};

List: PUBLIC PROC [r1, r2, r3, r4, r5, r6: ROPE _ NIL] RETURNS [lor: ROPES _ NIL] = {
IF r6#NIL THEN lor _ CONS [r6, lor];
IF r5#NIL THEN lor _ CONS [r5, lor];
IF r4#NIL THEN lor _ CONS [r4, lor];
IF r3#NIL THEN lor _ CONS [r3, lor];
IF r2#NIL THEN lor _ CONS [r2, lor];
IF r1#NIL THEN lor _ CONS [r1, lor];
};
CheckAndDecorate: PROC [iconName: ROPE, icon: CD.Object, drawnPublic, resultPublic: WireSeq, globalNames: ROPES _ NIL] RETURNS [ok: BOOL _ TRUE] = {
resultToDrawn: RefTab.Ref _ RefTab.Create[]; -- associates resultPublic to drawnPublic
FOR i: NAT IN [0 .. drawnPublic.size) DO
EachResultWire: CoreOps.EachWireProc = {
resultName: ROPE _ CoreOps.GetShortWireName[wire];
IF NOT Rope.Equal[resultName, drawnName] THEN RETURN;
IF wire=resultWire THEN RETURN;
IF resultWire#NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has a wire %g whose name appears more than once in the schematic\n", IO.rope[iconName], IO.rope[drawnName]]; quit _ TRUE; ok _ FALSE; RETURN};
resultWire _ wire;
};
drawnWire: Wire _ drawnPublic[i];
drawnName: ROPE _ CoreOps.GetShortWireName[drawnWire];
resultWire: Wire _ NIL;
IF drawnName=NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has an unnamed wire\n", IO.rope[iconName]]; ok _ FALSE; LOOP};
IF CoreOps.VisitWire[resultPublic, EachResultWire] THEN LOOP;
IF resultWire=NIL THEN {TerminalIO.PutF["*** Cell %g: Drawn Icon has wire %g that doesn't correspond to any wire in the schematic\n", IO.rope[iconName], IO.rope[drawnName]]; ok _ FALSE; LOOP};
CoreGeometry.PutIndirectLazyPins[mode.decoration, resultWire, drawnWire];
[] _ RefTab.Store[resultToDrawn, resultWire, drawnWire];
ENDLOOP;
FOR i: NAT IN [0 .. resultPublic.size) DO
resultWire: Wire _ resultPublic[i];
resultName: ROPE _ CoreOps.GetShortWireName[resultWire];
drawnWire: Wire _ NARROW [RefTab.Fetch[resultToDrawn, resultWire].val];
IF resultName=NIL THEN LOOP;
IF drawnWire#NIL THEN LOOP;
IF RopeList.Memb[globalNames, resultName] THEN LOOP;
TerminalIO.PutF["*** Warning in Cell %g: schematic has wire %g that corresponds to no wire in the drawn Icon\n", IO.rope[iconName], IO.rope[resultName]]; 
ENDLOOP;
};

ProcessGlobalName: PROC [record: CellType, name: ROPE] = { -- JMF
globals: Wires;
ReplaceSeq: PROC [old: WireSeq] ~ {
FOR i: NAT IN [0 .. old.size) DO old[i] _ Replace[old[i]] ENDLOOP;
};
Replace: PROC [old: Wire] RETURNS [new: Wire] = {
new _ old; -- presumably ...
IF old.size#0 THEN FOR i: NAT IN [0 .. old.size) DO new[i] _ Replace[old[i]] ENDLOOP
ELSE IF CoreOps.Member[globals, old] THEN new _ global;
};
ReplaceAndCleanSeq: PROC [old: WireSeq] RETURNS [new: WireSeq] = {
news: Wires _ LIST [global];
FOR i: NAT IN [0 .. old.size) DO
new _ Replace[old[i]];
IF NOT CoreOps.Member[news, new] THEN news _ CONS [new, news];
ENDLOOP;
new _ CoreOps.CreateWire[news];
};
InsertGlobal: PROC [wire: Wire] = {
IF wire.size#0 THEN SIGNAL GlobalNonAtomic[record, name, wire];
IF NOT CoreOps.Member[globals, wire] THEN globals _ CONS [wire, globals];
};
FindGlobals: CoreOps.EachWirePairProc = {
publicName: ROPE = CoreOps.GetShortWireName[publicWire];
IF Rope.Equal[publicName, name] THEN { -- a sub global candidate
actualName: ROPE = CoreOps.GetShortWireName[actualWire];
IF actualName=NIL OR Rope.Equal[actualName, name] THEN InsertGlobal[actualWire];
};
};
FindWire: CoreOps.EachWireProc = {
IF Rope.Equal[CoreOps.GetShortWireName[wire], name] THEN InsertGlobal[wire];
};
rct: CoreClasses.RecordCellType = NARROW [record.data];
global: Wire;
FOR i: NAT IN [0..rct.size) DO
[] _ CoreOps.VisitBindingSeq[rct[i].actual, rct[i].type.public, FindGlobals];
ENDLOOP;
[] _ CoreOps.VisitWireSeq[rct.internal, FindWire];
IF globals=NIL THEN RETURN;
IF globals.rest=NIL AND Rope.Equal[CoreOps.GetShortWireName[globals.first], name] AND CoreOps.RecursiveMember[record.public, globals.first] THEN RETURN; -- all right already, nothing to do!
global _ CoreOps.SetShortWireName[globals.first, name];
globals _ globals.rest;
record.public _ ReplaceAndCleanSeq[record.public];
rct.internal _ ReplaceAndCleanSeq[rct.internal];
FOR i: NAT IN [0..rct.size) DO ReplaceSeq[rct[i].actual] ENDLOOP;
WHILE globals#NIL DO
Sinix.FuseProperties[mode, globals.first, global, CoreOps.GetCellTypeName[record]];
globals _ globals.rest;
ENDLOOP;
};

Name: PROC [obj: CD.Object, userData: REF] RETURNS [ROPE] = {
cx: Context _ NARROW [userData];
RETURN [CDDirectory.Name[obj, GetDesign[cx]]];
};

Touch: CoreGeometry.TouchProc = {
IF instance1.obj.class#CDRects.bareRectClass OR instance2.obj.class#CDRects.bareRectClass THEN ERROR; -- the only thing we know is Rectangles!
IF ~SilTouchRect[CoreGeometry.InlineBBox[instance1], CoreGeometry.InlineBBox[instance2]] THEN RETURN;
RETURN [CDLayers.AbstractToPaint[instance1.obj.layer]=CDLayers.AbstractToPaint[instance2.obj.layer]];
};

SilTouchRect: PROC [r1, r2: CD.Rect] RETURNS [BOOL] = INLINE {
Intersect: PROC [i1min, i1max, i2min, i2max: CD.Number] RETURNS [BOOL] = INLINE {
RETURN [(i1max >= i2min) AND (i2max >= i1min)];
};
Adjoin: PROC [i1min, i1max, i2min, i2max: CD.Number] RETURNS [BOOL] = INLINE {
RETURN [(i2min >= i1min AND i2min <= i1max AND i2max >= i1max) OR
 (i1min >= i2min AND i1min <= i2max AND i1max >= i2max)];
};
RETURN [(Intersect[r1.x1, r1.x2, r2.x1, r2.x2] AND Adjoin[r1.y1, r1.y2, r2.y1, r2.y2]) OR (Intersect[r1.y1, r1.y2, r2.y1, r2.y2] AND Adjoin[r1.x1, r1.x2, r2.x1, r2.x2]) OR CDBasics.Inside[r1, r2] OR CDBasics.Inside[r2, r1]]
};

GetRef: PROC [cx: Context, var: ROPE] RETURNS [ref: REF] = {
val: SymTab.Val _ SymTab.Fetch[cx, var].val;
IF val=NIL THEN ERROR;
ref _ RefFromTV[val];
};

GetCDObj: PUBLIC PROC [cx: Context] RETURNS [CD.Object] = {
RETURN [NARROW [GetRef[cx, cdObjRope]]]
};

GetCoreProps: PUBLIC PROC [cx: Context] RETURNS [Properties] = {
RETURN [NARROW [GetRef[cx, corePropsRope]]]
};

GetCoreInstProps: PUBLIC PROC [cx: Context] RETURNS [Properties] = {
RETURN [NARROW [GetRef[cx, coreInstPropsRope]]]
};

GetDesign: PUBLIC PROC [cx: Context] RETURNS [CD.Design] = {
RETURN [NARROW [GetRef[cx, designRope]]]
};

GetGlobalNames: PUBLIC PROC [cx: Context] RETURNS [ROPES] = {
RETURN [NARROW [GetRef[cx, globalNamesRope]]]
};

RefFromTV: PROC [tv: REF] RETURNS [REF] = {
IF tv=NIL THEN RETURN [NIL];
IF ~ISTYPE [tv, AMTypes.TV] THEN ERROR; 
TRUSTED {RETURN [SELECT AMTypes.UnderClass[AMTypes.TVType[tv]] FROM
nil, atom, rope, list, ref	=> AMBridge.TVToRef[tv],
ENDCASE		=> AMBridge.SomeRefFromTV[tv]]};
};

TVFromRef: PROC [ref: REF] RETURNS [AMTypes.TV] = TRUSTED {
RETURN [AMBridge.TVForReferent[ref]];
};

TVEqual: PROC [tv1, tv2: REF] RETURNS [BOOL] = { -- JMF
IF AMTypes.TVEqual[tv1, tv2] THEN RETURN [TRUE];
WITH RefFromTV[tv1] SELECT FROM -- manage standard types not covered by AMTypes
rr1: ROPES	=> WITH RefFromTV[tv2] SELECT FROM
rr2: ROPES	=> RETURN [EqualRopes[rr1, rr2]];
ENDCASE	=> RETURN [FALSE];
r1: ROPE	=> WITH RefFromTV[tv2] SELECT FROM -- JMF
r2: ROPE	=> RETURN [Rope.Equal[r1, r2]]; -- JMF
ENDCASE	=> RETURN [FALSE]; -- JMF
ENDCASE	=> RETURN [FALSE];
};

PutCoreProps: PROC [onto, from: Properties] RETURNS [new: Properties] = {
PutProp: PROC [prop: ATOM, val: REF ANY] = {
new _ CoreProperties.PutProp[new, prop, val];
};
new _ onto;
CoreProperties.Enumerate[from, PutProp];
};

StripCellTypeName: PROC [cellType: CellType, dropPart: ROPE] = {
[] _ CoreOps.SetCellTypeName[cellType, CDNameToCTName[CoreOps.GetCellTypeName[cellType], dropPart]];
};

CDNameToCTName: PROC [cdName, dropPart: ROPE] RETURNS [ctName: ROPE] = {
ctName _ Rope.Substr[cdName, 0, Rope.Index[cdName, 0, dropPart]];
};

DefaultUserData: PROC [design: CD.Design] RETURNS [REF] ~ {
RETURN [Create[design]];
};
ParseRope: PUBLIC PROC [rope: ROPE] RETURNS [tokenKind: IO.TokenKind, token, rest: ROPE] = {
ENABLE {
IO.Error => GOTO Error;
IO.EndOfStream => GOTO EOF;
};
stream: IO.STREAM _ IO.RIS[rope];
charsSkipped1: INT _ IO.SkipWhitespace[stream];
ampersand: BOOL _ IO.PeekChar[stream]='&;
charsSkipped2: INT;
IF ampersand THEN {[] _ IO.GetChar[stream]; charsSkipped1 _ charsSkipped1 + 1};
[tokenKind, token, charsSkipped2] _ IO.GetCedarTokenRope[stream];
rest _ Rope.Substr[rope, charsSkipped1+charsSkipped2+Rope.Length[token]];
IF ampersand THEN {
IF tokenKind=tokenID THEN token _ Rope.Cat["&", token] ELSE GOTO Error;
TerminalIO.PutF["*** Variable name starting with &: %g.\n", IO.rope[token]];
};
EXITS 
Error => RETURN [tokenERROR, NIL, NIL];
EOF => RETURN [tokenEOF, NIL, NIL];
};

IsParsedID: PUBLIC PROC [tokenKind: IO.TokenKind, token, id: ROPE] RETURNS [BOOL] = {
RETURN [tokenKind=tokenID AND Rope.Equal[token, id]];
};

IsParsedChar: PUBLIC PROC [tokenKind: IO.TokenKind, token: ROPE, char: CHAR] RETURNS [BOOL] = {
RETURN [tokenKind=tokenSINGLE AND Rope.Fetch[token]=char];
};

EvaluateParameters: PUBLIC PROC [userData: REF, obj: CD.Object, properties: CD.PropList] RETURNS [cx: Context] = {
EvalExprs: PROC [exprs: ROPES, inst: BOOL] = {
WHILE exprs#NIL DO
expr: ROPE _ exprs.first;
tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE;
[tokenKind1, token1, rest] _ ParseRope[expr];
[tokenKind2, token2, rest] _ ParseRope[rest];
SELECT TRUE FROM
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest];
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, ':] => AddProp[cx, Convert.AtomFromRope[token1], rest, inst];
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE];
Rope.Find[expr, "_"]>=0 OR Rope.Find[expr, ":"]>=0=> {
TerminalIO.PutF["*** Old syntax in %g: Side effect in '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]];
Eval[cx, expr];
};
ENDCASE	=> {
previousName: ROPE _ NARROW [CoreProperties.GetProp[(IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx], CoreOps.nameProp]];
IF previousName#NIL AND NOT Rope.Equal[previousName, expr] THEN {
TerminalIO.PutF["*** Error in object '%g': Conflicting names '%g' and '%g' [probably two satellites].\n", IO.rope[Name[obj, cx]], IO.rope[previousName], IO.rope[expr]]; ERROR;
};
IF Rope.Find[expr, " "]>=0 THEN TerminalIO.PutF["*** Warning in %g: name contains space '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]];
AddPropInternal[cx, CoreOps.nameProp, expr, inst];
};
exprs _ exprs.rest;
ENDLOOP;
};
cx _ Copy[NARROW [userData]];
Store[cx, cdObjRope, NEW [CD.Object _ obj]];
CDSequencer.CheckAborted[GetDesign[cx]];
EvalExprs[NARROW [CDProperties.GetObjectProp[obj, expressionsProp]], FALSE];
EvalExprs[NARROW [CDProperties.GetObjectProp[obj, Sinix.satellitesProp]], FALSE];
EvalExprs[NARROW [CDProperties.GetListProp[properties, expressionsProp]], TRUE];
EvalExprs[NARROW [CDProperties.GetListProp[properties, Sinix.satellitesProp]], TRUE];
};

ProcessGlobalNames: PUBLIC PROC [record: CellType, cx: Context] = {
FOR names: ROPES _ GetGlobalNames[cx], names.rest WHILE names#NIL DO
ProcessGlobalName[record, names.first];
ENDLOOP;
};
ExtractSchematic: PRIVATE Sinix.ExtractProc = {
cx: Context;
resultVar, resultExpr: ROPE;
[cx, resultVar, resultExpr] _ OldEvaluateParameters[userData, obj, properties, IsResultVar];
SELECT TRUE FROM
Rope.Equal[resultVar, "cI"] =>	{
cellType: CellType;
EvalExpr[cx, resultVar, resultExpr, FALSE];
cellType _ ExtractCellIconInternal[obj, cx]; 
TerminalIO.PutF["*** Old syntax for cell icon in %g: '%g _%g'.  Convert!\n", IO.rope[Name[obj, userData]], IO.rope[resultVar], IO.rope[resultExpr]];
cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]];
result _ cellType; props _ GetCoreInstProps[cx];
};
Rope.Equal[resultVar, "wI"] =>	{
wire: Wire;
EvalExpr[cx, resultVar, resultExpr, FALSE];
wire _ ExtractNamedWireIconInternal[obj, cx]; 
TerminalIO.PutF["*** Old syntax for named wire icon in %g: '%g _%g'.  Convert!\n", IO.rope[Name[obj, userData]], IO.rope[resultVar], IO.rope[resultExpr]];
wire.properties _ PutCoreProps[wire.properties, GetCoreProps[cx]];
result _ wire; props _ GetCoreInstProps[cx];
};
Rope.Equal[resultVar, "wire"] => ERROR;
ENDCASE => {
cellType: CellType;
result _ Sinix.ExtractCell[obj, mode, properties, cx].result;
cellType _ NARROW [result];
ProcessGlobalNames[cellType, cx];
cellType.properties _ PutCoreProps[cellType.properties, GetCoreProps[cx]];
StripCellTypeName[cellType, ".sch"];
props _ GetCoreInstProps[cx];
};
};

ExtractCellIconInternal: PROC [icon: CD.Object, cx: Context] RETURNS [cellType: CellType] = {
iconName: ROPE = Name[icon, cx];
iconCT: CellType _ NARROW [Sinix.ExtractCell[icon, mode, NIL, cx].result];
cellType _ NARROW [GetRef[cx, "cI"]];
IF cellType=NIL 
THEN {
cellType _ CoreOps.CreateCellType[class: CoreClasses.unspecifiedCellClass, public: iconCT.public, name: CDNameToCTName[iconName, ".icon"]];
} 
ELSE {
name: ROPE _ CoreOps.GetCellTypeName[cellType];
IF name=NIL THEN name _ CDNameToCTName[iconName, ".icon"];
cellType _ Sinix.CreateIcon[cellType: cellType, name: name];
};
CoreGeometry.PutObject[mode.decoration, cellType, icon];
IF NOT CheckAndDecorate[iconName, icon, iconCT.public, cellType.public, GetGlobalNames[cx]] THEN {
TerminalIO.PutF["*** Error: icon public and schematic public for cell icon %g do NOT conform\n", IO.rope[iconName]];
TerminalIO.PutF["Icon public is:"];
CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\nSchematic public is:"];
CoreOps.PrintWire[wire: cellType.public, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\n"];
ERROR
}
};

ExtractNamedWireIconInternal: PROC [icon: CD.Object, cx: Context] RETURNS [result: Wire] = {
iconName: ROPE = Name[icon, cx];
iconCT: CellType _ NARROW [Sinix.ExtractCell[icon, mode, NIL, cx].result];
result _ NARROW [GetRef[cx, "wI"]];
IF result=NIL THEN ERROR;
IF iconCT.public.size=1 THEN  {
CoreGeometry.PutPins[mode.decoration, result, CoreGeometry.GetPins[mode.decoration, iconCT.public[0]]];
RETURN;
};
IF ~CheckAndDecorate[iconName, icon, iconCT.public, CoreOps.CreateWire[LIST [result]]] THEN {
TerminalIO.PutF["*** Error: icon wire and result wire for wire icon %g don't conform\n", IO.rope[iconName]];
TerminalIO.PutF["Icon wire is:"];
CoreOps.PrintWire[wire: iconCT.public, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\nResult wire is:"];
CoreOps.PrintWire[wire: result, out: TerminalIO.TOS[], level: LAST [NAT]];
TerminalIO.PutF["\n"];
ERROR
}
};

IsResultVarProc: TYPE = PROC [var: ROPE] RETURNS [BOOL];
IsResultVar: IsResultVarProc = {
RETURN [Rope.Equal[var, "cI"] OR Rope.Equal[var, "wI"] OR Rope.Equal[var, "wire"]];
};

OldEvaluateParameters: PROC [userData: REF, obj: CD.Object, properties: CD.PropList, isResultVar: IsResultVarProc _ NIL] RETURNS [cx: Context, resultVar, resultExpr: ROPE _ NIL] = {
EvalExprs: PROC [exprs: ROPES, inst: BOOL] = {
tempResultVar, tempResultExpr: ROPE _ NIL;
WHILE exprs#NIL DO
expr: ROPE _ exprs.first;
tokenKind1, tokenKind2: IO.TokenKind; token1, token2, rest: ROPE;
[tokenKind1, token1, rest] _ ParseRope[expr];
[tokenKind2, token2, rest] _ ParseRope[rest];
SELECT TRUE FROM
tokenKind1=tokenID AND isResultVar#NIL AND isResultVar[token1] => {
IF tempResultVar#NIL THEN {TerminalIO.PutF["*** Error: multiple result expressions encountered: '%g' and '%g'.\n", IO.rope[expr], IO.rope[tempResultVar]]; ERROR};
IF NOT IsParsedChar[tokenKind2, token2, '_] AND NOT IsParsedChar[tokenKind2, token2, ':] THEN {TerminalIO.PutF["*** Error: result expression has wrong syntax: '%g'.\n", IO.rope[expr]]; ERROR};
tempResultVar _ token1; tempResultExpr _ rest;
};
inst AND IsParsedID[tokenKind1, token1, "name"] AND IsParsedChar[tokenKind2, token2, '_] => {
tokenKind: IO.TokenKind; token, rr: ROPE;
[tokenKind, token, rr] _ ParseRope[rest];
IF tokenKind=tokenROPE 
THEN TerminalIO.PutF["*** Old syntax in %g: Use an expression or a satellite %g instead of '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[token], IO.rope[expr]] 
ELSE TerminalIO.PutF["*** Old syntax in %g: Use 'CoreName: %g' instead of '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[rest], IO.rope[expr]];
AddProp[cx, CoreOps.nameProp, rest, inst];
};
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '_] => EvalExpr[cx, token1, rest];
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, ':] => AddProp[cx, Convert.AtomFromRope[token1], rest, inst];
tokenKind1=tokenID AND IsParsedChar[tokenKind2, token2, '~] => EvalExpr[cx, token1, rest, FALSE];
Rope.Find[expr, "_"]>=0 OR Rope.Find[expr, ":"]>=0=> {
TerminalIO.PutF["*** Old syntax in %g: Side effect in '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]];
Eval[cx, expr];
};
ENDCASE	=> {
previousName: ROPE _ NARROW [CoreProperties.GetProp[(IF inst THEN GetCoreInstProps ELSE GetCoreProps)[cx], CoreOps.nameProp]];
IF previousName#NIL AND NOT Rope.Equal[previousName, expr] THEN {
TerminalIO.PutF["*** Error in object '%g': Conflicting names '%g' and '%g' [probably two satellites].\n", IO.rope[Name[obj, cx]], IO.rope[previousName], IO.rope[expr]]; ERROR;
};
IF Rope.Find[expr, " "]>=0 THEN TerminalIO.PutF["*** Warning in %g: name contains space '%g'.\n", IO.rope[Name[obj, userData]], IO.rope[expr]];
AddPropInternal[cx, CoreOps.nameProp, expr, inst];
};
exprs _ exprs.rest;
ENDLOOP;
IF tempResultVar#NIL THEN {resultVar _ tempResultVar; resultExpr _ tempResultExpr};
};

cx _ Copy[NARROW [userData]];
Store[cx, cdObjRope, NEW [CD.Object _ obj]];
CDSequencer.CheckAborted[GetDesign[cx]];
EvalExprs[NARROW [CDProperties.GetObjectProp[obj, expressionsProp]], FALSE];
EvalExprs[NARROW [CDProperties.GetObjectProp[obj, Sinix.satellitesProp]], FALSE];
EvalExprs[NARROW [CDProperties.GetListProp[properties, expressionsProp]], TRUE];
EvalExprs[NARROW [CDProperties.GetListProp[properties, Sinix.satellitesProp]], TRUE];
};
GlobalNonAtomic: PUBLIC SIGNAL [record: CellType, name: ROPE, wire: Wire] = CODE;

InterpreterError: PUBLIC SIGNAL [cx: Context, var, expr, errorRope: ROPE] = CODE;
Sinix.RegisterExtractProc[$SisyphExtractSchematic, ExtractSchematic];
Sinix.RegisterExtractProc[$SisyphExtractCellIcon, ExtractCellIcon];
Sinix.RegisterExtractProc[$SisyphExtractNamedWireIcon, ExtractNamedWireIcon];
Sinix.RegisterExtractProc[$SisyphExtractUnNamedWireIcon, ExtractUnNamedWireIcon];
Sinix.RegisterExtractProc[$SisyphExtractWire, ExtractWire];
Sinix.RegisterExtractProc[$SisyphExtractImport, ExtractImport];

CDProperties.PutProp[CDCells.pCellClass, mode.extractProcProp, $SisyphExtractSchematic];
CDProperties.PutProp[CDRects.bareRectClass, mode.extractProcProp, $SisyphExtractWire];
CDProperties.PutProp[CDTexts.rigidTextClass, mode.extractProcProp, $ExtractNull];
CDProperties.PutProp[CDTexts.flipTextClass, mode.extractProcProp, $ExtractNull];
CDProperties.PutProp[CDImports.importsClass, mode.extractProcProp, $SisyphExtractImport];

END.

�� ��SisyphImpl.mesa
Copyright Ó 1985, 1986, 1987 by Xerox Corporation.  All rights reserved.
Created by Sindhu and Serlet, November 27, 1985 9:11:39 pm PDT
Pradeep Sindhu June 25, 1987 4:59:16 pm PDT
Barth, October 15, 1986 10:25:34 am PDT
Bertrand Serlet, September 16, 1987 4:15:58 pm PDT
Jean-Marc Frailong December 12, 1987 5:41:02 pm PST
Christian Jacobi, July 15, 1986 6:24:40 pm PDT
Don Curry May 7, 1987 10:30:40 pm PDT
Constants and Variables
name of Sisyph variable that holds the ChipNDale design.
name of Sisyph variable that represents a list of names of global wires.
name of Sisyph variable that holds the CD object being extracted.
ExtractProcs
Check public
special case
Special case mostly for compatibility
IF obj.layer#CD.commentLayer THEN 
IF CDLayers.Kind[obj.layer]#paint OR CD.LayerTechnology[obj.layer]#NIL THEN ERROR;
Once we get rid of "wire _ ..." we can avoid Evaluating the context, by just evaluating the coreInstProps.  Things will gho much, much faster!

Context Handling Procedures
Copy: PUBLIC PROC [oldCx: Context] RETURNS [cx: Context] = {
Old version that copies TVs. TVs should now be immutable... (needs to be checked...)
CopyItem: SymTab.EachPairAction = {
[] _ SymTab.Store[cx, key, AMTypes.Copy[val]]; 
};
cx _ SymTab.Create[(SymTab.GetSize[oldCx]/2)*2+3]; -- and Odd size, at least as big as oldCx
[] _ SymTab.Pairs[oldCx, CopyItem];
Store[cx, corePropsRope, NEW [Properties _ NIL]];
Store[cx, coreInstPropsRope, NEW [Properties _ NIL]];
Store[cx, cdObjRope, NEW [CD.Object _ NIL]];
};

CopyItem: SymTab.EachPairAction = { -- JMF: TV's don't need copying any longer
[] _ SymTab.Store[cx, key, AMTypes.Copy[val]]; 
};
cx _ SymTab.Create[(SymTab.GetSize[oldCx]/2)*2+3]; -- and Odd size, at least as big as oldCx
[] _ SymTab.Pairs[oldCx, CopyItem];

result: ROPE; errorRope: ROPE; noResult: BOOL; -- JMF: use Evaluate instead of EvaluateToRope
TRUSTED {[result, errorRope, noResult] _ Interpreter.EvaluateToRope[
rope: expr, 
context: AMModelBridge.ContextForFrame[
AMBridge.TVForFrame[PrincOpsUtils.GetReturnFrame[]]
], 
symbolsList: LIST [cx]
]};
ContextEqual: PROC [cx1, cx2: Context, parmNames: ROPES] RETURNS [BOOL] = { -- JMF
Returns FALSE iff a is a subset of b
IsDifferent: PROC [a, b: Context] RETURNS [BOOL] = {
CheckAbsentInb: SymTab.EachPairAction = {
found: BOOL; bVal: SymTab.Val;
IF val=NIL THEN RETURN;
If its a local variable then return right away
IF RopeList.Memb[localVariablesRopes, key] THEN RETURN [FALSE];
If its not a parameter then return right away also
IF parmNames#NIL AND NOT RopeList.Memb[parmNames, key] THEN RETURN [FALSE];
It is a parameter. Check if its there in the context and equal
[found, bVal] _ SymTab.Fetch[b, key];
quit _ NOT found OR bVal=NIL OR NOT TVEqual[bVal, val];
};
RETURN [SymTab.Pairs[a, CheckAbsentInb]];
};
RETURN [cx1=cx2 OR (NOT IsDifferent[cx1, cx2] AND NOT IsDifferent[cx2, cx1])]
};

New version that does parametered cells a bit faster by limiting searching when parameters are specified
Conventions are the parmNames=LIST["0"] ==> no parameters at all
Returns TRUE iff a is a subset of b, parmNames is always NIL in this routine
If its a local variable then return right away
It is a potential parameter. Check if its there in the context and equal
Handle zero parameters as a special case
Conveniences
Utilities for the implementation
Construct the association by searching in resultPublic for every name found in drawnPublic
We decorate the resultWire with the pins of drawnWire
Ensure that each resultPublic corresponds to some iconic Wire (apart may be from the wires in globalNames).  Warning only for those.
ProcessGlobalName: PROC [record: CellType, name: ROPE] = { -- JMF
Replaced by new version, only a few extremely minor speedup hacks -- JMF
globals: Wires;
ReplaceSeq: PROC [old: WireSeq] RETURNS [new: WireSeq] = {
new _ old;
FOR i: NAT IN [0 .. old.size) DO new[i] _ Replace[old[i]] ENDLOOP;
};
Replace: PROC [old: Wire] RETURNS [new: Wire] = {
IF old.size#0 THEN RETURN [ReplaceSeq[old]];
RETURN [IF CoreOps.Member[globals, old] THEN global ELSE old];
};
ReplaceAndCleanSeq: PROC [old: WireSeq] RETURNS [new: WireSeq] = {
news: Wires _ LIST [global];
FOR i: NAT IN [0 .. old.size) DO
new _ Replace[old[i]];
IF NOT CoreOps.Member[news, new] THEN news _ CONS [new, news];
ENDLOOP;
new _ CoreOps.CreateWire[news];
};
InsertGlobal: PROC [wire: Wire] = {
IF wire.size#0 THEN SIGNAL GlobalNonAtomic[record, name, wire];
IF NOT CoreOps.Member[globals, wire] THEN globals _ CONS [wire, globals];
};
FindGlobals: CoreOps.EachWirePairProc = {
actualName: ROPE = CoreOps.GetShortWireName[actualWire];
publicName: ROPE = CoreOps.GetShortWireName[publicWire];
IF NOT Rope.Equal[publicName, name] THEN RETURN; -- not a sub global candidate
IF actualName=NIL OR Rope.Equal[actualName, name] THEN InsertGlobal[actualWire];
};
FindWire: CoreOps.EachWireProc = {
IF Rope.Equal[CoreOps.GetShortWireName[wire], name] THEN InsertGlobal[wire];
};
rct: CoreClasses.RecordCellType = NARROW [record.data];
global: Wire;
FOR i: NAT IN [0..rct.size) DO
[] _ CoreOps.VisitBindingSeq[rct[i].actual, rct[i].type.public, FindGlobals];
ENDLOOP;
[] _ CoreOps.VisitWireSeq[rct.internal, FindWire];
IF globals=NIL THEN RETURN;
IF globals.rest=NIL AND Rope.Equal[CoreOps.GetShortWireName[globals.first], name] AND CoreOps.RecursiveMember[record.public, globals.first] THEN RETURN; -- all right already, nothing to do!
global _ CoreOps.SetShortWireName[globals.first, name];
globals _ globals.rest;
record.public _ ReplaceAndCleanSeq[record.public];
rct.internal _ ReplaceAndCleanSeq[rct.internal];
FOR i: NAT IN [0..rct.size) DO rct[i].actual _ ReplaceSeq[rct[i].actual] ENDLOOP;
WHILE globals#NIL DO
Sinix.FuseProperties[mode, globals.first, global, CoreOps.GetCellTypeName[record]];
globals _ globals.rest;
ENDLOOP;
};

Minor speedup modifications, no semantic changes -- JMF
The algorithm is:
- globals _ list of wires in internal/public to be identified with global `name'
Identified by looking up the internal by name and the 1st levels bindings by name of the internal and actual simultaneously (actual may be unnamed)
- if there is a single such wire, it has the right name and is public, then we're done
- define the 1st elem of globals to be the new single wire representing `name'
- cleanup public, internal and 1st level actuals
- public and internal may change size (extra copies of the global are removed, global is forced to be public)
- 1st level actuals cannot change sizes
- merge properties of all other representative of global into it
IF instance1.obj.layer=instance2.obj.layer THEN RETURN [TRUE];
Added code to handle the special case of ROPE as well as ROPES
more cases could be added in the SELECT statement, but some are not necessary (for example REF INT, due to the behavior of AMTypes.TVEqual).
Semi-public Utilities 
Compatibility code
We are trying to get rid of these ones, do not use them!
This was the top-level extract proc.  It evaluates the arguments to the schematic and then calls either ExtractCellIconInternal or Sinix.ExtractCell to do its job.
High risk code here: it costed BS 3 days of debugging.  The problem is that since Sinix.ExtractCell caches its result, some instances might have been created earlier with the returned cellType, and so it is incorrect to modify it in place.  Therefore ProcessGlobalNames must not change the cellType when all the work has already been done.  Properties are a bit funny too, and this code assumes that all cellType properties come from object expression/satellite, but not from an instance expression/satellite.  Therefore it is incorrect to put "coreProps _ ..." as an instance satellite.
This proc is called for cell icons. If a core definition is found then it is returned, otherwise a core cell of class Unspecified is returned.
Compute core for the schematic
Check public
This proc is called for wire icons. If a core definition is found it is returned, otherwise an error is signalled. As for cell icons, pins provide the attatchment points to the wire.

Check wire
special case
Tells if this variable is a result variable.
 
following token must be ': or '_ (': is a hack for the sequence stuff)
Exceptions
Module Initialization

�Ê*¡��˜�šœ™JšœH™HIcodešœ;Ïk™>Kšœ(™+Kšœ$™'Kšœ2™2Kšœ3™3Kšœ+™.Kšœ"™%J˜�—š	˜	Kšœœœ˜0Kšœ	œ5˜CKšœœ˜Kšœœ˜&Kšœ„˜†K˜	K˜+K˜
Kšœ˜Kšœœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—J˜�šÏn
œœœ˜JšœÝœœ4˜­Jšœ˜Jšœ/˜5Jšœœ	˜—head™š	œœœœ"œ˜IK˜�—šœœœ˜$K™8—šœœœ˜.K™H—Kšœœœ˜)Kšœœœ˜1šœœœ˜"Kšœ'œ™AK˜�—šœœœN˜oK˜�—Kš	œœœœ œ˜Ešœœœœ%˜LJ˜�—šœœœ˜0Jšœœ"œ˜;Jšœ4˜4Jšœ!˜!Jšœ˜Jšœ*˜*Jšœ˜Jšœ˜Jšœ˜J˜J˜——šœ™šž	œœœœœ
œœ˜fJšœ	œœ2˜HJšœ	œœ2˜HJšœ	œœœ-˜QJšœ	œœœ-˜Qšœœ˜Jš
œœœ	œœÏc˜=šœœ˜Jšœ ˜ šœœœœœ˜*Jšœ˜Jšœ˜Jšœ˜Jšœœ˜—J˜—Jšœœœ˜.JšœœŸ*˜C—J˜J˜�—šžœœ˜-Jšœ<˜<Jšœœœ˜IJšœ
œ˜Jšœ˜Jšœœ˜Jšœ(˜(Jšœœœœ˜Jšœœ
˜Jšœ)˜)Jšœœœ*˜:Jšœ<˜<Jšœ˜Jšœ7˜7J™šœœUœ˜aJšœaœ˜tJšœ#˜#Jšœ7œœœ˜QJšœ*˜*Jšœ9œœœ˜SJšœ˜Jš˜J˜—JšœJ˜JJšœ˜Jšœ˜J˜�—šžœœ˜2Jšœ<˜<Jšœœœ˜IJšœ
œ˜J˜Jšœ(˜(šœœ˜Jšœ'œ˜2šœœœ˜šœ˜Jšœ1˜1JšœN˜NJ˜—Jšœ<œ˜HJšœO˜OJšœœ˜——Jšœ™šœœ˜šœœ˜/Jšœ%™%Jšœ$˜$KšœP˜PJ˜—JšœA˜Ašœ˜JšœYœ˜lJšœ!˜!Jšœ7œœœ˜QJšœ%˜%Jšœ4œœœ˜NJšœ˜Jš˜J˜——Jšœ˜Jšœ˜J˜�—šžœœ˜4Jšž	œ>œ˜MJ˜JšœH˜HJšœœ
˜J˜(J˜J˜�—šžœ˜"J˜Jšœ˜Jšœœ˜Jšœ!œœ˜/Jšœœœœ˜)šÐbkÏb ¡ ¡™"Jš ¡  ¡ ¡ ¡ ¡ ¡™R—JšœŽ™ŽJšœ]˜]šœœ˜Jšœ˜!Jšœ˜Kšœ$œ˜+Jšœœ˜#Jšœmœ˜‚Jšœ˜—Jšœ,œ
˜:JšœF˜FJ˜Jšœ˜J™�—šž
œ˜$Kšœœ˜ Kšœœ˜"Kšœ#œ˜9Jšœ!˜!š
œœœœœ˜6KšœœsœœNœœœ˜‘Kšœœœœœ=œœœ˜±K˜—Kšœr˜xK˜K˜�—š œžœœœœœ˜XKšœœ˜"Kšœœ1˜8KšœœœMœ
œœ˜‰Kšœœ2œ˜\Kšœ˜——™šžœœœ
œœœ˜\šžœœ	œ˜(šœœ˜Kšœœ˜Kšœœ"œ˜AKšœ-˜-Kšœ-˜-šœœ˜KšœœD˜ZKšœœDœ˜ašœ˜Kšœ\œ
˜kKšœ˜K˜——Kšœ˜Kšœ˜—K˜—Kš	œœœœœ˜DKšœœœ˜0Kšœœœ˜>Kšœœ8˜NKšœ8˜8Kšœ˜K˜�—šžœœœœ™<K™TšÐbnœ™#Kšœ/™/Kšœ™—Kšœ3Ÿ)™\Kšœ#™#Kšœœœ™1Kšœœœ™5Kšœœœ
œ™,Kšœ™K™�—šžœœœœ˜<š¢œŸÐbcŸ$™NKšœ/™/Kšœ™—Kšœ3Ÿ)™\Kšœ#™#KšœŸ£Ÿ0˜OKšœœœŸ$˜VKšœœœ˜5Kšœœœ
œ˜,Kšœ˜K˜�—šžœœœœ	œœ˜AKšœ-˜-Kšœ˜K˜�—šžœœœœ	œœ˜BKšœ.˜.Kšœ˜K˜�—šžœœœœœ	œœ	œ˜\Kšœ,˜,Kšœœœœ˜šœœ˜Jš	œœœœœ˜*Jšœœœœœœ˜/JšœœŸ
˜—Kšœ˜K˜�—šž	œœœœœ	œœ	œ˜^Kšœ,˜,Kšœœœœ˜Jšœœœ˜(Kšœ˜K˜�—šž	œœœœœ	œœ	œ˜^Kšœ,˜,Kšœœœœ˜šœœ˜Jšœœœœ˜#Jš	œœœœœ˜8JšœœŸ
˜!—Kšœ˜K˜�—šžœœœœœ
œœœ˜ršœ5˜5Kšœ˜šœ'˜'Kšœ3˜3Kšœ˜—Kšœ
œ˜Kšœ˜—Kšœ˜K˜�—šž	œœœœœ
œœ˜RKšœœ
œœ˜0Kšœ/˜/šœœ˜Kšœ
œœœ˜CKšœœœ˜@Kšœ˜"—Kšœ˜K˜�—šžœœœœœœ˜TKšœœ
œœ˜4Kšœ3˜3šœœ˜Kšœ
œœ,˜CKšœ
œ.˜AKšœœœ4˜MKšœœœœd˜œ—Kšœ˜K˜�—šžœœœœœœ˜IKšœ4˜4K˜K™�—š
žœœœ	œœ˜JKšœœœœ˜RKš	œ
œœœœC˜ƒK˜K˜�—šžœ œœœ˜0Kš
œœ
œœŸ£Ÿ(™]šœ=™DKšœ™šœ'™'Kšœ3™3Kšœ™—Kšœ
œ™Kšœ™—Kš	œœ
œœŸ£˜;šœ7˜>Kšœ˜šœ'˜'Kšœ3˜3Kšœ˜—Kšœ
œ˜Kšœ˜—Kšœœœœ˜Kšœœ˜2Kšœ˜K˜�—šžœœ œœœ	¡™RKšœœ™$šžœœœœ™4šžœ™)Kšœœ™Kšœœœœ™K™.Kšœ)œœœ™?K™2Jšœœœœœœœ™KK™>K™%Jšœœœœœœ™7K™—Kšœ#™)Kšœ™—Kš
œ
œœœœ™Mšœ™K™�——šžœœ œœœŸ£˜RK™hKšœœ™@šžœœœœ˜1Kšœœ-œ™Lšžœ˜)Kšœœ˜KšœœœœœŸ ˜@K™.Kšœ)œœœ˜?K™HK˜%Jšœœœœœœ˜7K˜—Kšœœ"˜-Kšœ˜—šœœ˜KšœœœŸ˜(Kšœ
œœœŸ˜YKš
œœœ%œœŸ˜ZšœŸ-˜:Kšœœ˜Kšœœ˜š	œœœœ˜8Kšœ/˜/Kšœ/˜/KšœœœŸ&˜DKšœœœ˜Kš	œœœœŸ˜AKš
œœœœœœŸ˜IKšœ˜—KšœœŸ˜(Kšœ˜——šœ˜K˜�——šž
œœœ
œœœœœœ˜mKšœœœ1˜JKšœ
œœ6˜NKšœ
œœ6˜MKšœœœ1˜JKšœ
œœ6˜NKšœ
œœ6˜MKšœœœ2˜KKšœœœœ˜)Kšœœ"œœ œœœ˜bK™(Kšœœœ"œœœ˜IKšœœœœ˜7Kšœ˜K˜�—šžœœœœœœœ˜IKšœœœ2˜KKšœœœ"œœœ˜IKšœœœ˜=Kšœ˜——™šž
œœœœœœ˜Bš	œœœœ˜/Kš
œœ!œœœ˜;Kšœ˜	—š	œœœœ˜/Kš
œœ!œœœ˜;Kšœ˜	—Kšœœ˜˜K˜�——šžœœœœœœœ˜;Kšœœ˜Kšœ˜K˜�—šžœœœœœœœœ˜UKšœœœœ˜$Kšœœœœ˜$Kšœœœœ˜$Kšœœœœ˜$Kšœœœœ˜$Kšœœœœ˜$J˜——™ š¢œœœœ:œœœœœ˜”Kšœ-Ÿ)˜VKšœZ™Zšœœœ˜(šžœ˜(Kšœœ"˜2Kšœœ#œœ˜5Kšœœœ˜Kšœœœpœœœœœ˜ÏKšœ˜K˜—Jšœ!˜!Kšœœ'˜6Kšœœ˜JšœœœCœœœ˜~Kšœ1œœ˜=Kšœœœpœœœœ˜ÀKšœ5™5KšœI˜IKšœ8˜8Jšœ˜—Kšœ„™„šœœœ˜)Jšœ#˜#Kšœœ(˜8Kšœœ/˜GJšœœœœ˜Jšœœœœ˜Jšœ(œœ˜4Jšœqœœ˜šJšœ˜—K˜K˜�—šžœœœŸ£™AJšœBŸ£™HJšœ™šž
œœœ™:Jšœ
™
Jš
œœœœœ™BJ™—šžœœ
œ™1Jšœœœ™,Jšœœœœ™>J™—šžœœœ™BJšœœ
™šœœœ™ Jšœ™Jšœœœœ
™>Jšœ™—Jšœ™J™—šžœœ™#Jšœ
œœ%™?Jšœœœœ™IJ™—šžœ™)Jšœœ(™8Jšœœ(™8Jš	œœœœŸ™NJšœœœœ™PJ™—šžœ™"Jšœ2œ™LJ™—Jšœ"œ™7Jšœ
™
šœœœ™JšœM™MJšœ™—Jšœ2™2Jšœ	œœœ™Jš
œœœ;œ7œœŸ$™½Jšœ7™7Jšœ™Jšœ2™2Jšœ0™0Jš
œœœœ+œ™Qšœ	œ™JšœS™SJ™Jšœ™—J™J™�—šžœœœŸ£˜AJšœ1Ÿ£™7™™PJ™“—J™VJ™N™0J™mJ™'—J™@—Jšœ˜šž
œœ˜#Jš
œœœœœ˜BJ˜—šžœœ
œ˜1JšœŸ˜Jš
œœœœœœ˜TKšœœœ˜7J˜—šžœœœ˜BJšœœ
˜šœœœ˜ Jšœ˜Jšœœœœ
˜>Jšœ˜—Jšœ˜J˜—šžœœ˜#Jšœ
œœ%˜?Jšœœœœ˜IJ˜—šžœ˜)Jšœœ(˜8šœœŸ˜@Jšœœ(˜8Jšœœœœ˜PJ˜—J˜—šžœ˜"Jšœ2œ˜LJ˜—Jšœ"œ˜7Jšœ
˜
šœœœ˜JšœM˜MJšœ˜—Jšœ2˜2Jšœ	œœœ˜Jš
œœœ;œ7œœŸ$˜½Jšœ7˜7Jšœ˜Jšœ2˜2Jšœ0˜0Jš
œœœœœ˜Ašœ	œ˜JšœS˜SJ˜Jšœ˜—J˜J˜�—šžœœœœœœ˜=Jšœœ˜ Jšœ(˜.J˜J˜�—š¢œ˜!Jš	œ+œ+œœŸ(˜ŽJšœWœœ˜eJš ¡) ¡ ¡ ¡™>Jšœ_˜eJšœ˜J˜�—šžœœ
œœœœ˜>šž	œœœ	œœœ˜QJšœœ˜/J˜—šžœœœ	œœœ˜Nšœœœ˜AJšœœœ˜9—J˜—Jšœ)œ%œ(œ%œœ˜ßJšœ˜K˜�—š
žœœœœœ˜<Kšœ,˜,Kšœœœœ˜Kšœ˜K˜K˜�—š
žœœœœœ˜;Kšœœ˜'K˜K˜�—šžœœœœ˜@Kšœœ˜+K˜K˜�—šžœœœœ˜DKšœœ!˜/K˜K˜�—š
ž	œœœœœ˜<Kšœœ˜(K˜K˜�—š
žœœœœœ˜=Kšœœ˜-K˜K˜�—š
ž	œœœœœ˜+Kš
œœœœœ˜Kš
œœœœœ˜(šœœœ(˜CKšœ3˜3Kšœ"˜)—Kšœ˜J˜�—šž	œœœœ
œœ˜;Kšœ˜%Kšœ˜K˜�—šžœœœœœŸ£˜7Kšœ)œ™>Kšœœœœ˜0šœœœŸ/˜Ošœœœœ˜-Kšœœœ˜,Kšœœœ˜—šœœœœœŸ£˜2KšœœœŸ£˜/KšœœœŸ£˜!—Jšœ!œ4œœ*™ŒKšœœœ˜—K˜K˜�—šžœœœ˜Iš
žœœœœœ˜,K˜-K˜—K˜K˜(Kšœ˜K˜�—šžœœ œ˜@Kšœd˜dK˜K˜�—š
žœœœœ
œ˜HK˜AKšœ˜K˜�—š
žœœ
œ	œœ˜;Kšœ˜K˜——™šž	œœœœœ
œœ˜\šœ˜Kšœ
œ˜Kšœœœ˜K˜—Kš	œœœœœ˜!Kšœœœ˜/Kšœœœ˜)Kšœœ˜Kšœœœ5˜OKšœ$œ˜AKšœI˜Išœœ˜Kšœœœœ˜GKšœ<œ˜LK˜—šœ˜Kšœ	œœœ˜'Kšœœœœ˜#—K˜K˜�—šž
œœœ
œœœœ˜UKšœœ˜5K˜K˜�—šžœœœ
œœœœœ˜_Kšœœ˜:K˜K˜�—šžœœœœœœœ˜ršž	œœ	œœ˜.šœœ˜Kšœœ˜Kšœœ"œ˜AKšœ-˜-Kšœ-˜-šœœ˜KšœœD˜ZKšœœ_˜uKšœœDœ˜ašœœ˜6Kšœ@œœ
˜mKšœ˜K˜—šœ˜Kšœœœœœœ'˜~š
œœœœ œ˜AKš	œjœœœœ˜¯K˜—KšœœCœœ
˜Kšœ2˜2K˜——Kšœ˜Kšœ˜—K˜—Jšœ
œ
˜Kšœœœ˜,Jšœ(˜(Kšœ
œ5œ˜LKšœ
œ:œ˜QKšœ
œ:œ˜PKšœ
œ?œ˜UK˜K˜�—šžœœœ$˜Cš	œœ"œœ˜DJšœ'˜'Jšœ˜—J˜——™Jš¡8™8Jšœ£™£šžœœ˜/Jšœ˜Jšœœ˜Jšœ\˜\šœœ˜šœ ˜ Jšœ˜Kšœ$œ˜+Jšœ-˜-KšœMœœœ˜”JšœJ˜JJšœ0˜0J˜—šœ ˜ Jšœ˜Kšœ$œ˜+Jšœ.˜.KšœSœœœ˜šJšœB˜BJšœ,˜,J˜—Jšœ!œ˜'šœ˜Jšœ˜Jšœœª™ËJšœ=˜=Jšœœ
˜Jšœ!˜!JšœJ˜JKšœ$˜$Jšœ˜Jšœ˜——Jšœ˜J˜�—J™Žšžœœœœ˜]Jšœ
œ˜ Jšœœ œ˜JJ™Jšœœ˜%šœ
œ˜šœ˜Jšœ‹˜‹Jšœ˜—šœ˜Jšœœ%˜/Jšœœœ*˜:Jšœ<˜<J˜——Jšœ8˜8J™šœœVœ˜bJšœaœ˜tJšœ#˜#Jšœ7œœœ˜QJšœ*˜*Jšœ9œœœ˜SJšœ˜Jš˜J˜—Jšœ˜K˜�—J™¶šžœœœœ˜\Jšœ
œ˜ Jšœœ œ˜JJšœ	œ˜#Jšœœœœ˜J™�J™
šœœ˜Jšœ™Kšœg˜gJšœ˜J˜—šœEœœ˜]JšœYœ˜lJšœ!˜!Jšœ7œœœ˜QJšœ%˜%Jšœ0œœœ˜JJšœ˜Jš˜J˜—Jšœ˜J˜�—šœœœœœœ˜8K™,K™—šžœ˜ Kšœœœ˜SKšœ˜K˜�—šžœœœœœ*œœ&œœ˜µšž	œœ	œœ˜.Kšœœœ˜*šœœ˜Kšœœ˜Kšœœ"œ˜AKšœ-˜-Kšœ-˜-šœœ˜šœœ
œœ˜CKšœœœZœ
œœ˜¢KšœF™FKšœœ&œœ&œLœœ˜ÀKšœ.˜.K˜—šœœ(œ*˜]Kšœœœ˜)Kšœ)˜)šœ˜Kšœaœœœ
˜¢KšœPœœ
œ
˜—Kšœ*˜*K˜—KšœœD˜ZKšœœ_˜uKšœœDœ˜ašœœ˜6Kšœ@œœ
˜mKšœ˜K˜—šœ˜Kšœœœœœœ'˜~š
œœœœ œ˜AKš	œjœœœœ˜¯K˜—KšœœCœœ
˜Kšœ2˜2K˜——Kšœ˜Kšœ˜—Kšœœœ:˜SK˜—K˜�Jšœ
œ
˜Kšœœœ˜,Jšœ(˜(Kšœ
œ5œ˜LKšœ
œ:œ˜QKšœ
œ:œ˜PKšœ
œ?œ˜UK˜——™
š
žœœœœœ˜QK˜�—Kš
žœœœ%œœ˜Q—™KšœE˜EKšœC˜CKšœM˜MKšœQ˜QKšœ;˜;Kšœ?˜?K˜�KšœX˜XKšœV˜VKšœQ˜QKšœP˜PKšœY˜YK˜�—šœ˜J˜�—K™�—�…—����‚f��Í��