You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Clasp is an implementation of the Common Lisp programming language which uses LLVM as its compiler backend. This has, mostly, worked pretty well; despite LLVM being originally designed for C++, problems with converting Lisp semantics to a form LLVM can understand have mostly been minor to moderate.
A prominent and unfortunate exception to this is in LLVM's treatment of what i'll call "nonlocal control flow". Lisp and C++ have very different semantics in this area, and LLVM is almost entirely oriented around C++'s way of doing things. While Clasp does fully implement Lisp's nonlocal exit semantics, it does so in a very inefficient and convoluted way. This has caused major performance issues in real programs (the compiler itself).
Nonlocal semantics
By "nonlocal control" I mean a transfer of control between functions by any means other than a call or a normal return. A nonlocal "exit" is one that transfers to some function that is already on the call stack, i.e.
Types are not first class objects in Lisp. They can only be referred to indirectly with type specifiers, which are environment dependent. There is no way to determine if a given object is a valid type specifier in any environment.
Proposal:
Add a type type defined below. Add it to the pairwise disjoint types listed in 4.2.2 "Type Relationships". Define that types are externalizable, and that types are similar if they refer to similar sets; more specifically, that two types corresponding to classes are similar if those classes are similar, that two satisfies types are similar if they have the same function name, bla bla bla it should all be pretty intuitive.
Lisp does not have a mechanism to bind derived types lexically analogous to macrolet. This would be occasionally useful for some forms of metaprogramming. For example, Massimiliano Ghilardi's cl-parametric-types system uses "dumb" form rewriting (like sublis) to accomplish a similar task; actual lexical type definitions would represent an improvement.
Proposal:
Add the typelet and type special operators described below.
Common Lisp defines a macro mechanism for types, and the glossary mentions a "type expansion", but access to these by programmers is limited. Programmers cannot determine if a type specifier is a derived type, or the expansion of that type.
Some metaprogramming projects could use this information. Implementation-specific type expansion functions are used by, for example, Jan Moringen's configuration.options project, Massimiliano Ghilardi's cl-parametric-types project, and Masataro Asai's type-i project.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Because CL specifies bitwise operations treat integers as being in two's complement, if your bignums use a signed magnitude representation they are nontrivial. You will have to test signs while doing your arithmetic operations, and do different things depending. Generally, keep in mind that for integer x, (- x) = (lognot (1- x)) = (1+ (lognot x)), and that the number of bignum elements in the output may exceed those in the input. (Consider (logand -2 -3): It's -4, and 4 needs one more bit to represent than 2 or 3 do.)
For bitwise operations of two operands, you can understand the sign of the result by thinking of the infinite left bits. For example, if logior is given one positive and one negative operand, the result is negative, because for each of these infinitely many bits, (logior 0 1) = 1.
Here are some particular identities that are useful, derived from basic boolean algebra plus the above. `(- (