axiom-developer
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Axiom-developer] RE: algebra Makefiles with explicitdependencies, b


From: root
Subject: Re: [Axiom-developer] RE: algebra Makefiles with explicitdependencies, bootstrap, fixed-points etc.
Date: Mon, 10 Jan 2005 22:55:18 -0500

Bill, Steve,

> It is not so clear to me why the build appears to succeed
> even though these definitions are missing. In other languages
> I would presume that this situation would be easily caught
> as a missing file during `linking'. But here we have this
> "domain vector" thing. Is there not some why that the
> compilation could be made more robust by verifying the
> domain vector at compile time?

Bill, there is no "linking" step in any sense of the word.
This needs to be documented somewhere.

If we look at one of the random BOOTSTRAP files, say, CHAR we see:

Character: OrderedFinite() with
        ord: % -> Integer
            ++ ord(c) provides an integral code corresponding to the
            ++ character c.  It is always true that \spad{char ord c = c}.
        char: Integer  -> %
            ++ char(i) provides a character corresponding to the integer
            ++ code i.  It is always true that \spad{ord char i = i}.
        char: String   -> %
            ++ char(s) provides a character from a string s of length one.
        space:  () -> %
            ++ space() provides the blank character.
        quote:  () -> %
            ++ quote() provides the string quote character, \spad{"}.
        escape: () -> %
            ++ escape() provides the escape character, \spad{_}, which
            ++ is used to allow quotes and other characters {\em within}
            ++ strings.
        upperCase: % -> %
            ++ upperCase(c) converts a lower case letter to the corresponding
            ++ upper case letter.  If c is not a lower case letter, then
            ++ it is returned unchanged.
        lowerCase: % -> %
            ++ lowerCase(c) converts an upper case letter to the corresponding
            ++ lower case letter.  If c is not an upper case letter, then
            ++ it is returned unchanged.
        digit?: % -> Boolean
            ++ digit?(c) tests if c is a digit character,
            ++ i.e. one of 0..9.
        hexDigit?: % -> Boolean
            ++ hexDigit?(c) tests if c is a hexadecimal numeral,
            ++ i.e. one of 0..9, a..f or A..F.
        alphabetic?: % -> Boolean
            ++ alphabetic?(c) tests if c is a letter,
            ++ i.e. one of a..z or A..Z.
        upperCase?: % -> Boolean
            ++ upperCase?(c) tests if c is an upper case letter,
            ++ i.e. one of A..Z.
        lowerCase?: % -> Boolean
            ++ lowerCase?(c) tests if c is an lower case letter,
            ++ i.e. one of a..z.
        alphanumeric?: % -> Boolean
            ++ alphanumeric?(c) tests if c is either a letter or number,
            ++ i.e. one of 0..9, a..z or A..Z.

    == add
        Rep := SingleInteger      -- 0..255

        CC ==> CharacterClass()
        import CC

        --cl: Record(dig:CC,hex:CC,upp:CC,low:CC,alpha:CC,alnum:CC) :=
        --    [ digit(), hexDigit(),
        --      upperCase(), lowerCase(), alphabetic(), alphanumeric() ]

        OutChars:PrimitiveArray(OutputForm) :=
           construct [NUM2CHAR(i)$Lisp for i in 0..255]

        minChar := minIndex OutChars

        a = b                  == a =$Rep b
        a < b                  == a <$Rep b
        size()                 == 256
        index n                == char((n - 1)::Integer)
        lookup c               == (1 + ord c)::PositiveInteger
        char(n:Integer)        == n::%
        ord c                  == convert(c)$Rep
        random()               == char(random()$Integer rem size())
        space                  == QENUM("   ", 0$Lisp)$Lisp
        quote                  == QENUM("_" ", 0$Lisp)$Lisp
        escape                 == QENUM("__ ", 0$Lisp)$Lisp
        coerce(c:%):OutputForm == OutChars(minChar + ord c)
        digit? c               == member?(c pretend Character, digit())
        hexDigit? c            == member?(c pretend Character, hexDigit())
        upperCase? c           == member?(c pretend Character, upperCase())
        lowerCase? c           == member?(c pretend Character, lowerCase())
        alphabetic? c          == member?(c pretend Character, alphabetic())
        alphanumeric? c        == member?(c pretend Character, alphanumeric())

        latex c ==
            concat("\mbox{`", concat(new(1,c pretend Character)$String, 
