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]; }; 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 ͺLast Edited by: teitelman, April 19, 1983 12:14 pm Atom: TypeGetProp UserExec: AcquireStreams, ReleaseStreams connecting concrete and opaque types help procedures WOULD BE NICE IF COULD DISTINGUISH LISTT.APPEND FROM LISTT SO THAT COULD TRY MODULE CORRECTION FIRST ON FORMER. still inside of Undefined 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; spelling correction generators used by dwim are stored in the private.generators field. They are initialized first time they are used. frame cache interfaceList: LIST OF ATOM _ NIL; -- workaround so I can tell if something is the name of an interface interfaceList _ RTMiniModel.GetLoadstateDefsNames[]; eval head 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 Edited on March 25, 1983 5:32 pm, by Teitelman UserExecInterpImpl no longer saves & variables in global table. Installed fix so that things like &A3 would work by looking up the exec, etc. changes to: DIRECTORY, HelpId, untilNumber (local of HelpId), HelpId, untilNumber (local of HelpId) Edited on April 8, 1983 1:35 pm, by Teitelman changes to: HelpId, DIRECTORY Edited on April 19, 1983 12:14 pm, by Teitelman changes to: DIRECTORY, IMPORTS Κλ– "Cedar" style˜J˜Jšœ2™2šΟk ˜ Jšœ œ˜Jšœœν˜ϊJšœœ˜$Jšœœ+˜>Jšœ œg˜vJšœœl˜xJš œœ1œ%œœ œ'˜¦Jšœœ˜Jšœœ ˜Jšœœ<œ ˜VJšœœ ˜Jšœ œ(˜9Jšœœ7˜BJšœœ˜$Jšœ œYœe˜ΞJšœœa˜vJšœœ˜Jšœ œ˜.J˜J˜—J˜JšΠblœœ˜J˜Jšœ-œb˜˜J˜Jšœ˜!J˜šœ˜Jšœ™Jšœ(™(—J˜Jšœœœ˜*headšœ$™$JšΟnœœœ%˜C—™šŸ œΟc/œ˜OJšœœœ ˜3Jšœ5˜:J˜—J˜šŸ œ dœ˜ŒJšœ ˜ Jšœœœ ˜3Jšœœœ˜Jšœœ˜Jšœ œ˜Jšœm k˜ΨJšœœœ˜&šœ˜šœ ˜šœ œœ ˜'šœ˜Jšœœ˜Jšœ œ˜J˜.J˜J˜"Jšœœ( L˜J˜"J˜šœ˜Jšœœ˜ J˜J˜0Jšœ ˜ J˜'Jšœœ˜>J˜—Jšœ˜J˜——J˜J˜—Jšœ˜—J˜šœ˜šœœ˜ Jšœ Πbo œF 9˜“Jšœ 4˜KJ˜—J˜„J˜—Jšœ.˜4J˜—J˜šŸœrœ˜ŒJšœœœ ˜3Jšœ.˜.Jšœ%˜%J˜%Jšœ œ˜Jšœ œ˜Jšœ œœ˜šœ ˜!šœ˜Jšœ  S˜sJ˜$Jšœ ˜ J˜—šœ˜$˜J˜,J˜4J˜ Jšœœ˜Jš o™oJ˜ Jš œ œœœœ˜4šœœ 5˜VJšœœœœ˜Jšœœ˜ Jšœ˜Jšœ œ#˜/šŸ œ˜Jš œœœ œœ˜2J˜—Jšœ ˜ Jšœ&˜&Jšœ/œœœ˜DJšœ0˜0Jšœe˜eJšœ œœ ˜Jšœ˜ J˜—šœœ˜˜J˜\Jšœœœ˜FJ˜/JšœPœ˜qJšœ œœœ ˜%J˜——šœœœH˜hšœ˜Jšœœ˜ Jšœ6œœœ˜Zšœœ @˜NJšœœ ˜AJšœ œ˜šœ8˜8Jšœœ+œœ˜LJšœ˜—Jš œœœœ  ˜@J˜J˜—š˜J˜\Jšœœœ˜NJ˜bJšœPœ˜qJšœ œœœ ˜$J˜J˜—J˜——Jšœ™šœ˜šœ;œœœ˜hJšœ$œœœ˜kJšœ ˜ Jšœ˜Jšœ˜—Jšœœ ™2š œœœœœœ™<šœ™ Jšœ$œœœ ™SJšœ ™—Jšœ™—Jšœ˜—šœ!œ˜-Jšœœ˜$Jšœh˜hJšœœ0˜8Jšœg˜gJšœ9˜9JšœœO˜jJšœ ˜ Jšœ˜J˜—šœ ˜"Jšœœ0˜6Jš œœœuœœœ ˜›J˜—šœ %œ ˜GJšœœ˜šŸ œ 6œ˜]Jšœœ˜J˜ Jš œœœNœœ ζ˜οJšœ˜Jšœ.œ˜8Jšœœœ,œ˜Gš˜Jšœtœœœ˜ŒJšœ$œœœ˜4Jšœ˜—šœœ0œ˜FJšœyœœœ˜’J˜—Jšœuœœœ˜ŽJšœ ˜—Jšœœ˜Jšœ œ˜JšœœœP˜jJšœ œœœ ˜$J˜—šœ˜"šœ˜Jšœœ˜Jšœœ˜Jšœ œ˜š œœ/œ#œ >˜£˜J˜UJšœœœ˜EJ˜9Jš œœ œDœœOœ˜ηJšœ œœœ ˜$J˜——J˜——J˜PJšœœœ ˜J˜——šœœ%˜0šœ˜Jš œœœœœ˜2J˜TJšœ œœœ ˜$J˜——Jšœ˜ Jš˜Jšœœ K˜gJšœœ˜ Jšœ˜—šœ˜"Jšœ-˜-Jšœœ˜#Jšœ˜—Jšœœ œœ ˜'šœœ œ˜Jšœœ˜Jšœœœœ(˜GJšœœ˜J˜—Jšœœ˜J˜—J˜šŸ œpœ˜–Jšœ ˜ Jšœœœ ˜3Jšœ œ˜+Jšœ œ˜J˜(J˜š˜šœ˜J˜,J˜$Jšœ˜ J˜J˜—Jšœœœ˜0šœ˜˜Jšœ-˜.JšœX˜XJšœ œœœ ˜$Jšœ˜J˜—šœ ˜J˜'J˜šœ˜˜"Jšœ œœœ˜7J˜$J˜J˜—Jšœ˜—šœ˜˜JšœQ˜QJšœ œœœ ˜$J˜—Jšœ˜—Jšœ˜J˜—˜ JšœQ˜RJšœ œœœ ˜$Jšœ˜J˜—Jšœ˜—Jšœ˜ š˜Jšœ œ˜Jšœœ˜ —Jšœ˜—šœ˜"Jšœ-˜-Jšœœ˜#Jšœ˜—Jš œ œœœœœ˜NJ˜—J˜šŸ œhœ˜ŒJšœ ˜ Jšœœœ ˜3Jšœœ ˜Jšœœ˜Jšœ œ˜ J˜)Jšœ œ˜Jšœ3 w˜ͺJšœœœ˜$šœ˜šœœ˜ Jšœ/˜/Jšœ ‘ œ9 9˜…Jšœ˜—J˜2J˜#Jšœ œœ!˜6JšœJ˜NJšœœ˜0J˜—Jšœ.˜4J˜——šœ™šŸœœœœœœœ œ˜†J˜aJšœœœ"˜IJ˜Hš œœœœ˜DJšœ,˜,Jšœœ˜"J˜—JšœXœ8˜“šœ œœ˜!J˜&Jšœœœœ˜.J˜—J˜—J˜Jš r™rJ˜š Ÿ œœœœœ˜Všœœœ0œ˜kšœ˜Jšœhœ˜€Jšœfœ˜~Jšœiœ˜…Jšœcœ˜{J˜—J˜—Jšœ˜ J˜—J˜JšŸ œœœœœœ œœ˜^J˜šŸ œ œ!œ œ˜RJšœœ˜Jšœœœ˜9Jšœ(œœœ˜;J˜?J˜,Jšœ˜ J˜—J˜Jš Ÿ œœœœœ˜*J˜šŸ œ œ!œ œ˜RJšœœœ˜9Jšœœ˜Jšœœ˜Jš œœœœœ˜J˜J˜#Jšœ˜ J˜—J˜Jš Ÿœœœ œœœ˜IJ˜šŸœ œ!œ œ˜VJšœœœ˜AJšœœ˜Jšœœ˜Jš œœœœœ ˜4J˜BJ˜'Jšœ˜ J˜—J˜JšŸ œœœ  œœ œœ œ˜\J˜šŸ œ œ!œ œ˜SJšœœœ˜;Jšœ'˜'Jšœ>œœœ˜QJšœ7˜7Jšœ ˜——™ JšŸ œœœ œ œ œœ ^˜žIprocš Ÿ œœœœœ˜Lš Ÿ œœœœœ D™hLšŸœœœ˜L˜šŸœœ˜%šŸ œΠckCœ˜jšœœ˜Jšœœœ˜3Jšœ œ˜"Jšœ˜—Jšœ ˜J˜—šŸœ˜Jš œœ œœ œœ˜MJšœ˜—Jšœ  œœœ˜Jšœ3™4š œœœœ/œœ˜RJšœ œ$˜4Jšœ˜—Jšœe˜lJšœœœ œœœœœœœ˜zJšœ œœ œ œœœœœœ˜Fš œœœœœœ˜8Jšœ  œ&˜9šœœ˜Jšœ/˜/Jšœ˜—Jšœ˜—Jšœ˜—J˜šŸœœ˜,šŸ œ’Bœ˜išœœ˜Jšœœ"œœ  :˜sJšœ œœ˜)Jšœœ˜*Jšœ˜—Jšœ ˜J˜—Lšœœœœ˜Jšœ œœ˜Jš œœœœ A˜fJšœe˜lš œœœœœœ˜