shithub: sl

Download patch

ref: c141adb1002f51f9754b288de7102f7d76dd5373
parent: 5090b2fec4c35cfc5b41fcb32e8efc33a078567f
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Mar 18 22:39:09 EDT 2025

refactor gen.lsp, add more docs; simplify (help ...)

--- a/boot/sl.boot
+++ b/boot/sl.boot
@@ -12,40 +12,35 @@
               #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)
-            *properties* #table(*funvars* #table(zero? ((x))  >= ((a . rest))  void? ((x))  identity ((x))  length= ((lst
+            *properties* #table(*funvars* #table(zero? ((x))  bound? ((symbol))  void? ((x))  >= ((a . rest))  identity ((x))  1+ ((n))  length= ((lst
   n))  positive? ((x))  doc-for ((term (doc NIL)))  io-eof? ((io))  car ((lst))  <= ((a . rest))  str (term)  remprop ((symbol
-  key))  negative? ((x))  void (rest)  rand (NIL)  nan? ((x))  sym (term)  file ((path (:read NIL)
-                                                                                       (:write NIL)
-                                                                                       (:create NIL)
-                                                                                       (:truncate
-                                                                                        NIL)
-                                                                                       (:append NIL)))  rand-double (NIL)  exit ((status))  1- ((n))  cdr ((lst))  + ((num…))  > ((a . rest))  __finish ((status))  lz-unpack ((data
-  :to destination)
-  (data :size decompressed-bytes))  io? ((term))  defstruct ((name doc options… (slot-1 DEFAULT)
-                                                                   slot-2 (slot-3 :read-only))
-                                                             (name (:type vec) (:named T) (:constructor
-  T)
-                                                                   (:conc-name NIL) (:predicate NIL) . slots))  eof-object? ((term))  help ((term))  rand-u32 (NIL)  = ((a . rest))  rand-u64 (NIL)  buffer (NIL)  add-exit-hook ((fun))  /= ((a . rest))  lz-pack ((data
-  (level 0)))  rand-float (NIL)  *prompt* (NIL)  cons? ((value))  putprop ((symbol key val))  * ((num…))  vm-stats (NIL)  getprop ((symbol
-  key (def NIL)))  1+ ((n))  io->str ((io)))  *doc* #table(*properties* "All properties of symbols recorded with `putprop` are recorded in this table."  >= "Return `T` if the arguments are in non-increasing order (previous\none is greater than or equal to the next one)."  void? "Return `T` if `x` is `#<void>`, `NIL` otherwise."  zero? "Return `T` if `x` is zero."  identity "Return `x`."  length= "Perform a bounded length test.\n\nUse this instead of `(= (length lst) 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."  io-eof? "Return `T` if `io` is currently in the \"end of file\" state, `NIL`\notherwise."  car "Return the first element of a list or `NIL` if not available."  *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."  remprop "Remove a property value associated with a symbol."  <= "Return `T` if the arguments are in non-decreasing order (previous\none is less than or equal to the next one)."  negative? "Return `T` if `x` is negative."  rand "Return a random non-negative fixnum on its maximum range."  sym "Convert terms to a symbol.\n\nThis is equivalent to `(sym (str terms…))`."  nan? "Return `T` if the argument is *NaN*, regardless of the sign."  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."  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]."  exit "Terminate the process with the specified status. Does not return."  1- "Equivalent to `(- n 1)`."  cdr "Return the tail of a list or `NIL` if not available."  + "Return sum of the numbers or `0` with no arguments."  T "A boolean \"true\".\n\n(not T)         → NIL\n(if T 'yes 'no) → 'yes"  > "Return `T` if the arguments are in strictly decreasing order (previous\none is greater than the next one)."  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."  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."  help "Display documentation for the specified term, if available."  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\nD
\ No newline at end of file
+  key))  negative? ((x))  rand (NIL)  sym (term)  nan? ((x) (v))  void (rest)  file ((path (:read
+  NIL)
+  (:write NIL) (:create NIL) (:truncate NIL) (:append NIL)))  fixnum? ((v))  rand-double (NIL)  exit ((status))  cdr ((lst))  + ((num…))  vec? ((v))  for ((min
+  max fn))  lz-unpack ((data :to destination)
+                       (data :size decompressed-bytes))  > ((a . rest))  1- ((n))  io? ((term))  defstruct ((name
+  doc options… (slot-1 DEFAULT) slot-2 (slot-3 :read-only))
+  (name (:type vec) (:named T) (:constructor T) (:conc-name NIL) (:predicate NIL) . slots))  eof-object? ((term))  help ((term))  __finish ((status))  rand-u32 (NIL)  = ((a . rest)
+  (num…))  rand-u64 (NIL)  buffer (NIL)  compare ((x y))  num? ((v))  /= ((a . rest))  fn? ((v))  add-exit-hook ((fun))  lz-pack ((data
+  (level 0)))  rand-float (NIL)  *prompt* (NIL)  builtin? ((v))  cons? ((value))  vm-stats (NIL)  * ((num…))  putprop ((symbol
+  key val))  getprop ((symbol key (def NIL)))  aref ((seq subscript…))  io->str ((io)))  *doc* #table(io->str "Return an in-memory `io` buffer converted to a string."  bound? "Return `T` if `symbol` has a value associated with it, `NIL` otherwise."  io-eof? "Return `T` if `io` is currently in the \"end of file\" state, `NIL`\notherwise."  sym "Convert terms to a symbol.\n\nThis is equivalent to `(sym (str terms…))`."  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."  > "Return `T` if the arguments are in strictly decreasing order (previous\none is greater than the next one)."  + "Return sum of the numbers or `0` with no arguments."  __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\nsingle argument, which is (usually) `0` on success and any other\nnumber on error."  rand-float "Return a random float on [0.0, 1.0] interval."  builtin? "Return `T` if `v` is a built-in function, `NIL` otherwise."  cons? "Return `T` if the value is a cons cell, `NIL` otherwise."  1+ "Equivalent to `(+ n 1)`."  aref "Return the sequence element by the subscripts.  The sequence can be an\narray, vector or a list.\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 table."  zero? "Return `T` if `x` is zero."  >= "Return `T` if the arguments are in non-increasing order (previous\none is greater than or equal to the next one)."  void? "Return `T` if `x` is `#<void>`, `NIL` otherwise."  length= "Perform 
\ No newline at end of file
 efault predicate name (`name?`) can be changed:\n\n    ; use \"blargh?\" instead of \"blah?\"\n    (defstruct blah :predicate blargh? a b c)"  rand-u32 "Return a random integer on interval [0, 2³²-1]."  = "Return `T` if the arguments are equal."  rand-u64 "Return a random integer on interval [0, 2⁶⁴-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."  NIL "An empty list. Also used as the opposite of T.\n\n(not NIL)         → T\n(if NIL 'yes 'no) → 'no\n(car NIL)         → NIL\n(cdr NIL)         → NIL"  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\nsingle argument, which is (usually) `0` on success and any other\nnumber on error."  /= "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."  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."  rand-float "Return a random float on [0.0, 1.0] interval."  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 `#;> `."  cons? "Return `T` if the value is a cons cell."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  getprop "Get a property value associated with a symbol or `def` if missing."  1+ "Equivalent to `(+ n 1)`."  io->str "Return an in-memory `io` buffer converted to a string."))
             *syntax-environment* #table(bcode:nconst #fn("n1200r2e3:" #(aref))  doc-for #fn("\x8710002000W1000J60q?140B86;35040<;J404086;35040=863H020212287e212288e2e4e2:20212287e21e3e2:" #(void
   sym-set-doc quote))  with-input-from #fn("z12021e1220e2e1e12315163:" #(#fn(nconc) with-bindings
                                                                          *io-in* #fn(copy-list)))  unless #fn("z1200q211Pe4:" #(if
   begin))  defmacro #fn("z170151863D0710<860=5341=?1@30q42223240<e22526e10=e12715153e3e2:" #(value-get-doc
