DIRECTORY
AMBridge USING [TVForReferent],
AMTypes USING [Class, Coerce, Domain, EnclosingBody, Error, First, GlobalParent, Globals, GroundStar, IndexToName, IndexToType, Last, Locals, NameToIndex, NComponents, Next, Procedure, Referent, Signal, TVToName, TVType, TypeClass, UnderType, Value],
Atom USING [GetPName, TypeGetProp],
BasicUserExec USING [Interface, InterfaceRec, CorrectionProc],
BBContext USING [Context, FindAction, FindMatchingGlobalFrames, FrameAction, EnumerateFramesInContext, GetContents],
BBEval USING [AbortProc, NewEvalHead, HelpFatal, HelpWrongType, HelpId, HelpSelector, HelpDefault, EvalHead, RopeOrTV],
IO USING [BreakProc, GetChar, card, GetOutputStreamRope, NUL, Put, PutF, PutRope, refAny, Reset, RIS, ROPE, rope, ROS, STREAM, text, tv, type, GetToken, UserAborted],
List USING [CompareProc, Sort],
Process USING [Detach],
Rope USING [Compare, Equal, Find, Substr, Concat, Cat, Fetch, Length, ROPE, Upper],
RTBasic USING [nullType],
RTMiniModel USING [AcquireIRType, GetLoadstateDefsNames],
Spell USING [GeneratorFromProcs, SpellingList, SpellingGenerator],
SymTab USING [Create, Fetch, Store],
UserExec USING [EvalExpr, CreateExpr, HistoryEvent, Expression, ExecHandle, UserAbort, ResetUserAbort, TV, Type, GetTheOne, FinishAskUser, SetupAskUser, EvaluationFailed, GetExecHandle, Viewer, GetStreams],
UserExecPrivate USING [GetPrivateStuff, PrintDeclFromSource, ExecPrivateRecord, GeneratorsRecord, Zone, EvalHeadData],
WorldVM USING [LocalWorld],
ViewerAbort USING [UserAbort, ResetUserAbort]
;
help procedures
HelpFatal: BBEval.HelpFatal
-- [head: EvalHead, parent: Tree, msg: ROPE] -- = {
evalHeadData: REF EvalHeadData = NARROW[head.data];
ERROR EvaluationFailed[expr: evalHeadData.expr, msg: msg];
};
HelpWrongType: BBEval.HelpWrongType
-- [head: EvalHead, parent: Tree, value: TV, target: Type, msg: ROPE] RETURNS [correct: RopeOrTV] -- = {
OPEN AMTypes;
evalHeadData: REF EvalHeadData = NARROW[head.data];
outRopeStream: STREAM = ROS[];
flag: BOOLEAN;
shouldBeTV: TV;
[flag, shouldBeTV] ← SupplyCorrectValue[exec: evalHeadData.exec, targetType: target, valueSupplied: value]; -- e.g. convert value to REF value, convert ROPE to Long String, REF TEXT, REF READONLY TEXT, or Rope.Text
IF flag THEN RETURN[[tv[shouldBeTV]]];
SELECT TypeClass[target]
FROM
procedure =>
{
IF value =
NIL
THEN
-- check for inline
{
i: INT;
firstToken: ROPE;
exec: UserExec.ExecHandle = evalHeadData.exec;
outRopeStream.Reset[];
outRopeStream.Put[refAny[parent]];
firstToken ← IO.GetToken[RIS[GetOutputStreamRope[outRopeStream]]]; -- GetToken used, rather than GetMesaToken, so that Foo.Fie will be returned
msg ← "Can't call an INLINE yet";
i ← Rope.Find[firstToken, "."];
IF i # -1
THEN
{r: ROPE;
outRopeStream.Reset[];
outRopeStream.Put[rope[firstToken], text[": "]];
[] ← UserExecPrivate.PrintDeclFromSource[target: Rope.Substr[firstToken, i + 1], file: Rope.Concat[Rope.Substr[base: firstToken, len: i], ".mesa"], exec: exec];
r ← GetOutputStreamRope[outRopeStream];
IF Rope.Find[r, "INLINE"] # -1 THEN msg ← Rope.Concat[r, msg];
};
RETURN[[fail[msg]]];
};
};
ENDCASE;
outRopeStream.Reset[];
{
ENABLE
ANY =>
{UserExec.GetStreams[evalHeadData.exec].out.PutRope[outRopeStream.GetOutputStreamRope[]]; -- if error occurs while printing, print how far you got.
outRopeStream.Reset[]; -- so wont get printed twice if more than one signal
};
outRopeStream.PutF["*n********Wrong Type: %g\nshould be of type: %g\nis of type: %g", tv[value], type[target], type[TVType[value]]];
};
RETURN[[fail[outRopeStream.GetOutputStreamRope[]]]];
};
HelpId: BBEval.HelpId
-- [head: EvalHead, parent: Tree, id: ROPE, context: Type, target: Type, msg: ROPE] RETURNS [correct: RopeOrTV] -- = {
evalHeadData: REF EvalHeadData = NARROW[head.data];
exec: UserExec.ExecHandle = evalHeadData.exec;
viewer: Viewer = evalHeadData.viewer;
expr: Expression = evalHeadData.expr;
shouldBe: ROPE;
shouldBeTV: TV;
success: BOOL ← FALSE;
{
-- to establish scope for exits
ENABLE IO.UserAborted =>
{UserExec.ResetUserAbort[exec]; -- so guy up above will be able to print the message without himself being aborted.
msg ← Rope.Concat["aborted\n", msg];
GOTO Fail;
};
IF Rope.Equal[msg, "undefined"]
THEN
{
underType: Type ← AMTypes.UnderType[target];
class: AMTypes.Class = AMTypes.TypeClass[underType];
ground: Type;
flag: BOOLEAN;
WOULD BE NICE IF COULD DISTINGUISH LISTT.APPEND FROM LISTT SO THAT COULD TRY MODULE CORRECTION FIRST ON FORMER.
msg ← Rope.Cat[id, " is ", msg];
IF (expr # NIL AND expr.dontCorrect) THEN GOTO Fail;
IF Rope.Fetch[id, 0] = '&
THEN {
-- user types &A3 to refer to 3rd & var in workarea A
stream: STREAM = IO.RIS[id];
execId: ROPE;
exec: UserExec.ExecHandle;
private: REF UserExecPrivate.ExecPrivateRecord;
untilNumber: IO.BreakProc = {
RETURN[IF char IN ['0..'9] THEN break ELSE other];
};
[] ← stream.GetChar[]; -- the &
execId ← stream.GetToken[untilNumber];
IF (exec ← UserExec.GetExecHandle[id: execId]) = NIL THEN GOTO Fail;
private ← UserExecPrivate.GetPrivateStuff[exec];
[success, shouldBeTV] ← SymTab.Fetch[private.evalHead.specials, Rope.Concat["&", stream.GetToken[]]];
IF success THEN GOTO Success;
GOTO Fail;
};
IF class = enumerated
THEN
{
enumTypeGenerator: Spell.SpellingGenerator ← GetGenerators[evalHeadData].enumTypeGenerator;
enumGenState: REF EnumGenState = NARROW[enumTypeGenerator.clientData];
enumGenState^ ← [tv: AMTypes.First[underType]];
shouldBe ← UserExec.GetTheOne[unknown: id, generator: enumTypeGenerator, event: NIL, exec: exec, viewer: viewer];
IF shouldBe # NIL THEN GOTO Success;
}
ELSE
IF class = subrange
AND AMTypes.TypeClass[ground ← AMTypes.GroundStar[underType]] = enumerated
THEN
{
i: INT ← 0;
i ← AMTypes.NameToIndex[ground, id ! AMTypes.Error => IF reason = badName THEN CONTINUE];
IF i # 0
THEN
-- WORK AROUND means id was in the enumerated type to begin with
{tv: TV = AMTypes.Value[ground, i]; -- gets the corresponding tv.
shouldBeTV ← NIL;
shouldBeTV ← AMTypes.Coerce[tv: tv, targetType: target !
AMTypes.Error => IF reason = typeFault OR reason = rangeFault THEN CONTINUE;
];
IF shouldBeTV # NIL THEN GOTO Success; -- was correct all along
msg ← "out of range";
}
ELSE
{subrangeGenerator: Spell.SpellingGenerator ← GetGenerators[evalHeadData].subrangeGenerator;
subrangeGenState: REF SubrangeGenState = NARROW[subrangeGenerator.clientData];
subrangeGenState^ ← [tv: AMTypes.First[underType], last: AMTypes.Last[underType], ground: ground];
shouldBe ← UserExec.GetTheOne[unknown: id, generator: subrangeGenerator, event: NIL, exec: exec, viewer: viewer];
IF shouldBe # NIL THEN GOTO Success;
};
};
still inside of Undefined
{
IF RTMiniModel.AcquireIRType[defsName: id ! AMTypes.Error =>
CONTINUE] # RTBasic.nullType
THEN
TRUSTED {
shouldBeTV ← AMBridge.TVForReferent[NEW[BasicUserExec.Interface ← NEW[BasicUserExec.InterfaceRec ← [id]]]];
GOTO Success;
};
name: ATOM = Atom.MakeAtom[id]; -- work around.
FOR l: LIST OF ATOM ← interfaceList, l.rest UNTIL l = NIL DO
IF l.first = name THEN TRUSTED {
shouldBeTV ← AMBridge.TVForReferent[NEW[BasicUserExec.Interface ← NEW[ROPE ← id]]];
GOTO Success;
};
ENDLOOP;
};
IF evalHeadData.defaultInterface #
NIL
THEN {
ENABLE EvaluationFailed => CONTINUE;
expr: UserExec.Expression = UserExec.CreateExpr[rope: Rope.Cat[evalHeadData.defaultInterface, ".", id]];
save: TV = SymTab.Fetch[x: head.specials, key: "&"].val;
shouldBeTV ← UserExec.EvalExpr[expr: expr, exec: evalHeadData.exec, viewer: evalHeadData.viewer].value;
[] ← SymTab.Store[x: head.specials, key: "&", val: save];
IF expr.correctionMade THEN shouldBe ← Rope.Substr[base: expr.rope, start: Rope.Find[expr.rope, "."] + 1];
GOTO Success;
};
{ --
search default global context
gf: TV = BBContext.GetContents[head.globalContext].gf;
IF gf # NIL AND (shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: AMTypes.TVType[AMTypes.Globals[gf]]]) # NIL THEN GOTO Success;
};
{ --
search local frames (still inside of Rope.Equal[msg, "undefined"]
)
gf: TV;
SearchFrame: BBContext.FrameAction
-- [lf: TV] RETURNS [ActionContinuation ← continue] -- = {
ptv: TV;
type: Type;
IF (count ← count + 1) > howMany AND NOT Rope.Equal[AMTypes.TVToName[gf], AMTypes.TVToName[AMTypes.GlobalParent[lf]]] THEN RETURN[quit]; -- says once you go beyond howMany, you can keep going so long as you are in the same global frame. Heuristic is to prevent searching off into space somewhere, but to allow climbing stack inside of procedure calls in same module.
gf ← AMTypes.GlobalParent[lf];
ptv ← AMTypes.Procedure[lf ! AMTypes.Error => CONTINUE];
IF ptv = NIL THEN ptv ← AMTypes.Signal[lf ! AMTypes.Error => CONTINUE];
DO
IF (shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: AMTypes.TVType[AMTypes.Locals[lf]]]) # NIL THEN RETURN[quit];
IF (lf ← AMTypes.EnclosingBody[lf]) = NIL THEN EXIT;
ENDLOOP;
IF ptv #
NIL AND (type ← AMTypes.TVType[ptv]) # RTBasic.nullType
THEN
{IF (shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: AMTypes.UnderType[AMTypes.Domain[type]]]) # NIL THEN RETURN[quit];
};
IF (shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: AMTypes.TVType[AMTypes.Globals[gf]]]) # NIL THEN RETURN[quit];
}; -- end of SearchFrame
count: INT ← 0;
howMany: INT = 3;
IF head.context # NIL THEN BBContext.EnumerateFramesInContext[context: head.context, action: SearchFrame];
IF shouldBe # NIL THEN GOTO Success;
};
IF target = RTBasic.nullType
THEN
{
line: ROPE = expr.rope;
i: INT ← Rope.Find[line, id];
char: CHARACTER;
IF i = -1
OR (i ← i + Rope.Length[id]) = Rope.Length[line]
OR (char ← Rope.Fetch[line, i]) # '[
THEN
-- id[ can't possibly be frame name. cuts down a lot of cases.
{
frameGenerator: Spell.SpellingGenerator = GetGenerators[evalHeadData].frameGenerator;
frameGenState: REF FrameGenState = NARROW[frameGenerator.clientData];
frameGenState.startsWith ← Rope.Upper[Rope.Fetch[id, 0]];
IF frameGenState.startsWith IN ['A..'Z] AND (frameGenState.frameList ← frameCache[frameGenState.startsWith]) # NIL THEN shouldBe ← UserExec.GetTheOne[unknown: id, generator: frameGenerator, event: NIL, exec: exec, viewer: viewer];
IF shouldBe # NIL THEN GOTO Success;
};
};
[flag, shouldBeTV] ← CorrectUndefinedId[exec: exec, targetType: target, id: id];
IF flag THEN GOTO Success;
}
ELSE
IF Rope.Equal[msg, "invalid selector"]
THEN
{
IF expr # NIL AND expr.dontCorrect THEN GOTO Fail;
shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: context];
IF shouldBe # NIL THEN GOTO Success;
};
GOTO Fail;
EXITS
Success => success ← TRUE; -- necessary because a plausible successful return is with shouldBeTV = NIL
Fail => NULL;
};
IF evalHeadData.confirmMenuUp
THEN
{UserExec.FinishAskUser[evalHeadData.viewer];
evalHeadData.confirmMenuUp ← FALSE;
};
IF NOT success THEN RETURN[[fail[msg]]]
ELSE
IF shouldBe #
NIL
THEN
{expr.correctionMade ← TRUE;
IF shouldBeTV # NIL THEN RETURN[[both[rope: shouldBe, tv: shouldBeTV]]]
ELSE RETURN[[rope[shouldBe]]];
}
ELSE RETURN[[tv[shouldBeTV]]];
};
HelpSelector: BBEval.HelpSelector
-- [head: EvalHead, parent: Tree, id: ROPE, context: TV, target: Type, msg: ROPE] RETURNS [correct: RopeOrTV] -- = {
OPEN AMTypes;
evalHeadData: REF EvalHeadData = NARROW[head.data];
errorMsg: ROPE ← Rope.Cat[msg, " on ", id];
shouldBe: ROPE;
type: Type = UnderType[TVType[context]];
class: Class ← TypeClass[type];
{
ENABLE IO.UserAborted =>
{UserExec.ResetUserAbort[evalHeadData.exec];
msg ← Rope.Concat["aborted\n", msg];
GOTO Fail;
};
IF evalHeadData.expr.dontCorrect THEN GOTO Fail;
SELECT class
FROM
globalFrame =>
{globalsType: Type = TVType[Globals[context]];
shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: globalsType];
IF shouldBe # NIL THEN GOTO Success;
};
ref, list =>
BEGIN
typ: Type ← UnderType[TVType[context]];
class ← TypeClass[typ];
SELECT class
FROM
ref, list, pointer, longPointer =>
{referentTV: TV ← Referent[context ! ANY => GOTO Fail];
typ ← UnderType[TVType[referentTV]];
class ← TypeClass[typ];
};
ENDCASE;
SELECT class
FROM
record, structure =>
{shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: typ];
IF shouldBe # NIL THEN GOTO Success;
};
ENDCASE;
END;
record =>
{shouldBe ← FixSpellFromType[evalHeadData: evalHeadData, unknown: id, type: type];
IF shouldBe # NIL THEN GOTO Success;
};
ENDCASE;
GOTO Fail;
EXITS
Success => NULL;
Fail => NULL;
};
IF evalHeadData.confirmMenuUp
THEN
{UserExec.FinishAskUser[evalHeadData.viewer];
evalHeadData.confirmMenuUp ← FALSE;
};
IF shouldBe # NIL THEN RETURN[[rope[shouldBe]]]
ELSE RETURN[[fail[errorMsg]]];
};
HelpDefault: BBEval.HelpDefault
-- [head: EvalHead, parent: Tree, type: Type, index: CARDINAL, msg: ROPE] RETURNS [correct: RopeOrTV] -- = {
OPEN AMTypes;
evalHeadData: REF EvalHeadData = NARROW[head.data];
outRopeStream: STREAM = ROS[];
flag: BOOLEAN;
shouldBe: TV;
argType: Type ← IndexToType[type, index];
argName: ROPE;
[flag, shouldBe] ← SupplyMissingArgument[argType]; -- until IndexToDefaultInitialValue works for all cases. e.g. Docs uses this to default REALS to notSpecifiedreal, etc.
IF flag THEN RETURN[[tv[shouldBe]]];
{
ENABLE
ANY =>
{exec: UserExec.ExecHandle = evalHeadData.exec;
UserExec.GetStreams[exec].out.PutRope[outRopeStream.GetOutputStreamRope[]]; -- if error occurs while printing, print how far you got.
};
outRopeStream.PutF["\n******Missing Arguments: "];
argName ← IndexToName[type, index];
IF argName # NIL THEN outRopeStream.Put[rope[argName]]
ELSE {PrintOrdinal[outRopeStream, index]; outRopeStream.PutRope[" argument"]};
outRopeStream.Put[rope[": "], IO.type[argType]];
};
RETURN[[fail[outRopeStream.GetOutputStreamRope[]]]];
};
spelling correction
FixSpellFromType:
PROC [evalHeadData:
REF EvalHeadData, unknown:
ROPE, type: Type, signal:
BOOLEAN ←
TRUE]
RETURNS[shouldBe:
ROPE] = {
typeElementGenerator: Spell.SpellingGenerator = GetGenerators[evalHeadData].typeElementGenerator;
typeGenState: REF TypeGenState = NARROW[typeElementGenerator.clientData];
typeGenState^ ← [type: type, last: AMTypes.NComponents[type], index: 1];
IF
NOT evalHeadData.confirmMenuUp
AND evalHeadData.viewer #
NIL
THEN
{UserExec.SetupAskUser[evalHeadData.viewer];
evalHeadData.confirmMenuUp ← TRUE;
};
shouldBe ← UserExec.GetTheOne[unknown: unknown, generator: typeElementGenerator, event: NIL, exec: evalHeadData.exec, viewer: evalHeadData.viewer];
IF shouldBe #
NIL
AND signal
THEN
{expr: Expression = evalHeadData.expr;
IF expr # NIL THEN expr.correctionMade ← TRUE;
};
};
generators used by dwim are stored in the private.generators field. They are initialized first time they are used.
GetGenerators:
PROC [evalHeadData:
REF EvalHeadData]
RETURNS[
REF GeneratorsRecord] = {
IF evalHeadData.generators =
NIL
THEN evalHeadData.generators ← UserExecPrivate.Zone.
NEW[GeneratorsRecord ←
[
typeElementGenerator: Spell.GeneratorFromProcs[generate: TypeGenerate, clientData: UserExecPrivate.Zone.NEW[TypeGenState ← []]],
enumTypeGenerator: Spell.GeneratorFromProcs[generate: EnumGenerate, clientData: UserExecPrivate.Zone.NEW[EnumGenState ← []]],
subrangeGenerator: Spell.GeneratorFromProcs[generate: SubrangeGenerate, clientData: UserExecPrivate.Zone.NEW[SubrangeGenState ← []]],
frameGenerator: Spell.GeneratorFromProcs[generate: FrameGenerate, clientData: UserExecPrivate.Zone.NEW[FrameGenState ← []]]
]
];
RETURN[evalHeadData.generators];
};
TypeGenState: TYPE = RECORD[type: Type ← NULL, last: CARDINAL ← NULL, index: CARDINAL ← NULL];
TypeGenerate:
PROCEDURE [self: Spell.SpellingGenerator]
RETURNS [object:
ROPE] = {
r: ROPE;
typeGenState: REF TypeGenState = NARROW[self.clientData];
IF typeGenState.index > typeGenState.last THEN RETURN[NIL];
r ← AMTypes.IndexToName[typeGenState.type, typeGenState.index];
typeGenState.index ← typeGenState.index + 1;
RETURN[r]
};
EnumGenState: TYPE = RECORD[tv: TV ← NIL];
EnumGenerate:
PROCEDURE [self: Spell.SpellingGenerator]
RETURNS [object:
ROPE] = {
enumGenState: REF EnumGenState = NARROW[self.clientData];
tv: TV = enumGenState.tv;
r: ROPE;
IF tv = NIL THEN RETURN[NIL];
r ← AMTypes.TVToName[tv];
enumGenState.tv ← AMTypes.Next[tv];
RETURN[r]
};
SubrangeGenState: TYPE = RECORD[tv, last: TV ← NIL, ground: Type ← NULL];
SubrangeGenerate:
PROCEDURE [self: Spell.SpellingGenerator]
RETURNS [object:
ROPE] = {
subrangeGenState: REF SubrangeGenState = NARROW[self.clientData];
tv: TV = subrangeGenState.tv;
r: ROPE;
IF tv = NIL THEN RETURN[NIL]; -- HOW TEST FOR LAST?
r ← AMTypes.TVToName[AMTypes.Coerce[tv, subrangeGenState.ground]];
subrangeGenState.tv ← AMTypes.Next[tv];
RETURN[r]
};
FrameGenState: TYPE = RECORD[startsWith: CHARACTER ← IO.NUL, frameList: LIST OF ROPE ← NIL];
FrameGenerate:
PROCEDURE [self: Spell.SpellingGenerator]
RETURNS [object:
ROPE] = {
frameGenState: REF FrameGenState ← NARROW[self.clientData];
object ← frameGenState.frameList.first;
IF Rope.Upper[Rope.Fetch[object, 0]] > frameGenState.startsWith THEN RETURN[NIL];
frameGenState.frameList ← frameGenState.frameList.rest;
}; -- of FrameGenerate
frame cache
frameCache: REF ARRAY CHARACTER['A..'Z] OF LIST OF ROPE ← NIL; -- contains a pointer into frameList starting at first frame which begins with given character
frameList: LIST OF ROPE ← NIL;
interfaceList: LIST OF ATOM ← NIL; -- workaround so I can tell if something is the name of an interface
previouslySeen: ROPE ← NIL;
BuildFrameCache:
ENTRY PROCEDURE = {
FindAction: BBContext.FindAction
-- [gf: TV, name: ROPE] RETURNS [ActionContinuation ← continue] -- = {
IF name #
NIL
THEN {
IF previouslySeen = NIL THEN previouslySeen ← name;
frameList ← CONS[name, frameList];
};
RETURN[continue];
};
compare: List.CompareProc = {
RETURN[Rope.Compare[NARROW[ref1, Rope.ROPE], NARROW[ref2, Rope.ROPE], FALSE]]
};
lastChar: CHARACTER ← IO.NUL;
interfaceList ← RTMiniModel.GetLoadstateDefsNames[];
FOR l:
LIST
OF
ATOM ← RTMiniModel.GetLoadstateDefsNames[], l.rest
UNTIL l =
NIL
DO
frameList ← CONS[Atom.GetPName[l.first], frameList];
ENDLOOP;
TRUSTED {BBContext.FindMatchingGlobalFrames[world: WorldVM.LocalWorld[], pattern: "*", action: FindAction]};
TRUSTED {frameList ← LOOPHOLE[List.Sort[list: LOOPHOLE[frameList, LIST OF REF ANY], compareProc: compare], LIST OF ROPE]};
frameCache ← NEW[ARRAY CHARACTER['A..'Z] OF LIST OF ROPE ← ALL[NIL]];
FOR l:
LIST
OF
ROPE ← frameList, l.rest
UNTIL l =
NIL
DO
thisChar: CHARACTER = Rope.Upper[Rope.Fetch[l.first, 0]];
IF thisChar # lastChar
THEN
{lastChar ← thisChar;
frameCache[thisChar] ← l;
};
ENDLOOP;
};
UpdateFrameCache:
PUBLIC ENTRY PROCEDURE = {
FindAction: BBContext.FindAction
-- [gf: TV, name: ROPE] RETURNS [ActionContinuation ← continue] -- = {
IF name #
NIL
THEN
{IF Rope.Equal[name, previouslySeen] THEN RETURN[quit]; -- now entering that part of the enumeration already seen.
IF firstSeen = NIL THEN firstSeen ← name;
newFramesList ← CONS[name, newFramesList];
};
RETURN[continue];
};
newFramesList: LIST OF ROPE;
firstSeen: ROPE ← NIL;
IF previouslySeen = NIL THEN RETURN; -- cache is not yet built, e.g. user runs a bcd from his profile.
TRUSTED {BBContext.FindMatchingGlobalFrames[world: WorldVM.LocalWorld[], pattern: "*", action: FindAction]};
FOR l:
LIST
OF
ROPE ← newFramesList, l.rest
UNTIL l =
NIL
DO
thisChar: CHARACTER = Rope.Upper[Rope.Fetch[l.first, 0]];
IF frameCache[thisChar] = NIL THEN frameCache[thisChar] ← LIST[l.first]
ELSE
FOR l1:
LIST
OF
ROPE ← frameCache[thisChar], l1.rest
UNTIL l1 =
NIL
DO
IF Rope.Compare[l.first, l1.first] = less
THEN
{l1.rest ← CONS[l1.first, l1.rest];
l1.first ← l.first;
EXIT;
};
ENDLOOP;
ENDLOOP;
IF firstSeen # NIL THEN previouslySeen ← firstSeen;
};
miscellaneous
AttachDefaultArgVal, AttachTypeCorrectionProc are in BasicUserExecImpl
Currently the following defaultArgVals are defined:
targetType; PROC ANY, default: NIL
Currently the following type correction procs are defined for the indicated target types
ATOM, undefined id goes to corresponding atom, e.g. foo -> $foo
REF ANY, undefined id goes to corresponding atom, e.g. foo -> $foo,
something of type T goes to REF T
LONG STRING, object of type ROPE goes to correspoding long string
REF TEXT, object of type ROPE goes to corresponding REF TEXT
REF READONLY TEXT, object of type ROPE goes to corresponding REF READONLY TEXT
SupplyCorrectValue:
PROC [exec: ExecHandle, targetType: Type, valueSupplied:
TV]
RETURNS[flag:
BOOLEAN ←
FALSE, shouldBe:
TV ←
NIL] = {
OPEN AMTypes;
ref: REF ANY ← Atom.TypeGetProp[type: targetType, prop: $WrongTypeProc];
IF ref #
NIL
THEN
{proc: BasicUserExec.CorrectionProc ← (NARROW[ref, REF BasicUserExec.CorrectionProc])^;
[flag, shouldBe] ← proc[targetType: targetType, wrongValue: valueSupplied, exec: exec]
};
}; -- of SupplyCorrectValue
CorrectUndefinedId:
PROC [exec: ExecHandle, targetType: Type, id:
ROPE]
RETURNS[flag:
BOOLEAN ←
FALSE, shouldBe:
TV ←
NIL] = {
OPEN AMTypes;
ref: REF ANY ← Atom.TypeGetProp[type: targetType, prop: $WrongTypeProc];
IF ref #
NIL
THEN {
proc: BasicUserExec.CorrectionProc ← (NARROW[ref, REF BasicUserExec.CorrectionProc])^;
[flag, shouldBe] ← proc[targetType: targetType, undefinedId: id, exec: exec]
};
}; -- of CorrectUndefinedId
SupplyMissingArgument:
PROC [argType: Type]
RETURNS[flag:
BOOLEAN, shouldBe:
TV] = {
shouldBe ← Atom.TypeGetProp[type: argType, prop: $DefaultValue];
IF shouldBe # NIL THEN RETURN[TRUE, shouldBe];
BEGIN OPEN AMTypes;
underType: Class ← TypeClass[UnderType[argType]];
SELECT underType
FROM
ref, list, procedure, unspecified, pointer => RETURN[TRUE, NIL]; -- for case of procedure, gets converted to a REF short NIL in CheckArgType
ENDCASE;
END;
RETURN[FALSE, NIL];
}; -- of SupplyMissingArgument