"'}")$String)$String

        char(s:String) ==
--        one?(#s) => s(minIndex s) pretend %
          (#s) = 1 => s(minIndex s) pretend %
          error "String is not a single character"

        upperCase c ==
          QENUM(PNAME(UPCASE(NUM2CHAR(ord c)$Lisp)$Lisp)$Lisp,
                0$Lisp)$Lisp

        lowerCase c ==
          QENUM(PNAME(DOWNCASE(NUM2CHAR(ord c)$Lisp)$Lisp)$Lisp,
                0$Lisp)$Lisp



The BOOTSTRAP code, annotated, looks like:


=====================================================================
The VERSIONCHECK variable came about when we were writing the Aldor
compiler. We had completely reimplemented the algebra so that it was
incompatible with previous versions. This is checked on loading.

(|/VERSIONCHECK| 2) 

=====================================================================
This implements the 
        a = b                  == a =$Rep b
function. Note that the function name |CHAR;=;2$B;1| is constructed
from the domain abbreviation; the function name; the number of arguments
and their types; and a unique number

Also note that the compiler claims that it knows that the '='
function can be replaced with lisp 'EQL' in compiled code so
this function is never run. It uses a property list marker
'|SPADreplace|' on the function symbol to implement the replacement
during compiles.

(PUT (QUOTE |CHAR;=;2$B;1|) (QUOTE |SPADreplace|) (QUOTE EQL)) 

(DEFUN |CHAR;=;2$B;1| (|a| |b| |$|) (EQL |a| |b|)) 

=====================================================================
This implements the 
        a < b                  == a <$Rep b
function. Again note that the compiler knows that calls to this 
function can be replaced by the lisp QSLESSP function. The 'QS' 
prefix is a VMLisp idiom. 'Q' == quick (no type check) 'S'=singleinteger
which, at least in VMLisp turns into a single instruction. QSLESSP
(uppercased here because spad is case-sensitive and lisp is not)
is defined in src/interp/vmlisp.lisp.pamphlet as a macro with
embedded type information.

(PUT (QUOTE |CHAR;<;2$B;2|) (QUOTE |SPADreplace|) (QUOTE QSLESSP)) 

(DEFUN |CHAR;<;2$B;2| (|a| |b| |$|) (QSLESSP |a| |b|)) 

=====================================================================
This implements 
        size()                 == 256
and just returns a "boxed integer" (XLAM is a marker for boxing).

(PUT (QUOTE |CHAR;size;Nni;3|) (QUOTE |SPADreplace|) (QUOTE (XLAM NIL 256))) 

(DEFUN |CHAR;size;Nni;3| (|$|) 256) 

=====================================================================
This implements the
        index n                == char((n - 1)::Integer)
function. Notice that this does a 'QREFELT'. This is another VMLisp
idiom 'Q' is quick, 'REFELT' is a vector lookup function. This is
also implmented as a macro in src/interp/vmlisp.lisp.pamphlet where
it does a 'svref', simple vector reference into the current domain
(that's what '|$|' means) and calls the 18th element from this domain.

The domain is represented by a vector (the domain vector) which you'll
find at the bottom of this file. The domain vector for a domain is
kept on the property list of the domain name symbol, in this case it
is "Character". So we see the code:

(MAKEPROP (QUOTE |Character|) (QUOTE |infovec|) (LIST (QUOTE #(NIL NIL ...

The |infovec|, the information vector, contains a lot of domain specific
information which is looked up at runtime. In this case we are doing a
(QVREFELT |$| 18). If you count 18 elements into the |infovec| you'll
find |CHAR;char;I$;6|. If you examine the symbol name carefully you
can decode that it is a function from the domain "CHAR" (this domain)
called "char" that takes one argument of type "I" (integer), and is
the 6th function in this domain, which happens to be 
        char(n:Integer)        == n::%

So this function does what it says, it subtracts 1 from its argument,
treats it as an integer and returns the integer. The reason this works
is that "Characters" have a representation of SingleInteger:
        Rep := SingleInteger      -- 0..255

(DEFUN |CHAR;index;Pi$;4| (|n| |$|) (SPADCALL (|-| |n| 1) (QREFELT |$| 18))) 

.....[snip]....

=====================================================================
This is the function that gets executed when "Character" gets instantiated.
This function has the effect, if memory serves, of putting the function
"Character;" into the |$ConstructorCache|. The |$ConstructorCache| is a
hash table used for fast lookup and function dispatch. The call to 
|Character| will call |Character;| (see below).

(DEFUN |Character| NIL 
  (PROG NIL 
    (RETURN 
      (PROG (#1=#:G90941) 
        (RETURN 
          (COND 
            ((LETT #1# (HGET |$ConstructorCache| (QUOTE |Character|)) 
                 |Character|)
               (|CDRwithIncrement| (CDAR #1#)))
            ((QUOTE T) 
              (|UNWIND-PROTECT| 
                (PROG1 
                  (CDDAR 
                    (HPUT |$ConstructorCache| 
                      (QUOTE |Character|) 
                      (LIST 
                        (CONS NIL (CONS 1 (|Character;|))))))
                  (LETT #1# T |Character|)) 
                (COND 
                  ((NOT #1#) 
                    (HREM |$ConstructorCache| (QUOTE |Character|)))))))))))) 

=====================================================================
This function initializes the |infovec| data structure. Notice the calls
to QSETREFV, another VMLisp-ism, which does a "(setf (svref ...", that
is, it sets an element of a simple vector (|infovec|). Notice the call
to |SingleInteger|. This will cause the domain SingleInteger to be loaded,
initialized, and put in the constructor cache. This domain needs the
SingleInteger domain for its representation.

(DEFUN |Character;| NIL 
  (PROG (|dv$| |$| |pv$| #1=#:G90939 |i|) 
    (RETURN 
      (SEQ 
        (PROGN 
          (LETT |dv$| (QUOTE (|Character|)) . #2=(|Character|)) 
          (LETT |$| (GETREFV 53) . #2#) 
          (QSETREFV |$| 0 |dv$|) 
          (QSETREFV |$| 3 (LETT |pv$| (|buildPredVector| 0 0 NIL) . #2#)) 
          (|haddProp| |$ConstructorCache| (QUOTE |Character|) NIL (CONS 1 |$|))
          (|stuffDomainSlots| |$|) 
          (QSETREFV |$| 6 (|SingleInteger|)) 
          (QSETREFV |$| 10 
           (SPADCALL 
             (PROGN 
               (LETT #1# NIL . #2#) 
               (SEQ 
                 (LETT |i| 0 . #2#) 
                 G190 
                 (COND 
                   ((QSGREATERP |i| 255) (GO G191))) 
                 (SEQ 
                   (EXIT 
                     (LETT #1# (CONS (NUM2CHAR |i|) #1#) . #2#))) 
                 (LETT |i| (QSADD1 |i|) . #2#) 
                 (GO G190) 
                 G191 
                 (EXIT (NREVERSE0 #1#))))
             (QREFELT |$| 9)))
          (QSETREFV |$| 11 0) |$|))))) 

=====================================================================
This is the actual representation of the Character domain. The main
point of the compiler is to construct the |infovec|. I'm not up to
explaining the details of this at this moment.

(MAKEPROP 
 (QUOTE |Character|) 
 (QUOTE |infovec|) 
 (LIST 
  (QUOTE 
   #(NIL NIL NIL NIL NIL NIL (QUOTE |Rep|) (|List| 28) (|PrimitiveArray| 28) 
     (0 . |construct|) (QUOTE |OutChars|) (QUOTE |minChar|) (|Boolean|)
     |CHAR;=;2$B;1| |CHAR;<;2$B;2| (|NonNegativeInteger|) |CHAR;size;Nni;3| 
     (|Integer|) |CHAR;char;I$;6| (|PositiveInteger|) |CHAR;index;Pi$;4| 
     |CHAR;ord;$I;7| |CHAR;lookup;$Pi;5| (5 . |coerce|) |CHAR;random;$;8| 
     |CHAR;space;$;9| |CHAR;quote;$;10| |CHAR;escape;$;11| (|OutputForm|) 
     |CHAR;coerce;$Of;12| (|CharacterClass|) (10 . |digit|) (|Character|) 
     (14 . |member?|) |CHAR;digit?;$B;13| (20 . |hexDigit|) 
     |CHAR;hexDigit?;$B;14| (24 . |upperCase|) |CHAR;upperCase?;$B;15| 
     (28 . |lowerCase|) |CHAR;lowerCase?;$B;16| (32 . |alphabetic|) 
     |CHAR;alphabetic?;$B;17| (36 . |alphanumeric|) |CHAR;alphanumeric?;$B;18|
     (|String|) |CHAR;latex;$S;19| (40 . |minIndex|) (45 . |elt|) 
     |CHAR;char;S$;20| |CHAR;upperCase;2$;21| |CHAR;lowerCase;2$;22| 
     (|SingleInteger|))) (QUOTE #(|~=| 51 |upperCase?| 57 |upperCase| 62 
     |space| 67 |size| 71 |random| 75 |quote| 79 |ord| 83 |min| 88 |max| 94 
     |lowerCase?| 100 |lowerCase| 105 |lookup| 110 |latex| 115 |index| 120 
     |hexDigit?| 125 |hash| 130 |escape| 135 |digit?| 139 |coerce| 144 |char| 
     149 |alphanumeric?| 159 |alphabetic?| 164 |>=| 169 |>| 175 |=| 181 |<=| 
     187 |<| 193)) (QUOTE NIL) 
     (CONS (|makeByteWordVec2| 1 
       (QUOTE (0 0 0 0 0 0))) 
       (CONS 
         (QUOTE #(NIL |OrderedSet&| NIL |SetCategory&| |BasicType&| NIL))
         (CONS 
           (QUOTE #((|OrderedFinite|) (|OrderedSet|) (|Finite|) 
                    (|SetCategory|) (|BasicType|) (|CoercibleTo| 28)))
           (|makeByteWordVec2| 52 
             (QUOTE 
               (1 8 0 7 9 1 6 0 17 23 0 30 0 31 2 30 12 32 0 33 0 30 0 35 0 
                30 0 37 0 30 0 39 0 30 0 41 0 30 0 43 1 45 17 0 47 2 45 32 0 
                17 48 2 0 12 0 0 1 1 0 12 0 38 1 0 0 0 50 0 0 0 25 0 0 15 16 
                0 0 0 24 0 0 0 26 1 0 17 0 21 2 0 0 0 0 1 2 0 0 0 0 1 1 0 12 
                0 40 1 0 0 0 51 1 0 19 0 22 1 0 45 0 46 1 0 0 19 20 1 0 12 0 
                36 1 0 52 0 1 0 0 0 27 1 0 12 0 34 1 0 28 0 29 1 0 0 45 49 1 
                0 0 17 18 1 0 12 0 44 1 0 12 0 42 2 0 12 0 0 1 2 0 12 0 0 1 2 
                0 12 0 0 13 2 0 12 0 0 1 2 0 12 0 0 14))))))
     (QUOTE |lookupComplete|))) 

(MAKEPROP (QUOTE |Character|) (QUOTE NILADIC) T) 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]