-f the list of exit hooks.\n\nOn shutdown each exit hook is called with the exit status as a\nsingle argument, which is (usually) `0` on success and any other\nnumber on error."  /= "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."  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."  rand-float "Return a random float on [0.0, 1.0] interval."  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 `#;> `."  cons? "Return `T` if the value is a cons cell."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  getprop "Get a property value associated with a symbol or `def` if missing."  1+ "Equivalent to `(+ n 1)`."  io->str "Return an in-memory `io` buffer converted to a string."))
+mprop "Remove a property value associated with a symbol."  <= "Return `T` if the arguments are in non-decreasing order (previous\none is less than or equal to the next one)."  negative? "Return `T` if `x` is negative."  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."  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 tail of a list or `NIL` if not available."  T "A boolean \"true\".\n\n(not T)         → NIL\n(if T 'yes 'no) → 'yes"  vec? "Return `T` if `v` is a vector, `NIL` otherwise."  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."  help "Display documentation for the specified term, if available."  rand-u32 "Return a random integer on interval [0, 2³²-1]."  = "Numerical equality test.  Return `T` if all numbers are equal,"  rand-u64 "Return a random integer on interval [0, 2⁶⁴-1]."  NIL "An empty list. Also used as the opposite of T.\n\n(not NIL)         → T\n(if NIL 'yes 'no) → 'no\n(car NIL)         → NIL\n(cdr NIL)         → NIL"  /= "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."  fn? "Return `T` if `v` is a function, `NIL` otherwise."  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 `#;> `."  getprop "Get a property value associated with a symbol or `def` if missing."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  identity "Return `x`."))
 ccess and any other\nnumber on error."  /= "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."  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."  rand-float "Return a random float on [0.0, 1.0] interval."  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 `#;> `."  cons? "Return `T` if the value is a cons cell."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  getprop "Get a property value associated with a symbol or `def` if missing."  1+ "Equivalent to `(+ n 1)`."  io->str "Return an in-memory `io` buffer converted to a string."))
             *syntax-environment* #table(bcode:nconst #fn("n1200r2e3:" #(aref))  doc-for #fn("\x8710002000W1000J60q?140B86;35040<;J404086;35040=863H020212287e212288e2e4e2:20212287e21e3e2:" #(void
-ween time/space and ratio.  Level\n`10` is optimal but very slow."  rand-float "Return a random float on [0.0, 1.0] interval."  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 `#;> `."  cons? "Return `T` if the value is a cons cell."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  getprop "Get a property value associated with a symbol or `def` if missing."  1+ "Equivalent to `(+ n 1)`."  io->str "Return an in-memory `io` buffer converted to a string."))
+e, REPL will not print\nit."  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 tail of a list or `NIL` if not available."  T "A boolean \"true\".\n\n(not T)         → NIL\n(if T 'yes 'no) → 'yes"  vec? "Return `T` if `v` is a vector, `NIL` otherwise."  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."  help "Display documentation for the specified term, if available."  rand-u32 "Return a random integer on interval [0, 2³²-1]."  = "Numerical equality test.  Return `T` if all numbers are equal,"  rand-u64 "Return a random integer on interval [0, 2⁶⁴-1]."  NIL "An empty list. Also used as the opposite of T.\n\n(not NIL)         → T\n(if NIL 'yes 'no) → 'no\n(car NIL)         → NIL\n(cdr NIL)         → NIL"  /= "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."  fn? "Return `T` if `v` is a function, `NIL` otherwise."  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 `#;> `."  getprop "Get a property value associated with a symbol or `def` if missing."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  identity "Return `x`."))
 uctions mapped to their expected arguments count."  *prompt* "Function called by REPL to signal the user input is required.\n\nDefault function prints `#;> `."  cons? "Return `T` if the value is a cons cell."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  getprop "Get a property value associated with a symbol or `def` if missing."  1+ "Equivalent to `(+ n 1)`."  io->str "Return an in-memory `io` buffer converted to a string."))
             *syntax-environment* #table(bcode:nconst #fn("n1200r2e3:" #(aref))  doc-for #fn("\x8710002000W1000J60q?140B86;35040<;J404086;35040=863H020212287e212288e2e4e2:20212287e21e3e2:" #(void
   sym-set-doc quote))  with-input-from #fn("z12021e1220e2e1e12315163:" #(#fn(nconc) with-bindings
                                                                          *io-in* #fn(copy-list)))  unless #fn("z1200q211Pe4:" #(if
   begin))  defmacro #fn("z170151863D0710<860=5341=?1@30q42223240<e22526e10=e12715153e3e2:" #(value-get-doc
