shithub: sl

Download patch

ref: 73f66925d5ebf3e5ba97a71c46d2c90931d7e5af
parent: c971f253270dbd2e421a9740d342136335ed3256
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sun Mar 23 20:39:50 EDT 2025

docs: more groupings; extend doc-for docstring

References: https://todo.sr.ht/~ft/sl/27

References: https://todo.sr.ht/~ft/sl/16

--- a/boot/sl.boot
+++ b/boot/sl.boot
@@ -29,8 +29,8 @@
   (:print-header help-print-header)))  rand-u32 (NIL)  = ((a . rest))  rand-u64 (NIL)  not ((v))  separate-doc-from-body ((body
   (doc NIL)))  set-cdr! ((cell new-second))  fn? ((v))  help-print-header ((term sigs))  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`."  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."  > "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"  __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`),\nwhere the first element is the name of the structure's type, the\nrest are the slot values.  If the name as the first element isn't\nrequired, `:named NIL` should be used.  A list can be used instead\nof a vector by adding `:type list` option.\n\nAn example of a default constructor signature, based on structure\ndefinition:\n\n    (defstruct blah a b c) →\n      (make-blah (:a NIL) (:b NIL) (:c NIL))\n\nIt can be customized in several ways. For example:\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 `name-`.\n\nDefault predicate name (`name?`) can be changed:\n\n    ; use \"blargh?\" instead of \"blah?\"\n    (defstruct blah :predicate blargh? a b c)"  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."  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)"  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 se
\ No newline at end of file
-  props)  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 . docs))  aset! ((:doc-group . builtin))  car ((:doc-group . builtin))  *builtins* ((:doc-group . builtin))  str ((:doc-see . T))  cons ((:doc-group . builtin))  - ((:doc-group . builtin))  remprop ((:doc-group . props))  <= ((:doc-group . compare))  negative? ((:doc-group . compare))  Instructions ((:doc-group . builtin))  file ((:doc-group . io))  cdr ((:doc-group . builtin))  atom? ((:doc-group . builtin))  T ((:doc-see))  vec? ((:doc-group . builtin))  equal? ((:doc-group . builtin))  / ((:doc-group . builtin))  eqv? ((:doc-group . builtin))  io? ((:doc-group . io))  eof-object? ((:doc-group . io))  list ((:doc-group . builtin))  apply ((:doc-group . builtin))  help ((:doc-group . docs))  separate-doc-from-body ((:doc-group . docs))  = ((:doc-group . builtin))  not ((:doc-group . builtin))  set-cdr! ((:doc-group . builtin))  fn? ((:doc-group . builtin))  help-print-header ((:doc-group . docs))  arg-counts ((:doc-group . builtin))  eq? ((:doc-group . builtin))  getprop ((:doc-group . props))  putprop ((:doc-group . props))  * ((:doc-group . builtin))  io->str ((:doc-group . io))))
+  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."  < "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)"  > "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"  __finish "A function called right before exit by the VM."  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."  defstruct "Defines a structure type with a specific name and slots.\n\nThe default underlying type is a \"named\" vector (`:type vec`),\nwhere the first element is the name of the structure's type, the\nrest are the slot values.  If the name as the first element isn't\nrequired, `:named NIL` should be used.  A list can be used instead\nof a vector by adding `:type list` option.\n\nAn example of a default constructor signature, based on structure\ndefinition:\n\n    (defstruct blah a b c) →\n      (make-blah (:a NIL) (:b NIL) (:c NIL))\n\nIt can be customized in several ways. For example:\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 `name-`.\n\nDefault predicate name (`name?`) can be changed:\n\n    ; use \"blargh?\" instead of \"blah?\"\n    (defstruct blah :predicate blargh? a b c)"  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)    
\ No newline at end of file
+  props)  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 . builtin))  *builtins* ((:doc-group . builtin))  str ((:doc-group . string))  cons ((:doc-group . builtin))  - ((:doc-group . builtin))  remprop ((:doc-group . props))  <= ((:doc-group . compare))  rand ((:doc-group . random))  negative? ((:doc-group . compare))  Instructions ((:doc-group . builtin))  file ((:doc-group . io))  rand-double ((:doc-group . random))  atom? ((:doc-group . builtin))  cdr ((:doc-group . builtin))  T ((:doc-see))  vec? ((:doc-group . builtin))  equal? ((:doc-group . builtin))  / ((:doc-group . builtin))  eqv? ((: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 . random))  = ((:doc-group . builtin))  rand-u64 ((:doc-group . random))  not ((:doc-group . builtin))  NIL ((:doc-see . T))  set-cdr! ((: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 . builtin))  getprop ((:doc-group . props))  vm-stats ((:doc-group . vm))  * ((:doc-group . builtin))  putprop ((:doc-group . props))  io->str ((:doc-group . io))))
 ripts 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 "Convert terms to a concatenated string.\n\nThis is equivalent to `(princ terms…)`, except the string is\nreturned, rather than printed."  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)."  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."  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"  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."  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
