<> 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] ; DwimImpl: CEDAR MONITOR IMPORTS AMBridge, AMTypes, Atom, BBContext, BBEval, IO, List, Process, Rope, RTMiniModel, Spell, SymTab, UserExec, UserExecPrivate, WorldVM, ViewerAbort EXPORTS UserExec, UserExecPrivate SHARES UserExec, Atom = <> <> BEGIN OPEN IO, UserExec, UserExecPrivate; <> ExecPrivateRecord: PUBLIC TYPE = UserExecPrivate.ExecPrivateRecord; <> 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; <> 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; }; }; <> { IF RTMiniModel.AcquireIRType[defsName: id ! AMTypes.Error => CONTINUE] # RTBasic.nullType THEN TRUSTED { shouldBeTV _ AMBridge.TVForReferent[NEW[BasicUserExec.Interface _ NEW[BasicUserExec.InterfaceRec _ [id]]]]; GOTO Success; }; <> <> <> <> <> <> }; 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[]]]]; }; <> 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; }; }; <> 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 <> 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; <> 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; <> 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; }; <> GetEvalHead: PUBLIC PROC [exec: UserExec.ExecHandle, expr: Expression, viewer: Viewer _ NIL] RETURNS [evalHead: BBEval.EvalHead] = { evalHeadData: REF EvalHeadData; MakeNewEvalHead: PROC RETURNS[BBEval.EvalHead] = { RETURN[BBEval.NewEvalHead[ context: NIL, data: NEW[EvalHeadData _ [ exec: exec, viewer: IF viewer # NIL THEN viewer ELSE IF exec # NIL THEN exec.viewer ELSE NIL ]], helpFatal: HelpFatal, helpWrongType: HelpWrongType, helpId: HelpId, helpSelector: HelpSelector, helpDefault: HelpDefault, specials: SymTab.Create[], abortProc: Abort ]] }; private: REF ExecPrivateRecord; IF exec # NIL THEN {private _ exec.privateStuff; IF (evalHead _ private.evalHead) = NIL THEN {evalHead _ MakeNewEvalHead[]; private.evalHead _ evalHead; }; } ELSE IF viewer # NIL THEN {exec: UserExec.ExecHandle = UserExec.GetExecHandle[viewer: viewer]; evalHead _ MakeNewEvalHead[]; -- might also consider saving (caching) evalHead on viewer's property list, in situation where evaluation did not come from exec (e.g. ^E expansion) IF exec # NIL THEN {private: REF ExecPrivateRecord = exec.privateStuff; IF private.evalHead # NIL THEN evalHead.specials _ private.evalHead.specials; -- exec not specified, so don't pass it in for use with Abort and Confirm, but if viewer corresponds to an exec, use its context and evalHead, e.g. for ^E expansion in exec. }; ViewerAbort.ResetUserAbort[viewer]; } ELSE evalHead _ MakeNewEvalHead[]; evalHeadData _ NARROW[evalHead.data]; evalHeadData.expr _ expr; }; Abort: BBEval.AbortProc -- PROC [data: REF] RETURNS [abort: BOOL] -- = { evalHeadData: REF EvalHeadData = NARROW[data]; RETURN[ IF evalHeadData.exec # NIL AND UserExec.UserAbort[evalHeadData.exec] THEN TRUE ELSE IF evalHeadData.viewer # NIL AND ViewerAbort.UserAbort[evalHeadData.viewer] THEN TRUE ELSE FALSE]; }; <> <> <> <> <> < $foo>> < $foo,>> <> <> <> <> 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 PrintOrdinal: PROC [handle: STREAM, n: NAT] = { SELECT n FROM 1 => handle.Put[text["first"]]; 2 => handle.Put[text["second"]]; 3 => handle.Put[text["third"]]; 4 => handle.Put[text["fourth"]]; ENDCASE => handle.Put[card[n], text["th"]]; }; -- of PrintOrdinal Sum: PROC [list: LIST OF INT] RETURNS [sum: INT] = { sum _ 0; FOR l: LIST OF INT _ list, l.rest UNTIL l = NIL DO sum _ sum + l.first; ENDLOOP; }; RefSum: PROC [list: LIST OF REF INT] RETURNS [sum: INT] = { sum _ 0; FOR l: LIST OF REF INT _ list, l.rest UNTIL l = NIL DO sum _ sum + l.first^; ENDLOOP; }; TRUSTED {Process.Detach[FORK BuildFrameCache[]]}; -- to get it started, so don't have a long wait after everything else is up but before messagewindow says ready. -- EndOps.Register[UpdateFrameCache]; END. -- of DwimImpl <> <> <> <<>> <> <> <<>> <> <> <<>>