aboutsummaryrefslogtreecommitdiff
path: root/src/interp/int-top.boot.pamphlet
diff options
context:
space:
mode:
Diffstat (limited to 'src/interp/int-top.boot.pamphlet')
-rw-r--r--src/interp/int-top.boot.pamphlet497
1 files changed, 497 insertions, 0 deletions
diff --git a/src/interp/int-top.boot.pamphlet b/src/interp/int-top.boot.pamphlet
new file mode 100644
index 00000000..77f36f8e
--- /dev/null
+++ b/src/interp/int-top.boot.pamphlet
@@ -0,0 +1,497 @@
+\documentclass{article}
+\usepackage{axiom}
+\begin{document}
+\title{\$SPAD/src/interp int-top.boot}
+\author{The Axiom Team}
+\maketitle
+\begin{abstract}
+\end{abstract}
+\eject
+\tableofcontents
+\eject
+\section{intloopReadConsole}
+
+This is the top level loop when reading from the input console. This
+function calls itself after processing the current line. Because of
+this it is important that the underlying common lisp supports
+tail-recursion.
+
+Normally we never really exit this function.
+
+We read a string from the input. The serverReadLine\cite{1} function
+is a special readline function that handles communication with the
+session manager code, which is a separate process running in parallel.
+In the usual case it just returns the current string.
+
+If the user enters a blank line ([[#a=]]) then just put up another prompt
+and then tail-recursively call [[intloopReadConsole]].
+
+If the user has set [[$DALYMODE]] to true and the new line starts with
+an open parenthesis then the input is assumed to be a lisp expression
+and is evaluated by the underlying common lisp. This is useful if you
+are doing a lot of debugging. Commands can also be executed in the
+underlying common lisp by using the [[)lisp]] command. In either case we
+tail-recursively call [[intloopReadConsole]].
+
+If the user typed [[)fin]] then we exit the loop and drop into the
+underlying common lisp. You can use the [[(restart)]] function call
+to return to the top level loop.
+
+If the input line starts with a close parenthesis we parse the
+input line as a command rather than an expression. We execute the command
+and then tail-recursively call [[intloopReadConsole]].
+
+If the input line contains a trailing underscore, which is the standard
+end-of-line escape character, then we continue to read the line by
+tail-recursively calling [[intloopReadConsole]].
+
+If none of the above conditions occur we simply evaluate the input line
+and then tail-recursively call [[intloopReadConsole]].
+
+However, there was a small bug in the test for the system command
+[[)fin]]. Originally, the test took the form:
+\begin{verbatim}
+ intloopPrefix?('")fin",a) => []
+\end{verbatim}
+This test was flawed in two ways. First, it would match {\sl any}
+command beginning with [[)fin]]. Second, it would {\sl only} match
+names beginning with [[)fin]], although [[)fi]] is an acceptable
+abbreviation for this command. The improved test takes the form:
+\begin{verbatim}
+ pfx := stripSpaces intloopPrefix?('")fi",a)
+ pfx and ((pfx = '")fi") or (pfx = '")fin")) => []
+\end{verbatim}
+
+\section{intloopPrefix?}
+The [[intloopPrefix?(prefix, whole)]] function simply tests if the string
+[[prefix]] is a prefix of the string [[whole]]. The original
+implementation discounts {\sl any} whitespace in [[whole]] in deciding a
+match, when a more sensible behavior would be to discount only leading
+whitespace.
+
+Moreover, the function SUBSTRING\cite{2} was being improperly called.
+The reason why this improper call had gone undetected is that
+generally [[intloopPrefix?]] is invoked with a prefix string of length
+one -- hence the start position for the substring would generally
+begin at index [[spaces]] (which is what we want).
+
+The original code read:
+\begin{verbatim}
+intloopPrefix?(prefix,whole) ==
+ #prefix > #whole => false
+ good:=true
+ spaces := 0
+ i := 0
+ len := #prefix
+ wlen := #whole
+ for j in 0.. while (good and i < len and j < wlen) repeat
+ good:= (prefix.i = whole.j) or (whole.j = char " ")
+ if prefix.i = whole.j then i := i+1
+ if whole.j = char " " then spaces := spaces + 1
+ spaces = wlen => nil
+ if good then SUBSTRING(whole,#prefix+spaces-1,nil) else good
+
+\end{verbatim}
+
+The improved version of [[inloopPrefix?(prefix, whole)]] returns the
+string [[whole]] sans leading whitespace if the match succeeds, else nil.
+
+<<intloopPrefix?>>=
+intloopPrefix?(prefix,whole) ==
+ #prefix > #whole => false
+ good := true
+ leading := true
+ spaces := 0
+ i := 0
+ len := #prefix
+ wlen := #whole
+ for j in 0.. while (good and i < len and j < wlen) repeat
+ good := (prefix.i = whole.j) or (leading and (whole.j = char " "))
+ if prefix.i = whole.j then i := i+1
+ if (whole.j = char " ") and leading then
+ spaces := spaces + 1
+ else leading := false
+ spaces = wlen => nil
+ if good then SUBSTRING(whole,spaces,nil) else good
+
+@
+\section{License}
+<<license>>=
+-- Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are
+-- met:
+--
+-- - Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+--
+-- - Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in
+-- the documentation and/or other materials provided with the
+-- distribution.
+--
+-- - Neither the name of The Numerical ALgorithms Group Ltd. nor the
+-- names of its contributors may be used to endorse or promote products
+-- derived from this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+-- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+-- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+-- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+-- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+-- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+-- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+@
+<<*>>=
+<<license>>
+
+)package "BOOT"
+
+--% INTERPRETER TOP LEVEL
+
+spad() ==
+ -- starts the interpreter but does not read in profiles, etc.
+ $PrintCompilerMessageIfTrue: local
+ $inLispVM : local := nil
+ setOutputAlgebra "%initialize%"
+ runspad()
+ 'EndOfSpad
+
+runspad() ==
+ mode:='restart
+ while mode='restart repeat
+ resetStackLimits()
+ CATCH($quitTag, CATCH('coerceFailure,
+ mode:=CATCH('top__level, ncTopLevel())))
+
+ncTopLevel() ==
+-- Top-level read-parse-eval-print loop for the interpreter. Uses
+-- the Bill Burge's parser.
+ IN_-STREAM: fluid := CURINSTREAM
+ _*EOF_*: fluid := NIL
+ $InteractiveMode :fluid := true
+ $BOOT: fluid := NIL
+ $NEWSPAD: fluid := true
+ $SPAD: fluid := true
+ $e:fluid := $InteractiveFrame
+ ncIntLoop()
+
+
+ncIntLoop() ==
+ CURINSTREAM : local := _*STANDARD_-OUTPUT_*
+ CUROUTSTREAM : local := _*STANDARD_-INPUT_*
+ intloop()
+
+
+intloop () ==
+ mode := $intRestart
+ while mode = $intRestart repeat
+ resetStackLimits()
+ mode := CATCH($intTopLevel,
+ SpadInterpretStream(1, ["TIM", "DALY", "?"], true))
+
+
+SpadInterpretStream(str, source, interactive?) ==
+ $fn : local := source
+ pile? := not interactive?
+ $libQuiet : local := not interactive?
+ $newcompMode : local := false
+-- following seems useless and causes ccl package problems
+-- $InteractiveMode : local := false
+
+ $newcompErrorCount: local := 0 -- SMW Feb 2/90.
+ -- Used in highComplete, ncHardError etc.
+
+ $okToExecuteMachineCode: local := true -- set false on error
+ $inclAssertions: local := ["AIX", "CommonLisp"] -- Jan 28/90
+
+
+ $lastPos : local := $nopos ------------>!!!
+ $erMsgToss : local := false --------------->!!!
+ $ncMsgList : local := nil
+
+ $systemCommandFunction : local := function InterpExecuteSpadSystemCommand
+ $shoeReadLineFunction : local := function serverReadLine
+ $promptMsg : local := 'S2CTP023
+
+ interactive? =>
+ PRINC(MKPROMPT())
+ intloopReadConsole('"", str)
+ []
+ intloopInclude (source,0)
+ []
+
+ -----------------------------------------------------------------
+
+intloopReadConsole(b, n)==
+ a:= serverReadLine(_*STANDARD_-INPUT_*)
+ not STRINGP a => leaveScratchpad()
+ #a=0 =>
+ PRINC(MKPROMPT())
+ intloopReadConsole('"", n)
+ $DALYMODE and intloopPrefix?('"(",a) =>
+ intnplisp(a)
+ PRINC(MKPROMPT())
+ intloopReadConsole('"",n)
+ pfx := stripSpaces intloopPrefix?('")fi",a)
+ pfx and ((pfx = '")fi") or (pfx = '")fin")) => []
+ b = '"" and (d := intloopPrefix?('")", a)) =>
+ setCurrentLine d
+ c := ncloopCommand(d,n)
+ PRINC(MKPROMPT())
+ intloopReadConsole('"", c)
+ a:=CONCAT(b,a)
+ ncloopEscaped a => intloopReadConsole(SUBSEQ(a, 0, (LENGTH a) - 1),n)
+ c := intloopProcessString(a, n)
+ PRINC(MKPROMPT())
+ intloopReadConsole('"", c)
+
+<<intloopPrefix?>>
+
+intloopProcess(n,interactive,s)==
+ StreamNull s => n
+ [lines,ptree]:=CAR s
+ pfAbSynOp?(ptree,"command")=>
+ if interactive then setCurrentLine tokPart ptree
+ FUNCALL($systemCommandFunction, tokPart ptree)
+ intloopProcess(n ,interactive ,CDR s)
+ intloopProcess(intloopSpadProcess(n,lines,ptree,interactive)
+ ,interactive ,CDR s)
+
+intloopEchoParse s==
+ [dq,stream]:=CAR s
+ [lines,rest]:=ncloopDQlines(dq,$lines)
+ setCurrentLine(mkLineList(lines))
+ if $EchoLines then ncloopPrintLines lines
+ $lines:=rest
+ cons([[lines,npParse dqToList dq]],CDR s)
+
+intloopInclude0(st, name, n) ==
+ $lines:local:=incStream(st,name)
+ intloopProcess(n,false,
+ next(function intloopEchoParse,
+ next(function insertpile,
+ next(function lineoftoks,$lines))))
+
+intloopInclude1(name,n) ==
+ a:=ncloopIncFileName name
+ a => intloopInclude(a,n)
+ n
+
+intloopProcessString(s,n) ==
+ setCurrentLine s
+ intloopProcess(n,true,
+ next(function ncloopParse,
+ next(function lineoftoks,incString s)))
+
+$pfMacros := []
+
+intloopSpadProcess(stepNo,lines,ptree,interactive?)==
+ $stepNo:local := stepNo
+ $currentCarrier := cc := ['carrier]
+ ncPutQ(cc, 'stepNumber, stepNo)
+ ncPutQ(cc, 'messages, $ncMsgList)
+ ncPutQ(cc, 'lines, lines)
+ $ncMsgList := nil
+ result := CatchAsCan(flung, Catch("SpadCompileItem",
+ CATCH($intCoerceFailure, CATCH($intSpadReader,
+ interp(cc, ptree, interactive?))))) where
+
+ interp(cc, ptree, interactive?) ==
+ ncConversationPhase(function phParse, [cc, ptree])
+ ncConversationPhase(function phMacro, [cc])
+ ncConversationPhase(function phIntReportMsgs,[cc, interactive?])
+ ncConversationPhase(function phInterpret, [cc])
+
+ #ncEltQ(cc, 'messages) ^= 0 => ncError()
+
+ intSetNeedToSignalSessionManager()
+ $prevCarrier := $currentCarrier
+ result = 'ncEnd => stepNo
+ result = 'ncError => stepNo
+ result = 'ncEndItem => stepNo
+ stepNo+1
+
+phInterpret carrier ==
+ ptree := ncEltQ(carrier, 'ptree)
+ val := intInterpretPform(ptree)
+ ncPutQ(carrier, 'value, val)
+
+
+--% phReportMsgs: carrier[lines,messages,..]-> carrier[lines,messages,..]
+phIntReportMsgs(carrier, interactive?) ==
+ $erMsgToss => 'OK
+ lines := ncEltQ(carrier, 'lines)
+ msgs := ncEltQ(carrier, 'messages)
+ nerr := #msgs
+ ncPutQ(carrier, 'ok?, nerr = 0)
+ nerr = 0 => 'OK
+ processMsgList(msgs, lines)
+ intSayKeyedMsg ('S2CTP010,[nerr])
+ 'OK
+
+mkLineList lines ==
+ l := [CDR line for line in lines | nonBlank CDR line]
+ #l = 1 => CAR l
+ l
+
+nonBlank str ==
+ value := false
+ for i in 0..MAXINDEX str repeat
+ str.i ^= char " " =>
+ value := true
+ return value
+ value
+
+ncloopCommand (line,n) ==
+ a:=ncloopPrefix?('")include",line)=>
+ ncloopInclude1( a,n)
+ FUNCALL($systemCommandFunction,line)
+ n
+
+ncloopEscaped x==
+ esc :=false
+ done:=false
+ for i in (# x) - 1 .. 0 by -1 while not done repeat
+ done:=
+ x.i='" ".0 =>false
+ x.i='"__".0=>
+ esc:=true
+ true
+ true
+ esc
+
+ncloopDQlines (dq,stream)==
+ StreamNull stream
+ a:= poGlobalLinePosn tokPosn CADR dq
+ b:= poGlobalLinePosn CAAR stream
+ streamChop (a-b+1,stream)
+
+streamChop(n,s)==
+ if StreamNull s
+ then [nil,nil]
+ else if EQL(n,0)
+ then [nil,s]
+ else
+ [a,b]:= streamChop(n-1,cdr s)
+ line:=car s
+ c:=ncloopPrefix?('")command",CDR line)
+ d:= cons(car line,if c then c else cdr line)
+ [cons(d,a),b]
+
+ncloopPrintLines lines ==
+ for line in lines repeat WRITE_-LINE CDR line
+ WRITE_-LINE '" "
+
+ncloopIncFileName string==
+ fn := incFileName string
+ not fn =>
+ WRITE_-LINE (CONCAT(string, '" not found"))
+ []
+ fn
+
+ncloopParse s==
+ [dq,stream]:=CAR s
+ [lines,rest]:=ncloopDQlines(dq,stream)
+ cons([[lines,npParse dqToList dq]],CDR s)
+
+ncloopInclude0(st, name, n) ==
+ $lines:local := incStream(st, name)
+ ncloopProcess(n,false,
+ next(function ncloopEchoParse,
+ next(function insertpile,
+ next(function lineoftoks,$lines))))
+
+ncloopInclude1(name,n) ==
+ a:=ncloopIncFileName name
+ a => ncloopInclude(a,n)
+ n
+
+incString s== incRenumber incLude(0,[s],0,['"strings"] ,[Top])
+
+ncError() ==
+ THROW("SpadCompileItem",'ncError)
+
+--% Compilation Carriers
+-- This data structure is used to carry information between phases.
+
+--% phParse: carrier[tokens,...] -> carrier[ptree, tokens,...]
+--)line (defun pretty (x) (boottran::reallyprettyprint x))
+--)line (defun packagetran (x) (boot::|packageTran|))
+phParse(carrier,ptree) ==
+ phBegin 'Parsing
+ if $ncmParse then
+ nothing
+ intSayKeyedMsg ('S2CTP003,[%pform ptree])
+ ncPutQ(carrier, 'ptree, ptree)
+ 'OK
+
+
+--% phMacro: carrier[ptree,...] -> carrier[ptree, ptreePremacro,...]
+phMacro carrier ==
+ phBegin 'Macroing
+ ptree := ncEltQ(carrier, 'ptree)
+ ncPutQ(carrier, 'ptreePremacro, ptree)
+
+ ptree := macroExpanded ptree
+ if $ncmMacro then
+ intSayKeyedMsg ('S2CTP007,[%pform ptree] )
+
+ ncPutQ(carrier, 'ptree, ptree)
+ 'OK
+
+--% phReportMsgs: carrier[lines,messages,..]-> carrier[lines,messages,..]
+phReportMsgs(carrier, interactive?) ==
+ $erMsgToss => 'OK
+ lines := ncEltQ(carrier, 'lines)
+ msgs := ncEltQ(carrier, 'messages)
+ nerr := #msgs
+ ncPutQ(carrier, 'ok?, nerr = 0)
+ interactive? and nerr = 0 => 'OK
+ processMsgList(msgs, lines)
+ intSayKeyedMsg ('S2CTP010,[nerr])
+ 'OK
+
+ncConversationPhase(fn, args) ==
+ carrier := first args
+
+ $ncMsgList: local := []
+ $convPhase: local := 'NoPhase
+
+ UNWIND_-PROTECT( APPLY(fn, args), wrapup(carrier) ) where
+ wrapup(carrier) ==
+ for m in $ncMsgList repeat
+ ncPutQ(carrier, 'messages, [m, :ncEltQ(carrier, 'messages)])
+
+ncloopPrefix?(prefix,whole) ==
+ #prefix > #whole => false
+ good:=true
+ for i in 0..#prefix-1 for j in 0.. while good repeat
+ good:= prefix.i = whole.j
+ if good then SUBSTRING(whole,#prefix,nil) else good
+
+phBegin id ==
+ $convPhase := id
+ if $ncmPhase then intSayKeyedMsg('S2CTP021,[id])
+
+PullAndExecuteSpadSystemCommand stream ==
+ ExecuteSpadSystemCommand CAR stream
+ CDR stream
+
+ExecuteSpadSystemCommand string ==
+ FUNCALL($systemCommandFunction, string)
+
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} [[src/interp/server.boot.pamphlet]]
+\bibitem{2} [[src/interp/vmlisp.lisp.pamphlet]]
+\end{thebibliography}
+\end{document}