\ No newline at end of file
   props)  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 . docs))  aset! ((:doc-group . builtin))  car ((:doc-group . builtin))  *builtins* ((:doc-group . builtin))  str ((:doc-see . T))  cons ((:doc-group . builtin))  - ((:doc-group . builtin))  remprop ((:doc-group . props))  <= ((:doc-group . compare))  negative? ((:doc-group . compare))  Instructions ((:doc-group . builtin))  file ((:doc-group . io))  cdr ((:doc-group . builtin))  atom? ((:doc-group . builtin))  T ((:doc-see))  vec? ((:doc-group . builtin))  equal? ((:doc-group . builtin))  / ((:doc-group . builtin))  eqv? ((:doc-group . builtin))  io? ((:doc-group . io))  eof-object? ((:doc-group . io))  list ((:doc-group . builtin))  apply ((:doc-group . builtin))  help ((:doc-group . docs))  separate-doc-from-body ((:doc-group . docs))  = ((:doc-group . builtin))  not ((:doc-group . builtin))  set-cdr! ((:doc-group . builtin))  fn? ((:doc-group . builtin))  help-print-header ((:doc-group . docs))  arg-counts ((:doc-group . builtin))  eq? ((:doc-group . builtin))  getprop ((:doc-group . props))  putprop ((:doc-group . props))  * ((:doc-group . builtin))  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
