Input

Input is fetched by the interpeter

intloopReadConsole is the main loop which is tail-recursively called to remain in the loop.

We read a string from the input. The serverReadLine 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.

interpreter

fricas / src / interp / i-toplev.boot

read-line

(1) -> a := read_-line(_*STANDARD_-INPUT_*$Lisp)$Lisp
hello

   (1)  hello
                                                            Type: SExpression

serverReadLine

This reads in a line of text upto carrage-return from the curinstream variable which is set by *standard-input* common lisp variable.

(1) -> a:= serverReadLine(_*STANDARD_-INPUT_*$Lisp)$Lisp                    
hello                                                                       
      
   (1)  hello                                                               
                                                            Type: SExpression                                                                           
(2) -> a                                                                    

   (2)  hello
                                                            Type: SExpression

processInteractive
this takes an SExpression and converts it into a type and does any numeric calculations that it can.

(7) -> processInteractive(parseFromString("2*3.4")$Lisp,nil)$Lisp

   (7)  6.8
                                                                  Type: Float
 
interpretTopLevel(parseFromString("2*3.4")$Lisp,nil)$Lisp

   (9)  ((Float) WRAPPED 250875719402449901978 . - 65)
                                                            Type: SExpression

fricas / src / interp / i-syscmd.boot

'parseFromString' is called to take user input and convert it into an SExpression.
(1) -> parseFromString("1")$Lisp

   (1)  1
                                                            Type: SExpression
(2) -> parseFromString("a")$Lisp

   (2)  a
                                                            Type: SExpression
(3) -> parseFromString("1.2")$Lisp

   (3)  (($elt (Float) float) 12 - 1 10)
                                                            Type: SExpression
(4) -> parseFromString("%a")$Lisp

   (4)  %a
                                                            Type: SExpression
(5) -> parseFromString("2*3.4")$Lisp

   (5)  (* 2 (($elt (Float) float) 34 - 1 10))
                                                            Type: SExpression 

g-util.boot

'packageTran'

parseFromString is usually composed with 'packageTran' although packageTran does not seem to do anything.

(6) -> packageTran(parseFromString("2*3.4")$Lisp)$Lisp                      
                                                                            
   (6)  (* 2 (($elt (Float) float) 34 - 1 10))                              
                                                            Type: SExpression

fricas / src / interp / int-top.boot

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.

fricas / src / interp / i-intern.boot

Internal Interpreter Facilities

Vectorized Attributed Trees

The interpreter translates parse forms into vats for analysis.
These contain a number of slots in each node for information.
The leaves are now all vectors, though the leaves for basic types
such as integers and strings used to just be the objects themselves.
The vectors for the leaves with such constants now have the value
of $immediateDataSymbol as their name. Their are may still be
some functions that still check whether a leaf is a constant. Note
that if it is not a vector it is a subtree.

attributed tree nodes have the following form:

slot description
0 operation name or literal
1 declared mode (type?) of variable
2 computed value of subtree from this node
3 modeset: list of single computed mode of subtree
4 prop list for extra things

mkAtreeWithSrcPos

mkAtreeWithSrcPos
(10) -> mkAtreeWithSrcPos(parseFromString("2*3.4")$Lisp,nil)$Lisp

   (10)
   ([*,NIL,NIL,NIL,NIL]  [--immediateData--,NIL,PositiveInteger()(),NIL,NIL]

     ([Dollar,NIL,NIL,NIL,NIL]  (Float)

       ([float,NIL,NIL,NIL,NIL]
        [--immediateData--,NIL,PositiveInteger()(),NIL,NIL]
        [--immediateData--,NIL,Integer()(),NIL,NIL]
        [--immediateData--,NIL,PositiveInteger()(),NIL,NIL])
       )
     )
                                                            Type: SExpression

