The reference manual provides a detailed account of the programming language. It supplements and amends the user manual (particularly the sections “Programming Language” and “Listener Buffers”) and the tutorial.
Let us examine what happens when the form (+ 123 456) is evaluated in a listener buffer:
> (+ 123 456)
579
The process can be broken down into the following five steps:
Step 1 The sequence of characters (+ 123 456) is read from the listener buffer.
Step 2 The reader converts the sequence of characters (+ 123 456) into the list (+ 123 456). (The sequence of characters is a readable representation of the list.) This step can be broken down into the following two substeps:
Step 2.1 A component of the reader called the tokenizer converts the sequence of characters (+ 123 456) into a sequence of tokens. A token consists of the following pieces of information bundled together: a category and, if required by the category, a value. Each token category has an associated pattern and each token has an associated lexeme. A lexeme is a sequence of contiguous characters extracted from the input sequence of characters. The lexeme associated with a token must match the pattern associated with the token's category and the sequence of characters resulting from the concatenation of the lexemes associated with the tokens must match the input sequence of characters. The sequence of characters (+ 123 456) is converted into the following sequence of tokens:
opening-parenthesis whose associated lexeme is (. This token has no value.variable whose associated lexeme is +. The value of this token is the object of type variable whose name is +.whitespace whose associated lexeme is . This token has no value.number whose associated lexeme is 123. The value of this token is an object of type number representing the mathematical number $123$.whitespace whose associated lexeme is . This token has no value.number whose associated lexeme is 456. The value of this token is an object of type number representing the mathematical number $456$.closing-parenthesis whose associated lexeme is ). This token has no value.Note that some whitespace is needed to separate the lexeme + from the lexeme 123 and the lexeme 123 from the lexeme 456 but no whitespace is needed to separate the lexeme ( from the lexeme + or the lexeme 456 from the lexeme ).
Step 2.2 A component of the reader called the parser converts the sequence of tokens from step 2.1 (minus the tokens of category whitespace, which are ignored by the parser) into a cons whose car is the variable from step 2.1 and whose cdr is a cons whose car is the first number from step 2.1 and whose cdr is a cons whose car is the second number from step 2.1 and whose cdr is the empty list. Together, those three conses represent the list (+ 123 456).
Step 3 The evaluator evaluates the list (+ 123 456) to the number 579. The evaluation of the top-level form (+ 123 456) entails the evaluation of other non-top-level forms. Each form must be analyzed in order to determine how it should be evaluated. The form (+ 123 456) is analyzed as a plain function call. The variable + is treated as an abbreviation for the form (fref +). The form (fref +) is analyzed as an fref form. The forms 123 and 456 are analyzed as self-evaluating objects. Because the global function + is a closure, its invocation entails the evaluation (and thus the analysis) of other forms. The component of the evaluator responsible for analyzing forms is called the form analyzer.
Step 4 The printer converts the number 579 into the sequence of characters 579. (The sequence of characters is the printable representation of the number.)
Step 5 The sequence of characters 579 is written into the listener buffer.
EVLambda has three levels of syntax:
Each level of syntax is described later in its own section.
The reader is used not only to convert the characters typed into a listener buffer into an object but also to convert the characters contained inside an EVLambda source file into a sequence of objects.
EVLambda source files come in two varieties: the plain EVLambda source files, which only contain EVLambda source code, and the documented EVLambda source files, which contain a mix of EVLambda source code and documentation in XML format.
Here is an example of a plain EVLambda source file:
(fdef fact (n)
(if (= n 0)
1
(* n (fact (- n 1)))))
(test 1 (fact 0))
(test 120 (fact 5))
(test 3628800 (fact 10))
(fdef fib (n)
(if (= n 0)
0
(if (= n 1)
1
(+ (fib (- n 1)) (fib (- n 2))))))
(test 0 (fib 0))
(test 5 (fib 5))
(test 55 (fib 10))
Here is an example of a documented EVLambda source file:
<chapter>
<title>Recursive Functions</title>
<p>...para...</p>
<p>...para...</p>
<section>
<title>Factorial Function</title>
<p>...para...</p>
<p>...para...</p>
(fdef fact (n)
<p>...block...</p>
<p>...block...</p>
(if (= n 0)
1 <comment>...eol...</comment>
(* n (fact (- n 1))))) <comment>...eoll...</comment>
(test 1 (fact 0))
(test 120 (fact 5))
(test 3628800 (fact 10))
</section>
<section>
<title>Fibonacci Sequence</title>
<p>...para...</p>
<p>...para...</p>
(fdef fib (n)
<p>...block...</p>
<p>...block...</p>
(if (= n 0)
0 <comment>...eol...</comment>
(if (= n 1)
1 <comment>...eol...</comment>
(+ (fib (- n 1)) (fib (- n 2)))))) <comment>...eoll...</comment>
(test 0 (fib 0))
(test 5 (fib 5))
(test 55 (fib 10))
</section>
</chapter>
Documented EVLambda source files can be converted to HTML by a component of the programming language called the documentation generator.
An extensible markup language (XML) document is a annotated text document. An XML document is divided into two intermingled parts: the character data (the content) and the markup (the annotations). Markup can take many forms. Documented EVLambda source files use the following forms of markup:
<chapter>, <section>, <title>, <p>, <comment>, …</chapter>, </section>, </title>, </p>, </comment>, …<br/>, …<!-- FIXME -->, …< (refers to the character <), > (refers to the character >), & (refers to the character &), …⏎ (refers to the character ⏎), …⏎ (refers to the character ⏎), …Many constraints must be satisfied for an XML document to be well-formed. The main well-formedness constraints are noted below.
Well-formedness constraint: Start tags and end tags must appear in pairs. In each pair, the start tag must precede the end tag and both tags must have the same name.
An element is a sequence of characters delimited by a pair of start and end tags or by an empty-element tag. The characters of the delimiting tags or tag belong to the element. The characters that belong to an element but not to its delimiting tags or tag constitute the content of the element. The content of an element delimited by an empty-element tag is empty. The name of an element is the name of its delimiting tags or tag.
Well-formedness constraint: Elements must not overlap. Let $X$ and $Y$ be two distinct elements. One of the following conditions must be true: $X$ precedes $Y$, $Y$ precedes $X$, $X$ is inside the content of $Y$, or $Y$ is inside the content of $X$.
Let $X$ and $Y$ be two elements. If $X$ is inside the content of $Y$ and there does not exist a third element $Z$ such that $X$ is inside the content of $Z$ and $Z$ is inside the content of $Y$, then $X$ is called a child of $Y$.
Let $X$, $Y$, and $Z$ be three elements. If $X$ is a child of $Y$ and $Z$, then $Y$ and $Z$ are the same element. That element is called the parent of $X$.
Not all elements have a parent. An element that has no parent is called a root element.
Well-formedness constraint: There must exist exactly one root element.
Well-formedness constraint: The characters < and & must not appear literally inside character data. They must be escaped using an entity reference or a character reference.
Documented EVLambda source files are structured as follows:
Because the characters < and & can appear inside EVLambda source code, a documented EVLambda source file is not always a well-formed XML document.
The documentation generator converts a documented EVLambda source file to HTML in two steps:
Step 1 The characters < and & appearing inside EVLambda source code are escaped and some tags are added to better delimit the code from the surrounding documentation and the comments from the surrounding code. The resulting file is a well-formed XML document.
Step 2 The resulting file from step 1 is converted to HTML by an XSLT stylesheet.
The characters contained inside listener buffers and EVLambda source files are Unicode characters. Unicode is a character set containing, as of version 17.0, $159801$ characters. Each Unicode character is uniquely identified by a nonnegative integer called its code point. Code points range from $0$ to $1114111$ in decimal and from 0 to 10FFFF in hexadecimal. (Not all code points are assigned to a character.) The notation $U{+}\mlvar{hex}$ denotes the Unicode character whose code point is represented by the hexadecimal numeral $\mlvar{hex}$. The order on integers directly translates into an order on Unicode characters. With respect to that order, the Unicode character $c_1$ precedes the Unicode character $c_2$ if and only if the code point of $c_1$ is strictly less than the code point of $c_2$. That order can be used to define ranges of Unicode characters.
The range from $0$ to $1114111$ is divided into $17$ planes each containing $65536$ code points. The first plane is called the basic multilingual plane (BMP) and the other planes are called the supplementary planes. Most of the characters in common use in the world are located in the BMP.
An encoding form is a mapping that maps a character to a sequence of $n$-bit words called code units. The following encoding forms are in common use:
An encoding scheme is a mapping that maps a character to a sequence of bytes. (A byte is an $8$-bit word.) The following encoding schemes are in common use:
Contrary to what was said in the user manual, an object of type character represents a UTF-$16$ code unit (instead of a Unicode character) and an object of type string represents an indexed sequence of UTF-$16$ code units (instead of an indexed sequence of Unicode characters).
Each Unicode character has a name (“LATIN CAPITAL LETTER A” for instance) and a set of properties. An important property is the general category. The general category property can take the following values:
| Lu | Uppercase_Letter | uppercase letters |
| Ll | Lowercase_Letter | lowercase letters |
| Lt | Titlecase_Letter | digraphs whose first constituent is an uppercase letter |
| LC | Cased_Letter | Lu, Ll, or Lt |
| Lm | Modifier_Letter | noncombining modifier letters |
| Lo | Other_Letter | letters from unicase alphabets and ideographs |
| L | Letter | Lu, Ll, Lt, Lm, or Lo |
| Mn | Nonspacing_Mark | nonspacing combining marks (accents, …) |
| Mc | Spacing_Mark | spacing combining marks |
| Me | Enclosing_Mark | enclosing combining marks |
| M | Mark | Mn, Mc, or Me |
| Nd | Decimal_Number | decimal digits |
| Nl | Letter_Number | letterlike numeric characters (Roman numerals, …) |
| No | Other_Number | other numeric characters (fractions, …) |
| N | Number | Nd, Nl, or No |
| Pc | Connector_Punctuation | connecting punctuation marks (underscore, …) |
| Pd | Dash_Punctuation | dashlike punctuation marks (hyphen, dashes, …) |
| Ps | Open_Punctuation | opening punctuation marks (opening parenthesis, …) |
| Pe | Close_Punctuation | closing punctuation marks (closing parenthesis, …) |
| Pi | Initial_Punctuation | initial quotation marks |
| Pf | Final_Punctuation | final quotation marks |
| Po | Other_Punctuation | other punctuation marks (period, comma, colon, semicolon, …) |
| P | Punctuation | Pc, Pd, Ps, Pe, Pi, Pf, or Po |
| Sm | Math_Symbol | mathematical symbols |
| Sc | Currency_Symbol | currency symbols |
| Sk | Modifier_Symbol | noncombining modifier symbols |
| So | Other_Symbol | other symbols (Emojis, …) |
| S | Symbol | Sm, Sc, Sk, or So |
| Zs | Space_Separator | space characters |
| Zl | Line_Separator | line separator character |
| Zp | Paragraph_Separator | paragraph separator character |
| Z | Separator | Zs, Zl, or Zp |
| Cc | Control | C0 and C1 control characters (horizontal tab, line feed, carriage return, …) |
| Cf | Format | format control characters (left-to-right and right-to-left marks, …) |
| Cs | Surrogate | surrogate code points |
| Co | Private_Use | private-use characters |
| Cn | Unassigned | noncharacters and unassigned code points |
| C | Other | Cc, Cf, Cs, Co, or Cn |
Most Unicode characters have associated visual representations called glyphs. For instance, the Unicode character “LATIN CAPITAL LETTER A” ($\unicode{0041}$) has the following associated glyphs (and infinitely more considering all possible variations in font, size, weight, style, etc.):
In general, the association is not between Unicode characters and glyphs but between sequences of Unicode characters and glyphs and it is possible for different sequences of Unicode characters to have the same associated glyphs. For example, the sequence of one Unicode character “LATIN CAPITAL LETTER A WITH DIAERESIS” ($\unicode{00C4}$) and the sequence of two Unicode characters “LATIN CAPITAL LETTER A” ($\unicode{0041}$) “COMBINING DIAERESIS” ($\unicode{0308}$) have the same associated glyphs:
The tokenizer uses regular expressions to specify the patterns associated with the token categories.
The following table summarizes the syntax of the regular expressions used in this document:
| Syntax | Meaning |
|---|---|
'…' | literal string (literal single quotes and backslashes must be escaped) |
"…" | literal string (literal double quotes and backslashes must be escaped) |
[…] | positive character class (literal carets, hyphens, closing square brackets, and backslashes must be escaped) |
[^…] | negative character class (literal carets, hyphens, closing square brackets, and backslashes must be escaped) |
$\mlvar{char}_1$-$\mlvar{char}_2$ | range of characters (inside character classes) |
$\mlvar{re}_1\mlvar{re}_2$ | concatenation operation |
$\mlvar{re}_1$|$\mlvar{re}_2$ | union (alternation) operation |
$\mlvar{re}_1$-$\mlvar{re}_2$ | difference operation |
$\mlvar{re}$* | zero-or-more-times (Kleene star) operation |
$\mlvar{re}$+ | one-or-more-times (Kleene plus) operation |
$\mlvar{re}$? | zero-or-one-time (optional) operation |
| $\metavar{name}\Coloneq\mlvar{re}$ | definition of a named regular expression |
Literal strings can contain the following escape sequences:
| Escape sequence | Meaning |
|---|---|
\\\\ | the backslash |
\' | the single quote |
\" | the double quote |
\U{$\mlvar{hex}$} | the Unicode character whose code point is represented by the hexadecimal numeral $\mlvar{hex}$ |
Character classes can contain the following escape sequences:
| Escape sequence | Meaning |
|---|---|
\\\\ | the backslash |
\^ | the caret |
\- | the hyphen |
\] | the closing square bracket |
\U{$\mlvar{hex}$} | the Unicode character whose code point is represented by the hexadecimal numeral $\mlvar{hex}$ |
\C{$\mlvar{cat}$} | the Unicode characters whose general categories are $\mlvar{cat}$ |
The zero-or-more-times, one-or-more-times, and zero-or-one-time operations have precedence over the concatenation operation and the concatenation operation has precedence over the union and difference operations. All operations are left associative. Parenthesis can be added to override those precedence and associativity rules.
References to named regular expressions can be used wherever regular expressions can be used. References to named regular expressions denoting classes of characters can also be used inside character classes. Circular definitions are not allowed.
Except for the parts referencing named regular expressions, regular expressions are typeset in a monospaced typeface. Spaces can be added freely outside literal strings and character classes without modifying the meaning of a regular expression.
The parser and the form analyzer use a variant of the extended Backus-Naur form (EBNF) notation to define various context-free grammars.
The following table summarizes the syntax of the variant of the EBNF notation used in this document:
| Syntax | Meaning |
|---|---|
$\mlvar{lhs}$ $\Coloneq$ $\mlvar{rhs}$ | definition of a production rule |
$\metavar{nonterminal}$ | nonterminal symbol |
terminal | terminal symbol |
$\epsilon$ | empty sequence of symbols |
$\mlvar{rhs}_1$ | … | $\mlvar{rhs}_n$ | union (alternation) operation |
$\mlvar{symbol}$* | zero-or-more-times (Kleene star) operation |
$\mlvar{symbol}$+ | one-or-more-times (Kleene plus) operation |
$\mlvar{symbol}$? | zero-or-one-time (optional) operation |
{$\mlvar{rhs}$} | group |
? … ? | special sequence |
A left-hand-side ($\mlvar{lhs}$) consists of a nonterminal symbol. A right-hand-side ($\mlvar{rhs}$) consists of a sequence of zero or more nonterminal and/or terminal symbols. A group can be used wherever a symbol can be used. A special sequence is a free-form text specifying a set of terminal symbols.
The tokenizer converts an input sequence of Unicode characters into a sequence of tokens in two steps. During the first step, the tokenizer converts the input sequence of Unicode characters into a provisional sequence of tokens. During the second step, the tokenizer converts the provisional sequence of tokens into a final sequence of tokens.
Let us first define the following named regular expressions:
| $\metavar{valid-char}$ | $\Coloneq$ | [\C{L}\C{M}\C{N}\C{P}\C{S}\C{Z}\U{0009}-\U{000D}\U{0085}\C{Cf}\C{Co}] |
| $\metavar{whitespace-char}$ | $\Coloneq$ | [\U{0009}-\U{000D}\U{0020}\U{0085}\U{200E}\U{200F}\U{2028}\U{2029}] |
| $\metavar{syntax-char}$ | $\Coloneq$ | ['`,"()#] |
| $\metavar{xml-name-char}$ | $\Coloneq$ | [a-z] |
Each of those named regular expressions specifies a class of Unicode characters.
The whitespace characters are the following characters:
In Linux and macOS operating systems, an end of line is represented by an LF character. In Windows operating systems, an end of line is represented by a CR character followed by an LF character.
From the definition of $\metavar{valid-char}$, we can infer that the input sequence of Unicode characters must not contain any of the following characters and code points:
The unassigned code points are actually allowed by the current version of the code.
During the first step, the tokenizer converts the input sequence of Unicode characters into a provisional sequence of tokens of the following categories (patterns are regular expressions):
whitespace$\metavar{whitespace-char}$+quote"'"quasiquote'`'unquote','unquote-splicing',@'string'"' (($\metavar{valid-char}$ - ["\\\\]) | ('\\\\' [\\\\"tnvfr]) | ('\\\\U{' [a-fA-F0-9]+ '}'))* '"'string representing the sequence of UTF-16 code units encoding the sequence of Unicode characters delimited by the double quotes (after interpretation of the escape sequences).opening-parenthesis'('closing-parenthesis')'hash-opening-parenthesis'#('hash-plus'#+'hash-minus'#-'void'#v'void.boolean'#t' | '#f''#t', then the value is the single object of type boolean representing true. If the lexeme matches '#f', then the value is the single object of type boolean representing false.hash-string'#' [0-9]* '"' (($\metavar{valid-char}$ - ["\\\\]) | ('\\\\' [\\\\"tnvfr]) | ('\\\\U{' [a-fA-F0-9]+ '}'))* '"'xml-start-tag'<' $\metavar{xml-name-char}$+ '>'xml-end-tag'</' $\metavar{xml-name-char}$+ '>'xml-empty-element-tag'<' $\metavar{xml-name-char}$+ '/>'xml-comment'<!--' (($\metavar{valid-char}$ - '-') | ('-' ($\metavar{valid-char}$ - '-')))* '-->'proto-token(($\metavar{valid-char}$ - ($\metavar{whitespace-char}$ | $\metavar{syntax-char}$ | '\\\\')) | ('\\\\' [\\\\<]) | ('\\\\U{' [a-fA-F0-9]+ '}'))+Escape sequences in lexemes associated with tokens of categories string and hash-string are interpreted as follows:
| Escape sequence | Meaning |
|---|---|
\\\\ | the backslash |
\" | the double quote |
\t | the horizontal tab control character |
\n | the line feed control character |
\v | the vertical tab control character |
\f | the form feed control character |
\r | the carriage return control character |
\U{$\mlvar{hex}$} | the Unicode character whose code point is represented by the hexadecimal numeral $\mlvar{hex}$ |
Escape sequences in lexemes associated with tokens of category proto-token are interpreted as follows:
| Escape sequence | Meaning |
|---|---|
\\\\ | the backslash |
\< | the less-than sign |
\U{$\mlvar{hex}$} | the Unicode character whose code point is represented by the hexadecimal numeral $\mlvar{hex}$ |
Let $\mlvar{input}$ be the input sequence of Unicode characters. For any token $T$, let us denote by $\lex(T)$ the lexeme associated with $T$ and by $\pat(T)$ the pattern associated with $T$'s category. The tokenizer must find a sequence of tokens $\langle T_1,\ldots,T_n\rangle$ such that the following conditions are satisfied:
Because the meaning of a program cannot be ambiguous, there cannot exist more than one sequence of tokens satisfying the previous conditions for any given input. As the following examples demonstrate, the patterns alone do not provide this guarantee:
foobar has many competing interpretations, including the following two:
fooproto-token barproto-tokenfoobarproto-token (this is the intended interpretation),@foo has many competing interpretations, including the following two:
,unquote @fooproto-token,@unquote-splicing fooproto-token (this is the intended interpretation)foo<bar>baz has many competing interpretations, including the following two:
foo<bar>bazproto-tokenfooproto-token <bar>xml-start-tag bazproto-token(this is the intended interpretation)The tokenizer uses additional rules to resolve the ambiguities. Those additional rules are embedded into the algorithm provided below.
EVLambda source code can only be found outside any XML element (this is the case in listener buffers and plain EVLambda source files) or directly inside a chapter or section XML element (this is the case in documented EVLambda source files). A context that cannot contain EVLambda source code is called a pure-xml context. When processing a pure-xml context, the tokenizer only recognizes tokens of the following categories: whitespace (any character data is treated as whitespace when processing a pure-xml context), xml-start-tag, xml-end-tag, xml-empty-element-tag, and xml-comment. The tokenizer uses a stack of XML element names to determine if it is processing a pure-xml context. The tokenizer is processing a pure-xml context when the stack is not empty and the name at the top of the stack is neither chapter nor section.
Here is the algorithm used by the tokenizer to convert the input sequence of Unicode characters into a provisional sequence of tokens (control normally flows from one step to the next and it is assumed that the stack of XML element names is initially empty):
whitespace whose associated lexeme contains all the characters up to the end of the input or the first character that is a less-than sign (that character is not included in the lexeme).whitespace whose associated lexeme contains all the characters up to the end of the input or the first character that is not a whitespace character (that character is not included in the lexeme).quote and loop to the top.quasiquote and loop to the top.unquote-splicing and loop to the top.unquote and loop to the top.string whose associated lexeme contains all the characters up to the first unescaped double quote (that character is included in the lexeme) and loop to the top. Fail if the lexeme contains an invalid escape sequence or the closing double quote is missing.opening-parenthesis and loop to the top.closing-parenthesis and loop to the top.hash-opening-parenthesis and loop to the top.hash-plus and loop to the top.hash-minus and loop to the top.v, emit a token of category void and loop to the top.t, emit a token of category boolean and loop to the top.f, emit a token of category boolean and loop to the top.hash-string whose associated lexeme contains all the characters up to the first unescaped double quote (that character is included in the lexeme) and loop to the top. Fail if the lexeme contains an invalid escape sequence or the closing double quote is missing.xml-start-tag, push the name of the start tag on the stack, and loop to the top.xml-end-tag, pop the top name off the stack, and loop to the top. Fail if the stack is empty or the top name does not match the name of the end tag.xml-empty-element-tag and loop to the top.xml-comment and loop to the top.proto-token whose associated lexeme contains all the characters up to the end of the input or the first character that is a whitespace character, a syntax character, or an unescaped less-than sign that is the first character of a piece of XML markup (that character is not included in the lexeme) and loop to the top. Fail if the lexeme contains an invalid escape sequence.During the second step, the tokenizer converts the provisional sequence of tokens into a final sequence of tokens as follows:
whitespace are discarded.hash-string is processed as follows:
hash-string. The token of category hash-string is replaced by a sequence of $n$ token(s) of category character such that the value of the $i$-th token of category character is an object of type character representing $\mlvar{code-unit}_i$.hash-string and $i$ be the nonnegative integer represented by the optional decimal numeral. If $i\lt n$, then the token of category hash-string is replaced by a token of category character whose value is an object of type character representing $\mlvar{code-unit}_i$. Otherwise, the tokenization fails.proto-token is replaced by a token of one of the following categories (patterns are regular expressions matched against the value of the token of category proto-token; the first pattern matching the value wins; tokenization fails if no pattern matches the value):
dot'.'number('+' | '-')? [0-9]+ ('.' [0-9]+)?number representing the mathematical number of which the value matching the pattern is a decimal representation.keyword':' [^:]+keyword whose name is the value matching the pattern minus the initial colon.variable[^:]+variable whose name is the value matching the pattern.This section illustrates the use of the hash-string construct.
The Unicode character “NINJA” ($\unicode{1F977}$, high-surrogate $\unicode{D83E}$, low-surrogate $\unicode{DD77}$) represents a ninja with a nonrealistic skin tone:
> '(#"🥷")
(#"\U{D83E}" #"\U{DD77}")
> #0"🥷"
#"\U{D83E}"
> #1"🥷"
#"\U{DD77}"
It is possible to obtain a ninja with a realistic skin tone by combining the Unicode character "NINJA" with one of the following skin-tone modifiers:
| Name | Code Point | High-Surrogate | Low-Surrogate | Sample |
|---|---|---|---|---|
| EMOJI MODIFIER FITZPATRICK TYPE-1-2 | $\unicode{1F3FB}$ | $\unicode{D83C}$ | $\unicode{DFFB}$ | 🏻 |
| EMOJI MODIFIER FITZPATRICK TYPE-3 | $\unicode{1F3FC}$ | $\unicode{D83C}$ | $\unicode{DFFC}$ | 🏼 |
| EMOJI MODIFIER FITZPATRICK TYPE-4 | $\unicode{1F3FD}$ | $\unicode{D83C}$ | $\unicode{DFFD}$ | 🏽 |
| EMOJI MODIFIER FITZPATRICK TYPE-5 | $\unicode{1F3FE}$ | $\unicode{D83C}$ | $\unicode{DFFE}$ | 🏾 |
| EMOJI MODIFIER FITZPATRICK TYPE-6 | $\unicode{1F3FF}$ | $\unicode{D83C}$ | $\unicode{DFFF}$ | 🏿 |
Here is the result of combining the Unicode character “NINJA” with the different skin-tone modifiers:
> '(#"🥷🏻")
(#"\U{D83E}" #"\U{DD77}" #"\U{D83C}" #"\U{DFFB}")
> '(#"🥷🏼")
(#"\U{D83E}" #"\U{DD77}" #"\U{D83C}" #"\U{DFFC}")
> '(#"🥷🏽")
(#"\U{D83E}" #"\U{DD77}" #"\U{D83C}" #"\U{DFFD}")
> '(#"🥷🏾")
(#"\U{D83E}" #"\U{DD77}" #"\U{D83C}" #"\U{DFFE}")
> '(#"🥷🏿")
(#"\U{D83E}" #"\U{DD77}" #"\U{D83C}" #"\U{DFFF}")
The parser uses a context-free grammar to convert the sequence of tokens produced by the tokenizer into a sequence of objects. The conversion is conceptually a two-step process. During the first step, the parser converts the sequence of tokens into a derivation tree. During the second step, the parser assigns a meaning to the derivation tree.
The construction of the derivation tree is directed by the context-free grammar. Because the parser ignores the tokens' values and only takes into account the tokens' categories when constructing the derivation tree, the terminal symbols of the context-free grammar are the names of the token categories.
The production rule describing the whole sequence of tokens produced by the tokenizer depends on the origin of the input sequence of characters.
When the origin of the input sequence of characters is a listener buffer, the whole sequence of tokens is described by the following production rule:
| $\metavar{input}$ | $\Coloneq$ | $\metavar{object}$ |
When the origin of the input sequence of characters is a plain EVLambda source file, the whole sequence of tokens is described by the following production rule:
| $\metavar{input}$ | $\Coloneq$ | $\metavar{object}$* |
When the origin of the input sequence of characters is a documented EVLambda source file, the whole sequence of tokens is described by the following production rule (the XML element is a chapter element):
| $\metavar{input}$ | $\Coloneq$ | $\metavar{xml-comment}$* $\metavar{xml-element}$ $\metavar{xml-comment}$* |
The rest of the context-free grammar, which does not depend on the origin of the input sequence of characters, is defined as follows:
| $\metavar{xml-markup}$ | $\Coloneq$ | $\metavar{xml-element}$ | $\metavar{xml-comment}$ |
| $\metavar{xml-element}$ | $\Coloneq$ | xml-start-tag $\metavar{xml-element-content}$* xml-end-tag | xml-empty-element-tag |
| $\metavar{xml-element-content}$ | $\Coloneq$ | $\metavar{xml-markup}$ | $\metavar{object}$ |
| $\metavar{xml-comment}$ | $\Coloneq$ | xml-comment |
| $\metavar{object}$ | $\Coloneq$ | void | boolean | number | character | string | keyword | variable | $\metavar{abbreviation}$ | $\metavar{list}$ | $\metavar{vector}$ |
| $\metavar{abbreviation}$ | $\Coloneq$ | $\metavar{quotation}$ | $\metavar{quasiquotation}$ | $\metavar{unquotation}$ | $\metavar{splicing-unquotation}$ |
| $\metavar{quotation}$ | $\Coloneq$ | quote $\metavar{xml-markup}$* $\metavar{object}$ |
| $\metavar{quasiquotation}$ | $\Coloneq$ | quasiquote $\metavar{xml-markup}$* $\metavar{object}$ |
| $\metavar{unquotation}$ | $\Coloneq$ | unquote $\metavar{xml-markup}$* $\metavar{object}$ |
| $\metavar{splicing-unquotation}$ | $\Coloneq$ | unquote-splicing $\metavar{xml-markup}$* $\metavar{object}$ |
| $\metavar{list}$ | $\Coloneq$ | $\metavar{proper-list}$ | $\metavar{dotted-list}$ |
| $\metavar{proper-list}$ | $\Coloneq$ | left-parenthesis {$\metavar{xml-markup}$* $\metavar{object}$}* $\metavar{xml-markup}$* right-parenthesis |
| $\metavar{dotted-list}$ | $\Coloneq$ | left-parenthesis {$\metavar{xml-markup}$* $\metavar{object}$}+ $\metavar{xml-markup}$* dot $\metavar{xml-markup}$* $\metavar{object}$ $\metavar{xml-markup}$* right-parenthesis |
| $\metavar{vector}$ | $\Coloneq$ | hash-left-parenthesis {$\metavar{xml-markup}$* $\metavar{object}$}* $\metavar{xml-markup}$* right-parenthesis |
Let us denote by $\mathcal{M}$ the function assigning a meaning to a derivation tree. The function $\mathcal{M}$ is defined by specifying, for each production rule, how the meaning of the nonterminal symbol on the left-hand side is computed from (1) the meanings of the nonterminal symbols on the right-hand side and (2) the terminal symbols on the right-hand side. Here is the definition of the function $\mathcal{M}$, where a pair of square brackets denotes sequence formation and $\|$ denotes sequence concatenation):
$\metavar{object}$$\metavar{object}_1\ldots\metavar{object}_{n\ge0}$$\metavar{cmt}_1\ldots\metavar{cmt}_{n\ge0}$ $\metavar{xml-element}$ $\metavar{cmt}'_1\ldots\metavar{cmt}'_{n'\ge0}$$\metavar{xml-element}$$\metavar{xml-comment}$xml-start-tag $\metavar{xml-element-content}_1\ldots\metavar{xml-element-content}_{n\ge0}$ xml-end-tagxml-empty-element-tag$\metavar{xml-markup}$$\metavar{object}$xml-commentvoidvoidbooleanbooleannumbernumbercharactercharacterstringstringkeywordkeywordvariablevariable$\metavar{abbreviation}$$\metavar{list}$$\metavar{vector}$$\metavar{quotation}$$\metavar{quasiquotation}$$\metavar{unquotation}$$\metavar{splicing-unquotation}$quote $\metavar{object}$quote and whose cdr is a cons whose car is $\mathcal{M}(\metavar{object})$ and whose cdr is the empty listquasiquote $\metavar{object}$quasiquote and whose cdr is a cons whose car is $\mathcal{M}(\metavar{object})$ and whose cdr is the empty listunquote $\metavar{object}$unquote and whose cdr is a cons whose car is $\mathcal{M}(\metavar{object})$ and whose cdr is the empty listunquote-splicing $\metavar{object}$unquote-splicing and whose cdr is a cons whose car is $\mathcal{M}(\metavar{object})$ and whose cdr is the empty list$\metavar{proper-list}$$\metavar{dotted-list}$left-parenthesis right-parenthesisleft-parenthesis $\metavar{object}_1\ldots\metavar{object}_{n\ge1}$ right-parenthesisleft-parenthesis $\metavar{object}_1\ldots\metavar{object}_{n\ge1}$ dot $\metavar{object}_{n+1}$ right-parenthesishash-left-parenthesis $\metavar{object}_1\ldots\metavar{object}_{n\ge0}$ right-parenthesisNote that the XML markup inside abbreviations, lists, and vectors cannot produce objects and has therefore been omitted from the definition of the function $\mathcal{M}$.
The pattern language is a context-free language whose sentences are patterns meant to be matched against objects. The pattern language can be used to specify a set of objects $S$ as follows:
The language specified by a grammar such as $G$ is called a template language. Template languages will be used to specify the forms recognized by the form analyzer, to specify template macro calls, to specify data structures, …
Here are the terminal symbols of the context-free grammar specifying the pattern language:
void, boolean, number, character, string, keyword, and variable.Here are the production rules of the context-free grammar specifying the pattern language:
| $\metavar{pattern}$ | $\Coloneq$ | $\metavar{type}$ | $\metavar{void}$ | $\metavar{boolean}$ | $\metavar{number}$ | $\metavar{character}$ | $\metavar{string}$ | $\metavar{keyword}$ | $\metavar{variable}$ | $\metavar{list}$ | $\metavar{vector}$ |
| $\metavar{type}$ | $\Coloneq$ | $\object$ | $\void$ | $\boolean$ | $\number$ | $\character$ | $\string$ | $symbol$ | $\keyword$ | $\variable$ | $\list$ | $\emptylist$ | $\cons$ | $\vector$ | $\function$ | $\primitivefunction$ | $\closure$ |
| $\metavar{void}$ | $\Coloneq$ | ? any readable representation of an object of type void ? |
| $\metavar{boolean}$ | $\Coloneq$ | ? any readable representation of an object of type boolean ? |
| $\metavar{number}$ | $\Coloneq$ | ? any readable representation of an object of type number ? |
| $\metavar{character}$ | $\Coloneq$ | ? any readable representation of an object of type character ? |
| $\metavar{string}$ | $\Coloneq$ | ? any readable representation of an object of type string ? |
| $\metavar{keyword}$ | $\Coloneq$ | ? any readable representation of an object of type keyword ? |
| $\metavar{variable}$ | $\Coloneq$ | ? any readable representation of an object of type variable ? |
| $\metavar{list}$ | $\Coloneq$ | $\metavar{proper-list}$ | $\metavar{dotted-list}$ |
| $\metavar{proper-list}$ | $\Coloneq$ | ($\metavar{pattern}$*) |
| $\metavar{dotted-list}$ | $\Coloneq$ | ($\metavar{pattern}$+ . $\metavar{pattern}$) |
| $\metavar{vector}$ | $\Coloneq$ | #($\metavar{pattern}$*) |
The rules specifying whether an object matches a pattern are the following:
eql? to the object denoted by the readable representation.() if and only if the object is the empty list.($\metavar{pattern}_1\ldots\metavar{pattern}_{n\ge0}$) if and only if the object is the first cons of a chain of $n$ conses $\cons_1,\ldots,\cons_n$ such that the car of $\cons_i$ matches $\metavar{pattern}_i$, the cdr of $\cons_{i\lt n}$ is $\cons_{i+1}$, and the cdr of $\cons_n$ is the empty list.($\metavar{pattern}_1\ldots\metavar{pattern}_{n\ge1}$ . $\metavar{pattern}_{n+1}$) if and only if the object is the first cons of a chain of $n$ conses $\cons_1,\ldots,\cons_n$ such that the car of $\cons_i$ matches $\metavar{pattern}_i$, the cdr of $\cons_{i\lt n}$ is $\cons_{i+1}$, and the cdr of $\cons_n$ matches $\metavar{pattern}_{n+1}$.#($\metavar{pattern}_1\ldots\metavar{pattern}_{n\ge0}$) if and only if the object is a vector of $n$ elements $\mlvar{elem}_1,\ldots,\mlvar{elem}_n$ such that $\mlvar{elem}_i$ matches $\metavar{pattern}_i$.By way of example, let us consider the template language specified by the following context-free grammar:
| $\metavar{association-list}$ | $\Coloneq$ | ({($\metavar{key}$ . $\metavar{value}$)}*) |
| $\metavar{key}$ | $\Coloneq$ | $\object$ |
| $\metavar{value}$ | $\Coloneq$ | $\object$ |
The sentences of the example template language are the following:
()(($\object$ . $\object$))(($\object$ . $\object$) ($\object$ . $\object$))(($\object$ . $\object$) ($\object$ . $\object$) ($\object$ . $\object$))The objects specified by the example template language (= the objects matching at least one sentence of the example template language) are the proper lists of conses of arbitrary objects. As suggested by the names of the nonterminal symbols, the first object of each cons operates as a key, the second object of each cons operates as a value, and the proper list as a whole is called an association list.
A feature is a symbol associated with a property of the implementation. The feature list is the proper list of features that is the value of the global variable *features*. For each feature, the meanings of the presence of the feature on the feature list and the absence of the feature from the feature list must be specified.
Each evaluator has an associated feature:
| Feature | Meaning |
|---|---|
directstyle | The feature is present on the feature list if and only if the evaluator is an instance of the direct style evaluator. |
cps | The feature is present on the feature list if and only if the evaluator is an instance of the continuation passing style evaluator. |
oocps | The feature is present on the feature list if and only if the evaluator is an instance of the object-oriented CPS evaluator. |
sboocps | The feature is present on the feature list if and only if the evaluator is an instance of the stack-based object-oriented CPS evaluator. |
trampoline | The feature is present on the feature list if and only if the evaluator is an instance of the trampoline evaluator. |
trampolinepp | The feature is present on the feature list if and only if the evaluator is an instance of the trampoline++ evaluator. |
The purpose of the read-time conditionalization facility is to alter the flow of tokens according to whether or not some features belong or do not belong to the feature list. Because the facility is conceptually located between the tokenizer and the parser, its associated syntax does not belong to the context-free grammar used by the parser. It is however convenient to specify the syntax of a read-time conditional by the following production rule:
| $\metavar{read-time-conditional}$ | $\Coloneq$ | {hash-plus | hash-minus} $\metavar{xml-markup}$* $\metavar{object}$ $\metavar{xml-markup}$* $\metavar{object}$ |
The first object is called the feature expression and the second object is called the conditionalized object.
When the facility encounters a hash-plus or a hash-minus token, it instructs the parser to parse, hand over, and discard the feature expression. The feature expression is then evaluated by the facility according to the rules stated below. If the read-time conditional starts with a hash-plus token and the feature expression evaluates to true or the read-time conditional starts with a hash-minus token and the feature expression evaluates to false, then the facility ends its processing of the read-time conditional by instructing the parser to parse and retain the conditionalized object. (The net effect is the same as if only the tokens of the conditionalized object had existed.) If the read-time conditional starts with a hash-plus token and the feature expression evaluates to false or the read-time conditional starts with a hash-minus token and the feature expression evaluates to true, then the facility ends its processing of the read-time conditional by instructing the parser to parse and discard the conditionalized object. (The net effect is the same as if the tokens of the read-time conditional had not existed.)
Feature expressions must belong to the set of objects specified by the template language specified by the following context-free grammar:
| $\metavar{feature-expression}$ | $\Coloneq$ | $\metavar{feature}$ | (not $\metavar{operand}$) | (and $\metavar{operand}$*) | (or $\metavar{operand}$*) |
| $\metavar{feature}$ | $\Coloneq$ | $\symbol$ |
| $\metavar{operand}$ | $\Coloneq$ | $\metavar{feature-expression}$ |
Feature expressions are evaluated as follows:
$\metavar{feature}$(not $\metavar{operand}$)(and $\metavar{operand}_1\ldots\metavar{operand}_{n\ge0}$)(or $\metavar{operand}_1\ldots\metavar{operand}_{n\ge0}$)By way of example, let us consider the following sequence of characters:
(1 . #+foo 2 #-foo 3)
If the feature foo belongs to the feature list, then the sequence of characters is parsed as the dotted list (1 . 2). Otherwise, the sequence of characters is parsed as the dotted list (1 . 3).
A form is any object submitted to the evaluator. A top-level form is a form submitted to the evaluator by an entity other than the evaluator, the IDE for instance. A non-top-level form is a form submitted to the evaluator by the evaluator in the course of the evaluation of a top-level form.
Analyzing a form is the first step in evaluating a form. If a form is not recognized by the form analyzer, then the evaluation of the form completes abruptly for a reason of type error. The forms recognized by the form analyzer are specified by the template language specified by the following context-free grammar ($\metavar{form}$ is a misnomer as any object submitted to the evaluator is a form):
| $\metavar{form}$ | $\Coloneq$ | $\metavar{special-form}$ | $\metavar{macro-call}$ | $\metavar{plain-function-call}$ | $\metavar{self-evaluating-object}$ |
| $\metavar{special-form}$ | $\Coloneq$ | $\metavar{quote-form}$ | $\metavar{progn-form}$ | $\metavar{if-form}$ | $\metavar{\_for-each-form}$ | $\metavar{lambda-abstraction}$ | $\metavar{variable-reference}$ | $\metavar{variable-assignment}$ | $\metavar{block-form}$ | $\metavar{return-from-form}$ | $\metavar{catch-form}$ | $\metavar{throw-form}$ | $\metavar{\_handler-bind-form}$ | $\metavar{unwind-protect-form}$ | $\metavar{apply-form}$ | $\metavar{multiple-value-call-form}$ | $\metavar{multiple-value-apply-form}$ |
| $\metavar{quote-form}$ | $\Coloneq$ | (quote $\metavar{literal}$) |
| $\metavar{literal}$ | $\Coloneq$ | $\object$ |
| $\metavar{progn-form}$ | $\Coloneq$ | (progn $\metavar{serial-form}$*) |
| $\metavar{serial-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{if-form}$ | $\Coloneq$ | (if $\metavar{test-form}$ $\metavar{then-form}$ $\metavar{else-form}$) |
| $\metavar{test-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{then-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{else-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{\_for-each-form}$ | $\Coloneq$ | (_for-each $\metavar{function-form}$ $\metavar{list-form}$) |
| $\metavar{function-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{list-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{lambda-abstraction}$ | $\Coloneq$ | $\metavar{\_vlambda-form}$ | $\metavar{\_mlambda-form}$ | $\metavar{\_flambda-form}$ | $\metavar{\_dlambda-form}$ |
| $\metavar{\_vlambda-form}$ | $\Coloneq$ | (_vlambda $\metavar{parameter-list}$ $\metavar{body}$) |
| $\metavar{\_mlambda-form}$ | $\Coloneq$ | (_mlambda $\metavar{parameter-list}$ $\metavar{body}$) |
| $\metavar{\_flambda-form}$ | $\Coloneq$ | (_flambda $\metavar{parameter-list}$ $\metavar{body}$) |
| $\metavar{\_dlambda-form}$ | $\Coloneq$ | (_dlambda $\metavar{parameter-list}$ $\metavar{body}$) |
| $\metavar{parameter-list}$ | $\Coloneq$ | $\variable$ | ($\variable$*) | ($\variable$+ . $\variable$) |
| $\metavar{body}$ | $\Coloneq$ | $\metavar{serial-form}$* |
| $\metavar{variable-reference}$ | $\Coloneq$ | $\variable$ | $\metavar{vref-form}$ | $\metavar{fref-form}$ | $\metavar{dref-form}$ |
| $\metavar{vref-form}$ | $\Coloneq$ | (vref $\variable$) |
| $\metavar{fref-form}$ | $\Coloneq$ | (fref $\variable$) |
| $\metavar{dref-form}$ | $\Coloneq$ | (dref $\variable$) |
| $\metavar{variable-assignment}$ | $\Coloneq$ | $\metavar{vset-form}$ | $\metavar{fset-form}$ | $\metavar{dset-form}$ |
| $\metavar{vset-form}$ | $\Coloneq$ | (vset! $\variable$ $\metavar{value-form}$) |
| $\metavar{fset-form}$ | $\Coloneq$ | (fset! $\variable$ $\metavar{value-form}$) |
| $\metavar{dset-form}$ | $\Coloneq$ | (dset! $\variable$ $\metavar{value-form}$) |
| $\metavar{value-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{block-form}$ | $\Coloneq$ | (block $\metavar{block-name}$ $\metavar{serial-form}$*) |
| $\metavar{return-from-form}$ | $\Coloneq$ | (return-from $\metavar{block-name}$ $\metavar{values-form}$) |
| $\metavar{catch-form}$ | $\Coloneq$ | (catch $\metavar{exit-tag-form}$ $\metavar{serial-form}$*) |
| $\metavar{throw-form}$ | $\Coloneq$ | (throw $\metavar{exit-tag-form}$ $\metavar{values-form}$) |
| $\metavar{block-name}$ | $\Coloneq$ | $\variable$ |
| $\metavar{exit-tag-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{values-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{\_handler-bind-form}$ | $\Coloneq$ | (_handler-bind $\metavar{handler-form}$ $\metavar{serial-form}$*) |
| $\metavar{handler-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{unwind-protect-form}$ | $\Coloneq$ | (unwind-protect $\metavar{protected-form}$ $\metavar{cleanup-form}$*) |
| $\metavar{protected-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{cleanup-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{apply-form}$ | $\Coloneq$ | (apply $\metavar{operator-form}$ $\metavar{operand-form}$*) |
| $\metavar{multiple-value-call-form}$ | $\Coloneq$ | (multiple-value-call $\metavar{operator-form}$ $\metavar{operand-form}$*) |
| $\metavar{multiple-value-apply-form}$ | $\Coloneq$ | (multiple-value-apply $\metavar{operator-form}$ $\metavar{operand-form}$*) |
| $\metavar{macro-call}$ | $\Coloneq$ | ($\metavar{macro-operator}$ $\metavar{macro-operand}$*) |
| $\metavar{macro-operator}$ | $\Coloneq$ | $\variable$ |
| $\metavar{macro-operand}$ | $\Coloneq$ | $\object$ |
| $\metavar{plain-function-call}$ | $\Coloneq$ | ($\metavar{operator-form}$ $\metavar{operand-form}$*) |
| $\metavar{operator-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{operand-form}$ | $\Coloneq$ | $\metavar{form}$ |
| $\metavar{self-evaluating-object}$ | $\Coloneq$ | $\void$ | $\boolean$ | $\number$ | $\character$ | $\string$ | $\keyword$ | $\vector$ | $\primitivefunction$ | $\closure$ |
The names of the nonterminal symbols are the names that will be used throughout this document to name the forms and their components.
The following production rules introduce additional terminology:
| $\metavar{special-operator}$ | $\Coloneq$ | quote | progn | if | _for-each | _vlambda | _mlambda | _flambda | _dlambda | vref | fref | dref | vset! | fset! | dset! | block | return-from | catch | throw | _handler-bind | unwind-protect | apply | multiple-value-call | multiple-value-apply |
| $\metavar{call}$ | $\Coloneq$ | $\metavar{macro-call}$ | $\metavar{function-call}$ |
| $\metavar{function-call}$ | $\Coloneq$ | $\metavar{plain-function-call}$ | $\metavar{apply-form}$ | $\metavar{multiple-value-call-form}$ | $\metavar{multiple-value-apply-form}$ |
The parameters of a parameter list fall into two categories: the required parameters, of which there can be any number, and the rest parameters, of which there can be zero or one. Here are the required and rest parameters for the different forms of parameter lists:
| Parameter list | Required parameters | Rest parameters |
|---|---|---|
$\var$ | none | $\var$ |
($\var_1\ldots\var_{n\ge0}$) | $\var_1,\ldots,\var_n$ | none |
($\var_1\ldots\var_{n\ge1}$ . $\var_{n+1}$) | $\var_1,\ldots,\var_n$ | $\var_{n+1}$ |
The variables quasiquote, unquote, and unquote-splicing are not special operators. The variable quasiquote is the name of a global macro and the variables unquote and unquote-splicing are variables having special meanings in the context of a call to the global macro quasiquote.
A form consisting of a variable $\variable$ is treated as an abbreviation. If it appears in operator position, then it is treated as an abbreviation for the special form (fref $\variable$). Otherwise, it is treated as an abbreviation for the special form (vref $\variable$).
According to the template language, some objects can simultaneously be a special form, a macro call, and a plain function call. Additional rules are needed to disambiguate the situation.
The following rules used by the form analyzer are not expressed by the template language:
fref is never analyzed as a plain function call.The direct subforms of a form are the direct components of the form that are identified as forms by the form's production rule. Note that the body of a lambda abstraction is not considered to be a direct subform of the lambda abstraction as the evaluation of a lambda abstraction does not entail the evaluation of its body. The subforms of a form are the direct subforms of the form, the direct subforms of the direct subforms of the form, …
A form is said to be in tail position with respect to a lambda abstraction other than a _dlambda form if and only if one of the following conditions is satisfied:
progn form in tail position with respect to the lambda abstraction.if form in tail position with respect to the lambda abstraction.In this section, the character ⇰ marks the places where line breaks have been added to wrap long lines.
Let us consider the following documented EVLambda source file:
<chapter>
<title>Recursive Functions</title>
<p>...para...</p>
<p>...para...</p>
<section>
<title>Factorial Function</title>
<p>...para...</p>
<p>...para...</p>
(fdef fact (n)
<p>...block...</p>
<p>...block...</p>
(if (= n 0)
1 <comment>...eol...</comment>
(* n (fact (- n 1))))) <comment>...eoll...</comment>
(test 1 (fact 0))
(test 120 (fact 5))
(test 3628800 (fact 10))
</section>
<section>
<title>Fibonacci Sequence</title>
<p>...para...</p>
<p>...para...</p>
(fdef fib (n)
<p>...block...</p>
<p>...block...</p>
(if (= n 0)
0 <comment>...eol...</comment>
(if (= n 1)
1 <comment>...eol...</comment>
(+ (fib (- n 1)) (fib (- n 2)))))) <comment>...eoll...</comment>
(test 0 (fib 0))
(test 5 (fib 5))
(test 55 (fib 10))
</section>
</chapter>
The first step of the documentation generation process converts the documented EVLambda source file into the following XML document:
<chapter>
<title>Recursive Functions</title>
<p>...para...</p>
<p>...para...</p>
<section>
<title>Factorial Function</title>
<p>...para...</p>
<p>...para...</p>
<toplevelcode><blockcode>(fdef fact (n)⇰
</blockcode><indentation style="margin-left: 2ch;"><blockcomment>
<p>...block...</p>
<p>...block...</p></blockcomment></indentation><blockcode>
(if (= n 0)
1 <comment>...eol...</comment>
(* n (fact (- n 1))))) ⇰
<comment>...eoll...</comment></blockcode></toplevelcode>
<toplevelcode><blockcode>(test 1 (fact 0))
(test 120 (fact 5))
(test 3628800 (fact 10))</blockcode></toplevelcode>
</section>
<section>
<title>Fibonacci Sequence</title>
<p>...para...</p>
<p>...para...</p>
<toplevelcode><blockcode>(fdef fib (n)⇰
</blockcode><indentation style="margin-left: 2ch;"><blockcomment>
<p>...block...</p>
<p>...block...</p></blockcomment></indentation><blockcode>
(if (= n 0)
0 <comment>...eol...</comment>
(if (= n 1)
1 <comment>...eol...</comment>
(+ (fib (- n 1)) (fib (- n 2)))))) ⇰
<comment>...eoll...</comment></blockcode></toplevelcode>
<toplevelcode><blockcode>(test 0 (fib 0))
(test 5 (fib 5))
(test 55 (fib 10))</blockcode></toplevelcode>
</section>
</chapter>
Here are a few remarks about the XML document:
toplevelcode elements.toplevelcode element.toplevelcode element is segmented into a sequence of blockcode elements, which contain code and end-of-line/end-of-last-line comments, and blockcomment elements, which contain block comments.blockcomment element is wrapped into an indentation element that specifies its indentation through the CSS property margin-left.The second step of the documentation generation process converts the XML document into the following HTML document:
<html>
<head>
</head>
<body>
<h1>Recursive Functions</h1>
<p>...para...</p>
<p>...para...</p>
<h2>Factorial Function</h2>
<p>...para...</p>
<p>...para...</p>
<pre class="blockcode">(fdef fact (n)</pre>
<div class="indentation" style="margin-left: 2ch;">
<div class="blockcomment">
<p>...block...</p>
<p>...block...</p>
</div>
</div>
<pre class="blockcode">
(if (= n 0)
1 <span class="eolcomment">...eol...</span>
(* n (fact (- n 1))))) ⇰
<span class="eolcomment">...eoll...</span></pre>
<pre class="blockcode">(test 1 (fact 0))
(test 120 (fact 5))
(test 3628800 (fact 10))</pre>
<h2>Fibonacci Sequence</h2>
<p>...para...</p>
<p>...para...</p>
<pre class="blockcode">(fdef fib (n)</pre>
<div class="indentation" style="margin-left: 2ch;">
<div class="blockcomment">
<p>...block...</p>
<p>...block...</p>
</div>
</div>
<pre class="blockcode">
(if (= n 0)
0 <span class="eolcomment">...eol...</span>
(if (= n 1)
1 <span class="eolcomment">...eol...</span>
(+ (fib (- n 1)) (fib (- n 2)))))) ⇰
<span class="eolcomment">...eoll...</span></pre>
<pre class="blockcode">(test 0 (fib 0))
(test 5 (fib 5))
(test 55 (fib 10))</pre>
</body>
</html>
This section inventories all the primitive data types and all the primitive functions.
Here is a tree-view representation of the hierarchy of primitive data types:
object
|-void
|-boolean
|-number
|-character
|-string
|-symbol
| |-keyword
| |-variable
|-list
| |-empty-list
| |-cons
|-vector
|-function
| |-primitive-function
| |-closure
object and Related Primitive Functions(object? $\object$) ⇒ $\boolean$#t if $\object$ is of type object (which is always the case) and #f otherwise.(eq? $\object_1$ $\object_2$) ⇒ $\boolean$#t if and only if the two objects are one and the same. In other words, the function returns #t if and only if the two objects have the same address in the heap.(eql? $\object_1$ $\object_2$) ⇒ $\boolean$number, then the function returns #t if and only if the two objects represent the same mathematical number. Otherwise, if both objects are of type character, then the function returns #t if and only if the two objects represent the same UTF-$16$ code unit. Otherwise, if both objects are of type string, then the function returns #t if and only if the two objects represent the same indexed sequence of UTF-$16$ code units. Otherwise, the function returns #t if and only if the two objects are eq?.void and Related Primitive Functions(void? $\object$) ⇒ $\boolean$#t if $\object$ is of type void and #f otherwise.boolean and Related Primitive Functions(boolean? $\object$) ⇒ $\boolean$#t if $\object$ is of type boolean and #f otherwise.number and Related Primitive FunctionsObjects of type number represent mathematical numbers using the floating-point format IEEE 754 binary 64. Some (but not all) of the integers that can be represented exactly by an object of type number are the integers between $-2^{53}=−9,007,199,254,740,992$ and $2^{53}=9,007,199,254,740,992$ (bounds included).
(number? $\object$) ⇒ $\boolean$#t if $\object$ is of type number and #f otherwise.(_+ $\number_1$ $\number_2$) ⇒ $\number$(_- $\number_1$ $\number_2$) ⇒ $\number$(_* $\number_1$ $\number_2$) ⇒ $\number$(_/ $\number_1$ $\number_2$) ⇒ $\number$(% $\number_1$ $\number_2$) ⇒ $\number$(= $\number_1$ $\number_2$) ⇒ $\boolean$#t if $\number_1$ and $\number_2$ are numerically equal and #f otherwise.(/= $\number_1$ $\number_2$) ⇒ $\boolean$#t if $\number_1$ and $\number_2$ are numerically different and #f otherwise.(< $\number_1$ $\number_2$) ⇒ $\boolean$#t if $\number_1$ is numerically less than $\number_2$ and #f otherwise.(<= $\number_1$ $\number_2$) ⇒ $\boolean$#t if $\number_1$ is numerically less than or equal to $\number_2$ and #f otherwise.(> $\number_1$ $\number_2$) ⇒ $\boolean$#t if $\number_1$ is numerically greater than $\number_2$ and #f otherwise.(>= $\number_1$ $\number_2$) ⇒ $\boolean$#t if $\number_1$ is numerically greater than or equal to $\number_2$ and #f otherwise.The functions _+, _-, _*, and _/ have an underscore at the beginning of their names to distinguish them from the similarly named nonprimitive functions +, -, *, and /, which all accept a variable number of arguments.
character and Related Primitive FunctionsContrary to what was said in the user manual, an object of type character represents a UTF-$16$ code unit (instead of a Unicode character).
(character? $\object$) ⇒ $\boolean$#t if $\object$ is of type character and #f otherwise.string and Related Primitive FunctionsContrary to what was said in the user manual, an object of type string represents an indexed sequence of UTF-$16$ code units (instead of an indexed sequence of Unicode characters).
(string? $\object$) ⇒ $\boolean$#t if $\object$ is of type string and #f otherwise.symbol and Related Primitive Functions(symbol? $\object$) ⇒ $\boolean$#t if $\object$ is of type symbol and #f otherwise.keyword and Related Primitive Functions(keyword? $\object$) ⇒ $\boolean$#t if $\object$ is of type keyword and #f otherwise.(make-keyword? $\string$) ⇒ $\keyword$variable and Related Primitive Functions(variable? $\object$) ⇒ $\boolean$#t if $\object$ is of type variable and #f otherwise.(make-variable $\string$) ⇒ $\variable$(variable-value $\variable$) ⇒ $\object$#v.(variable-set-value! $\variable$ $\object$) ⇒ $\object$(variable-value-bound? $\variable$) ⇒ $\boolean$#t. Otherwise, the function returns #f.(variable-unbind-value! $\variable$) ⇒ #v#v. Otherwise, the function simply returns #v.(variable-function $\variable$) ⇒ $\object$#v.(variable-set-function! $\variable$ $\object$) ⇒ $\object$(variable-function-bound? $\variable$) ⇒ $\boolean$#t. Otherwise, the function returns #f.(variable-unbind-function! $\variable$) ⇒ #v#v. Otherwise, the function simply returns #v.A property list is an association between keys (usually of type keyword) and values (of any type). Each variable has an associated property list. The keys must be of type keyword and the values are accessed through the following primitive functions:
(variable-plist-ref $\variable$ $\keyword$) ⇒ $\object$#v.(variable-plist-set! $\variable$ $\keyword$ $\object$) ⇒ $\object$(variable-plist-bound? $\variable$ $\keyword$) ⇒ $\boolean$#t. Otherwise, the function returns #f.(variable-plist-unbind! $\variable$ $\keyword$) ⇒ #v#v. Otherwise, the function simply returns #v.list and Related Primitive Functions(list? $\object$) ⇒ $\boolean$#t if $\object$ is of type list and #f otherwise.(_make-list $\number$) ⇒ $\list$error. Otherwise, the function returns a new list of length $\number$ whose elements are all #v. The function exists mainly for testing purposes.empty-list and Related Primitive Functions(empty-list? $\object$) ⇒ $\boolean$#t if $\object$ is of type empty-list and #f otherwise.cons and Related Primitive Functions(cons? $\object$) ⇒ $\boolean$#t if $\object$ is of type cons and #f otherwise.(cons $\object_1$ $\object_2$) ⇒ $\cons$(car $\cons$) ⇒ $\object$(set-car! $\cons$ $\object$) ⇒ $\object$(cdr $\cons$) ⇒ $\object$(set-cdr! $\cons$ $\object$) ⇒ $\object$vector and Related Primitive FunctionsA vector is an association between indexes (nonnegative integers between zero and the length of the vector minus one) and values of arbitrary types. Not all indexes need to have an associated value. Vectors with missing values have no readable representations. In printable representations, indexes with no associated value appear to be associated with the value #v.
(vector? $\object$) ⇒ $\boolean$#t if $\object$ is of type vector and #f otherwise.(make-vector $\number$ $\object$) ⇒ $\vector$error. Otherwise, the function returns a new vector of length $\number$. The argument $\object$ is optional. If $\object$ is not provided, then the indexes are all with no associated value. If $\object$ is provided, then the indexes are all associated with the value $\object$.(vector-length $\vector$) ⇒ $\number$(vector-ref $\vector$ $\number$) ⇒ $\object$error. Otherwise, if there exists an association between $\number$ and a value, then the function returns that value. Otherwise, the function returns #v.(vector-set! $\vector$ $\number$ $\object$) ⇒ $\object$error. Otherwise, if there exists an association between $\number$ and a value, then that value is replaced by $\object$ and the function returns $\object$. Otherwise, an association between $\number$ and $\object$ is created and the function returns $\object$.(vector-bound? $\vector$ $\number$) ⇒ $\boolean$error. Otherwise, if there exists an association between $\number$ and a value, then the function returns #t. Otherwise, the function returns #f.(vector-unbind! $\vector$ $\number$) ⇒ #verror. Otherwise, if there exists an association between $\number$ and a value, then that association is deleted and the function returns #v. Otherwise, the function simply returns #v.function and Related Primitive Functions(function? $\object$) ⇒ $\boolean$#t if $\object$ is of type function and #f otherwise.primitive-function and Related Primitive Functions(primitive-function? $\object$) ⇒ $\boolean$#t if $\object$ is of type primitive-function and #f otherwise.closure and Related Primitive Functions(closure? $\object$) ⇒ $\boolean$#t if $\object$ is of type closure and #f otherwise.(values $\object_1\ldots\object_n$) ⇒ $\object_1,\ldots,\object_n$(error $\string$) ⇒ completes abruptly for a reason of type errorerror carrying the category "Error" and the description $\string$.(now) ⇒ $\number$This section supplements and amends the evaluation rules stated in the user manual.
_for-eachThe special form _for-each is evaluated as follows:
(_for-each $\metavar{function-form}$ $\metavar{list-form}$)_for-each form completes abruptly for a reason of type error. Otherwise, the list form is evaluated. Let $\mlvar{list}$ be the primary value of the list form. If $\mlvar{list}$ is not a proper list, then the evaluation of the _for-each form completes abruptly for a reason of type error. Otherwise, the function $\mlvar{function}$ is invoked in sequence on each element of the list $\mlvar{list}$, from the first element to the last element. If any invocation completes abruptly for any reason or does not complete, then the following invocations do not happen and the evaluation of the _for-each form also completes abruptly for the same reason or does not complete either. Otherwise, the _for-each form evaluates to #v.The two pairs of special forms block/return-from and catch/throw use two additional namespaces: the block namespace, which is only found in lexical environments, and the exit-point namespace, which is only found in dynamic environments.
block/return-fromThe special forms block and return-from are evaluated as follows:
(block $\metavar{block-name}$ $\metavar{serial-form}$*)#v (the value is unimportant). If the evaluation of any serial form completes abruptly for any reason, then the following serial forms are not evaluated and the evaluation of the block form proceeds as follows:
Let $\mlvar{reason}$ be the reason for the abrupt completion of the serial form. If $\mlvar{reason}$ is of typeOtherwise, the evaluations of the serial forms all complete normally and the evaluation of thenonlocal-exitand carries an exit tageq?to $\mlvar{exit-tag}$, then the evaluation of theblockform completes normally and produces the values carried by $\mlvar{reason}$. Otherwise, the evaluation of theblockform completes abruptly for the reason $\mlvar{reason}$.
block form completes normally and produces the values of the last serial form or #v if there are no serial forms.(return-from $\metavar{block-name}$ $\metavar{values-form}$)return-from form completes abruptly for a reason of type error. Otherwise, let $\mlvar{exit-tag}$ be the value of the binding for the variable $\metavar{block-name}$ in the block namespace of the current lexical environment. If there exists no binding for the variable $\mlvar{exit-tag}$ in the exit-point namespace of the current dynamic environment, then the evaluation of the return-from form completes abruptly for a reason of type error. Otherwise, the values form is evaluated. If the evaluation of the values form completes abruptly for any reason, then the evaluation of the return-from form completes abruptly for the same reason. Otherwise, the evaluation of the return-from form completes abruptly for a reason of type nonlocal-exit carrying $\mlvar{exit-tag}$ and the values of the values form.catch/throwThe special forms catch and throw are evaluated as follows:
(catch $\metavar{exit-tag-form}$ $\metavar{serial-form}$*)catch form completes abruptly for the same reason. Otherwise, let $\mlvar{exit-tag}$ be the primary value of the exit-tag form. If $\mlvar{exit-tag}$ is not a variable, then the evaluation of the catch form completes abruptly for a reason of type error. Otherwise, the serial forms are evaluated in sequence from left to right with respect to (1) the current lexical environment and (2) the environment extending the current dynamic environment to bind, in the exit-point namespace, the variable $\mlvar{exit-tag}$ to #v (the value is unimportant). If the evaluation of any serial form completes abruptly for any reason, then the following serial forms are not evaluated and the evaluation of the catch form proceeds as follows:
Let $\mlvar{reason}$ be the reason for the abrupt completion of the serial form. If $\mlvar{reason}$ is of typeOtherwise, the evaluations of the serial forms all complete normally and the evaluation of thenonlocal-exitand carries an exit tageq?to $\mlvar{exit-tag}$, then the evaluation of thecatchform completes normally and produces the values carried by $\mlvar{reason}$. Otherwise, the evaluation of thecatchform completes abruptly for the reason $\mlvar{reason}$.
catch form completes normally and produces the values of the last serial form or #v if there are no serial forms.(throw $\metavar{exit-tag-form}$ $\metavar{values-form}$)throw form completes abruptly for the same reason. Otherwise, let $\mlvar{exit-tag}$ be the primary value of the exit-tag form. If $\mlvar{exit-tag}$ is not a variable, then the evaluation of the throw form completes abruptly for a reason of type error. Otherwise, if there exists no binding for the variable $\mlvar{exit-tag}$ in the exit-point namespace of the current dynamic environment, then the evaluation of the throw form completes abruptly for a reason of type error. Otherwise, the values form is evaluated. If the evaluation of the values form completes abruptly for any reason, then the evaluation of the throw form completes abruptly for the same reason. Otherwise, the evaluation of the throw form completes abruptly for a reason of type nonlocal-exit carrying $\mlvar{exit-tag}$ and the values of the values form._handler-bindThe special form _handler-bind is evaluated as follows:
(_handler-bind $\metavar{handler-form}$ $\metavar{serial-form}$*)_handler-bind form completes abruptly for the same reason. Otherwise, let $\mlvar{handler}$ be the primary value of the handler form. If $\mlvar{handler}$ is not a function, then the evaluation of the _handler-bind form completes abruptly for a reason of type error. Otherwise, the serial forms are evaluated in sequence from left to right. If the evaluation of any serial form completes abruptly for any reason, then the following serial forms are not evaluated and the evaluation of the _handler-bind form proceeds as follows:
Let $\mlvar{reason}$ be the reason for the abrupt completion of the serial form. If $\mlvar{reason}$ is of typeOtherwise, the evaluations of the serial forms all complete normally and the evaluation of thenonlocal-exit, then the evaluation of the_handler-bindform completes abruptly for the reason $\mlvar{reason}$. Otherwise, $\mlvar{reason}$ is necessarily of typeerrorand $\mlvar{handler}$ is invoked on the category and description carried by $\mlvar{reason}$. If the invocation completes abruptly for any reason, then the evaluation of the_handler-bindform also completes abruptly for the same reason. Otherwise, if the invocation does not complete, then the evaluation of the_handler-bindform does not complete either. Otherwise, the evaluation of the_handler-bindform completes abruptly for the reason $\mlvar{reason}$.
_handler-bind form completes normally and produces the values of the last serial form or #v if there are no serial forms.unwind-protectThe special form unwind-protect is evaluated as follows:
(unwind-protect $\metavar{protected-form}$ $\metavar{cleanup-form}$*)unwind-protect form proceeds as follows:
Let $\mlvar{reason}$ be the reason for the abrupt completion of the protected form. The cleanup forms are evaluated in sequence from left to right. If the evaluation of any cleanup form completes abruptly for any reason, then the following cleanup forms are not evaluated and the evaluation of theOtherwise, the evaluation of the protected form completes normally and the evaluation of theunwind-protectform completes abruptly for the same reason. Otherwise, the evaluations of the cleanup forms all complete normally and the evaluation of theunwind-protectform completes abruptly for the reason $\mlvar{reason}$.
unwind-protect form proceeds as follows:
The cleanup forms are evaluated in sequence from left to right. If the evaluation of any cleanup form completes abruptly for any reason, then the following cleanup forms are not evaluated and the evaluation of theunwind-protectform completes abruptly for the same reason. Otherwise, the evaluations of the cleanup forms all complete normally and the evaluation of theunwind-protectform completes normally and produces the values of the protected form.
A spreadable sequence of objects is a nonempty sequence of objects such that the last element of the sequence is a proper list of objects. Let $\mlvar{seq}=[\obj_1,\ldots,\obj_n,\code{(}\obj'_1\ldots\obj'_m\code{)}]$, where $n$ and $m$ are nonnegative integers, be a spreadable sequence of objects. We will denote by $\spread(\mlvar{seq})$ the sequence of objects $[\obj_1,\ldots,\obj_n,\obj'_1,\ldots,\obj'_m]$.
The function calls are evaluated as follows (the differences in behavior between the different types of function calls are highlighted with a gray background):
($\metavar{operator-form}$ $\metavar{operand-forms}$)error. Otherwise, the operand forms are evaluated in sequence from left to right, the primary values of the operand forms are collected into a sequence $\mlvar{seq}$, and $\mlvar{operator}$ is invoked on $\mlvar{seq}$. If the invocation completes abruptly for any reason, then the evaluation of the plain function call also completes abruptly for the same reason. Otherwise, if the invocation does not complete, then the evaluation of the plain function call does not complete either. Otherwise, the plain function call evaluates to the values of the invocation. (The behavior described here is identical to the behavior described in the user manual.)(apply $\metavar{operator-form}$ $\metavar{operand-forms}$)apply form completes abruptly for a reason of type error. Otherwise, the operand forms are evaluated in sequence from left to right, the primary values of the operand forms are collected into a sequence $\mlvar{seq}$, and $\mlvar{operator}$ is invoked on $\spread(\mlvar{seq})$. (The evaluation of the apply form completes abruptly for a reason of type error if $\mlvar{seq}$ is not a spreadable sequence of objects.) If the invocation completes abruptly for any reason, then the evaluation of the apply form also completes abruptly for the same reason. Otherwise, if the invocation does not complete, then the evaluation of the apply form does not complete either. Otherwise, the apply form evaluates to the values of the invocation.(multiple-value-call $\metavar{operator-form}$ $\metavar{operand-forms}$)multiple-value-call form completes abruptly for a reason of type error. Otherwise, the operand forms are evaluated in sequence from left to right, all the values of the operand forms are collected into a sequence $\mlvar{seq}$, and $\mlvar{operator}$ is invoked on the sequence $\mlvar{seq}$. If the invocation completes abruptly for any reason, then the evaluation of the multiple-value-call form also completes abruptly for the same reason. Otherwise, if the invocation does not complete, then the evaluation of the multiple-value-call form does not complete either. Otherwise, the multiple-value-call form evaluates to the values of the invocation.(multiple-value-apply $\metavar{operator-form}$ $\metavar{operand-forms}$)multiple-value-apply form completes abruptly for a reason of type error. Otherwise, the operand forms are evaluated in sequence from left to right, all the values of the operand forms are collected into a sequence $\mlvar{seq}$, and $\mlvar{operator}$ is invoked on $\spread(\mlvar{seq})$. (The evaluation of the multiple-value-apply form completes abruptly for a reason of type error if $\mlvar{seq}$ is not a spreadable sequence of objects.) If the invocation completes abruptly for any reason, then the evaluation of the multiple-value-apply form also completes abruptly for the same reason. Otherwise, if the invocation does not complete, then the evaluation of the multiple-value-apply form does not complete either. Otherwise, the multiple-value-apply form evaluates to the values of the invocation.A primitive function is invoked as described in the user manual. A closure is invoked as described in the user manual except for the way the parameters are paired with the arguments in order to extend the value namespace of the lexical environment captured by the closure (when the corresponding lambda abstraction is a _vlambda form or an _mlambda form), the function namespace of the lexical environment captured by the closure (when the corresponding lambda abstraction is an _flambda form), or the value namespace of the current dynamic environment (when the corresponding lambda abstraction is a _dlambda form). Let $var_1,\ldots,\var_n$ be the required parameters and $\arg_1,\ldots,\arg_m$ be the arguments. The way the parameters are paired with the arguments depends on the absence or presence of a rest parameter:
error. Otherwise, the appropriate namespace of the appropriate environment is extended to bind $\var_i$ to $\arg_i$ for all $i$ from $1$ to $n$. (This is the behavior described in the user manual.)error. Otherwise, the appropriate namespace of the appropriate environment is extended to bind $\var_i$ to $\arg_i$ for all $i$ from $1$ to $n$ and $\var_{n+1}$ to a proper list whose elements are $\arg_{n+1},\ldots,arg_{m}$. The conses used to build the proper list are not necessarily new conses. When the function call is an apply form or a multiple-value-apply form, the proper list and the last element of the spreadable sequence of objects can share conses.Here are some examples, where the bindings are assumed to belong to the value namespace:
| Parameter list | Arguments | Bindings |
|---|---|---|
(a b) | $[\code{1},\code{2},\code{3}]$ | N/A (error: too many arguments) |
(a b c) | $[\code{1},\code{2},\code{3}]$ | $[\vbinding{a}{1},\vbinding{b}{2},\vbinding{c}{3}]$ |
(a b c d) | $[\code{1},\code{2},\code{3}]$ | N/A (error: too few arguments) |
a | $[\code{1},\code{2},\code{3}]$ | $[\vbinding{a}{(1 2 3)}]$ |
(a . b) | $[\code{1},\code{2},\code{3}]$ | $[\vbinding{a}{1},\vbinding{b}{(2 3)}]$ |
(a b . c) | $[\code{1},\code{2},\code{3}]$ | $[\vbinding{a}{1},\vbinding{b}{2},\vbinding{c}{(3)}]$ |
(a b c . d) | $[\code{1},\code{2},\code{3}]$ | $[\vbinding{a}{1},\vbinding{b}{2},\vbinding{c}{3},\vbinding{d}{()}]$ |
(a b c d . e) | $[\code{1},\code{2},\code{3}]$ | N/A (error: too few arguments) |
Here is one way to reproduce the preceding examples using plain function calls and _vlambda forms:
> ((_vlambda (a b) (list a b)) 1 2 3)
EvaluatorError: too-many-arguments: Too many arguments.
> ((_vlambda (a b c) (list a b c)) 1 2 3)
(1 2 3)
> ((_vlambda (a b c d) (list a b c d)) 1 2 3)
EvaluatorError: too-few-arguments: Too few arguments.
> ((_vlambda a (list a)) 1 2 3)
((1 2 3))
> ((_vlambda (a . b) (list a b)) 1 2 3)
(1 (2 3))
> ((_vlambda (a b . c) (list a b c)) 1 2 3)
(1 2 (3))
> ((_vlambda (a b c . d) (list a b c d)) 1 2 3)
(1 2 3 ())
> ((_vlambda (a b c d . e) (list a b c d e)) 1 2 3)
EvaluatorError: too-few-arguments: Too few arguments.
Elementary continuations:
Auxiliary functions:
(quote $\mlvar{literal}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(progn $\mlvar{serial-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:#v. Otherwise, invoke the auxiliary function $\evalserialformforms$ on $\mlvar{serial-forms}$, $\lexenv$, $\dynenv$, and $k$.(if $\mlvar{test-form}$ $\mlvar{then-form}$ $\mlvar{else-form}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error. If $\mlvar{test}$ is the boolean #t, then evaluate $\mlvar{then-form}$ with respect to $\lexenv$, $\dynenv$, and $k$. If $\mlvar{test}$ is the boolean #f, then evaluate $\mlvar{else-form}$ with respect to $\lexenv$, $\dynenv$, and $k$.(_for-each $\mlvar{function-form}$ $\mlvar{list-form}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error. Otherwise, evaluate $\mlvar{list-form}$ with respect to $\lexenv$, $\dynenv$, and a $\foreachlistform$ continuation capturing $\mlvar{function}$, $\dynenv$, and $k$.error. Otherwise, invoke the auxiliary function $\foreach$ on $\mlvar{function}$, $\mlvar{list}$, $\dynenv$, and $k$.#v. Otherwise, invoke the auxiliary function $\invoke$ on $\mlvar{function}$, the car of $\mlvar{list}$, $\dynenv$, and a $\foreachinvocation$ continuation capturing $\mlvar{function}$, $\mlvar{list}$, $\dynenv$, and $k$.(_vlambda $\mlvar{parameter-list}$ $\mlvar{body}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(_mlambda $\mlvar{parameter-list}$ $\mlvar{body}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(_flambda $\mlvar{parameter-list}$ $\mlvar{body}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(_dlambda $\mlvar{parameter-list}$ $\mlvar{body}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(vref $\mlvar{variable}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(fref $\mlvar{variable}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(dref $\mlvar{variable}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error.(vset! $\mlvar{variable}$ $\mlvar{value-form}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(fset! $\mlvar{variable}$ $\mlvar{value-form}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(dset! $\mlvar{variable}$ $\mlvar{value-form}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(block $\mlvar{block-name}$ $\mlvar{serial-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:#v, and a $\blockserialforms$ continuation capturing $\mlvar{exit-tag}$ and $k$.nonlocal-exit carrying an exit tag eq? to $\mlvar{exit-tag}$, then invoke $k$ on the values carried by $\outcome$. Otherwise, invoke $k$ on $\outcome$.(return-from $\mlvar{block-name}$ $\mlvar{values-form}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error. Otherwise, let $\mlvar{exit-tag}$ be the value of the binding for the variable $\mlvar{block-name}$ in the block namespace of $\lexenv$. If there exists no binding for the variable $\mlvar{exit-tag}$ in the exit-point namespace of $\dynenv$, then invoke $k$ on an abrupt completion reason of type error. Otherwise, evaluate $\mlvar{values-form}$ with respect to $\lexenv$, $\dynenv$, and a $\returnfromvaluesform$ continuation capturing $\mlvar{exit-tag}$ and $k$.nonlocal-exit carrying $\mlvar{exit-tag}$ and $\outcome$.(catch $\mlvar{exit-tag-form}$ $\mlvar{serial-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error. Otherwise, invoke the auxiliary function $\evalserialforms$ on $\mlvar{serial-forms}$, $\lexenv$, the environment extending $\dynenv$ to bind, in the exit-point namespace, the variable $\mlvar{exit-tag}$ to #v, and a $\catchserialforms$ continuation capturing $\mlvar{exit-tag}$ and $k$.nonlocal-exit carrying an exit tag eq? to $\mlvar{exit-tag}$, then invoke $k$ on the values carried by $\outcome$. Otherwise, invoke $k$ on $\outcome$.(throw $\mlvar{exit-tag-form}$ $\mlvar{values-form}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error. Otherwise, if there exists no binding for the variable $\mlvar{exit-tag}$ in the exit-point namespace of $\dynenv$, then invoke $k$ on an abrupt completion reason of type error. Otherwise, evaluate $\mlvar{values-form}$ with respect to $\lexenv$, $\dynenv$, and a $\throwvaluesform$ continuation capturing $\mlvar{exit-tag}$ and $k$.nonlocal-exit carrying $\mlvar{exit-tag}$ and $\outcome$.(_handler-bind $\mlvar{handler-form}$ $\mlvar{serial-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error. Otherwise, invoke the auxiliary function $\evalserialforms$ on $\mlvar{serial-forms}$, $\lexenv$, $\dynenv$, and a $\handlerbindserialforms$ continuation capturing $\mlvar{handler}$, $\dynenv$, and $k$.error, then invoke the auxiliary function $\invoke$ on $\mlvar{handler}$, the category and description carried by $\outcome$, $\dynenv$, and a $\handlerbindinvocation$ continuation capturing $\mlvar{outcome}$ and $k$. Otherwise, invoke $k$ on $\outcome$.(unwind-protect $\mlvar{protected-form}$ $\mlvar{cleanup-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:($\mlvar{operator-form}$ $\mlvar{operand-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(apply $\mlvar{operator-form}$ $\mlvar{operand-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(multiple-value-call $\mlvar{operator-form}$ $\mlvar{operand-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:(multiple-value-apply $\mlvar{operator-form}$ $\mlvar{operand-forms}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following:error. Otherwise, invoke the auxiliary function $\evaloperandforms$ on $\mlvar{function}$, $\mlvar{operand-forms}$, $[]$, $\lexenv$, $\dynenv$, and $k$.($\mlvar{macro-operator}$ $\mlvar{macro-operands}$) with respect to $\lexenv$, $\dynenv$, and $k$, do the following: