--- a/ReadEvalPrintLoop.st Thu Feb 20 08:03:34 2014 +0100
+++ b/ReadEvalPrintLoop.st Thu Feb 20 08:44:35 2014 +0100
@@ -13,7 +13,8 @@
Object subclass:#ReadEvalPrintLoop
instanceVariableNames:'inputStream outputStream errorStream compiler prompt
- doChunkFormat traceFlag timingFlag exitAction'
+ doChunkFormat traceFlag timingFlag printFlag exitAction
+ currentDirectory'
classVariableNames:''
poolDictionaries:''
category:'System-Support'
@@ -44,65 +45,94 @@
Lines starting with '#' are directives:
#exit - exit the rep-loop
+ The input can be in one of two formats:
+ 1) traditional chunk format (bang-separated chunks, bangs duplicated)
+ this is the traditional fileIn format, as generated by fileOut from the browser
+
+ 2) interactive line mode. Chunks are any number of lines up to either an empty line or
+ a line ending in a period. This is more useful for an interactive REPL, where statements/expressions
+ are entered linewise by a user.
+
+ The input can is switched to non-chunk format whenever a line with a '#' in the first column appears.
"
! !
!ReadEvalPrintLoop methodsFor:'accessing'!
compiler:something
+ "assign a compiler to use;could be used to change the language"
+
compiler := something.
!
doChunkFormat
+ "true if currently reading chunk format"
+
^ doChunkFormat ? true
"Created: / 07-12-2006 / 18:24:04 / cg"
!
-doChunkFormat:something
- doChunkFormat := something.
+doChunkFormat:aBoolean
+ "enable/disable chunk format"
+
+ doChunkFormat := aBoolean.
"Created: / 07-12-2006 / 18:24:04 / cg"
!
-error:something
- errorStream := something.
+error:aStream
+ "assign an error stream"
+
+ errorStream := aStream.
"Created: / 07-12-2006 / 17:33:39 / cg"
!
errorStream
- ^ errorStream ? Transcript ? Stderr
+ "return the current error stream"
+
+ ^ errorStream ? Stderr
"Created: / 07-12-2006 / 19:11:56 / cg"
!
-input:something
- inputStream := something.
+input:aStream
+ "assign an input stream"
+
+ inputStream := aStream asLineNumberReadStream.
"Modified: / 07-12-2006 / 17:33:31 / cg"
!
inputStream
+ "get the current input stream"
+
^ inputStream ? Stdin
"Created: / 07-12-2006 / 19:12:13 / cg"
!
-output:something
- outputStream := something.
+output:aStream
+ "assign an output stream"
+
+ outputStream := aStream.
"Created: / 07-12-2006 / 17:27:48 / cg"
!
outputStream
+ "return the current outpt stream"
+
^ outputStream ? Stdout
"Created: / 07-12-2006 / 19:12:27 / cg"
!
-prompt:something
- prompt := something.
+prompt:aString
+ "set the prompt"
+
+ prompt := aString.
! !
!ReadEvalPrintLoop methodsFor:'compiler interface-error handling'!
@@ -169,8 +199,11 @@
#help ............... this text
#exit ............... exit interpreter loop
#use <package>....... use (load) a package
- stx:libwidg ........ GUI package
- stx:libtool ........ IDE tool package
+ stx:libwidg .............. GUI package
+ stx:libtool .............. IDE tool package
+ stx:goodies/regex ........ regex package
+ stx:goodies/petitparser .. peg parser package
+ #read <filename>..... read another script or source file
#show <what> ........ show info
variables .......... interpreter variables
processes .......... processes
@@ -182,12 +215,53 @@
timing ............. timing execution
chunkFormat ........ traditional bang chunk format input mode
-MiniDebugger shows its help with "?".
+The MiniDebugger (if entered) shows its own help with "?".
'
"Created: / 07-12-2006 / 18:54:20 / cg"
!
+cmd_read:lineStream
+ |filename newInput savedPrompt savedPrint savedInput savedCurrentDirectory|
+
+ lineStream skipSeparators.
+ filename := lineStream upToEnd withoutSeparators.
+
+ filename := filename asFilename.
+ filename isAbsolute ifFalse:[
+ filename := currentDirectory construct:filename.
+ ].
+
+ newInput := filename readStream.
+ newInput isNil ifTrue:[
+ ('Could not find file: "',filename,'"') errorPrintCR.
+ ^ self.
+ ].
+
+ [
+ savedCurrentDirectory := currentDirectory.
+ savedInput := inputStream.
+ savedPrint := printFlag.
+ savedPrompt := prompt.
+
+ currentDirectory := filename directory.
+ inputStream := newInput.
+
+ self
+ basicReadEvalPrintLoopWithInput:newInput
+ output:outputStream
+ error:errorStream
+ compiler:compiler
+ prompt:false
+ print:false.
+ ] ensure:[
+ currentDirectory := savedCurrentDirectory.
+ inputStream := savedInput.
+ printFlag := savedPrint.
+ prompt := savedPrompt
+ ].
+!
+
cmd_set:lineStream
self cmd_setOrClear:lineStream to:true
@@ -218,11 +292,13 @@
!
cmd_show:lineStream
- |what all printModule|
+ |errStream what all printModule|
"
self basicNew cmd_show:'packages' readStream
"
+ errStream := self errorStream.
+
lineStream skipSeparators.
what := lineStream nextAlphaNumericWord.
(what startsWith:'var') ifTrue:[
@@ -235,18 +311,18 @@
(what startsWith:'mod') ifTrue:[
printModule :=
[:mod |
- self errorStream
+ errStream
nextPutAll:' ';
nextPutAll:(mod package "libraryName");
nextPutLine:' (',(mod type),')'.
].
- self errorStream nextPutLine:'builtIn:'.
+ errStream nextPutLine:'builtIn:'.
((ObjectMemory binaryModuleInfo
reject:[:m | m dynamic])
asSortedCollection:[:a :b | a name < b name]) do:printModule.
- self errorStream nextPutLine:'dynamic:'.
+ errStream nextPutLine:'dynamic:'.
((ObjectMemory binaryModuleInfo
select:[:m | m dynamic])
asSortedCollection:[:a :b | a name < b name]) do:printModule.
@@ -256,7 +332,7 @@
(what startsWith:'mem') ifTrue:[
all := ObjectMemory oldSpaceUsed + ObjectMemory symSpaceUsed
+ ObjectMemory newSpaceUsed.
- self errorStream
+ errStream
nextPutLine:('overall: ',(all // 1024) printString,' Kb');
nextPutLine:('in use : ',(ObjectMemory bytesUsed // 1024) printString,' Kb');
nextPutLine:('free : ',(ObjectMemory freeSpace // 1024) printString,' Kb');
@@ -265,14 +341,14 @@
^ self.
].
(what startsWith:'flag') ifTrue:[
- self errorStream
+ errStream
nextPutLine:('trace : ',traceFlag printString);
nextPutLine:('timing: ',timingFlag printString);
nextPutLine:('chunkFormat: ',doChunkFormat printString).
^ self.
].
- self errorStream nextPutLine:'?? show what ?'.
+ errStream nextPutLine:'?? show what ?'.
"Modified: / 07-12-2011 / 22:15:07 / cg"
!
@@ -290,7 +366,7 @@
].
].
ok ifFalse:[
- ('Failed to load package: "',pkg,'"') infoPrintCR.
+ self errorStream nextPutLine:('Failed to load package: "',pkg,'"').
].
"Created: / 07-12-2006 / 19:07:56 / cg"
@@ -304,27 +380,141 @@
s skipSeparators.
cmd := s nextAlphaNumericWord.
- self
- perform:('cmd_',cmd,':') asSymbol with:s
- ifNotUnderstood:[
- self errorStream
- nextPutAll:'?? invalid command: ';
- nextPutAll:cmd;
- nextPutAll:'. Type "#help" for help.';
- cr.
- ].
+ cmd notNil ifTrue:[
+ self
+ perform:('cmd_',cmd,':') asSymbol with:s
+ ifNotUnderstood:[
+ self errorStream
+ nextPutAll:'?? invalid command: ';
+ nextPutAll:cmd;
+ nextPutAll:'. Type "#help" for help.';
+ cr.
+ ].
+ ].
"Created: / 07-12-2006 / 18:49:17 / cg"
! !
!ReadEvalPrintLoop methodsFor:'evaluation'!
+basicReadEvalPrintLoopWithInput:input output:output error:error
+ compiler:compilerClass prompt:prompt print:doPrint
+
+ "{ Pragma: +optSpace }"
+
+ "the core of the interpreter loop; extracted and parametrized, so it can be called recursive
+ for included scripts.
+ If chunkFormat is true, chunks are read.
+ Otherwise, lines up to an empty line (or EOF) or a line ending in '.' are read.
+ A '#' character appearing in the first column of the first line turns off chunkmode."
+
+ [
+ |lines chunk|
+
+ prompt notNil ifTrue:[
+ error nextPutAll:prompt.
+ ].
+
+ input atEnd ifTrue:[
+ ^ self.
+ ].
+
+ input peek == $# ifTrue:[
+ self doChunkFormat:false.
+ ].
+
+ self doChunkFormat ifTrue:[
+ input skipSeparators.
+ chunk := input nextChunk.
+ ] ifFalse:[
+ lines := OrderedCollection new.
+ [
+ |line|
+
+ line := input nextLine.
+ line notEmptyOrNil ifTrue:[
+ line = '?' ifTrue:[
+ self cmd_help:nil.
+ prompt notNil ifTrue:[
+ error nextPutAll:prompt.
+ ].
+ ] ifFalse:[
+ (line startsWith:'#') ifTrue:[
+ self directive:line.
+ prompt notNil ifTrue:[
+ error nextPutAll:prompt.
+ ].
+ ] ifFalse:[
+ lines add:line.
+ ]
+ ]
+ ].
+ line notEmptyOrNil and:[(line endsWith:$.) not].
+ ] whileTrue.
+ chunk := lines asStringWith:Character cr.
+ ].
+
+ chunk notEmptyOrNil ifTrue:[
+ "abortAll is handled, but not asked for here!!"
+ AbortAllOperationRequest handle:[:ex |
+ error nextPutLine:('Evaluation aborted: ', ex description)
+ ] do:[
+ (Error, ControlInterrupt) handle:[:ex |
+ prompt isNil ifTrue:[
+ ex reject
+ ].
+ MiniDebugger enterWithMessage:(ex errorString) mayProceed:true.
+ ex mayProceed ifTrue:[
+ ex proceed.
+ ].
+ error nextPutLine:('Evaluation aborted: ', ex description).
+ ex return.
+ ] do:[
+ |value ms us|
+
+ ms := Time millisecondsToRun:[
+ us := Time microsecondsToRun:[
+ value := (compilerClass new requestor:self) evaluate:chunk compile:true.
+ ].
+ ].
+ doPrint ifTrue:[
+ value printOn:output. output cr.
+ ].
+
+ timingFlag == true ifTrue:[
+ 'execution time: ' printOn:error.
+ ms < 1 ifTrue:[
+ us < 1 ifTrue:[
+ 'too small to measure (<1us)' printOn:error.
+ ] ifFalse:[
+ us printOn:output. 'us' printOn:error.
+ ]
+ ] ifFalse:[
+ ms printOn:output. 'ms' printOn:error.
+ ].
+ error cr.
+ ].
+ ].
+ ].
+ ].
+ ] loop.
+
+ "
+ (ReadEvalPrintLoop new prompt:'>') readEvalPrintLoop
+ "
+
+ "Created: / 07-12-2006 / 17:27:21 / cg"
+ "Modified: / 06-12-2011 / 15:29:03 / cg"
+!
+
readEvalPrintLoop
"{ Pragma: +optSpace }"
"simple read-eval-print loop for non-graphical Minitalk.
If the chunkFormat-argument is true, chunks are read.
- Otherwise, lines up to an empty line (or EOF) are read."
+ Otherwise, lines up to an empty line (or EOF) are read.
+ A '#' character appearing in the first column of the first line
+ switches to chunkmode."
exitAction := [^ self].
@@ -332,95 +522,21 @@
self errorStream nextPutLine:('Cought: ', ex description).
ex restart.
] do:[
- [
- |input output error lines chunk compilerClass|
-
- "/ re-evaluate these in the loop, so they can be changed dynamically
- input := self inputStream.
- output := self outputStream.
- error := self errorStream.
- compilerClass := compiler ? Compiler ? Parser.
- compilerClass isNil ifTrue:[
- self errorStream nextPutLine:('oops - no Compiler class found').
- ^ self.
- ].
+ |input output error compilerClass|
- prompt notNil ifTrue:[
- error nextPutAll:prompt.
- ].
-
- input atEnd ifTrue:[
- ^ self.
- ].
-
- self doChunkFormat ifTrue:[
- input skipSeparators.
- chunk := input nextChunk.
- ] ifFalse:[
- lines := OrderedCollection new.
- [
- |line|
+ "/ re-evaluate these in the loop, so they can be changed dynamically
+ input := self inputStream.
+ output := self outputStream.
+ error := self errorStream.
- line := input nextLine.
- line notEmptyOrNil ifTrue:[
- line = '?' ifTrue:[
- self cmd_help:nil.
- prompt notNil ifTrue:[
- error nextPutAll:prompt.
- ].
- ] ifFalse:[
- (line startsWith:'#') ifTrue:[
- self directive:line.
- prompt notNil ifTrue:[
- error nextPutAll:prompt.
- ].
- ] ifFalse:[
- lines add:line.
- ]
- ]
- ].
- line notEmptyOrNil and:[(line endsWith:$.) not].
- ] whileTrue.
- chunk := lines asStringWith:Character cr.
- ].
-
- chunk notEmptyOrNil ifTrue:[
- "abortAll is handled, but not asked for here!!"
- AbortAllOperationRequest handle:[:ex |
- error nextPutLine:('Evaluation aborted: ', ex description)
- ] do:[
- (Error, ControlInterrupt) handle:[:ex |
- prompt isNil ifTrue:[
- ex reject
- ].
- MiniDebugger enterWithMessage:(ex errorString) mayProceed:true.
- ex mayProceed ifTrue:[
- ex proceed.
- ].
- error nextPutLine:('Evaluation aborted: ', ex description).
- ex return.
- ] do:[
- |value t|
-
- t := Time millisecondsToRun:[
- value := (compilerClass new requestor:self) evaluate:chunk compile:true.
- ].
- value printOn:output.
- output cr.
- timingFlag == true ifTrue:[
- 'execution time: ' printOn:output.
- t = 0 ifTrue:[
- 'too small to measure (<1ms)' printOn:output.
- ] ifFalse:[
- t printOn:output.
- 'ms' printOn:output.
- ].
- output cr.
- ].
- ].
- ].
- ].
- ] loop.
+ compilerClass := compiler ? Compiler ? Parser.
+ compilerClass isNil ifTrue:[
+ self errorStream nextPutLine:('oops - no Compiler class found').
+ ^ self.
+ ].
+ self
+ basicReadEvalPrintLoopWithInput:input output:output error:error
+ compiler:compilerClass prompt:prompt print:(printFlag ? true).
]
"
@@ -434,10 +550,10 @@
!ReadEvalPrintLoop class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libbasic/ReadEvalPrintLoop.st,v 1.43 2014-02-19 22:29:15 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/ReadEvalPrintLoop.st,v 1.44 2014-02-20 07:44:35 cg Exp $'
!
version_CVS
- ^ '$Header: /cvs/stx/stx/libbasic/ReadEvalPrintLoop.st,v 1.43 2014-02-19 22:29:15 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libbasic/ReadEvalPrintLoop.st,v 1.44 2014-02-20 07:44:35 cg Exp $'
! !