-e:nconst #fn("n1200r2e3:" #(aref))  doc-for #fn("\x8710002000W1000J60q?140B86;35040<;J404086;35040=863H020212287e212288e2e4e2:20212287e21e3e2:" #(void
-  sym-set-doc quote))  with-input-from #fn("z12021e1220e2e1e12315163:" #(#fn(nconc) with-bindings
-                                                                         *io-in* #fn(copy-list)))  unless #fn("z1200q211Pe4:" #(if
-  begin))  defmacro #fn("z170151863D0710<860=5341=?1@30q42223240<e22526e10=e12715153e3e2:" #(value-get-doc
+-u32 "Return a random integer on interval [0, 2³²-1]."  = "Numerical equality test.  Return `T` if all numbers are equal,"  rand-u64 "Return a random integer on interval [0, 2⁶⁴-1]."  NIL "An empty list. Also used as the opposite of T.\n\n(not NIL)         → T\n(if NIL 'yes 'no) → 'no\n(car NIL)         → NIL\n(cdr NIL)         → NIL"  /= "Return `T` if not all arguments are equal. Shorthand for `(not (= …))`."  fn? "Return `T` if `v` is a function, `NIL` otherwise."  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 `#;> `."  getprop "Get a property value associated with a symbol or `def` if missing."  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 numbers or `1` with no arguments."  putprop "Associate a property value with a symbol."  identity "Return `x`."))
+            *syntax-environment* #table(bcode:nconst #fn("n1200r2e3:" #(aref))  doc-for #fn("\x8710002000W1000J60q?140B86;35040<;J404086;35040=863H020212287e212288e2e4e2:20212287e21e3e2:" #(void
+  sym-set-doc quote))  with-input-from #fn("z12021e1220e2e1e12315163:" #(#fn(nconc) with-bindings
 dr caadr let if cddr #:g20) cond-clauses->if)))  do #fn("z21<2071052207205220230522425268827872829e12:1=51522829e12:82512825e18:52e153e4e3e2e12825e18952e3:" #(#fn(map)
   car cadr #fn("n170051B38071061:0<:" #(cddr caddr)) letrec #:g351 λ if #fn(nconc) begin #fn(copy-list)))  mark-label #fn("n22002122e21e4:" #(emit
   quote label))  with-bindings #fn("z12071052207205220230522425e12076888653e12720288687535129242:e12715152242:e127202;8688535152e3e164:" #(#fn(map)
@@ -58,7 +53,7 @@
 ef))  > #fn("z12021e12273151510e163:" #(#fn(nconc)
   < #fn(copy-list) reverse!))  when #fn("z1200211Pqe4:" #(if begin))  quasiquote #fn("n1700E62:" #(bq-process))  help #fn("n1700215285;3;042285235270024q5387;3>0487<B;350487863q07586<51486=3Q0262786=52478504883907850@30q@30q488360q@607850@30q4883e086=360q@;07850478504752951478504262:0>1885247850@30q486;J50488360q@>0752;0524785047<60:" #(getprop
   *doc* #fn(str-split) "\n" *funvars* princ #fn(for-each)
-524785047<60:" #(getprop
+z0Ib520852185>1_51485<061:" #(#0=#fn("z0I:" #() void)
 e
   princ "    " print)) "no help for " void))  defstruct #fn("O10005000*///W1000J7071?14W2000J60D?24W3000J60D?34W4000J60q?44W5000J60q?54z6IIb;228;230>1_5142224?<5142586<51;360486<8=;360486=;J50486268>5127288>528<8>512912:5285;J:042902:5283;3\\0483H;3M0483DQ;3:04292;052;J504838AP;J5048382;36040e184;J:042<02=522>2?e12@8C2Ae22B8B2Ae22C2D2E8Ee2e22F2G2AEe32E0e2e3e32H2I2Ae2268E518?Me3e4e3e12J8=2K2E0e28=e3e3e18D3X02@8D2>1e12>2Ee12L8E5152e12L8@5153e3@30qe12L7M2N8;8A8@8F8C8E0>78?525165:" #(#(NIL
   NIL :named 1 :conc-name 3 :type 0 NIL NIL NIL NIL NIL NIL :predicate 4 NIL NIL NIL NIL NIL NIL
@@ -67,7 +62,7 @@
 28552485:" #(cddr #fn(for-each)
                                                           #fn("n17002152340q:722324A<25F2605661:" #(member
   (:read-only) error #fn(str) "invalid option in slot " " of struct " ": "))) slot-opts)