fricas / src / interp / i-eval.boot

 
(1) -> a := mkAtreeWithSrcPos(parseFromString("2*3.4")$Lisp,nil)$Lisp

   (1)
   ([*,NIL,NIL,NIL,NIL]  [--immediateData--,NIL,PositiveInteger()(),NIL,NIL]

     ([Dollar,NIL,NIL,NIL,NIL]  (Float)

       ([float,NIL,NIL,NIL,NIL]
        [--immediateData--,NIL,PositiveInteger()(),NIL,NIL]
        [--immediateData--,NIL,Integer()(),NIL,NIL]
        [--immediateData--,NIL,PositiveInteger()(),NIL,NIL])
       )
     )
                                                            Type: SExpression
(2) -> v := getValue(a)$Lisp

   (2)  ()
                                                            Type: SExpression
(3) -> om := objMode(v)$Lisp

   (3)  ()
                                                            Type: SExpression
(4) -> alt := altTypeOf(om,a,nil)$Lisp

   (4)  ()
                                                            Type: SExpression
(5) -> t1 := coerceInt(v,alt)$Lisp

   (5)  ()
                                                            Type: SExpression
(6) -> a := mkAtreeWithSrcPos(parseFromString("2")$Lisp,nil)$Lisp

   (6)  [--immediateData--,NIL,PositiveInteger()(),NIL,NIL]
                                                            Type: SExpression
(7) -> v := getValue(a)$Lisp

   (7)  ((PositiveInteger) . 2)
                                                            Type: SExpression
(8) -> om := objMode(v)$Lisp

   (8)  (PositiveInteger)
                                                            Type: SExpression
(9) -> alt := altTypeOf(om,a,nil)$Lisp

   (9)  (Integer)
                                                            Type: SExpression
(10) -> t1 := coerceInt(v,alt)$Lisp

   (10)  ((Integer) . 2)
                                                            Type: SExpression
(11) -> t1 := coerceOrRetract(t1,nil)$Lisp

   (11)  ()
                                                            Type: SExpression
(12) -> m := getMode(a)$Lisp

   (12)  ()
                                                            Type: SExpression
(13) -> o := objMode(v)$Lisp

   (13)  (PositiveInteger)
                                                            Type: SExpression

All spad values in the interpreter are passed around in triples. These are lists of three items: [value,mode,environment]. The value may be wrapped (this is a pair whose CAR is the atom WRAPPED and whose CDR is the value), which indicates that it is a real value, or unwrapped in which case it needs to be EVALed to produce the proper value. The mode is the type of value, and should always be completely specified (not contain $EmptyMode). The environment is always empty, and is included for historical reasons.

Modemaps:

