Added #? as a unary selector for help in the REPL and Debugger, and fixed the disasse...
[cslatevm.git] / src / lib / repl.slate
blob39d7b620683c44873f84ebdb94f129275f36408e
1 prototypes define: #REPL &parents: {Cloneable} &slots:
2   {#parser -> Syntax Parser clone.
3    #printer -> String writer.
4    #resource -> Console.
5    #namespace -> lobby newSubSpace.
6    #lineCount -> 0.
7    #basePrompt -> '> '.
8    #noviceMode -> False.
9    #inputs -> (RingBuffer new &capacity: 10).
10    #results -> (RingBuffer new &capacity: 10)}.
12 REPL traits define: #Workspace &parents: {Namespace}.
13 "A separate Namespace type for REPL usage."
15 repl@(REPL traits) refreshWorkspace
17   repl namespace: (repl Workspace newDelegatingTo: lobby).
18   repl installMethods.
19   repl parser currentScope: (repl parser currentScope for: repl namespace).
22 repl@(REPL traits) prompt
24   'slate[' ; repl lineCount printString ; ']' ; repl basePrompt
27 repl@(REPL traits) newBasedOn: resource@(ExternalResource traits)
28 "Answer a new REPL targetting the specified resource and reset it."
29 [repl clone `>> [on: resource. reset. ]].
31 repl@(REPL traits) on: resource
32 "Re-target the REPL to the specified resource."
34   repl parser: (repl parser newOn: resource reader).
35   repl printer: resource writer.
36   repl resource: resource.
37   repl
40 repl@(REPL traits) reset
41 "Clear out the line number and the evaluation result Collection."
43   repl lineCount: 0.
44   repl inputs clear.
45   repl results clear.
48 _@here interpretHook: block
49 "The default set of restarts for any errors in a block of code."
51   block
52     handlingCases:
53       {
54         Abort -> [| :_ | ^ Nil].
55         Quit -> [| :_ |]
56       }
59 repl@(REPL traits) installMethods
60 "This defines a number of namespace methods for convenient REPL access
61 and control."
63   _@(repl namespace) repl "Answer the currently used REPL." [repl].
64   "Set/clear the editting mode of the Parser."
65   ns@(repl namespace) pasteMode [ns repl parser parseInteractively: False].
66   ns@(repl namespace) interactiveMode [ns repl parser parseInteractively: True].
67   (#repl findOn: {repl namespace})
68     ifNotNilDo: [| :m | repl namespace addSlot: #previousREPLMethod valued: m].
69   "Define quick methods for the last 5 evaluation results."
70   ns@(repl namespace) it  [ns it1].
71   ns@(repl namespace) it1 [ns repl results first].
72   ns@(repl namespace) it2 [ns repl results second].
73   ns@(repl namespace) it3 [ns repl results third].
74   ns@(repl namespace) it4 [ns repl results fourth].
75   ns@(repl namespace) it5 [ns repl results fifth].
77   ns@(repl namespace) in: ns [ns atSlotNamed: #parentNamespace put: ns].
79   ns@(repl namespace) inform: message &target: r
80   "A simple way to print a message onto an ExternalResource (by default the Console)."
81   [r `defaultsTo: ns repl resource.
82    r writer ; message ; '\n'.
83    r writer flush. ].
85   ns@(repl namespace) print: obj &target: r
86   [r `defaultsTo: repl resource.
87    obj printOn: r writer.
88    r writer ; '\n'.
89    r writer flush. ].
91   ns@(repl namespace) query: message &target: r
92   "A simple way to ask input of the user on an ExternalResource (by default
93 the Console) and return a Slate String response."
94   [| response |
95    r `defaultsTo: ns repl resource.
96    r writer ; message.
97    r writer flush.
98    [response: (r interactor upTo: $\n).
99     response isEmpty] whileTrue. "Grabs the next line when it's available."
100    r writer flush.
101    response].
103   ns@(repl namespace) confirm: message &target: r
104   "A simple way to ask a Boolean question of the user on an ExternalResource
105 (by default the Console) and return a Slate Boolean answer."
106   [| response |
107    response: (ns query: message ; ' (y/n) ') toLowercase.
108    {'y'. 'yes'} anySatisfy: [| :option | option = response]].
110   ns@(repl namespace) doubleConfirm: message &target: r
111   [| response |
112    response: (ns confirm: message &target: r).
113    response /\ [ns confirm: 'Are you sure?' &target: r]
114   ].
116   ns@(repl namespace) help &target: r
117   [
118     r `defaultsTo: ns repl resource.
119     r writer ; 'The REPL is an interactive evaluator that parses expressions and prints their results back. It also keeps a return-value history and interaction messages:\n'
120       ; 'it\n\tAnswers the last result.\n'
121       ; 'itN\n\tAnswers the result from N (1..5) expressions ago in the history.\n'
122       ; 'repl\n\tAnswers the current REPL and its properties.\n'
123       ; 'pasteMode\n\t(Default) Evaluate only when a finished expression is followed by a period and newline.\n'
124       ; 'interactiveMode\n\tEvaluate when newline is entered and the expression is complete.\n'
125       ; 'inspect: obj\n\tStarts the interactive travelling inspector.\n'
126       ; 'inform: \'message\'\n\tPrints a message on a single line.\n'
127       ; 'query: \'message\'\n\tPrints a message, waiting on and answering a user response.\n'
128       ; 'confirm: \'message\'\n\tPrints a question on a single line and answering a user boolean response.\n'
129       ; 'resetOnStartup\n\tClears the history and line number on fresh runs of the VM.\n'
130       ; 'help\n\tPrints this helpful message.\n'.
131   ].
133   ns@(repl namespace) ? [ns help].
134   ns@(repl namespace) ? obj [ns helpFor: obj].
138 repl@(REPL traits) removeMethods
139 "This removes methods defined in installMethods."
141   {#repl. #pasteMode. #interactiveMode. #it. #it1. #it2. #it3. #it4. #it5.
142    #inform:. #query:. #confirm:. #help}
143     do: [| :sel | 
144       (sel findOn: {repl namespace})
145         ifNotNilDo:
146           [| :m | m removeFrom: {repl namespace}]]
149 repl@(REPL traits) enter
150 "Sets up the convenient namespace methods and runs the interactive loop.
151 This does not normally exit unless there is a serious error."
153   [repl refreshWorkspace.
154    repl parser parseInteractively: True.
155    [repl on: repl resource.
156     repl lineCount: repl lineCount + 1.
157     repl printer ; repl prompt.
158     repl printer flush.
159     repl namespace
160       interpretHook:
161         [| expr result |
162          [expr: repl parser next]
163            on: Stream Exhaustion
164            do: [| :c | c stream == repl resource reader ifTrue:
165                          [repl printer ; '\n'. ^ Nil]].
166          repl inputs addFirst: expr.
167          result: ([expr evaluateIn: repl namespace] on: SeriousCondition do:
168            [| :c |
169             repl noviceMode ifTrue:
170              [c describeOn: repl printer.
171               c exit: Nil]]).
172          repl results addFirst: result.
173          [result printOn: repl printer] on: SeriousCondition do:
174            [| :c |
175             repl printer newLine.
176             warn: result printName ; ' (Printing failed)'.
177             c exit: Nil]].
178     repl printer newLine.
179     repl printer flush.
180     "repl namespace interpretHook: [currentProcess run &limit: 1000]"]
181      loop] ensure: [repl removeMethods].
182   repl
185 repl@(REPL traits) completionsFor: word
186 "Answers an Array of all the possible complete Symbols defined in the system
187 which the given word is a valid prefix of.
188 TODO: Consult the recent literal frames for names.
189 TODO: sort the results by some suitable precedence."
191   [| :result |
192   globals Symbols keysDo:
193     [| :key | (word isPrefixOf: key) ifTrue: [result nextPut: key]]]
194    writingAs: {}
197 repl@(REPL traits) start &resource: r
198 "Enter a new REPL instance on the resource."
200   r `defaultsTo: repl resource.
201   (repl newBasedOn: r) enter
204 repl@(REPL traits) resetOnStartup
205 "Adds a handler for Image startup to reset the REPL."
206 [Image startupActions at: repl put: [repl reset]].