ReadEvalPrintLoop.st
changeset 22735 15ce04593d54
parent 22577 d47c7e41eda5
child 22736 db668a5e0106
equal deleted inserted replaced
22734:d6ccee71b508 22735:15ce04593d54
    17 
    17 
    18 Object subclass:#ReadEvalPrintLoop
    18 Object subclass:#ReadEvalPrintLoop
    19 	instanceVariableNames:'inputStream outputStream errorStream compiler prompt
    19 	instanceVariableNames:'inputStream outputStream errorStream compiler prompt
    20 		doChunkFormat traceFlag timingFlag profilingFlag printFlag
    20 		doChunkFormat traceFlag timingFlag profilingFlag printFlag
    21 		exitAction currentDirectory lastEditedClass lastEditedSelector
    21 		exitAction currentDirectory lastEditedClass lastEditedSelector
    22 		editorCommand'
    22 		editorCommand confirmDebugger debuggerUsed'
    23 	classVariableNames:''
    23 	classVariableNames:''
    24 	poolDictionaries:''
    24 	poolDictionaries:''
    25 	category:'System-Support'
    25 	category:'System-Support'
    26 !
    26 !
    27 
    27 
    42 !
    42 !
    43 
    43 
    44 documentation
    44 documentation
    45 "
    45 "
    46     A simple read-eval-print loop for non-GUI or stscript operation.
    46     A simple read-eval-print loop for non-GUI or stscript operation.
    47     Invoked, for example if stx is started with a --repl argument.
    47     Invoked, for example if stx is started with a --repl argument,
       
    48     or by the MiniDebugger with the 'I' command.
    48 
    49 
    49     A line starting with '?' shows the usage message.
    50     A line starting with '?' shows the usage message.
    50     Lines starting with '#' are directives:
    51     Lines starting with '#' are directives:
    51         #exit           - exit the rep-loop
    52         #exit           - exit the rep-loop
    52         #show ...       - show various infos
    53         #show ...       - show various infos
    75 
    76 
    76 compiler:something
    77 compiler:something
    77     "assign a compiler to use;could be used to change the language"
    78     "assign a compiler to use;could be used to change the language"
    78 
    79 
    79     compiler := something.
    80     compiler := something.
       
    81 !
       
    82 
       
    83 confirmDebugger
       
    84     "true if the user is asked for a debugger in case of errors"
       
    85 
       
    86     ^ confirmDebugger ? true
       
    87 !
       
    88 
       
    89 confirmDebugger:aBoolean
       
    90     "true if the user is asked for a debugger in case of errors"
       
    91 
       
    92     confirmDebugger := aBoolean
       
    93 !
       
    94 
       
    95 debuggerUsed
       
    96     "by default, the miniDebugger is given control in case of an error;
       
    97      you may want to write (subclass) your own ;-)"
       
    98 
       
    99     ^ debuggerUsed ? MiniDebugger
       
   100 !
       
   101 
       
   102 debuggerUsed:aDebuggerClass
       
   103     "by default, the miniDebugger is given control in case of an error;
       
   104      you may want to write (subclass) your own ;-)"
       
   105 
       
   106     debuggerUsed := aDebuggerClass
    80 !
   107 !
    81 
   108 
    82 doChunkFormat
   109 doChunkFormat
    83     "true if currently reading chunk format"
   110     "true if currently reading chunk format"
    84 
   111 
   219     ^ self
   246     ^ self
   220 ! !
   247 ! !
   221 
   248 
   222 !ReadEvalPrintLoop methodsFor:'directives'!
   249 !ReadEvalPrintLoop methodsFor:'directives'!
   223 
   250 
       
   251 askYesNo:message
       
   252     self errorStream show:message.
       
   253     ^ (self inputStream nextLine withoutSeparators startsWith:'y').
       
   254 !
       
   255 
       
   256 cmd_apropos:lineStream
       
   257     "apropos directive; i.e.
       
   258         #apropos collection [;more]
       
   259     "
       
   260 
       
   261     |words classNamesMatching selectorsMatching showList|
       
   262 
       
   263     lineStream skipSeparators.
       
   264     words := lineStream upToEnd asCollectionOfSubstringsSeparatedBy:$;.
       
   265     words := words select:[:each | each notEmpty].
       
   266     words := words select:[:each | each isBlank not].
       
   267 
       
   268     (words isEmpty) ifTrue:[
       
   269         self errorStream showCR:'? usage: #apropos <word> [; morewords]'.
       
   270         ^ self.
       
   271     ].
       
   272 
       
   273     "/ search in classes:
       
   274     classNamesMatching := Smalltalk allClasses 
       
   275                             select:[:cls | 
       
   276                                 cls isPrivate not
       
   277                                 and:[ words conform:[:word | 
       
   278                                         cls name matches:word caseSensitive:false]]]
       
   279                             thenCollect:#name.
       
   280     "/ search in method names:
       
   281     selectorsMatching := (Smalltalk allClasses
       
   282                             collectAll:[:cls |
       
   283                                 cls isPrivate 
       
   284                                     ifTrue:[#()]
       
   285                                     ifFalse:[
       
   286                                         cls selectors 
       
   287                                             select:[:sel |
       
   288                                                 words conform:[:word | 
       
   289                                                     sel matches:word caseSensitive:false]]]]
       
   290                          ) asSet.
       
   291 
       
   292     showList :=
       
   293         [:list :listName |
       
   294             |showIt sortedList longest limit numCols|
       
   295 
       
   296             showIt := true.
       
   297             list notEmpty ifTrue:[
       
   298                 list size > 20 ifTrue:[
       
   299                     showIt := self askYesNo:( 
       
   300                         'apropos: there are %1 matching %2; list them all (y/n)? '
       
   301                             bindWith:list size
       
   302                             with:listName)
       
   303                 ] ifFalse:[
       
   304                     self errorStream showCR:'matching %1:' with:listName.  
       
   305                 ].
       
   306                 showIt ifTrue:[
       
   307                     sortedList := list asOrderedCollection sort.
       
   308                     longest := (list collect:[:nm | nm size]) max.
       
   309                     limit := 78.
       
   310                     numCols := (80 // (longest min:limit)) max:1.
       
   311                     sortedList slicesOf:numCols do:[:eachGroupOfN |
       
   312                         self errorStream
       
   313                             spaces:2;
       
   314                             nextPutLine:(
       
   315                                 (eachGroupOfN 
       
   316                                     collect:[:nm | 
       
   317                                         (nm contractTo:limit) paddedTo:limit
       
   318                                     ] 
       
   319                                 ) asStringWith:' ').
       
   320                     ].
       
   321                 ].
       
   322             ].
       
   323         ].
       
   324 
       
   325     showList value:classNamesMatching value:'classes'.
       
   326     showList value:selectorsMatching value:'method names'.
       
   327     "
       
   328      self basicNew 
       
   329         input:Stdin;
       
   330         cmd_apropos:'Array' readStream
       
   331 
       
   332      self basicNew 
       
   333         input:Stdin;
       
   334         cmd_apropos:'at:' readStream
       
   335 
       
   336      self basicNew 
       
   337         input:Stdin;
       
   338         cmd_apropos:'*at:' readStream
       
   339     "
       
   340 !
       
   341 
   224 cmd_clear:lineStream
   342 cmd_clear:lineStream
   225     self cmd_setOrClear:lineStream to:false
   343     self cmd_setOrClear:lineStream to:false
   226 
   344 
   227     "Created: / 07-12-2006 / 19:04:50 / cg"
   345     "Created: / 07-12-2006 / 19:04:50 / cg"
   228 !
   346 !
   244     lineStream skipSeparators.
   362     lineStream skipSeparators.
   245     lineStream atEnd ifTrue:[
   363     lineStream atEnd ifTrue:[
   246         cls := lastEditedClass.
   364         cls := lastEditedClass.
   247         methodName := lastEditedSelector.
   365         methodName := lastEditedSelector.
   248     ] ifFalse:[    
   366     ] ifFalse:[    
   249 
       
   250         classOrMethodName := lineStream 
   367         classOrMethodName := lineStream 
   251                                 upToElementForWhich:[:ch | 
   368                                 upToElementForWhich:[:ch | 
   252                                     ch isLetterOrDigit not and:[ch ~~ $_]
   369                                     ch isLetterOrDigit not and:[ch ~~ $_]
   253                                 ].
   370                                 ].
   254         "/ 
   371         "/ 
   271 '                   bindWith:classOrMethodName.
   388 '                   bindWith:classOrMethodName.
   272             ] ifFalse:[ 
   389             ] ifFalse:[ 
   273                 lineStream skipSeparators.
   390                 lineStream skipSeparators.
   274                 lineStream atEnd ifFalse:[
   391                 lineStream atEnd ifFalse:[
   275                     methodName := lineStream upToSeparator.
   392                     methodName := lineStream upToSeparator.
       
   393                     methodName = 'class' ifTrue:[
       
   394                         cls := cls theMetaclass.
       
   395                         lineStream skipSeparators.
       
   396                         methodName := lineStream upToSeparator.
       
   397                     ].
   276                 ].
   398                 ].
   277             ].
   399             ].
   278         ] ifFalse:[
   400         ] ifFalse:[
   279             methodName := classOrMethodName   
   401             methodName := classOrMethodName   
   280         ].
   402         ].
   297             editFullClass := true.
   419             editFullClass := true.
   298             code := cls source asString
   420             code := cls source asString
   299         ] ifFalse:[    
   421         ] ifFalse:[    
   300             ((selector := methodName asSymbolIfInterned) isNil 
   422             ((selector := methodName asSymbolIfInterned) isNil 
   301             or:[ (cls implements:selector) not]) ifTrue:[
   423             or:[ (cls implements:selector) not]) ifTrue:[
   302                 errStream show:('"',methodName,'" is a new method; create (y/n)? ').
   424                 (self askYesNo:('"',methodName,'" is a new method; create (y/n)? ')) ifFalse:[^ self].
   303                 (self inputStream nextLine withoutSeparators startsWith:'y') ifFalse:[^ self].
   425 
   304                 code := 
   426                 code := 
   305 '"/ change the code as required, then save and exit the editor.
   427 '"/ change the code as required, then save and exit the editor.
   306 "/ To cancel this edit, leave the editor WITHOUT saving.
   428 "/ To cancel this edit, leave the editor WITHOUT saving.
   307 
   429 
   308 %1
   430 %1
   366      Smalltalk readEvalPrintLoop
   488      Smalltalk readEvalPrintLoop
   367 
   489 
   368      self new 
   490      self new 
   369         input:Stdin;
   491         input:Stdin;
   370         cmd_edit:'MyClass foo' readStream
   492         cmd_edit:'MyClass foo' readStream
       
   493 
       
   494      self new 
       
   495         input:Stdin;
       
   496         cmd_edit:'Array class new:' readStream
   371     "
   497     "
   372 
   498 
   373     "Modified: / 08-11-2016 / 22:46:12 / cg"
   499     "Modified: / 08-11-2016 / 22:46:12 / cg"
   374 !
   500 !
   375 
   501 
   413     #debug ................. enter a MiniDebugger
   539     #debug ................. enter a MiniDebugger
   414     #edit <what> ........ open an external editor 
   540     #edit <what> ........ open an external editor 
   415         class .............. on a class
   541         class .............. on a class
   416         class selector ..... on a method
   542         class selector ..... on a method
   417         <empty> ............ on previously edited method/last class
   543         <empty> ............ on previously edited method/last class
       
   544     #apropos word ....... list classes/selectors matching word
       
   545     #list <what> ........ show source
       
   546         class .............. class definition and comment
       
   547         class selector ..... method source
   418 
   548 
   419 The MiniDebugger (if entered) shows its own help with "?".
   549 The MiniDebugger (if entered) shows its own help with "?".
   420 '
   550 '
   421 
   551 
   422     "Created: / 07-12-2006 / 18:54:20 / cg"
   552     "Created: / 07-12-2006 / 18:54:20 / cg"
   423     "Modified: / 08-11-2016 / 22:53:53 / cg"
   553     "Modified: / 08-11-2016 / 22:53:53 / cg"
       
   554 !
       
   555 
       
   556 cmd_list:lineStream
       
   557     "list directive; i.e.
       
   558         #list <classname> ['class'] <selector>
       
   559     "
       
   560 
       
   561     |class selector source errStream|
       
   562 
       
   563     errStream := self errorStream.
       
   564 
       
   565     (self 
       
   566         getClassNameAndSelectorFrom:lineStream 
       
   567         into:[:classArg :selectorArg |
       
   568             class := classArg.
       
   569             selector := selectorArg.
       
   570         ]) ifFalse:[^ self].
       
   571 
       
   572     selector isNil ifTrue:[
       
   573         errStream nextPutAll:(class definition).
       
   574         errStream nextPutAll:(class commentOrDocumentationString).
       
   575     ] ifFalse:[
       
   576         source := class sourceCodeAt:selector asSymbol.
       
   577         source isEmptyOrNil ifTrue:[
       
   578             errStream nextPutLine:'Sorry, no sourcecode found'
       
   579         ] ifFalse:[
       
   580             errStream nextPutAll:source
       
   581         ].
       
   582     ].
       
   583 
       
   584     "
       
   585      self basicNew 
       
   586         input:Stdin;
       
   587         cmd_list:'Array' readStream
       
   588 
       
   589      self basicNew 
       
   590         input:Stdin;
       
   591         cmd_list:'Array at:put:' readStream
       
   592     "
   424 !
   593 !
   425 
   594 
   426 cmd_read:lineStream
   595 cmd_read:lineStream
   427     "read directive; i.e.
   596     "read directive; i.e.
   428         #read scriptFile
   597         #read scriptFile
   484 
   653 
   485     "Modified: / 07-12-2006 / 19:04:46 / cg"
   654     "Modified: / 07-12-2006 / 19:04:46 / cg"
   486 !
   655 !
   487 
   656 
   488 cmd_setOrClear:lineStream to:aBoolean
   657 cmd_setOrClear:lineStream to:aBoolean
       
   658     "set/clear one of my internal flags"
       
   659 
   489     |what|
   660     |what|
   490 
   661 
   491     lineStream skipSeparators.
   662     lineStream skipSeparators.
   492     what := lineStream nextAlphaNumericWord.
   663     what := lineStream nextAlphaNumericWord.
   493     what notNil ifTrue:[
   664     what notNil ifTrue:[
   515             ] ifFalse:[
   686             ] ifFalse:[
   516                 editorCommand := nil.
   687                 editorCommand := nil.
   517             ].
   688             ].
   518             ^ self.
   689             ^ self.
   519         ].
   690         ].
   520     ].
   691         (what startsWith:'con') ifTrue:[
   521     self errorStream showCR:'? usage: set/clear <flag>'.
   692             confirmDebugger := aBoolean.
   522     self errorStream showCR:'? (<flag> must be one of: trace, times, profile, chunk, editor)'.
   693             ^ self.
       
   694         ].
       
   695     ].
       
   696     self errorStream 
       
   697         showCR:'? usage: set/clear <flag>';
       
   698         showCR:'? (<flag> must be one of: trace, times, profile, chunk, editor, confirmDebug)'.
   523 
   699 
   524     "Modified: / 08-11-2016 / 22:49:17 / cg"
   700     "Modified: / 08-11-2016 / 22:49:17 / cg"
   525 !
   701 !
   526 
   702 
   527 cmd_show:lineStream
   703 cmd_show:lineStream
   588             errStream
   764             errStream
   589                 showCR:('trace :      ',(traceFlag ? false) printString);
   765                 showCR:('trace :      ',(traceFlag ? false) printString);
   590                 showCR:('timing:      ',(timingFlag ? false) printString);
   766                 showCR:('timing:      ',(timingFlag ? false) printString);
   591                 showCR:('profiling:   ',(profilingFlag ? false) printString);
   767                 showCR:('profiling:   ',(profilingFlag ? false) printString);
   592                 showCR:('chunkFormat: ',(doChunkFormat ? false) printString);
   768                 showCR:('chunkFormat: ',(doChunkFormat ? false) printString);
   593                 showCR:('editor:      ',self editorCommand printString).
   769                 showCR:('editor:      ',self editorCommand printString);
       
   770                 showCR:('confirmDebug:',self confirmDebugger printString).
   594             ok := true.
   771             ok := true.
   595         ].
   772         ].
   596     ].
   773     ].
   597 
   774 
   598     ok ifFalse:[
   775     ok ifFalse:[
   666                 ] do:[    
   843                 ] do:[    
   667                     self
   844                     self
   668                         perform:('cmd_',cmd) asMutator with:s
   845                         perform:('cmd_',cmd) asMutator with:s
   669                         ifNotUnderstood:[
   846                         ifNotUnderstood:[
   670                             self errorStream
   847                             self errorStream
   671                                 show:'?? invalid command: '; show:cmd;
   848                                 show:'?? invalid command: %1. Type "#help" for help.' with:cmd.
   672                                 showCR:'. Type "#help" for help.'
       
   673                         ].
   849                         ].
   674                 ].
   850                 ].
   675             ].
   851             ].
   676         ].
   852         ].
   677     ].
   853     ].
   678 
   854 
   679     "Created: / 07-12-2006 / 18:49:17 / cg"
   855     "Created: / 07-12-2006 / 18:49:17 / cg"
   680     "Modified: / 08-11-2016 / 21:59:16 / cg"
   856     "Modified: / 08-11-2016 / 21:59:16 / cg"
       
   857 !
       
   858 
       
   859 getClassNameAndSelectorFrom:lineStream into:aBlock
       
   860     "a helper for list and edit; parses class and selector name.
       
   861      returns false if nothing reasonable was entered"
       
   862 
       
   863     |words wordStream className class selector|
       
   864 
       
   865     lineStream skipSeparators.
       
   866     words := lineStream upToEnd asCollectionOfWords.
       
   867 
       
   868     (words isEmpty) ifTrue:[
       
   869         ^ false.
       
   870     ].
       
   871 
       
   872     wordStream := words readStream.
       
   873 
       
   874     "/ search in classes:
       
   875     className := wordStream next.
       
   876     class := Smalltalk classNamed:className.
       
   877     class isNil ifTrue:[
       
   878         self errorStream showCR:'no such class: ',className.
       
   879         ^ false.
       
   880     ].
       
   881 
       
   882     (wordStream atEnd not and:[wordStream peek = 'class']) ifTrue:[
       
   883         wordStream next.
       
   884         class := class theMetaclass
       
   885     ].
       
   886     (wordStream atEnd) ifFalse:[
       
   887         selector := wordStream next.
       
   888     ].
       
   889     aBlock value:class value:selector.
       
   890     ^ true
   681 !
   891 !
   682 
   892 
   683 showModules
   893 showModules
   684     |errStream printModule|
   894     |errStream printModule|
   685 
   895 
   752 basicReadEvalPrintLoopWithInput:input output:output error:error
   962 basicReadEvalPrintLoopWithInput:input output:output error:error
   753     compiler:compilerClass prompt:prompt print:doPrint
   963     compiler:compilerClass prompt:prompt print:doPrint
   754 
   964 
   755     "{ Pragma: +optSpace }"
   965     "{ Pragma: +optSpace }"
   756 
   966 
   757     "the core of the interpreter loop; extracted and parametrized, so it can be called recursive
   967     "the core of the interpreter loop; 
   758      for included scripts.
   968      extracted and parametrized, so it can be called recursively for included scripts.
   759      If chunkFormat is true, chunks are read.
   969      If chunkFormat is true, chunks are read.
   760      Otherwise, lines up to an empty line (or EOF) or a line ending in '.' are read.
   970      Otherwise, lines up to an empty line (or EOF) or a line ending in '.' are read.
   761      A '#' character appearing in the first column of the first line turns off chunkmode,
   971      A '#' character appearing in the first column of the first line turns off chunkmode,
   762      which allows for convenient shell scripts containing a #/bin/stx as the first line."
   972      which allows for convenient shell scripts containing a #/bin/stx as the first line."
   763 
   973