Modemaps are descriptions of compiled Spad function which the interpreter uses to perform type analysis. They consist of patterns of types for the arguments, and conditions the types must satisfy for the function to apply. For each function name there is a list of modemaps in file MODEMAP DATABASE for each distinct function with that name. The following is the list of the modemaps for "*" (multiplication. The first modemap (the one with the labels) is for module multiplication which is multiplication of an element of a module by a member of its scalar domain.

This is the signature pattern for the modemap, it is of the form:

      (DomainOfComputation TargetType <ArgumentType ...>)
            |
            |                This is the predicate that needs to be
            |                 satisfied for the modemap to apply
            |                            |
            V                            |
       /-----------/                     |
   ( ( (*1 *1 *2 *1)                     V
         /-----------------------------------------------------------/
       ( (AND (ofCategory *1 (Module *2)) (ofCategory *2 (SimpleRing))) )
        . CATDEF) <-- This is the file where the function was defined
     ( (*1 *1 *2 *1)
       ( (AND (isDomain *2 (Integer)) (ofCategory *1 (AbelianGroup))) )
        . CATDEF)
     ( (*1 *1 *2 *1)
       ( (AND
           (isDomain *2 (NonNegativeInteger))
           (ofCategory *1 (AbelianMonoid))) )
        . CATDEF)
     ((*1 *1 *1 *1) ((ofCategory *1 (SemiGroup)) ) . CATDEF)
        )
      -

Environments:

Environments associate properties with atoms.
(see CUTIL BOOT for the exact structure of environments).
Some common properties are:

modeSet:

During interpretation we build a modeSet property for each node in the expression. This is (in theory) a list of all the types possible for the node. In the current implementation these modeSets always contain a single type.

value:

Value properties are always triples. This is where the values of variables are stored. We also build value properties for internal nodes during the bottom up phase.

mode:

This is the declared type of an identifier.

Environments

There are several different environments used in the interpreter:

$InteractiveFrame This is the environment where the user values are stored. Any side effects of evaluation of a top-level expression are stored in this environment. It is always used as the starting environment for interpretation.
$e This is the name used for $InteractiveFrame while interpreting.
$env This is local environment used by the interpreter. Only temporary information (such as types of local variables is stored in $env. It is thrown away after evaluation of each expression.

InputForm

This is defined in: mkfunc.spad.pamphlet

Any domain can control how it is parsed by defining:

convert(%) : InputForm

 

++   Domain of parsed forms which can be passed to the interpreter.
++   This is also the interface between algebra code and facilities
++   in the interpreter.

InputForm():
  Join(SExpressionCategory(String, Symbol, Integer, DoubleFloat),
       ConvertibleTo SExpression) with
    interpret : % -> Any
      ++ interpret(f) passes f to the interpreter.
    convert  : SExpression -> %
      ++ convert(s) makes s into an input form.
    binary   : (%, List %) -> %
      ++ \spad{binary(op, [a1, ..., an])} returns the input form
      ++ corresponding to  \spad{a1 op a2 op ... op an}.
    function : (%, List Symbol, Symbol) -> %
      ++ \spad{function(code, [x1, ..., xn], f)} returns the input form
      ++ corresponding to \spad{f(x1, ..., xn) == code}.
    lambda   : (%, List Symbol) -> %
      ++ \spad{lambda(code, [x1, ..., xn])} returns the input form
      ++ corresponding to \spad{(x1, ..., xn) +-> code} if \spad{n > 1},
      ++ or to \spad{x1 +-> code} if \spad{n = 1}.
    "+"      : (%, %) -> %
      ++ \spad{a + b} returns the input form corresponding to \spad{a + b}.
    "*"      : (%, %) -> %
      ++ \spad{a * b} returns the input form corresponding to \spad{a * b}.
    "/"      : (%, %) -> %
      ++ \spad{a / b} returns the input form corresponding to \spad{a / b}.
    "^"     : (%, NonNegativeInteger) -> %
      ++ \spad{a ^ b} returns the input form corresponding to \spad{a ^ b}.
    "^"     : (%, Integer) -> %
      ++ \spad{a ^ b} returns the input form corresponding to \spad{a ^ b}.
    0        : constant -> %
      ++ \spad{0} returns the input form corresponding to 0.
    1        : constant -> %
      ++ \spad{1} returns the input form corresponding to 1.
    flatten  : % -> %
      ++ flatten(s) returns an input form corresponding to s with
      ++ all the nested operations flattened to triples using new
      ++ local variables.
      ++ If s is a piece of code, this speeds up
      ++ the compilation tremendously later on.
    unparse  : % -> String
      ++ unparse(f) returns a string s such that the parser
      ++ would transform s to f.
      ++ Error: if f is not the parsed form of a string.
    parse    : String -> %
      ++ parse(s) is the inverse of unparse. It parses a
      ++ string to InputForm
    declare  : List %   -> Symbol
      ++ declare(t) returns a name f such that f has been
      ++ declared to the interpreter to be of type t, but has
      ++ not been assigned a value yet.
      ++ Note: t should be created as \spad{devaluate(T)$Lisp} where T is the
      ++ actual type of f (this hack is required for the case where
      ++ T is a mapping type).
    compile  : (Symbol, List %) -> Symbol
      ++ \spad{compile(f, [t1, ..., tn])} forces the interpreter to compile
      ++ the function f with signature \spad{(t1, ..., tn) -> ?}.
      ++ returns the symbol f if successful.
      ++ Error: if f was not defined beforehand in the interpreter,
      ++ or if the ti's are not valid types, or if the compiler fails.

 


metadata block
see also:
Correspondence about this page

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2023 Martin John Baker - All rights reserved - privacy policy.