-3=071228652@30q423242586522087<51390q87P@408762:" #(#fn(keyword?)
+#fn("n1200Ee3:" #(aref))  make-label #fn("n120e1:" #(gensym))  bcode:cenv #fn("n1200r3e3:" #(aref))  > #fn("z12021e12273151510e163:" #(#fn(nconc)
 st*) #fn(sym) #\:))) tokw)
   #fn(str?) #fn(length) #fn(map) #fn("n10B3500<:0:" #())
   #fn(sym) #\? "make-" #fn(str) "-" #fn(nconc) begin def s and or not quote eq? aref = length when
@@ -451,7 +446,7 @@
                                                                            #fn(str-length)
                                                                                         #fn(str-sub)) str-trim)
             sym-set-doc #fn("z220Z3\x9f013\x9b0211225287<87=732489528:;3H04258:5125768:27285351~8:;3?04292:8;>1895270888<P22527;02<8=53^1^1^1^1^1^1^1@30q482B3\\07=02>q537?2@87>182527;02>2A87885253^1^1@30q47B60:" #(str-join
-^1^1@30q482B3\\07=02>q537?2@87>182527;02>2A87885253^1^1@30q47B60:" #(str-join
+   str-map #fn("n2205021151EI8887L23O0422860231885251524748851?8@\f/^14258661:" #(#fn(buffer)
 "\n" any #fn("n1E20051L2;3@040EG21l2;34040:" #(#fn(length) #\space))
   #fn(length) str-trim " " "" #fn(map) #fn("n170A2105152390220A62:0:" #(<= #fn(length)
                                                                         #fn(str-sub))) putprop
--- a/src/opcodes.c
+++ b/src/opcodes.c
@@ -1,38 +1,38 @@
 #include "sl.h"
 
 const Builtin builtins[N_OPCODES] = {
-	[OP_NANP] = {"nan?", 1},
-	[OP_SETCAR] = {"set-car!", 2},
-	[OP_VECP] = {"vec?", 1},
-	[OP_CDR] = {"cdr", 1},
-	[OP_FNP] = {"fn?", 1},
-	[OP_CADR] = {"cadr", 1},
-	[OP_SETCDR] = {"set-cdr!", 2},
-	[OP_EQ] = {"eq?", 2},
-	[OP_APPLY] = {"apply", -2},
-	[OP_ASET] = {"aset!", -3},
-	[OP_CONSP] = {"cons?", 1},
-	[OP_ATOMP] = {"atom?", 1},
-	[OP_NOT] = {"not", 1},
-	[OP_LIST] = {"list", ANYARGS},
-	[OP_NUMP] = {"num?", 1},
-	[OP_CONS] = {"cons", 2},
-	[OP_BOUNDP] = {"bound?", 1},
-	[OP_LT] = {"<", -1},
-	[OP_CAR] = {"car", 1},
-	[OP_EQV] = {"eqv?", 2},
-	[OP_IDIV] = {"div0", 2},
-	[OP_FIXNUMP] = {"fixnum?", 1},
-	[OP_NUMEQ] = {"=", -1},
 	[OP_BUILTINP] = {"builtin?", 1},
+	[OP_FIXNUMP] = {"fixnum?", 1},
+	[OP_COMPARE] = {"compare", 2},
 	[OP_SUB] = {"-", -1},
+	[OP_LT] = {"<", -1},
+	[OP_BOUNDP] = {"bound?", 1},
+	[OP_CAR] = {"car", 1},
 	[OP_VEC] = {"vec", ANYARGS},
-	[OP_COMPARE] = {"compare", 2},
+	[OP_DIV0] = {"div0", 2},
+	[OP_EQUALP] = {"equal?", 2},
+	[OP_DIV] = {"/", -1},
+	[OP_SYMP] = {"sym?", 1},
 	[OP_FOR] = {"for", 3},
-	[OP_MUL] = {"*", ANYARGS},
 	[OP_ADD] = {"+", ANYARGS},
 	[OP_AREF] = {"aref", -2},
-	[OP_DIV] = {"/", -1},
-	[OP_EQUAL] = {"equal?", 2},
-	[OP_SYMP] = {"sym?", 1},
+	[OP_MUL] = {"*", ANYARGS},
+	[OP_VECP] = {"vec?", 1},
+	[OP_CDR] = {"cdr", 1},
+	[OP_NUMEQP] = {"=", -1},
+	[OP_NANP] = {"nan?", 1},
+	[OP_EQP] = {"eq?", 2},
+	[OP_ATOMP] = {"atom?", 1},
+	[OP_SETCAR] = {"set-car!", 2},
+	[OP_ASET] = {"aset!", -3},
+	[OP_CONSP] = {"cons?", 1},
+	[OP_CONS] = {"cons", 2},
+	[OP_NOT] = {"not", 1},
+	[OP_NUMP] = {"num?", 1},
+	[OP_EQVP] = {"eqv?", 2},
+	[OP_LIST] = {"list", ANYARGS},
+	[OP_FNP] = {"fn?", 1},
+	[OP_CADR] = {"cadr", 1},
+	[OP_SETCDR] = {"set-cdr!", 2},
+	[OP_APPLY] = {"apply", -2},
 };
--- a/src/opcodes.h
+++ b/src/opcodes.h
@@ -32,7 +32,7 @@
 	OP_SETCDR,
 	OP_KEYARGS,
 	OP_CONS,
-	OP_EQ,
+	OP_EQP,
 	OP_SYMP,
 	OP_NOT,
 	OP_CADR,
@@ -50,8 +50,8 @@
 	OP_JMPL,
 	OP_BRNL,
 	OP_BOX,
-	OP_EQV,
-	OP_EQUAL,
+	OP_EQVP,
+	OP_EQUALP,
 	OP_LIST,
 	OP_APPLY,
 	OP_ADD,
@@ -58,8 +58,8 @@
 	OP_SUB,
 	OP_MUL,
 	OP_DIV,
