ref: 530f3242a5795d0f25d7fe5c82fd112893c9ec09
parent: c7c8af3159b3798bbb5682af8278dba388f5adfb
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Apr 17 16:13:19 EDT 2025
T, NIL, eof-object, #<void>: use its own tag; change isfn(..) to return true for any kind of function
--- a/boot/sl.boot
+++ b/boot/sl.boot
@@ -11,7 +11,7 @@
#fn("z0700}2:" #(div0)) #fn("z0700}2:" #(=))
#fn("n201m:") NIL #fn("z0700}2:" #(vec))
#fn("z0700}2:" #(aset!)) NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL #fn("n3012082>1|:" #(#fn("n1A061:")))
- NIL NIL NIL NIL NIL NIL NIL NIL #fn("z0700}2:" #(aref)) NIL NIL NIL)
+ NIL NIL NIL NIL NIL NIL NIL NIL #fn("z0700}2:" #(aref)) NIL NIL)
*properties* #table(*formals-list* #table(identity ((x)) bound? ((symbol)) sym-set-doc ((symbol
doc-seq . formals-list)) io-eof? ((io)) < ((a . rest)) cadr ((cell)) sym (term) nan? ((v)) for ((min
max fn)) fixnum? ((v)) exit (((status NIL))) > ((a . rest)) + (rest) div0 ((a b)) __finish ((status)) lz-unpack ((data
@@ -30,24 +30,25 @@
(doc NIL))) set-cdr! ((cell new-second)) fn? ((v)) help-print-header ((term sigs (:kind NIL)
(:lpad ""))) lz-pack ((data
(level 0))) *prompt* (NIL) eq? ((a b)) getprop ((symbol key (def NIL))) vm-stats (NIL) * (rest) putprop ((symbol
- key val)) io->str ((io))) *doc* #table(identity "Return `x`." (doc group vm) "VM-related functions." bound? "Return `T` if `symbol` has a value associated with it, `NIL` otherwise." sym-set-doc "Set the documentation for the symbol." io-eof? "Return `T` if `io` is currently in the \"end of file\" state, `NIL`\notherwise." < "Return `T` if the arguments are in strictly increasing order (next\none is greater than the previous one). With a single argument\nthe result is always `T`." cadr "Shorthand for `(car (cdr cell))`, that is, _first element of the\nsecond element_.\n\nExamples:\n\n (cadr '(1 2 3)) → 2\n (cadr '(1)) → NIL\n (cadr NIL) → NIL" nan? "Return `T` if `v` is a floating point representation of NaN, either\nnegative or positive, `NIL` otherwise." for "Call the function `fn` with a single integer argument, starting from\n`min` and ending with `max`.\n\nExamples:\n\n (for 0 2 (λ (i) (print (- 2 i)))) → 210" fixnum? "Return `T` if `v` is of a fixnum type, `NIL` otherwise." exit "Terminate the process with the specified status. Does not return.\nThe status is expected to be a string in case of an error.\n\nExamples:\n\n (exit) ; exit with status 0 (nil on Plan 9)\n (exit \"error\") ; exit with status 1 (\"error\" on Plan 9)" (doc
- group compare) "Comparison operators." (doc group compress) "Compression." + "Return sum of the arguments or `0` when none specified." (doc
- group builtin) "Built-in operators." div0 "Return the quotient of two numbers. For non-integers this is\nequivalent to `(div0 (floor a) (floor b))`. The result is always an\ninteger.\n\nExamples:\n\n (div0 7 2) → 3\n (div0 10 -2) → -5\n (div0 6.9 1.9) → 6" lz-unpack "Return decompressed data previously compressed using lz-pack.\n\nEither destination for the decompressed data or the expected size of\nthe decompressed data must be specified. In the latter case a new\narray is allocated." > "Return `T` if the arguments are in strictly decreasing order (previous\none is greater than the next one)." __finish "A function called right before exit by the VM." defstruct "Defines a structure type with a specific name and slots.\n\nThe default underlying type is a \"named\" vector (`:type vec`), where\nthe first element is the name of the structure's type, the rest are\nthe keyworded slot values. A list with slot values alone can be used\ninstead by adding `:type list` option. The list will not contain the\nname of the struct by default, which can be enabled with `:named T`\noption.\n\nAs an example, the following declaration\n\n (defstruct blah \"Return stuff.\" :doc-group stuff a b (c 1))\n\nGenerates the default constructor definition and accessors:\n\n (make-blah (:a NIL) (:b NIL) (:c 1))\n (blah-a s)\n (blah-b s)\n (blah-c s)\n\nThe constructor can be changed in several ways:\n\n ; disable the constructor altogether\n (defstruct blah :constructor NIL a b c)\n ; only change its name\n (defstruct blah :constructor blargh a b c)\n ; rename AND avoid using keywords\n (defstruct blah :constructor (blah a b c) a b c)\n\nThe option `:conc-name` specifies the slot accessor prefix, which\ndefaults to `structname-`. Prefix can be disabled entirely with\n`:conc-name NIL`.\n\nDefault predicate can be disabled or its name, which defaults to\n`structname?`, changed:\n\n ; use \"blargh?\" instead of \"blah?\"\n (defstruct blah :predicate blargh? a b c)\n ; without predicate\n (defstruct blah :predicate NIL a b c)" (doc
- group io) "I/O functionality." compare "Return -1 if `x` is less than `y`, 0 if equal, and `1` if `y` is\ngreater than `x`.\n\nExamples:\n\n (compare 'a 'b) → -1\n (compare 1 1) → 0\n (compare \"b\" \"a\") → 1" buffer "Return an in-memory buffer for I/O, of `io` type.\n\nA buffer can be used for both reading and writing at the same\ntime." num? "Return `T` if `v` is of a numerical type, `NIL` otherwise.\n\nNumerical types include floating point, fixnum, bignum, etc.\nNote: ironically, a NaN value is considered a number by this function\nsince it's only testing the _type_ of the value." add-exit-hook "Puts an one-argument function on top of the list of exit hooks.\n\nOn shutdown each exit hook is called with the exit status as a single\nargument, which is (usually) `NIL` on success and a string describing\nan error otherwise." rand-float "Return a random float on [0.0, 1.0] interval." builtin? "Return `T` if `v` is a built-in function implemented in C, `NIL`\notherwise.\n\nExamples:\n\n (builtin? map) → T\n (builtin? macroexpand) → NIL" set-car! "Modify a cons cell (a list) in-place by putting `new-first` as its\nfirst element (head of the list). Return the modified cons\ncell (list).\n\nExamples:\n\n (def q '(1 2 3 4 5))\n (set-car! q 0) → (0 6 7)\n q → (0 6 7)" doc-group "Define documentation for a group." cons? "Return `T` if `v` is a cons cell, `NIL` otherwise.\n\nExamples:\n\n (cons? 0) → NIL\n (cons? NIL) → NIL\n (cons? '(1)) → T" 1+ "Equivalent to `(+ n 1)`." aref "Return the sequence element specified by the subscripts. The sequence\ncan be an array, vector, a list. Multi-dimensional sequences\nof variating types are also supported.\n\nExamples:\n\n (def a '((1 #(2 (3)) 4)))\n (aref a 0) → (1 (2 (3)) 4)\n (aref a 1) → index 1 out of bounds\n (aref a 0 0) → 1\n (aref a 0 1 0) → 2\n (aref a 0 2) → 4" *properties* "All properties of symbols recorded with `putprop` are recorded in this\ntable." vec "Return a vector constructed of the arguments.\n\nExamples:\n\n (vec) → #() ; empty vector\n (vec 1 2.5 \"a\" 'b) → #(1 2.5 \"a\" b)" >= "Return `T` if the arguments are in non-increasing order (previous\none is greater than or equal to the next one)." sym? "Return `T` if `v` is a symbol, `NIL` otherwise." (doc
- group string) "String-related functionality." void? "Return `T` if `x` is `#<void>`, `NIL` otherwise." zero? "Return `T` if `x` is zero." (doc
- group list) "Working with lists." positive? "Return `T` if `x` is greater than zero." length= "Perform a bounded length test.\n\nUse this instead of `(= (length seq) n)`, since it avoids unnecessary\nwork and always terminates." doc-for "Define documentation for a top level term.\n\nIf `term` is a function signature and `doc` is not specified, just\nthe signature will be included in the documentation, without\nreplacing any previously defined.\n\nFirst `doc` argument is supposed to be a string with the description\nof the term. The following arguments are expected to be optional tag\npairings that provide grouping for multiple symbols and \"see also\"\nreferences.\n\nUseful in cases where setting the documentation for a term can't\n(or not preferred to) be made during the definition of said term.\nOne of those reasons is that the term is a built-in function\nimplemented in C.\n\nExamples:\n\n (doc-for (func arg (arg2 0))\n \"Return something about the `arg` and `arg2`. This is a short\n description.\n\n This is the longer description, following the short one.\n\n Examples:\n\n (func 0) → T\n (func 1 3) → NIL\"\n :doc-group stuff\n :doc-see func2)\n (doc-for (func arg (:another-variant NIL)))" aset! "Modify the sequence element specified by the subscripts and return the\nnew value. The sequence can be an array, vector, a list.\nMulti-dimensional sequences of variating types are also supported.\n\nExamples:\n\n (def a '((1 #(2 (3)) 4)))\n (aset! a 1 'x) → index 1 out of bounds\n (aset! a 0 0 'x) → x\n a → ((x #(2 (3)) 4))\n (aset! a 0 1 9) → 9\n a → ((x #(9 (3)) 4))" car "Return the first element of a cons cell (head of a list) or `NIL` if\nnot available.\n\nExamples:\n\n (car NIL) → NIL\n (car '(1 2 3)) → 1\n (car '(1 . 2)) → 1" *builtins* "VM instructions as closures." str "Return concatenation of terms formatted as strings.\n\nThis is equivalent to `(princ terms…)`, except the string is\nreturned, rather than printed.\n\nExamples:\n\n (str \"a\" 'b 1 #(0)) → \"ab1#(0)\"" cons "Return a cons cell containing two arguments.\n\nExamples:\n\n (cons 1 2) → (1 . 2)\n (cons 1 '(2)) → (1 2)\n (cons 1 (cons 2 (cons 3 NIL))) → (1 2 3)" - "Return the result of subtraction. With only one argument a\nnegation is performed.\n\nExamples:\n\n (- 1.5) → -1.5\n (- 3 2) → 1" remprop "Remove a property value associated with the symbol." <= "Return `T` if the arguments are in non-decreasing order (previous\none is less than or equal to the next one)." rand "Return a random non-negative fixnum on its maximum range." void "Return the constant `#<void>` while ignoring any arguments.\n\n`#<void>` is mainly used when a function has side effects but does not\nproduce any meaningful value to return, so even though `T` or `NIL` could\nbe returned instead, in case of `#<void>` alone, REPL will not print\nit." negative? "Return `T` if `x` is negative." Instructions "VM instructions mapped to their encoded byte representation." file "Open a file for I/O.\n\nAn `io` object is returned. Without any modes specified the file\nis opened in read-only mode." rand-double "Return a random double on interval [0.0, 1.0]." (doc
- group sys) "OS-specific functions." (doc group rand) "Random numbers generation." cdr "Return the second element of a cons cell (tail of a list) or `NIL` if\nnot available.\n\nExamples:\n\n (cdr NIL) → NIL\n (cdr '(1 2 3)) → (2 3)\n (cdr '(1 . 2)) → 2" atom? "Return `T` if `v` is a _not_ a cons cell, `NIL` otherwise. This is\nthe opposite of `cons?`.\n\nThe term \"atom\" comes from the idea of being indivisible.\n\nExamples:\n\n (atom? \"a\") → T\n (atom? NIL) → T\n (atom? '(1)) → NIL" T "A boolean \"true\".\n\nExamples:\n\n (not T) → NIL\n (if T 'yes 'no) → yes" vec? "Return `T` if `v` is a vector, `NIL` otherwise." (doc
- group prop) "Dealing with symbols' properties." equal? "Return `T` if both `a` and `b` are of the same value. For non-leaf\ntypes (cons cell and vector), the equality test is performed\nthroughout the whole structure of the values.\n\nExamples:\n\n (equal? 0.0 0) → NIL\n (equal? 0 0) → T\n (def a \"1\")\n (def b \"1\")\n (equal? a b) → T\n (def a '(1))\n (def b '(1))\n (equal? a b) → T" eqv? "Return `T` if both `a` and `b` are of the same value and primitive\n(leaf) type, `NIL` otherwise. Neither cons cell nor vector are not\nconsidered primitive types as they may define deep structures.\n\nExamples:\n\n (eqv? 0.0 0) → NIL\n (eqv? 0 0) → T\n (def a \"1\")\n (def b \"1\")\n (eqv? a b) → T\n (def a '(1))\n (def b '(1))\n (eqv? a b) → NIL" io? "Return `T` if `term` is of `io` type, `NIL` otherwise." eof-object? "Return `T` if `term` is `#<eof>`, `NIL` otherwise.\n\nThis object is returned by I/O functions to signal end of file,\nwhere applicable." list "Return a list constructed of the arguments.\n\nExamples:\n\n (list) → NIL ; empty list\n (list 1 2.5 \"a\" 'b) → (1 2.5 \"a\" b)" apply "Return the result of applying a function to a list of arguments.\n\nThe last argument must always be a list which gets spliced as\narguments to the function.\n\nExamples:\n\n (apply + 1 2 '(3 4 5)) → 15\n (apply vec '(1 2 3)) → #(3 4 5)\n (apply arr 'u8 '(3 4 5)) → #vu8(3 4 5)" / "Return the division of the arguments. With only one argument the\nresult of `1/x` is returned. If the result is integer-valued, it is\nreturned as an integer.\n\nExamples:\n\n (/ 2) → 0.5\n (/ 7 2 2) → 1.75\n (/ 10 -2) → -5 ; a fixnum\n (/ 6.9 1.9) → 3.6315…" help "Display documentation the specified term, if available.\n\nThe optional parameter `kind` can be set to `group` to show\ndocumentation for the specified group instead of a single term.\nAll available documentation groups can be displayed with `(help\ngroups)`." 1- "Equivalent to `(- n 1)`." rand-u32 "Return a random integer on interval [0, 2³²-1]." = "Numerical equality test. Return `T` if all numbers are equal,\n`NIL` otherwise." rand-u64 "Return a random integer on interval [0, 2⁶⁴-1]." not "Return `T` if `v` is `NIL`, `T` otherwise." NIL "An empty list. Can be used as the opposite of T in boolean\nexpressions.\n\nExamples:\n\n (not NIL) → T\n (if NIL 'yes 'no) → no\n (car NIL) → NIL\n (cdr NIL) → NIL" set-cdr! "Modify a cons cell (a list) in-place by putting `new-second` as its\nsecond element (tail of the list). Return the modified cons\ncell (list).\n\nExamples:\n\n (def q '(1 2 3 4 5))\n (set-cdr! q '(6 7)) → (1 6 7)\n q → (1 6 7)" (doc
- group doc) "Writing and reading documentation." fn? "Return `T` if `v` is a function, `NIL` otherwise.\n\nExamples:\n\n (fn? map) → T\n (fn? macroexpand) → T" separate-doc-from-body "Take a list of terms and return a pair `(doc . body)`, where the first\nelement contains a list of documentation-related terms, and the second\ncontains the rest of the terms." lz-pack "Return data compressed using Lempel-Ziv.\n\nThe data must be an array, returned value will have the same type.\nThe optional `level` is between `0` and `10`. With `level` set to\n`0` a simple LZSS using hashing will be performed. Levels between\n`1` and `9` offer a trade-off between time/space and ratio. Level\n`10` is optimal but very slow." arg-counts "VM instructions mapped to their expected arguments count." help-print-header "Format and print signature(s) of the term for `(help term)` output." eq? "Return `T` if `a` and `b` are the same object, `NIL` otherwise.\n\nExamples:\n\n (eq? 0.0 0) → NIL\n (eq? 0 0) → T\n (def a \"1\")\n (def b \"1\")\n (eq? a b) → NIL\n (def a '(1))\n (def b '(1))\n (eq? a b) → NIL" *prompt* "Function called by REPL to signal the user input is required.\n\nDefault function prints `#;> `." getprop "Return a property value associated with the symbol or `def` if\nmissing." vm-stats "Print various VM-related information, such as the number of GC\ncalls so far, heap and stack size, etc." * "Return product of the arguments or `1` when none specified." putprop "Associate a property value with the symbol." io->str "Return an in-memory `io` buffer converted to a string.") *doc-extra* #table(bound? ((:doc-group . builtin)) sym-set-doc ((:doc-group . doc)) io-eof? ((:doc-group . io)) < ((:doc-group . compare)
- (:doc-group . builtin)) cadr ((:doc-group . list) (:doc-group . builtin)) nan? ((:doc-group . builtin)) for ((:doc-group . builtin)) fixnum? ((:doc-group . builtin)) exit ((:doc-group . sys)) > ((:doc-group . compare)) + ((:doc-group . builtin)) div0 ((:doc-group . builtin)) lz-unpack ((:doc-group . compress)) compare ((:doc-group . builtin)) buffer ((:doc-group . io)) num? ((:doc-group . builtin)) rand-float ((:doc-group . rand)) builtin? ((:doc-group . builtin)) set-car! ((:doc-group . list)
- (:doc-group . builtin)) cons? ((:doc-group . builtin)) doc-group ((:doc-group . doc)) aref ((:doc-group . builtin)) *properties* ((:doc-group . prop)) vec ((:doc-group . builtin)) >= ((:doc-group . compare)) sym? ((:doc-group . builtin)) zero? ((:doc-group . compare)) length= ((:doc-group . list)) positive? ((:doc-group . compare)) doc-for ((:doc-group . doc)) aset! ((:doc-group . builtin)) car ((:doc-group . list)
+ key val)) io->str ((io))) *doc* #table(identity "Return `x`." bound? "Return `T` if `symbol` has a value associated with it, `NIL` otherwise." sym-set-doc "Set the documentation for the symbol." io-eof? "Return `T` if `io` is currently in the \"end of file\" state, `NIL`\notherwise." (doc
+ group io) "I/O functionality." < "Return `T` if the arguments are in strictly increasing order (next\none is greater than the previous one). With a single argument\nthe result is always `T`." cadr "Shorthand for `(car (cdr cell))`, that is, _first element of the\nsecond element_.\n\nExamples:\n\n (cadr '(1 2 3)) → 2\n (cadr '(1)) → NIL\n (cadr NIL) → NIL" (doc
+ group builtin) "Built-in operators." nan? "Return `T` if `v` is a floating point representation of NaN, either\nnegative or positive, `NIL` otherwise." NIL "An empty list. Can be used as the opposite of T in boolean\nexpressions.\n\nExamples:\n\n (not NIL) → T\n (if NIL 'yes 'no) → no\n (car NIL) → NIL\n (cdr NIL) → NIL" for "Call the function `fn` with a single integer argument, starting from\n`min` and ending with `max`.\n\nExamples:\n\n (for 0 2 (λ (i) (print (- 2 i)))) → 210" (doc
+ group vm) "VM-related functions." exit "Terminate the process with the specified status. Does not return.\nThe status is expected to be a string in case of an error.\n\nExamples:\n\n (exit) ; exit with status 0 (nil on Plan 9)\n (exit \"error\") ; exit with status 1 (\"error\" on Plan 9)" fixnum? "Return `T` if `v` is of a fixnum type, `NIL` otherwise." > "Return `T` if the arguments are in strictly decreasing order (previous\none is greater than the next one)." + "Return sum of the arguments or `0` when none specified." div0 "Return the quotient of two numbers. For non-integers this is\nequivalent to `(div0 (floor a) (floor b))`. The result is always an\ninteger.\n\nExamples:\n\n (div0 7 2) → 3\n (div0 10 -2) → -5\n (div0 6.9 1.9) → 6" (doc
+ group prop) "Dealing with symbols' properties." lz-unpack "Return decompressed data previously compressed using lz-pack.\n\nEither destination for the decompressed data or the expected size of\nthe decompressed data must be specified. In the latter case a new\narray is allocated." __finish "A function called right before exit by the VM." defstruct "Defines a structure type with a specific name and slots.\n\nThe default underlying type is a \"named\" vector (`:type vec`), where\nthe first element is the name of the structure's type, the rest are\nthe keyworded slot values. A list with slot values alone can be used\ninstead by adding `:type list` option. The list will not contain the\nname of the struct by default, which can be enabled with `:named T`\noption.\n\nAs an example, the following declaration\n\n (defstruct blah \"Return stuff.\" :doc-group stuff a b (c 1))\n\nGenerates the default constructor definition and accessors:\n\n (make-blah (:a NIL) (:b NIL) (:c 1))\n (blah-a s)\n (blah-b s)\n (blah-c s)\n\nThe constructor can be changed in several ways:\n\n ; disable the constructor altogether\n (defstruct blah :constructor NIL a b c)\n ; only change its name\n (defstruct blah :constructor blargh a b c)\n ; rename AND avoid using keywords\n (defstruct blah :constructor (blah a b c) a b c)\n\nThe option `:conc-name` specifies the slot accessor prefix, which\ndefaults to `structname-`. Prefix can be disabled entirely with\n`:conc-name NIL`.\n\nDefault predicate can be disabled or its name, which defaults to\n`structname?`, changed:\n\n ; use \"blargh?\" instead of \"blah?\"\n (defstruct blah :predicate blargh? a b c)\n ; without predicate\n (defstruct blah :predicate NIL a b c)" (doc
+ group rand) "Random numbers generation." (doc group compare) "Comparison operators." compare "Return -1 if `x` is less than `y`, 0 if equal, and `1` if `y` is\ngreater than `x`.\n\nExamples:\n\n (compare 'a 'b) → -1\n (compare 1 1) → 0\n (compare \"b\" \"a\") → 1" buffer "Return an in-memory buffer for I/O, of `io` type.\n\nA buffer can be used for both reading and writing at the same\ntime." num? "Return `T` if `v` is of a numerical type, `NIL` otherwise.\n\nNumerical types include floating point, fixnum, bignum, etc.\nNote: ironically, a NaN value is considered a number by this function\nsince it's only testing the _type_ of the value." add-exit-hook "Puts an one-argument function on top of the list of exit hooks.\n\nOn shutdown each exit hook is called with the exit status as a single\nargument, which is (usually) `NIL` on success and a string describing\nan error otherwise." rand-float "Return a random float on [0.0, 1.0] interval." builtin? "Return `T` if `v` is a built-in function implemented in C, `NIL`\notherwise.\n\nExamples:\n\n (builtin? map) → T\n (builtin? macroexpand) → NIL" set-car! "Modify a cons cell (a list) in-place by putting `new-first` as its\nfirst element (head of the list). Return the modified cons\ncell (list).\n\nExamples:\n\n (def q '(1 2 3 4 5))\n (set-car! q 0) → (0 6 7)\n q → (0 6 7)" doc-group "Define documentation for a group." cons? "Return `T` if `v` is a cons cell, `NIL` otherwise.\n\nExamples:\n\n (cons? 0) → NIL\n (cons? NIL) → NIL\n (cons? '(1)) → T" 1+ "Equivalent to `(+ n 1)`." aref "Return the sequence element specified by the subscripts. The sequence\ncan be an array, vector, a list. Multi-dimensional sequences\nof variating types are also supported.\n\nExamples:\n\n (def a '((1 #(2 (3)) 4)))\n (aref a 0) → (1 (2 (3)) 4)\n (aref a 1) → index 1 out of bounds\n (aref a 0 0) → 1\n (aref a 0 1 0) → 2\n (aref a 0 2) → 4" *properties* "All properties of symbols recorded with `putprop` are recorded in this\ntable." vec "Return a vector constructed of the arguments.\n\nExamples:\n\n (vec) → #() ; empty vector\n (vec 1 2.5 \"a\" 'b) → #(1 2.5 \"a\" b)" >= "Return `T` if the arguments are in non-increasing order (previous\none is greater than or equal to the next one)." sym? "Return `T` if `v` is a symbol, `NIL` otherwise." void? "Return `T` if `x` is `#<void>`, `NIL` otherwise." zero? "Return `T` if `x` is zero." length= "Perform a bounded length test.\n\nUse this instead of `(= (length seq) n)`, since it avoids unnecessary\nwork and always terminates." positive? "Return `T` if `x` is greater than zero." doc-for "Define documentation for a top level term.\n\nIf `term` is a function signature and `doc` is not specified, just\nthe signature will be included in the documentation, without\nreplacing any previously defined.\n\nFirst `doc` argument is supposed to be a string with the description\nof the term. The following arguments are expected to be optional tag\npairings that provide grouping for multiple symbols and \"see also\"\nreferences.\n\nUseful in cases where setting the documentation for a term can't\n(or not preferred to) be made during the definition of said term.\nOne of those reasons is that the term is a built-in function\nimplemented in C.\n\nExamples:\n\n (doc-for (func arg (arg2 0))\n \"Return something about the `arg` and `arg2`. This is a short\n description.\n\n This is the longer description, following the short one.\n\n Examples:\n\n (func 0) → T\n (func 1 3) → NIL\"\n :doc-group stuff\n :doc-see func2)\n (doc-for (func arg (:another-variant NIL)))" aset! "Modify the sequence element specified by the subscripts and return the\nnew value. The sequence can be an array, vector, a list.\nMulti-dimensional sequences of variating types are also supported.\n\nExamples:\n\n (def a '((1 #(2 (3)) 4)))\n (aset! a 1 'x) → index 1
\ No newline at end of file
+ group list) "Working with lists." Instructions "VM instructions mapped to their encoded byte representation." file "Open a file for I/O.\n\nAn `io` object is returned. Without any modes specified the file\nis opened in read-only mode." rand-double "Return a random double on interval [0.0, 1.0]." 1- "Equivalent to `(- n 1)`." cdr "Return the second element of a cons cell (tail of a list) or `NIL` if\nnot available.\n\nExamples:\n\n (cdr NIL) → NIL\n (cdr '(1 2 3)) → (2 3)\n (cdr '(1 . 2)) → 2" (doc
+ group string) "String-related functionality." atom? "Return `T` if `v` is a _not_ a cons cell, `NIL` otherwise. This is\nthe opposite of `cons?`.\n\nThe term \"atom\" comes from the idea of being indivisible.\n\nExamples:\n\n (atom? \"a\") → T\n (atom? NIL) → T\n (atom? '(1)) → NIL" vec? "Return `T` if `v` is a vector, `NIL` otherwise." equal? "Return `T` if both `a` and `b` are of the same value. For non-leaf\ntypes (cons cell and vector), the equality test is performed\nthroughout the whole structure of the values.\n\nExamples:\n\n (equal? 0.0 0) → NIL\n (equal? 0 0) → T\n (def a \"1\")\n (def b \"1\")\n (equal? a b) → T\n (def a '(1))\n (def b '(1))\n (equal? a b) → T" / "Return the division of the arguments. With only one argument the\nresult of `1/x` is returned. If the result is integer-valued, it is\nreturned as an integer.\n\nExamples:\n\n (/ 2) → 0.5\n (/ 7 2 2) → 1.75\n (/ 10 -2) → -5 ; a fixnum\n (/ 6.9 1.9) → 3.6315…" eqv? "Return `T` if both `a` and `b` are of the same value and primitive\n(leaf) type, `NIL` otherwise. Neither cons cell nor vector are not\nconsidered primitive types as they may define deep structures.\n\nExamples:\n\n (eqv? 0.0 0) → NIL\n (eqv? 0 0) → T\n (def a \"1\")\n (def b \"1\")\n (eqv? a b) → T\n (def a '(1))\n (def b '(1))\n (eqv? a b) → NIL" io? "Return `T` if `term` is of `io` type, `NIL` otherwise." eof-object? "Return `T` if `term` is `#<eof>`, `NIL` otherwise.\n\nThis object is returned by I/O functions to signal end of file,\nwhere applicable." list "Return a list constructed of the arguments.\n\nExamples:\n\n (list) → NIL ; empty list\n (list 1 2.5 \"a\" 'b) → (1 2.5 \"a\" b)" apply "Return the result of applying a function to a list of arguments.\n\nThe last argument must always be a list which gets spliced as\narguments to the function.\n\nExamples:\n\n (apply + 1 2 '(3 4 5)) → 15\n (apply vec '(1 2 3)) → #(3 4 5)\n (apply arr 'u8 '(3 4 5)) → #vu8(3 4 5)" help "Display documentation the specified term, if available.\n\nThe optional parameter `kind` can be set to `group` to show\ndocumentation for the specified group instead of a single term.\nAll available documentation groups can be displayed with `(help\ngroups)`." (doc
+ group doc) "Writing and reading documentation." rand-u32 "Return a random integer on interval [0, 2³²-1]." = "Numerical equality test. Return `T` if all numbers are equal,\n`NIL` otherwise." rand-u64 "Return a random integer on interval [0, 2⁶⁴-1]." (doc
+ group sys) "OS-specific functions." not "Return `T` if `v` is `NIL`, `T` otherwise." set-cdr! "Modify a cons cell (a list) in-place by putting `new-second` as its\nsecond element (tail of the list). Return the modified cons\ncell (list).\n\nExamples:\n\n (def q '(1 2 3 4 5))\n (set-cdr! q '(6 7)) → (1 6 7)\n q → (1 6 7)" separate-doc-from-body "Take a list of terms and return a pair `(doc . body)`, where the first\nelement contains a list of documentation-related terms, and the second\ncontains the rest of the terms." fn? "Return `T` if `v` is a function, `NIL` otherwise.\n\nExamples:\n\n (fn? map) → T\n (fn? macroexpand) → T" help-print-header "Format and print signature(s) of the term for `(help term)` output." lz-pack "Return data compressed using Lempel-Ziv.\n\nThe data must be an array, returned value will have the same type.\nThe optional `level` is between `0` and `10`. With `level` set to\n`0` a simple LZSS using hashing will be performed. Levels between\n`1` and `9` offer a trade-off between time/space and ratio. Level\n`10` is optimal but very slow." arg-counts "VM instructions mapped to their expected arguments count." *prompt* "Function called by REPL to signal the user input is required.\n\nDefault function prints `#;> `." eq? "Return `T` if `a` and `b` are the same object, `NIL` otherwise.\n\nExamples:\n\n (eq? 0.0 0) → NIL\n (eq? 0 0) → T\n (def a \"1\")\n (def b \"1\")\n (eq? a b) → NIL\n (def a '(1))\n (def b '(1))\n (eq? a b) → NIL" getprop "Return a property value associated with the symbol or `def` if\nmissing." vm-stats "Print various VM-related information, such as the number of GC\ncalls so far, heap and stack size, etc." (doc
+ group compress) "Compression." * "Return product of the arguments or `1` when none specified." putprop "Associate a property value with the symbol." io->str "Return an in-memory `io` buffer converted to a string.") *doc-extra* #table(bound? ((:doc-group . builtin)) sym-set-doc ((:doc-group . doc)) io-eof? ((:doc-group . io)) < ((:doc-group . compare)
+ (:doc-group . builtin)) cadr ((:doc-group . list) (:doc-group . builtin)) nan? ((:doc-group . builtin)) NIL ((:doc-see . T)) for ((:doc-group . builtin)) fixnum? ((:doc-group . builtin)) exit ((:doc-group . sys)) > ((:doc-group . compare)) + ((:doc-group . builtin)) div0 ((:doc-group . builtin)) lz-unpack ((:doc-group . compress)) compare ((:doc-group . builtin)) buffer ((:doc-group . io)) num? ((:doc-group . builtin)) rand-float ((:doc-group . rand)) builtin? ((:doc-group . builtin)) set-car! ((:doc-group . list)
+ (:doc-group . builtin)) cons? ((:doc-group . builtin)) doc-group ((:doc-group . doc)) aref ((:doc-group . builtin)) *properties* ((:doc-group . prop)) vec ((:doc-group . builtin)) >= ((:doc-group . compare)) sym? ((:doc-group . builtin)) zero? ((:doc-group . compare)) length= ((:doc-group . list)) positive? ((:doc-group . compare)) doc-for ((:doc-group . doc)) aset! ((:doc-group . builtin)) T ((:doc-see)) car ((:doc-group . list)
(:doc-group . builtin)) *builtins* ((:doc-group . builtin)) str ((:doc-group . string)) cons ((:doc-group . list)
- (:doc-group . builtin)) - ((:doc-group . builtin)) remprop ((:doc-group . prop)) <= ((:doc-group . compare)) rand ((:doc-group . rand)) negative? ((:doc-group . compare)) Instructions ((:doc-group . builtin)) file ((:doc-group . io)) rand-double ((:doc-group . rand)) atom? ((:doc-group . builtin)) cdr ((:doc-group . list)
- (:doc-group . builtin)) T ((:doc-see)) vec? ((:doc-group . builtin)) equal? ((:doc-group . compare)
- (:doc-group . builtin)) / ((:doc-group . builtin)) eqv? ((:doc-group . compare)
- (:doc-group . builtin)) io? ((:doc-group . io)) eof-object? ((:doc-group . io)) list ((:doc-group . builtin)) apply ((:doc-group . builtin)) help ((:doc-group . doc)) rand-u32 ((:doc-group . rand)) = ((:doc-group . compare)
- (:doc-group . builtin)) rand-u64 ((:doc-group . rand)) not ((:doc-group . builtin)) NIL ((:doc-see . T)) set-cdr! ((:doc-group . list)
- (:doc-group . builtin)) separate-doc-from-body ((:doc-group . doc)) fn? ((:doc-group . builtin)) help-print-header ((:doc-group . doc)) lz-pack ((:doc-group . compress)) arg-counts ((:doc-group . builtin)) eq? ((:doc-group . compare)
+rty value associated with the symbol or `def` if\nmissing." vm-stats "Print various VM-related information, such as the number of GC\ncalls so far, heap and stack size, etc." (doc
+ group compress) "Compression." * "Return product of the arguments or `1` when none specified." putprop "Associate a property value with the symbol." io->str "Return an in-memory `io` buffer converted to a string.") *doc-extra* #table(bound? ((:doc-group . builtin)) sym-set-doc ((:doc-group . doc)) io-eof? ((:doc-group . io)) < ((:doc-group . compare)
+ (:doc-group . builtin)) cadr ((:doc-group . list) (:doc-group . builtin)) nan? ((:doc-group . builtin)) NIL ((:doc-see . T)) for ((:doc-group . builtin)) fixnum? ((:doc-group . builtin)) exit ((:doc-group . sys)) > ((:doc-group . compare)) + ((:doc-group . builtin)) div0 ((:doc-group . builtin)) lz-unpack ((:doc-group . compress)) compare ((:doc-group . builtin)) buffer ((:doc-group . io)) num? ((:doc-group . builtin)) rand-float ((:doc-group . rand)) builtin? ((:doc-group . builtin)) set-car! ((:doc-group . list)
+ (:doc-group . builtin)) cons? ((:doc-group . builtin)) doc-group ((:doc-group . doc)) aref ((:doc-group . builtin)) *properties* ((:doc-group . prop)) vec ((:doc-group . builtin)) >= ((:doc-group . compare)) sym? ((:doc-group . builtin)) zero? ((:doc-group . compare)) length= ((:doc-group . list)) positive? ((:doc-group . compare)) doc-for ((:doc-group . doc)) aset! ((:doc-group . builtin)) T ((:doc-see)) car ((:doc-group . list)
+ (:doc-group . builtin)) *builtins* ((:doc-group . builtin)) str ((:doc-group . string)) cons ((:doc-group . list)
(:doc-group . builtin)) getprop ((:doc-group . prop) (:doc-see . putprop)) vm-stats ((:doc-group . vm)) * ((:doc-group . builtin)) putprop ((:doc-group . prop)
(:doc-see . getprop)) io->str ((:doc-group . io))))
*syntax-environment* #table(bcode:nconst #fn("n1200r2e3:" #(aref)) doc-for #fn("z10B86;35040<;J404086;35040=70151<863I0212287e22289e22288e2e4:212287e22289e2e3:" #(separate-doc-from-body
@@ -114,7 +115,7 @@
#fn("n10K~:" #() 1-) 1arg-lambda? #fn("n10B;3D040<20Q;3:04710TK62:" #(λ length=) 1arg-lambda?)
<= #fn("z1Ib6862086>1_486<^10162:" #(#fn("n21S;JL041<0L2;J5040V340q:A<1<1=62:")) <=) >
#fn("z1Ib6862086>1_486<^10162:" #(#fn("n21S;JE041<0L2;3;04A<1<1=62:")) >) >= #fn("z1Ib6862086>1_486<^10162:" #(#fn("n21S;JL0401<L2;J5040V340q:A<1<1=62:")) >=)
- Instructions #table(call.l #u8(81) trycatch #u8(75) loadg.l #u8(68) aref2 #u8(23) box #u8(50) cadr #u8(36) argc #u8(62) setg #u8(71) load0 #u8(21) nan? #u8(38) fixnum? #u8(41) loadc0 #u8(17) loada0 #u8(0) div0 #u8(59) keyargs #u8(31) call #u8(5) loada.l #u8(69) num? #u8(40) sub2 #u8(78) add2 #u8(29) loadc.l #u8(70) loadc #u8(9) builtin? #u8(43) set-car! #u8(47) vargc.l #u8(80) vec #u8(63) ret #u8(10) loadi8 #u8(66) tapply #u8(77) loadvoid #u8(25) loada1 #u8(1) shift #u8(46) atom? #u8(24) cdr #u8(13) brne.l #u8(83) / #u8(58) equal? #u8(52) apply #u8(54) dup #u8(11) loadt #u8(20) bounda #u8(39) jmp.l #u8(48) = #u8(60) not #u8(35) set-cdr! #u8(30) fn? #u8(44) eq? #u8(33) * #u8(57) load1 #u8(27) bound? #u8(42) box.l #u8(86) < #u8(28) brnn.l #u8(84) jmp #u8(16) loadv #u8(2) for #u8(76) dummy_eof #u8(88) + #u8(55) brne #u8(19) argc.l #u8(79) compare #u8(61) brn #u8(3) neg #u8(37) loadv.l #u8(67) vargc #u8(74) loadc1 #u8(22) setg.l #u8(72) cons? #u8(18) aref #u8(85) sym? #u8(34) aset! #u8(64) car #u8(12) cons #u8(32) tcall.l #u8(82) - #u8(56) brn.l #u8(49) optargs #u8(87) closure #u8(14) vec? #u8(45) pop #u8(4) eqv? #u8(51) list #u8(53) seta #u8(15) seta.l #u8(73) brnn #u8(26) loadnil #u8(65) loadg #u8(7) loada #u8(8) tcall #u8(6))
+onc)
S #fn("z1700215286380861}2:7223062:" #(getprop constructor error "no default constructor for struct: ") S)
__finish #fn("n120Z3>021220>17062:q:" #(*exit-hooks* #fn(for-each)
#fn("n10A61:")) __finish)
--- a/src/cvalues.c
+++ b/src/cvalues.c
@@ -667,6 +667,10 @@
return mk_list2(sl_structsym, vec_elt(v, 0));
return sl_vecsym;
case TAG_FN:
+ if(isbuiltin(v))
+ return sl_builtinsym;
+ return sl_fnsym;
+ case TAG_SPECIAL:
if(v == sl_t)
return sl_booleansym;
if(v == sl_nil)
@@ -675,11 +679,6 @@
return sl_eof;
if(v == sl_void)
return sl_void;
- if(isbuiltin(v))
- return sl_builtinsym;
- return sl_fnsym;
- case TAG_UNUSED:
- abort();
}
return cv_type(ptr(v));
}
--- a/src/equal.c
+++ b/src/equal.c
@@ -333,6 +333,8 @@
if(uintval(a) > N_BUILTINS)
return bounded_hash(((sl_fn*)ptr(a))->bcode, bound, oob);
return inthash(a);
+ case TAG_SPECIAL:
+ return inthash(a);
case TAG_SYM:
return ((sl_sym*)ptr(a))->hash;
case TAG_CVALUE:
@@ -346,7 +348,6 @@
h = memhash(data, cv_len(cv));
}
return h;
-
case TAG_VEC:
if(bound <= 0){
*oob = true;
@@ -360,7 +361,6 @@
*oob = *oob || oob2;
}
return h;
-
case TAG_CONS:
do{
if(bound <= 0){
--- a/src/opcodes.h
+++ b/src/opcodes.h
@@ -87,7 +87,6 @@
OP_AREF,
OP_BOXL,
OP_OPTARGS,
- OP_DUMMY_EOF,
N_OPCODES
}sl_op;
--- a/src/print.c
+++ b/src/print.c
@@ -184,10 +184,7 @@
}
if(sl_isstr(v))
return cv_len(ptr(v)) < SMALL_STR_LEN;
- return (
- isfixnum(v) || isunboxed(v) || isbuiltin(v) ||
- v == sl_t || v == sl_nil || v == sl_eof || v == sl_void
- );
+ return isfixnum(v) || isunboxed(v) || isbuiltin(v) || isspecial(v);
}
static bool
@@ -440,7 +437,7 @@
}else
print_sym_name(f, name);
break;
- case TAG_FN:
+ case TAG_SPECIAL:
if(v == sl_t)
outc(f, 'T');
else if(v == sl_nil)
@@ -447,9 +444,13 @@
outsc(f, "NIL");
else if(v == sl_eof)
outsc(f, "#<eof>");
- else if(v == sl_void){
+ else if(v == sl_void)
outsc(f, "#<void>");
- }else if(isbuiltin(v)){
+ else
+ abort();
+ break;
+ case TAG_FN:
+ if(isbuiltin(v)){
if(!sl.print_princ)
outsc(f, "#.");
outs(f, builtins[uintval(v)].name);
@@ -939,7 +940,6 @@
if(sl.print_level >= 0 || sl.print_length >= 0)
memset(sl.consflags, 0, 4*bitvector_nwords(slg.heapsize/sizeof(sl_cons)));
- if((iscons(v) || isvec(v) || isfn(v) || iscvalue(v)) &&
- !sl_isstr(v) && v != sl_t && v != sl_nil && v != sl_void)
+ if((iscons(v) || isvec(v) || isfn(v) || iscvalue(v)) && !sl_isstr(v))
htable_reset(&sl.printconses, 32);
}
--- a/src/sl.c
+++ b/src/sl.c
@@ -398,7 +398,7 @@
{
sl_v a, d, nc, first, *pcdr;
- if(isfixnum(v) || isunboxed(v))
+ if(isfixnum(v) || isunboxed(v) || isspecial(v))
return v;
uintptr t = tag(v);
@@ -591,8 +591,6 @@
sl_v v;
if(iscbuiltin(f))
v = ((sl_cv*)ptr(f))->cbuiltin(saveSP-n, n);
- else if(isfn(f))
- v = apply_cl(n);
else if(sl_likely(isbuiltin(f))){
sl_v tab = sym_value(sl_builtinssym);
if(sl_unlikely(ptr(tab) == nil))
@@ -599,6 +597,8 @@
cthrow(unbound_error(tab), n);
saveSP[-n-1] = vec_elt(tab, uintval(f));
v = apply_cl(n);
+ }else if(isfn(f)){
+ v = apply_cl(n);
}else{
cthrow(type_error("fn", f), n);
}
@@ -1015,10 +1015,10 @@
{
argcount(nargs, 1);
sl_v v = args[0];
- if(sl_unlikely(iscbuiltin(v)))
- return v;
if(sl_unlikely(!isfn(v)))
bthrow(type_error("fn", v));
+ if(sl_unlikely(iscbuiltin(v) || isbuiltin(v)))
+ return v;
return fn_bcode(v);
}
@@ -1027,10 +1027,10 @@
{
argcount(nargs, 1);
sl_v v = args[0];
- if(sl_unlikely(iscbuiltin(v)))
- return sl_emptyvec;
if(sl_unlikely(!isfn(v)))
bthrow(type_error("fn", v));
+ if(sl_unlikely(iscbuiltin(v) || isbuiltin(v)))
+ return sl_emptyvec;
return fn_vals(v);
}
@@ -1039,10 +1039,10 @@
{
argcount(nargs, 1);
sl_v v = args[0];
- if(sl_unlikely(iscbuiltin(v)))
- return sl_nil;
if(sl_unlikely(!isfn(v)))
bthrow(type_error("fn", v));
+ if(sl_unlikely(iscbuiltin(v) || isbuiltin(v)))
+ return sl_nil;
return fn_env(v);
}
@@ -1050,8 +1050,6 @@
{
argcount(nargs, 1);
sl_v v = args[0];
- if(isfn(v))
- return fn_name(v);
if(isbuiltin(v))
return mk_sym(builtins[uintval(v)].name, false);
if(iscbuiltin(v)){
@@ -1060,6 +1058,8 @@
return sl_nil;
return v;
}
+ if(isfn(v))
+ return fn_name(v);
bthrow(type_error("fn", v));
}
--- a/src/sl.h
+++ b/src/sl.h
@@ -12,7 +12,7 @@
enum {
TAG_FIXNUM,
- TAG_UNUSED,
+ TAG_SPECIAL,
TAG_FN,
TAG_VEC,
TAG_UNBOXED,
@@ -115,6 +115,7 @@
#define ubnumval(x) ((sl_fx)(x)>>(TAG_BITS+1+4))
#define uintval(x) (((unsigned int)(x))>>TAG_BITS)
#define builtin(n) tagptr(((sl_v)n<<TAG_BITS), TAG_FN)
+#define special(x) (tagptr(((sl_v)x<<TAG_BITS), TAG_SPECIAL))
#define iscons(x) (tag(x) == TAG_CONS)
#define issym(x) (tag(x) == TAG_SYM)
#define isfixnum(x) (tag(x) == TAG_FIXNUM)
@@ -122,6 +123,7 @@
#define isvec(x) (tag(x) == TAG_VEC)
#define iscvalue(x) (tag(x) == TAG_CVALUE)
#define isunboxed(x) (tag(x) == TAG_UNBOXED)
+#define isspecial(x) (tag(x) == TAG_SPECIAL)
// doesn't lead to other values
#define leafp(a) (((a)&TAG_NONLEAF_MASK) != TAG_NONLEAF_MASK)
@@ -186,9 +188,9 @@
#define sym_name_(s) (((sl_sym*)ptr(s))->name)
#define sym_to_numtype(s) (((sl_sym*)ptr(s))->numtype)
#define ismanaged(v) ((((u8int*)ptr(v)) >= slg.fromspace) && (((u8int*)ptr(v)) < slg.fromspace+slg.heapsize))
-#define isgensym(x) (issym(x) && ismanaged(x))
-#define isfn(x) (tag(x) == TAG_FN && (x) > (N_BUILTINS<<TAG_BITS))
-#define iscbuiltin(x) (iscvalue(x) && cv_class(ptr(x)) == sl_builtintype)
+#define isgensym(v) (issym(v) && ismanaged(v))
+#define iscbuiltin(v) (iscvalue(v) && cv_class(ptr(v)) == sl_builtintype)
+#define isfn(v) ((tag(v) == TAG_FN && ((v) > (N_BUILTINS<<TAG_BITS) || isbuiltin(v))) || iscbuiltin(v))
// utility for iterating over all arguments in a builtin
// i=index, i0=start index, arg = var for each arg, args = arg array
// assumes "nargs" is the argument count
@@ -369,10 +371,10 @@
#include "opcodes.h"
enum {
- sl_nil = builtin(OP_LOADNIL),
- sl_t = builtin(OP_LOADT),
- sl_void = builtin(OP_LOADVOID),
- sl_eof = builtin(OP_DUMMY_EOF),
+ sl_nil = special(1),
+ sl_t = special(2),
+ sl_void = special(3),
+ sl_eof = special(4),
};
typedef struct Sl Sl;
--- a/src/vm.h
+++ b/src/vm.h
@@ -32,7 +32,7 @@
SYNC;
sl_v v = sp[-n-1];
if(tag(v) == TAG_FN){
- if(v > (N_BUILTINS<<3)){
+ if(v > (N_BUILTINS<<TAG_BITS)){
nargs = n;
if(tail){
sl.curr_frame = (sl_v*)sl.curr_frame[-3];
@@ -943,14 +943,9 @@
NEXT_OP;
}
-OP(OP_FNP) {
- sl_v v = sp[-1];
- sp[-1] =
- ((tag(v) == TAG_FN &&
- (isbuiltin(v) || v>(N_BUILTINS<<3))) ||
- iscbuiltin(v)) ? sl_t : sl_nil;
+OP(OP_FNP)
+ sp[-1] = isfn(sp[-1]) ? sl_t : sl_nil;
NEXT_OP;
-}
OP(OP_JMPL)
ip += GET_S32(ip);
--- a/tools/gen.sl
+++ b/tools/gen.sl
@@ -387,7 +387,6 @@
(aref a 0 2) → 4"]})
(op box.l)
(op optargs)
- (op dummy_eof)
))
(def (new path)