ref: 47451dfe7e1fdecc6266f63e07ceeaa29040e114
parent: d87fa0118280aed3abcb02722a97283c9a881722
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Mar 19 23:56:47 EDT 2025
document all builtins except eq?, eqv? and equal? Make gen.lsp not rewrite opcodes.[ch] files on error - write to an in-memory buffer first, then copy.
--- a/boot/sl.boot
+++ b/boot/sl.boot
@@ -12,22 +12,23 @@
#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)) 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) < ((a . rest)) remprop ((symbol
- key)) negative? ((x)) rand (NIL) sym (term) nan? ((v)) void (rest) file ((path (:read NIL)
- (:write NIL)
- (:create NIL)
- (:truncate
- NIL)
- (:append NIL))) fixnum? ((v)) rand-double (NIL) exit ((status)) cdr ((lst)) + (rest) vec? ((v)) for ((min
- max fn)) lz-unpack ((data :to destination)
- (data :size decompressed-bytes)) > ((a . rest)) 1- ((n)) 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)) io? ((term)) help ((term
- (:print-header help-print-header))) __finish ((status)) rand-u32 (NIL) buffer (NIL) rand-u64 (NIL) = ((a . rest)) compare ((x
- y)) num? ((v)) /= ((a . rest)) fn? ((v)) help-print-header ((term sigs)) lz-pack ((data (level
- 0))) rand-float (NIL) *prompt* (NIL) builtin? ((v)) add-exit-hook ((fun)) cons? ((value)) vm-stats (NIL) * (rest) putprop ((symbol
- key val)) getprop ((symbol key (def NIL))) aref ((seq subscript0 . rest)) 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." < "Return `T` if the arguments are in strictly increasing order (next\none is greater than the previous one)." 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 specified by the subscripts. The sequence\n be an array, vector, a list. Multi-dimensional sequences\nvariating 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 table." zero? "Return `T` if `x` is zero." >=
\ No newline at end of file
+ *properties* #table(*funvars* #table(identity ((x)) bound? ((symbol)) io-eof? ((io)) < ((a . rest)) cadr ((cell)) sym (term) nan? ((v)) for ((min
+ max fn)) fixnum? ((v)) exit ((status)) > ((a . rest)) + (rest) div0 ((a b)) __finish ((status)) lz-unpack ((data
+ :to destination)
+ (data :size decompressed-bytes)) 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)) compare ((x y)) buffer (NIL) num? ((v)) add-exit-hook ((fun)) rand-float (NIL) builtin? ((v)) set-car! ((cell
+ new-first)) cons? ((v)) 1+ ((n)) aref ((sequence subscript0 . rest)) zero? ((x)) vec (rest) >= ((a . rest)) sym? ((v)) void? ((x)) length= ((lst
+ n)) positive? ((x)) doc-for ((term (doc NIL))) aset! ((sequence subscripts… new-value)) car ((lst)) <= ((a . rest)) str (term) cons ((first
+ second)) - ((a . rest)) remprop ((symbol key)) negative? ((x)) rand (NIL) void (rest) file ((path
+ (:read NIL) (:write NIL) (:create NIL) (:truncate NIL) (:append NIL))) rand-double (NIL) 1- ((n)) atom? ((value)) cdr ((lst)) vec? ((v)) / ((x . rest)) apply ((fn
+ arg . rest)) io? ((term)) eof-object? ((term)) list (rest) help ((term (:print-header
+ help-print-header))) rand-u32 (NIL) = ((a . rest)) rand-u64 (NIL) not ((v)) set-cdr! ((cell
+ new-second)) /= ((a . rest)) fn? ((v)) help-print-header ((term sigs)) lz-pack ((data (level
+ 0))) *prompt* (NIL) 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." 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)." 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" 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 arguments or `0` with none." 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\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." 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 c
\ No newline at end of file
"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 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." 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." 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\nExamples:\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\nExamples:\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." help-print-header "Format and print term's signature(s) 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 `#;> `." 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
--- a/tools/gen.lsp
+++ b/tools/gen.lsp
@@ -38,23 +38,42 @@
(op dup)
(op car 1 (λ (x) (car x))
{[(lst)
- "Return the first element of a list or `NIL` if not available."]})
+ "Return the first element of a cons cell (head of a list) or `NIL` if
+ not available.
+
+ Examples:
+
+ (car NIL) → NIL
+ (car '(1 2 3)) → 1
+ (car '(1 . 2)) → 1"]})
(op cdr 1 (λ (x) (cdr x))
{[(lst)
- "Return the tail of a list or `NIL` if not available."]})
+ "Return the second element of a cons cell (tail of a list) or `NIL` if
+ not available.
+
+ Examples:
+
+ (cdr NIL) → NIL
+ (cdr '(1 2 3)) → (2 3)
+ (cdr '(1 . 2)) → 2"]})
(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."]})
+ {[(v)
+ "Return `T` if `v` is a cons cell, `NIL` otherwise."]})
(op brne)
(op loadt)
(op load0)
(op loadc1)
(op aref2)
- (op atom? 1 (λ (x) (atom? x)))
+ (op atom? 1 (λ (x) (atom? x))
+ {[(value)
+ "Return `T` if `v` is a _not_ a cons cell, `NIL` otherwise. This is
+ the opposite of `cons?`.
+
+ The term \"atom\" comes from the idea of being indivisible."]})
(op loadvoid)
(op brnn)
(op load1)
@@ -64,13 +83,44 @@
one is greater than the previous one)."]}
:cname "LT")
(op add2)
- (op set-cdr! 2 (λ (x y) (set-cdr! x y)))
+ (op set-cdr! 2 (λ (x y) (set-cdr! x y))
+ {[(cell new-second)
+ "Modify a cons cell (a list) in-place by putting `new-second` as its
+ second element (tail of the list). Return the modified cons
+ cell (list).
+
+ Examples:
+
+ (def q '(1 2 3 4 5))
+ (set-cdr! q '(6 7)) → (1 6 7)
+ q → (1 6 7)"]})
(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 cons 2 (λ (x y) (cons x y))
+ {[(first second)
+ "Return a cons cell containing two arguments.
+
+ Examples:
+
+ (cons 1 2) → (1 . 2)
+ (cons 1 '(2)) → (1 2)
+ (cons 1 (cons 2 (cons 3 NIL))) → (1 2 3)"]})
+ (op eq? 2 (λ (x y) (eq? x y))) ; FIXME
+ (op sym? 1 (λ (x) (sym? x))
+ {[(v)
+ "Return `T` if `v` is a symbol, `NIL` otherwise."]})
+ (op not 1 (λ (x) (not x))
+ {[(v)
+ "Return `T` if `v` is `NIL`, `T` otherwise."]})
+ (op cadr 1 (λ (x) (cadr x))
+ {[(cell)
+ "Shorthand for `(car (cdr cell))`, that is, \"first element of the
+ second element\".
+
+ Examples:
+
+ (cadr '(1 2 3)) → 2
+ (cadr '(1)) → NIL
+ (cadr NIL) → NIL"]})
(op neg)
(op nan? 1 (λ (x) (nan? x))
{[(v)
@@ -100,32 +150,89 @@
{[(v)
"Return `T` if `v` is a vector, `NIL` otherwise."]})
(op shift)
- (op set-car! 2 (λ (x y) (set-car! x y)))
+ (op set-car! 2 (λ (x y) (set-car! x y))
+ {[(cell new-first)
+ "Modify a cons cell (a list) in-place by putting `new-first` as its
+ first element (head of the list). Return the modified cons
+ cell (list).
+
+ Examples:
+
+ (def q '(1 2 3 4 5))
+ (set-car! q 0) → (0 6 7)
+ q → (0 6 7)"]})
(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 eqv? 2 (λ (x y) (eqv? x y))) ; FIXME
+ (op equal? 2 (λ (x y) (equal? x y))) ; FIXME
+ (op list T (λ rest rest)
+ {[rest
+ "Return a list constructed of the arguments.
+
+ Examples:
+
+ (list) → NIL ; empty list
+ (list 1 2.5 \"a\" 'b) → (1 2.5 \"a\" b)"]})
+ (op apply -2 (λ rest (apply apply rest))
+ {[(fn arg . rest)
+ "Return the result of applying a function to a list of arguments.
+
+ The last argument must always be a list which gets spliced as
+ arguments to the function.
+
+ Examples:
+
+ (apply + 1 2 '(3 4 5)) → 15
+ (apply vec '(1 2 3)) → #(3 4 5)
+ (apply arr 'u8 '(3 4 5)) → #vu8(3 4 5)"]})
(op + T (λ rest (apply + rest))
{[rest
- "Return sum of the numbers or `0` with no arguments."]}
+ "Return sum of the arguments or `0` with none."]}
:cname "ADD")
(op - -1 (λ rest (apply - rest))
+ {[(a . rest)
+ "Return the result of subtraction. With only one argument a
+ negation is performed.
+
+ Examples:
+
+ (- 1.5) → -1.5
+ (- 3 2) → 1"]}
:cname "SUB")
(op * T (λ rest (apply * rest))
{[rest
- "Return product of the numbers or `1` with no arguments."]}
- :cname "MUL")
+ "Return product of the arguments or `1` with none."]}
+ :cname "MUL")
(op / -1 (λ rest (apply / rest))
+ {[(x . rest)
+ "Return the division of the arguments. With only one argument the
+ result of `1/x` is returned. If the result is integer-valued, it is
+ returned as an integer.
+
+ Examples:
+
+ (/ 2) → 0.5
+ (/ 7 2 2) → 1.75
+ (/ 10 -2) → -5 ; a fixnum
+ (/ 6.9 1.9) → 3.6315…"]}
:cname "DIV")
- (op div0 2 (λ rest (apply div0 rest)))
+ (op div0 2 (λ rest (apply div0 rest))
+ {[(a b)
+ "Return the quotient of two numbers. For non-integers this is
+ equivalent to `(div0 (floor a) (floor b))`. The result is always an
+ integer.
+
+ Examples:
+
+ (div0 7 2) → 3
+ (div0 10 -2) → -5
+ (div0 6.9 1.9) → 6"]})
(op = -1 (λ rest (apply = rest))
{[(a . rest)
- "Numerical equality test. Return `T` if all numbers are equal,
- `NIL` otherwise."]}
- :cname "NUMEQP")
+ "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
@@ -137,8 +244,28 @@
(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 vec T (λ rest (apply vec rest))
+ {[rest
+ "Return a vector constructed of the arguments.
+
+ Examples:
+
+ (vec) → #() ; empty vector
+ (vec 1 2.5 \"a\" 'b) → #(1 2.5 \"a\" b)"]})
+ (op aset! -3 (λ rest (apply aset! rest))
+ {[(sequence subscripts… new-value)
+ "Modify the sequence element specified by the subscripts and return the
+ new value. The sequence can be an array, vector, a list.
+ Multi-dimensional sequences of variating types are also supported.
+
+ Examples:
+
+ (def a '((1 #(2 (3)) 4)))
+ (aset! a 1 'x) → index 1 out of bounds
+ (aset! a 0 0 'x) → x
+ a → ((x #(2 (3)) 4))
+ (aset! a 0 1 9) → 9
+ a → ((x #(9 (3)) 4))"]})
(op loadnil)
(op loadi8)
(op loadv.l)
@@ -167,10 +294,10 @@
(op brne.l)
(op brnn.l)
(op aref -2 (λ rest (apply aref rest))
- {[(seq subscript0 . rest)
+ {[(sequence subscript0 . rest)
"Return the sequence element specified by the subscripts. The sequence
- can be an array, vector, a list. Multi-dimensional sequences
- of variating types are also supported.
+ can be an array, vector, a list. Multi-dimensional sequences
+ of variating types are also supported.
Examples:
@@ -188,8 +315,8 @@
(def (new path)
(file path :write :create :truncate))
-(let ((c-header (new "opcodes.h"))
- (c-code (new "opcodes.c"))
+(let ((c-header (buffer)) ; to avoid broken code truncating valid files
+ (c-code (buffer))
(instructions (new "instructions.lsp"))
(builtins (new "builtins.lsp"))
(docs-ops (new "docs_ops.lsp"))
@@ -208,8 +335,14 @@
(let* {[args (car doc)]
[sig (cons lop args)]
[docstr (cadr doc)]}
+ (unless (= (length doc) 2)
+ (error lop ": documentation has extra data"))
+ (unless (str? docstr)
+ (error lop ": documentation must be a string"))
+ (unless (or (sym? sig) (cons? sig))
+ (error lop ": invalid signature"))
(write `(doc-for ,sig ,docstr) docs-ops)
- (io-write docs-ops "\n")))
+ (newline docs-ops)))
(op-docs op))
(put! op-to-byte lop (byte i))
(when argc
@@ -222,7 +355,7 @@
(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
@@ -234,18 +367,18 @@
(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."
,op-to-byte)
instructions)
- (io-write instructions "\n\n")
+ (newline instructions)
+ (newline instructions)
(write `(def arg-counts
"VM instructions mapped to their expected arguments count."
,op-to-argc)
instructions)
- (io-write instructions "\n")
+ (newline instructions)
(io-close instructions)
(set! op-to-closure (cons vec (reverse! op-to-closure)))
(write `(def *builtins*
@@ -252,5 +385,11 @@
"VM instructions as closures."
,op-to-closure)
builtins)
- (io-write builtins "\n")
- (io-close builtins))
+ (newline builtins)
+ (io-close builtins)
+
+ ;; at last, copy the buffers to the actual files in git repo.
+ (io-seek c-header 0)
+ (io-copy (new "opcodes.h") c-header)
+ (io-seek c-code 0)
+ (io-copy (new "opcodes.c") c-code))