axiom-developer
[Top][All Lists]

## 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.

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