--- /dev/null
+++ b/src/docs.sl
@@ -1,0 +1,175 @@
+(defmacro (doc-for term . doc)
+  "Define documentation for a top level term.
+
+   If `term` is a function signature and `doc` is not specified, just
+   the signature will be included in the documentation, without
+   replacing any previously defined.
+
+   First `doc` argument is supposed to be a string with the description
+   of the term.  The following arguments are expected to be optional tag
+   pairings that provide grouping for multiple symbols and \"see also\"
+   references.
+
+   Useful in cases where setting the documentation for a term can't
+   (or not preferred to) be made during the definition of said term.
+   One of those reasons is that the term is a built-in function
+   implemented in C.
+
+   Examples:
+
+       (doc-for (func arg (arg2 0))
+         \"Return something about the `arg` and `arg2`.  This is a short
+          description.
+
+          This is the longer description, following the short one.
+
+          Examples:
+
+              (func 0)   → T
+              (func 1 3) → NIL\"
+         :doc-group stuff
+         :doc-see func2)
+       (doc-for (func arg (:another-variant NIL)))"
+  :doc-group doc
+  (let* {[call (cons? term)]
+         [sym (or (and call (car term))
+                  term)]
+         [callvars (and call (cdr term))]
+         [doc (car (separate-doc-from-body doc))]}
+    (if call
+        `(sym-set-doc ',sym ',doc ',callvars)
+        `(sym-set-doc ',sym ',doc))))
+
+(doc-for (vm-stats)
+  "Print various VM-related information, such as the number of GC
+   calls so far, heap and stack size, etc."
+  :doc-group vm)
+
+(doc-for (lz-pack data (level 0))
+  "Return data compressed using Lempel-Ziv.
+
+   The data must be an array, returned value will have the same type.
+   The optional `level` is between `0` and `10`.  With `level` set to
+   `0` a simple LZSS using hashing will be performed.  Levels between
+   `1` and `9` offer a trade-off between time/space and ratio.  Level
+   `10` is optimal but very slow."
+  :doc-group compress)
+
+(doc-for (lz-unpack data :to destination))
+(doc-for (lz-unpack data :size decompressed-bytes)
+  "Return decompressed data previously compressed using lz-pack.
+
+   Either destination for the decompressed data or the expected size of
+   the decompressed data must be specified.  In the latter case a new
+   array is allocated."
+  :doc-group compress)
+
+(doc-for (rand)
+  "Return a random non-negative fixnum on its maximum range."
+  :doc-group random)
+
+(doc-for (rand-u64)
+  "Return a random integer on interval [0, 2⁶⁴-1]."
+  :doc-group random)
+
+(doc-for (rand-u32)
+  "Return a random integer on interval [0, 2³²-1]."
+  :doc-group random)
+
+(doc-for (rand-double)
+  "Return a random double on interval [0.0, 1.0]."
+  :doc-group random)
+
+(doc-for (rand-float)
+  "Return a random float on [0.0, 1.0] interval."
+  :doc-group random)
+
+(doc-for (exit (status NIL))
+  "Terminate the process with the specified status.  Does not return.
+   The status is expected to be a string in case of an error.
+
+   Examples:
+
+       (exit) ; exit with status 0 (nil on Plan 9)
+       (exit \"error\") ; exit with status 1 (\"error\" on Plan 9)"
+  :doc-group system)
+
+(doc-for (file path (:read NIL)
+                    (:write NIL)
+                    (:create NIL)
+                    (:truncate NIL)
+                    (:append NIL))
+  "Open a file for I/O.
+
+   An `io` object is returned.  Without any modes specified the file
+   is opened in read-only mode."
+  :doc-group io)
+
+(doc-for (io? term)
+  "Return `T` if `term` is of `io` type, `NIL` otherwise."
+  :doc-group io)
+
+(doc-for (io->str io)
+  "Return an in-memory `io` buffer converted to a string."
+  :doc-group io)
+
+(doc-for (io-eof? io)
+  "Return `T` if `io` is currently in the \"end of file\" state, `NIL`
+   otherwise."
+  :doc-group io)
+
+(doc-for (eof-object? term)
+  "Return `T` if `term` is `#<eof>`, `NIL` otherwise.
+
+   This object is returned by I/O functions to signal end of file,
+   where applicable."
+  :doc-group io)
+
+(doc-for (buffer)
+  "Return an in-memory buffer for I/O, of `io` type.
+
+   A buffer can be used for both reading and writing at the same
+   time."
+  :doc-group io)
+
+(doc-for NIL
+  "An empty list.  Can be used as the opposite of T in boolean
+   expressions.
+
+   Examples:
+
+       (not NIL)         → T
+       (if NIL 'yes 'no) → no
+       (car NIL)         → NIL
+       (cdr NIL)         → NIL"
+  :doc-see T)
+
+(doc-for T
+  "A boolean \"true\".
+
+   Examples:
+
+       (not T)         → NIL
+       (if T 'yes 'no) → yes"
+  :doc-see NIL)
+
+(doc-for (str . term)
+  "Return concatenation of terms formatted as strings.
+
+   This is equivalent to `(princ terms…)`, except the string is
+   returned, rather than printed.
+
+   Examples:
+
+       (str \"a\" 'b 1 #(0)) → \"ab1#(0)\""
+  :doc-group string)
+
+(doc-for (sym . term)
+  "Return a symbol with the name being the concatenation of terms
+   formatted as strings.
+
+   This is equivalent to `(sym (str terms…))`.
+
+   Examples:
+
+       (sym \"a\" 'b 1) → ab1")
--- a/src/docs_extra.sl
+++ /dev/null
@@ -1,129 +1,0 @@
-(defmacro (doc-for term . doc)
-  "Define documentation for a top level term.
-
-   If `term` is a function signature and `doc` is not specified, just
-   the signature will be included in the documentation, without
-   replacing any previously defined."
-  :doc-group docs
-  (let* {[call (cons? term)]
-         [sym (or (and call (car term))
-                  term)]
-         [callvars (and call (cdr term))]
-         [doc (car (separate-doc-from-body doc))]}
-    (if call
-        `(sym-set-doc ',sym ',doc ',callvars)
-        `(sym-set-doc ',sym ',doc))))
-
-(doc-for (vm-stats)
-  "Print various VM-related information, such as the number of GC
-   calls so far, heap and stack size, etc.")
-
-(doc-for (lz-pack data (level 0))
-  "Return data compressed using Lempel-Ziv.
-
-   The data must be an array, returned value will have the same type.
-   The optional `level` is between `0` and `10`.  With `level` set to
-   `0` a simple LZSS using hashing will be performed.  Levels between
-   `1` and `9` offer a trade-off between time/space and ratio.  Level
-   `10` is optimal but very slow.")
-
-(doc-for (lz-unpack data :to destination))
-(doc-for (lz-unpack data :size decompressed-bytes)
-  "Return decompressed data previously compressed using lz-pack.
-
-   Either destination for the decompressed data or the expected size of
-   the decompressed data must be specified.  In the latter case a new
-   array is allocated.")
-
-(doc-for (rand)
-  "Return a random non-negative fixnum on its maximum range.")
-
-(doc-for (rand-u64)
-  "Return a random integer on interval [0, 2⁶⁴-1].")
-
-(doc-for (rand-u32)
-  "Return a random integer on interval [0, 2³²-1].")
-
-(doc-for (rand-double)
-  "Return a random double on interval [0.0, 1.0].")
-
-(doc-for (rand-float)
-  "Return a random float on [0.0, 1.0] interval.")
-
-(doc-for (exit (status NIL))
-  "Terminate the process with the specified status.  Does not return.
-   The status is expected to be a string in case of an error.
-
-   Examples:
-
-       (exit)
-       (exit \"error\")")
-
-(doc-for (file path (:read NIL)
-                    (:write NIL)
-                    (:create NIL)
-                    (:truncate NIL)
-                    (:append NIL))
-  "Open a file for I/O.
-
-   An `io` object is returned.  Without any modes specified the file
-   is opened in read-only mode."
-  :doc-group io)
-
-(doc-for (io? term)
-  "Return `T` if `term` is of `io` type, `NIL` otherwise."
-  :doc-group io)
-
-(doc-for (io->str io)
-  "Return an in-memory `io` buffer converted to a string."
-  :doc-group io)
-
-(doc-for (io-eof? io)
-  "Return `T` if `io` is currently in the \"end of file\" state, `NIL`
-   otherwise."
-  :doc-group io)
-
-(doc-for (eof-object? term)
-  "Return `T` if `term` is `#<eof>`, `NIL` otherwise.
-
-   This object is returned by I/O functions to signal end of file,
-   where applicable."
-  :doc-group io)
-
-(doc-for (buffer)
-  "Return an in-memory buffer for I/O, of `io` type.
-
-   A buffer can be used for both reading and writing at the same
-   time."
-  :doc-group io)
-
-(doc-for NIL
-  "An empty list. Also used as the opposite of T.
-
-   Examples:
-
-       (not NIL)         → T
-       (if NIL 'yes 'no) → no
-       (car NIL)         → NIL
-       (cdr NIL)         → NIL")
-
-(doc-for T
-  "A boolean \"true\".
-
-   Examples:
-
-       (not T)         → NIL
-       (if T 'yes 'no) → yes"
-  :doc-see NIL)
-
-(doc-for (str . term)
-  "Convert terms to a concatenated string.
-
-   This is equivalent to `(princ terms…)`, except the string is
-   returned, rather than printed."
-  :doc-see T)
-
-(doc-for (sym . term)
-  "Convert terms to a symbol.
-
-   This is equivalent to `(sym (str terms…))`.")
--- a/src/system.sl
+++ b/src/system.sl
@@ -137,7 +137,7 @@
   "Take a list of terms and return a pair `(doc . body)`, where the first
    element contains a list of documentation-related terms, and the second
    contains the rest of the terms."
-  :doc-group docs
+  :doc-group doc
   (def (doc? kw)
     (and (> (length kw) 5)
          (= (aref kw 1) #\d)
@@ -154,7 +154,7 @@
 
 (def (sym-set-doc symbol doc-seq . formals-list)
   "Set the documentation for the symbol."
-  :doc-group docs
+  :doc-group doc
   (let* {[doc-only (str? doc-seq)]
          [doc (if doc-only doc-seq (car doc-seq))]
          [extra (if doc-only NIL (cdr doc-seq))]}
@@ -193,7 +193,7 @@
 
 (def (help-print-header term sigs)
   "Format and print signature(s) of the term for `(help term)` output."
-  :doc-group docs
+  :doc-group doc
   (if sigs
       (for-each (λ (sig) (print (cons term sig))
                          (newline))
@@ -204,7 +204,7 @@
 
 (defmacro (help term (:print-header help-print-header))
   "Display documentation for the specified term, if available."
-  :doc-group docs
+  :doc-group doc
   (let* {[doc (getprop term '*doc*)]
          [formals-list (getprop term '*formals-list* NIL)]}
     (if (or doc formals-list)
--- a/tools/mkboot1.sl
+++ b/tools/mkboot1.sl
@@ -1,7 +1,7 @@
 (load "../src/builtins.sl")
 (load "../src/instructions.sl")
 (load "../src/system.sl")
-#.(load "../src/docs_extra.sl")
+#.(load "../src/docs.sl")
 #.(load "../src/docs_ops.sl")
 (load "../src/compiler.sl")
 (make-system-image "sl.boot")