-	OP_IDIV,
-	OP_NUMEQ,
+	OP_DIV0,
+	OP_NUMEQP,
 	OP_COMPARE,
 	OP_ARGC,
 	OP_VEC,
@@ -87,7 +87,7 @@
 	OP_AREF,
 	OP_BOXL,
 	OP_OPTARGS,
-	OP_EOF_OBJECT,
+	OP_DUMMY_EOF,
 	N_OPCODES
 }sl_op;
 
--- a/src/sl.h
+++ b/src/sl.h
@@ -348,7 +348,7 @@
 	sl_nil = builtin(OP_LOADNIL),
 	sl_t = builtin(OP_LOADT),
 	sl_void = builtin(OP_LOADVOID),
-	sl_eof = builtin(OP_EOF_OBJECT),
+	sl_eof = builtin(OP_DUMMY_EOF),
 };
 
 enum {
--- a/src/system.lsp
+++ b/src/system.lsp
@@ -163,29 +163,17 @@
 (defmacro (help term)
   "Display documentation for the specified term, if available."
   (let* {[doc (getprop term '*doc*)]
-         [lines (and doc (str-split doc "\n"))]
          [funvars (getprop term '*funvars* nil)]
          [fvs (and funvars (cons? (car funvars)) funvars)]}
-    (when lines
-      (princ (car lines))
-      (if (cdr lines)
-          (begin (for-each (λ (line) (newline) (princ line))
-                           (cdr lines))
-                 (newline)
-                 (when fvs
-                   (newline))))
-          (unless fvs
-            (newline)))
     (when fvs
-      (unless (cdr lines)
-        (newline)
-        (newline))
-      (princ "Signature:")
-      (newline)
-      (for-each (λ (fv) (newline) (princ "    ") (print (cons term fv)))
+      (for-each (λ (fv) (print (cons term fv))
+                        (newline))
                 fvs)
       (newline))
-    (unless (or lines fvs)
+    (when doc
+      (princ doc)
+      (newline))
+    (unless (or doc fvs)
       (princ "no help for " term)
       (newline))
     (void)))
--- a/src/vm.h
+++ b/src/vm.h
@@ -76,7 +76,7 @@
 		case OP_AREF: goto LABEL(apply_aref);
 		case OP_ASET: goto LABEL(apply_aset);
 		case OP_LT: goto LABEL(apply_lt);
-		case OP_NUMEQ: goto LABEL(apply_numeq);
+		case OP_NUMEQP: goto LABEL(apply_numeqp);
 		default:
 #if defined(COMPUTED_GOTO)
 			goto *ops[i];
@@ -573,7 +573,7 @@
 	NEXT_OP;
 }
 
-OP(OP_EQUAL) {
+OP(OP_EQUALP) {
 	sl_v a = sp[-2], b = sp[-1];
 	sp--;
 	sp[-1] = (a == b || sl_compare(a, b, true) == 0) ? sl_t : sl_nil;
@@ -640,7 +640,7 @@
 	NEXT_OP;
 }
 
-OP(OP_EQ)
+OP(OP_EQP)
 	sp[-2] = sp[-2] == sp[-1] ? sl_t : sl_nil;
 	sp--;
 	NEXT_OP;
@@ -662,9 +662,9 @@
 	NEXT_OP;
 }
 
-OP(OP_NUMEQ) {
+OP(OP_NUMEQP) {
 	n = *ip++;
-LABEL(apply_numeq):;
+LABEL(apply_numeqp):;
 	int i = n;
 	sl_v a = sp[-i], b, v;
 	for(v = sl_t; i > 1; a = b){
@@ -761,7 +761,7 @@
 	NEXT_OP;
 }
 
-OP(OP_IDIV) {
+OP(OP_DIV0) {
 	sl_v a = sp[-2];
 	sl_v b = sp[-1];
 	if(sl_unlikely(b == 0)){
@@ -885,7 +885,7 @@
 	ip += 4;
 	NEXT_OP;
 
-OP(OP_EQV) {
+OP(OP_EQVP) {
 	sl_v a = sp[-2], b = sp[-1];
 	sp[-2] = (a == b || (leafp(a) && leafp(b) && sl_compare(a, b, true) == 0)) ? sl_t : sl_nil;
 	sp--;
--- a/tools/gen.lsp
+++ b/tools/gen.lsp
@@ -1,173 +1,250 @@
+(defstruct op name cname nargs closure docs)
 
-(def opcodes '(
-  ; C opcode, lisp compiler opcode, arg count, builtin lambda, DOC (NEW)
-    OP_LOADA0         loada0     nil     nil nil
-    OP_LOADA1         loada1     nil     nil nil
-    OP_LOADV          loadv      nil     nil nil
-    OP_BRN            brn        nil     nil nil
-    OP_POP            pop        nil     nil nil
-    OP_CALL           call       nil     nil nil
-    OP_TCALL          tcall      nil     nil nil
-    OP_LOADG          loadg      nil     nil nil
-    OP_LOADA          loada      nil     nil nil
-    OP_LOADC          loadc      nil     nil nil
-    OP_RET            ret        nil     nil nil
-    OP_DUP            dup        nil     nil nil
-    OP_CAR            car        1       (λ (x) (car x)) (
-     ((lst) "Return the first element of a list or `NIL` if not available."))
-    OP_CDR            cdr        1       (λ (x) (cdr x)) (
-     ((lst) "Return the tail of a list or `NIL` if not available."))
-    OP_CLOSURE        closure    nil     nil nil
-    OP_SETA           seta       nil     nil nil
-    OP_JMP            jmp        nil     nil nil
-    OP_LOADC0         loadc0     nil     nil nil
-    OP_CONSP          cons?      1       (λ (x) (cons? x)) (
-     ((value) "Return `T` if the value is a cons cell."))
-    OP_BRNE           brne       nil     nil nil
-    OP_LOADT          loadt      nil     nil nil
-    OP_LOAD0          load0      nil     nil nil
-    OP_LOADC1         loadc1     nil     nil nil
-    OP_AREF2          aref2      nil     nil nil
-    OP_ATOMP          atom?      1       (λ (x) (atom? x)) nil
-    OP_LOADVOID       loadvoid   nil     nil nil
-    OP_BRNN           brnn       nil     nil nil
-    OP_LOAD1          load1      nil     nil nil
-    OP_LT             <          -1      (λ rest (apply < rest)) nil
-    OP_ADD2           add2       nil     nil nil
-    OP_SETCDR         set-cdr!   2       (λ (x y) (set-cdr! x y)) nil
-    OP_KEYARGS        keyargs    nil     nil nil
-    OP_CONS           cons       2       (λ (x y) (cons x y)) nil
-    OP_EQ             eq?        2       (λ (x y) (eq? x y)) nil
-    OP_SYMP           sym?       1       (λ (x) (sym? x)) nil
-    OP_NOT            not        1       (λ (x) (not x)) nil
-    OP_CADR           cadr       1       (λ (x) (cadr x)) nil
-    OP_NEG            neg        nil     nil nil
-    OP_NANP           nan?       1       (λ (x) (nan? x)) nil
-    OP_BRBOUND        brbound    nil     nil nil
-    OP_NUMP           num?       1       (λ (x) (num? x)) nil
-    OP_FIXNUMP        fixnum?    1       (λ (x) (fixnum? x)) nil
-    OP_BOUNDP         bound?     1       (λ (x) (bound? x)) nil
-    OP_BUILTINP       builtin?   1       (λ (x) (builtin? x)) nil
-    OP_FNP            fn?        1       (λ (x) (fn? x)) nil
-    OP_VECP           vec?       1       (λ (x) (vec? x)) nil
-    OP_SHIFT          shift      nil     nil nil
-    OP_SETCAR         set-car!   2       (λ (x y) (set-car! x y)) nil
-    OP_JMPL           jmp.l      nil     nil nil
-    OP_BRNL           brn.l      nil     nil nil
-    OP_BOX            box        nil     nil nil
-    OP_EQV            eqv?       2       (λ (x y) (eqv? x y)) nil
-    OP_EQUAL          equal?     2       (λ (x y) (equal? x y)) nil
-    OP_LIST           list       ANYARGS (λ rest rest) nil
-    OP_APPLY          apply      -2      (λ rest (apply apply rest)) nil
-    OP_ADD            +          ANYARGS (λ rest (apply + rest)) (
-      ((num…) "Return sum of the numbers or `0` with no arguments."))
-    OP_SUB            -          -1      (λ rest (apply - rest)) nil
-    OP_MUL            *          ANYARGS (λ rest (apply * rest))  (
-      ((num…) "Return product of the numbers or `1` with no arguments."))
-    OP_DIV            /          -1      (λ rest (apply / rest)) nil
-    OP_IDIV           div0       2       (λ rest (apply div0 rest)) nil
-    OP_NUMEQ          =          -1      (λ rest (apply = rest)) nil
-    OP_COMPARE        compare    2       (λ (x y) (compare x y)) nil
-    OP_ARGC           argc       nil     nil nil
-    OP_VEC            vec        ANYARGS (λ rest (apply vec rest)) nil
-    OP_ASET           aset!      -3      (λ rest (apply aset! rest)) nil
-    OP_LOADNIL        loadnil    nil     nil nil
-    OP_LOADI8         loadi8     nil     nil nil
-    OP_LOADVL         loadv.l    nil     nil nil
-    OP_LOADGL         loadg.l    nil     nil nil
-    OP_LOADAL         loada.l    nil     nil nil
-    OP_LOADCL         loadc.l    nil     nil nil
-    OP_SETG           setg       nil     nil nil
-    OP_SETGL          setg.l     nil     nil nil
-    OP_SETAL          seta.l     nil     nil nil
-    OP_VARGC          vargc      nil     nil nil
-    OP_TRYCATCH       trycatch   nil     nil nil
-    OP_FOR            for        3       (λ (a b f) (for a b (λ (x) (f x)))) nil
-    OP_TAPPLY         tapply     nil     nil nil
-    OP_SUB2           sub2       nil     nil nil
-    OP_ARGCL          argc.l     nil     nil nil
-    OP_VARGCL         vargc.l    nil     nil nil
-    OP_CALLL          call.l     nil     nil nil
-    OP_TCALLL         tcall.l    nil     nil nil
-    OP_BRNEL          brne.l     nil     nil nil
-    OP_BRNNL          brnn.l     nil     nil nil
-    OP_AREF           aref       -2      (λ rest (apply aref rest)) nil
-    OP_BOXL           box.l      nil     nil nil
-    OP_OPTARGS        optargs    nil     nil nil
-    OP_EOF_OBJECT     dummy_eof  nil     nil nil
+(def (rune-alphanumeric? r)
+  (or (rune-alphabetic? r)
+      (rune-numeric? r)))
+
+(def (name->cname name)
+  (let {[cname (buffer)]}
+    (for 0 (1- (length name))
+      (λ (i) (let {[r (rune (aref name i))]}
+               (io-write cname
+                         (cond [(rune-alphanumeric? r) (rune-upcase r)]
+                               [(= r #\?) #\P]
+                               [(= r #\_) #\_]
+                               [else ""])))))
+    (io->str cname)))
+
+(defmacro (op symbol (nargs NIL) (closure NIL) (docs NIL) (:cname NIL))
+  (let ((name (str symbol)))
+    `(make-op :name ,name
+              :cname ,(str "OP_" (or cname (name->cname name)))
+              :nargs ,nargs
+              :closure ',closure
+              :docs ,docs)))
+
+(def ops (vec
+  (op loada0)
+  (op loada1)
+  (op loadv)
+  (op brn)
+  (op pop)
+  (op call)
+  (op tcall)
+  (op loadg)
+  (op loada)
+  (op loadc)
+  (op ret)
+  (op dup)
+  (op car 1 (λ (x) (car x))
+    '{[(lst)
+       "Return the first element of a list or `NIL` if not available."]})
+  (op cdr 1 (λ (x) (cdr x))
+    '{[(lst)
+       "Return the tail of a list or `NIL` if not available."]})
+  (op closure)
+  (op seta)
+  (op jmp)
+  (op loadc0)
+  (op cons? 1 (λ (x) (cons? x))
+    '{[(value)
+       "Return `T` if the value is a cons cell, `NIL` otherwise."]})
+  (op brne)
+  (op loadt)
+  (op load0)
+  (op loadc1)
+  (op aref2)
+  (op atom? 1 (λ (x) (atom? x)))
+  (op loadvoid)
+  (op brnn)
+  (op load1)
+  (op < -1 (λ rest (apply < rest))
+    :cname "LT")
+  (op add2)
+  (op set-cdr! 2 (λ (x y) (set-cdr! x y)))
+  (op keyargs)
+  (op cons 2 (λ (x y) (cons x y)))
+  (op eq? 2 (λ (x y) (eq? x y)))
+  (op sym? 1 (λ (x) (sym? x)))
+  (op not 1 (λ (x) (not x)))
+  (op cadr 1 (λ (x) (cadr x)))
+  (op neg)
+  (op nan? 1 (λ (x) (nan? x))
+    '{[(v)
+       "Return `T` if `v` is a floating point representation of NaN, either
+        negative or positive, `NIL` otherwise."]})
+  (op brbound)
+  (op num? 1 (λ (x) (num? x))
+    '{[(v)
+       "Return `T` if `v` is of a numerical type, `NIL` otherwise.
+
+        Numerical types include floating point, fixnum, bignum, etc.
+        Note: ironically, a NaN value is considered a number by this function
+        since it's only testing the _type_ of the value."]})
+  (op fixnum? 1 (λ (x) (fixnum? x))
+    '{[(v)
+       "Return `T` if `v` is of a fixnum type, `NIL` otherwise."]})
+  (op bound? 1 (λ (x) (bound? x))
+    '{[(symbol)
+       "Return `T` if `symbol` has a value associated with it, `NIL` otherwise."]})
+  (op builtin? 1 (λ (x) (builtin? x))
+    '{[(v)
+       "Return `T` if `v` is a built-in function, `NIL` otherwise."]})
+  (op fn? 1 (λ (x) (fn? x))
+    '{[(v)
+       "Return `T` if `v` is a function, `NIL` otherwise."]})
+  (op vec? 1 (λ (x) (vec? x))
+    '{[(v)
+       "Return `T` if `v` is a vector, `NIL` otherwise."]})
+  (op shift)
+  (op set-car! 2 (λ (x y) (set-car! x y)))
+  (op jmp.l)
+  (op brn.l)
+  (op box)
+  (op eqv? 2 (λ (x y) (eqv? x y)))
+  (op equal? 2 (λ (x y) (equal? x y)))
+  (op list T (λ rest rest))
+  (op apply -2 (λ rest (apply apply rest)))
+  (op + T (λ rest (apply + rest))
+    '{[(num…)
+       "Return sum of the numbers or `0` with no arguments."]}
+    :cname "ADD")
+  (op - -1 (λ rest (apply - rest))
+    :cname "SUB")
+  (op * T (λ rest (apply * rest))
+    '{[(num…)
+	     "Return product of the numbers or `1` with no arguments."]}
+	:cname "MUL")
+  (op / -1 (λ rest (apply / rest))
+    :cname "DIV")
+  (op div0 2 (λ rest (apply div0 rest)))
+  (op = -1 (λ rest (apply = rest))
+    '{[(num…)
+	     "Numerical equality test.  Return `T` if all numbers are equal,
+	      `NIL` otherwise."]}
+	:cname "NUMEQP")
+  (op compare 2 (λ (x y) (compare x y))
+    '{[(x y)
+       "Return -1 if `x` is less than `y`, 0 if equal, and `1` if `y` is
+        greater than `x`.
+
+        Examples:
+
+            (compare 'a 'b)       → -1
+            (compare 1 1)         → 0
+            (compare \"b\" \"a\") → 1"]})
+  (op argc)
+  (op vec T (λ rest (apply vec rest)))
+  (op aset! -3 (λ rest (apply aset! rest)))
+  (op loadnil)
+  (op loadi8)
+  (op loadv.l)
+  (op loadg.l)
+  (op loada.l)
+  (op loadc.l)
+  (op setg)
+  (op setg.l)
+  (op seta.l)
+  (op vargc)
+  (op trycatch)
+  (op for 3 (λ (a b f) (for a b (λ (x) (f x))))
+    '{[(min max fn)
+       "Call the function `fn` with a single integer argument, starting from
+        `min` and ending with `max`.
+
+        Examples:
+
+        (for 0 2 (λ (i) (print (- 2 i)))) → 210"]})
+  (op tapply)
+  (op sub2)
+  (op argc.l)
+  (op vargc.l)
+  (op call.l)
+  (op tcall.l)
+  (op brne.l)
+  (op brnn.l)
+  (op aref -2 (λ rest (apply aref rest))
+    '{[(seq subscript…)
+       "Return the sequence element by the subscripts.  The sequence can be an
+        array, vector or a list.
+
+        Examples:
+
+            (def a '((1 (2 (3)) 4)))
+            (aref a 0)     → (1 (2 (3)) 4)
+            (aref a 1)     → index 1 out of bounds
+            (aref a 0 0)   → 1
+            (aref a 0 1 0) → 2
+            (aref a 0 2)   → 4"]})
+  (op box.l)
+  (op optargs)
+  (op dummy_eof)
 ))
 
-(def (for-each-n f lst n)
-  (when (and (> n 0) (cons? lst))
-    (apply f (list-head lst n))
-    (for-each-n f (list-tail lst n) n)))
+(def (new path)
+  (file path :write :create :truncate))
 
-(let ((c-header     (file "opcodes.h"        :write :create :truncate))
-      (c-code       (file "opcodes.c"        :write :create :truncate))
-      (instructions (file "instructions.lsp" :write :create :truncate))
-      (builtins     (file "builtins.lsp"     :write :create :truncate))
-      (builtins-doc (file "docs_ops.lsp"     :write :create :truncate))
-      (e (table))
-      (cl (table))
-      (ac (table))
-      (lms ())
+(let ((c-header     (new "opcodes.h"))
+      (c-code       (new "opcodes.c"))
+      (instructions (new "instructions.lsp"))
+      (builtins     (new "builtins.lsp"))
+      (docs-ops     (new "docs_ops.lsp"))
+      (op-to-byte (table))
+      (c-op-to-op-arg (table))
+      (op-to-argc (table))
+      (op-to-closure ())
       (i 0))
-  (begin
-    (io-write c-header "typedef enum {\n")
-    (for-each-n
-      (λ (cop lop argc f docs)
-        (begin
-          (io-write c-header "\t")
-          (write cop c-header)
-          (io-write c-header ",\n")
-          (for-each (λ (doc)
-                      (let ((docform (append `(,lop) (car doc))))
-                        (write (append `(doc-for ,docform)
-                                       (list (cadr doc)))
-                               builtins-doc)
-                        (io-write builtins-doc "\n")))
-                    docs)
-          (put! e lop (byte i))
-          (when argc
-            (put! cl cop (list lop argc))
-            (when (and (num? argc) (>= argc 0))
-              (put! ac lop argc)))
-          (set! lms (cons f lms))
-          (set! i (1+ i))))
-      opcodes 5)
-    (io-close builtins-doc)
-    (io-write c-header "\tN_OPCODES\n}sl_op;\n\n")
-    (io-write c-header "extern const Builtin builtins[N_OPCODES];\n")
-    (io-close c-header)
-    (io-write c-code "#include \"sl.h\"\n\n")
-    (io-write c-code "const Builtin builtins[N_OPCODES] = {\n")
-    (for-each
-      (λ (c la) (begin (io-write c-code "\t[")
-                       (write c c-code)
-                       (io-write c-code "] = {\"")
-                       (write (car la) c-code)
-                       (io-write c-code "\", ")
-                       (write (cadr la) c-code)
-                       (io-write c-code "},\n")))
-      cl)
-    (io-write c-code "};\n")
-    (io-close c-code)
+  (io-write c-header "typedef enum {\n")
+  (for-each
+    (λ (op)
+      (let {[lop (sym (op-name op))]
+            [argc (op-nargs op)]}
+        (io-write c-header (str "\t" (op-cname op) ",\n"))
+        (for-each (λ (doc)
+                    (write `(doc-for ,(cons lop (car doc)) ,(cadr doc))
+                           docs-ops)
+                    (io-write docs-ops "\n"))
+                  (op-docs op))
+        (put! op-to-byte lop (byte i))
+        (when argc
+          (put! c-op-to-op-arg (op-cname op) (list lop (if (eq? argc T) 'ANYARGS argc)))
+          (when (and (num? argc) (>= argc 0))
+            (put! op-to-argc lop argc)))
+        (set! op-to-closure (cons (op-closure op) op-to-closure))
+        (set! i (1+ i))))
+    ops)
+  (io-close docs-ops)
+  (io-write c-header "\tN_OPCODES\n}sl_op;\n\n")
+  (io-write c-header "extern const Builtin builtins[N_OPCODES];\n")
+  (io-close c-header)
+  (io-write c-code "#include \"sl.h\"\n\n")
+  (io-write c-code "const Builtin builtins[N_OPCODES] = {\n")
+  (for-each
+    (λ (c la) (begin (io-write c-code (str "\t[" c))
+                     (io-write c-code "] = {\"")
+                     (write (car la) c-code)
+                     (io-write c-code "\", ")
+                     (write (cadr la) c-code)
+                     (io-write c-code "},\n")))
+    c-op-to-op-arg)
+  (io-write c-code "};\n")
+  (io-close c-code)
 
-    (write `(def Instructions
-              "VM instructions mapped to their encoded byte representation."
-              ,e)
-           instructions)
-    (io-write instructions "\n\n")
-    (write `(def arg-counts
-              "VM instructions mapped to their expected arguments count."
-              ,ac)
-           instructions)
-    (io-write instructions "\n")
-    (io-close instructions)
-    (set! lms (cons vec (reverse! lms)))
-    (write `(def *builtins*
-              "VM instructions as closures."
-              ,lms)
-           builtins)
-    (io-write builtins "\n")
-    (io-close builtins)))
+  (write `(def Instructions
+            "VM instructions mapped to their encoded byte representation."
+            ,op-to-byte)
+         instructions)
+  (io-write instructions "\n\n")
+  (write `(def arg-counts
+            "VM instructions mapped to their expected arguments count."
+            ,op-to-argc)
+         instructions)
+  (io-write instructions "\n")
+  (io-close instructions)
+  (set! op-to-closure (cons vec (reverse! op-to-closure)))
+  (write `(def *builtins*
+            "VM instructions as closures."
+            ,op-to-closure)
+         builtins)
+  (io-write builtins "\n")
+  (io-close builtins))