shithub: sl

Download patch

ref: 52677147a7a0e4a4c0db4743dd9de3f7f24de8eb
parent: e9e65bff7f2881102adc9b48e3e47a17b6e2094d
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Feb 28 13:54:34 EST 2025

rename to StreetLISP

--- a/.build.yml
+++ b/.build.yml
@@ -10,18 +10,18 @@
   - rsync
   - samurai
 sources:
-  - https://git.sr.ht/~ft/femtolisp
+  - https://git.sr.ht/~ft/sl
 tasks:
   - setup: |
-      cd femtolisp
+      cd sl
       meson setup build . -Dbuildtype=release -Db_coverage=true
   - build: |
-      cd femtolisp
+      cd sl
       ninja -C build test
   - coverage: |
-      cd femtolisp
+      cd sl
       ninja -C build coverage-html
   - coverage-upload: |
       test $GIT_REF = refs/heads/main || exit 0
       set +x
-      rsync -Pavq femtolisp/build/meson-logs/coveragereport -e "ssh -p 8886 -i .ssh/05bf4496-881e-4741-b17f-5cc8640334bf" secretsauce@ftrv.se:incoming/femtolisp-coverage 2>/dev/null
+      rsync -Pavq sl/build/meson-logs/coveragereport -e "ssh -p 8886 -i .ssh/05bf4496-881e-4741-b17f-5cc8640334bf" secretsauce@ftrv.se:incoming/sl-coverage 2>/dev/null
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,10 @@
 *.[05678qvtoa]
 *.out
 *.bak
-flisp.boot
+sl.boot
 instructions.lsp
 builtins.lsp
 docs_ops.lsp
 builtin_fns.h
 *.core
-flisp.boot.s
+sl.boot.s
--- a/.lcovrc
+++ b/.lcovrc
@@ -1,3 +1,3 @@
 exclude = */3rd/*
 ignore_errors = unused
-genhtml_header = Coverage report for FemtoLisp
+genhtml_header = Coverage report for StreetLISP
--- a/3rd/brieflz/brieflz.c
+++ b/3rd/brieflz/brieflz.c
@@ -209,7 +209,7 @@
 };
 #endif
 
-fl_constfn
+sl_constfn
 static int
 blz_log2(unsigned long n)
 {
@@ -232,7 +232,7 @@
 #endif
 }
 
-fl_constfn
+sl_constfn
 static unsigned long
 blz_gamma_cost(unsigned long n)
 {
@@ -241,7 +241,7 @@
 	return 2 * (unsigned long) blz_log2(n);
 }
 
-fl_constfn
+sl_constfn
 static unsigned long
 blz_match_cost(unsigned long pos, unsigned long len)
 {
@@ -412,7 +412,7 @@
 // This is Fibonacci hashing, also known as Knuth's multiplicative hash. The
 // constant is a prime close to 2^32/phi.
 //
-fl_purefn
+sl_purefn
 static unsigned long
 blz_hash4_bits(const unsigned char *p, int bits)
 {
@@ -426,7 +426,7 @@
 	return (val * 2654435761U) >> (32 - bits);
 }
 
-fl_purefn
+sl_purefn
 static unsigned long
 blz_hash4(const unsigned char *p)
 {
--- a/3rd/brieflz/brieflz.h
+++ b/3rd/brieflz/brieflz.h
@@ -79,7 +79,7 @@
  * @return maximum size of compressed data
  */
 BLZ_API size_t
-blz_max_packed_size(size_t src_size) fl_constfn;
+blz_max_packed_size(size_t src_size) sl_constfn;
 
 /**
  * Get required size of `workmem` buffer.
@@ -90,7 +90,7 @@
  * @return required size in bytes of `workmem` buffer
  */
 BLZ_API size_t
-blz_workmem_size(size_t src_size) fl_constfn;
+blz_workmem_size(size_t src_size) sl_constfn;
 
 /**
  * Compress `src_size` bytes of data from `src` to `dst`.
@@ -114,7 +114,7 @@
  * @return required size in bytes of `workmem` buffer
  */
 BLZ_API size_t
-blz_workmem_size_level(size_t src_size, int level) fl_constfn;
+blz_workmem_size_level(size_t src_size, int level) sl_constfn;
 
 /**
  * Compress `src_size` bytes of data from `src` to `dst`.
--- a/3rd/brieflz/brieflz_hashbucket.h
+++ b/3rd/brieflz/brieflz_hashbucket.h
@@ -28,7 +28,7 @@
 #ifndef BRIEFLZ_HASHBUCKET_H_INCLUDED
 #define BRIEFLZ_HASHBUCKET_H_INCLUDED
 
-fl_constfn
+sl_constfn
 static size_t
 blz_hashbucket_workmem_size(size_t src_size, unsigned int bucket_size)
 {
--- a/3rd/dlmalloc.inc
+++ b/3rd/dlmalloc.inc
@@ -2707,7 +2707,7 @@
   ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
 
 /* Return segment holding given address */
-fl_purefn
+sl_purefn
 static msegmentptr segment_holding(mstate m, char* addr) {
   msegmentptr sp = &m->seg;
   for (;;) {
@@ -2719,7 +2719,7 @@
 }
 
 /* Return true if segment contains a segment link */
-fl_purefn
+sl_purefn
 static int has_segment_link(mstate m, msegmentptr ss) {
   msegmentptr sp = &m->seg;
   for (;;) {
@@ -5352,17 +5352,17 @@
   return result;
 }
 
-fl_purefn
+sl_purefn
 size_t dlmalloc_footprint(void) {
   return gm->footprint;
 }
 
-fl_purefn
+sl_purefn
 size_t dlmalloc_max_footprint(void) {
   return gm->max_footprint;
 }
 
-fl_purefn
+sl_purefn
 size_t dlmalloc_footprint_limit(void) {
   size_t maf = gm->footprint_limit;
   return maf == 0 ? MAX_SIZE_T : maf;
@@ -5395,7 +5395,7 @@
   return change_mparam(param_number, value);
 }
 
-fl_purefn
+sl_purefn
 size_t dlmalloc_usable_size(void* mem) {
   if (mem != 0) {
     mchunkptr p = mem2chunk(mem);
--- a/3rd/fn.c
+++ b/3rd/fn.c
@@ -14,7 +14,7 @@
 	if(t == nil)
 		return false;
 	while(isbranch(t)){
-		fl_prefetch(t->ptr);
+		sl_prefetch(t->ptr);
 		Tindex i = t->index;
 		Tbitmap b = twigbit(i, key, len);
 		if(!hastwig(i, b))
@@ -80,7 +80,7 @@
 	Tindex i = 0;
 	Tbitmap b = 0;
 	while(isbranch(t)){
-		fl_prefetch(t->ptr);
+		sl_prefetch(t->ptr);
 		i = t->index;
 		b = twigbit(i, key, len);
 		if(!hastwig(i, b))
@@ -96,7 +96,7 @@
 		return nil;
 	}
 	Trie *twigs = Tbranch_twigs(p);
-	uint32_t m = fl_popcount(Tindex_bitmap(i));
+	uint32_t m = sl_popcount(Tindex_bitmap(i));
 	assert(twigs <= t && t < twigs+m);
 	if(m == 2){
 		// Move the other twig to the parent branch.
@@ -136,7 +136,7 @@
 	// which can be at a lower index than the point at which we
 	// detect a difference.
 	while(isbranch(t)){
-		fl_prefetch(t->ptr);
+		sl_prefetch(t->ptr);
 		Tindex i = t->index;
 		Tbitmap b = twigbit(i, key, len);
 		// Even if our key is missing from this branch we need to
@@ -158,7 +158,7 @@
 	Tset_val(t, val);
 	return tbl;
 newkey:; // We have the branch's byte index; what is its chunk index?
-	uint32_t bit = off * 8 + fl_clz(xor) + 8 - sizeof(uint32_t) * 8;
+	uint32_t bit = off * 8 + sl_clz(xor) + 8 - sizeof(uint32_t) * 8;
 	uint32_t qo = bit / 5;
 	off = qo * 5 / 8;
 	shf = qo * 5 % 8;
@@ -173,7 +173,7 @@
 	t = tbl;
 	Tindex i;
 	while(isbranch(t)){
-		fl_prefetch(t->ptr);
+		sl_prefetch(t->ptr);
 		i = t->index;
 		if(off == Tindex_offset(i) && shf == Tindex_shift(i))
 			goto growbranch;
--- a/3rd/fn.h
+++ b/3rd/fn.h
@@ -25,7 +25,7 @@
 typedef struct Tbl {
 	Tindex index;
 	void *ptr;
-}fl_aligned(8) Trie;
+}sl_aligned(8) Trie;
 
 // accessor functions, except for the index word
 
@@ -61,11 +61,11 @@
 	} \
 	struct dummy
 
-fl_purefn
+sl_purefn
 Tcheck_get(Trie *,       Tbranch, twigs, t->ptr);
-fl_purefn
+sl_purefn
 Tcheck_get(const char *, Tleaf,   key,   t->ptr);
-fl_purefn
+sl_purefn
 Tcheck_get(void *,       Tleaf,   val,   (void*)(uintptr_t)t->index);
 
 // index word layout
@@ -181,10 +181,10 @@
 static inline uint32_t
 twigoff(Tindex i, Tbitmap bit)
 {
-	return fl_popcount(Tindex_bitmap(i) & (bit-1));
+	return sl_popcount(Tindex_bitmap(i) & (bit-1));
 }
 
 #define TWIGOFFMAX(off, max, i, b) do{ \
 		off = twigoff(i, b); \
-		max = fl_popcount(Tindex_bitmap(i)); \
+		max = sl_popcount(Tindex_bitmap(i)); \
 	}while(0)
--- a/3rd/iswprint.c
+++ b/3rd/iswprint.c
@@ -21,11 +21,11 @@
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
-#include "flisp.h"
+#include "sl.h"
 
 // straight from musl
 int
-fl_iswprint(Rune c)
+sl_iswprint(Rune c)
 {
 	if(c < 0xff)
 		return ((c+1) & 0x7f) >= 0x21;
--- a/3rd/mp/mp.h
+++ b/3rd/mp/mp.h
@@ -24,8 +24,8 @@
 #define mpdighi  (((mpdigit)1)<<(Dbits-1))
 #define DIGITS(x) ((int)(x) >= -(Dbits-1) ? ((Dbits - 1 + (x))/Dbits) : 0)
 
-extern	mpdigit	dec16chr(int) fl_constfn;
-extern	int	enc16chr(int) fl_constfn;
+extern	mpdigit	dec16chr(int) sl_constfn;
+extern	int	enc16chr(int) sl_constfn;
 
 /*
  * the code assumes mpdigit to be at least an int
@@ -76,15 +76,15 @@
 mpint*	betomp(uint8_t*, uint32_t, mpint*);	/* byte array, big-endian */
 int	mptobe(mpint*, uint8_t*, uint32_t, uint8_t**);
 void	mptober(mpint *b, uint8_t *p, int n);
-uint32_t	mptoui(mpint*) fl_purefn;			/* unsigned int */
+uint32_t	mptoui(mpint*) sl_purefn;			/* unsigned int */
 mpint*	uitomp(uint32_t, mpint*);
-int	mptoi(mpint*) fl_purefn;			/* int */
+int	mptoi(mpint*) sl_purefn;			/* int */
 mpint*	itomp(int, mpint*);
-uint64_t	mptouv(mpint*) fl_purefn;			/* unsigned int64_t */
+uint64_t	mptouv(mpint*) sl_purefn;			/* unsigned int64_t */
 mpint*	uvtomp(uint64_t, mpint*);
-int64_t	mptov(mpint*) fl_purefn;			/* int64_t */
+int64_t	mptov(mpint*) sl_purefn;			/* int64_t */
 mpint*	vtomp(int64_t, mpint*);
-double	mptod(mpint*) fl_purefn;			/* double */
+double	mptod(mpint*) sl_purefn;			/* double */
 mpint*	dtomp(double, mpint*);
 
 /* divide the 2 digit dividend by the one digit divisor and stick in quotient */
@@ -118,7 +118,7 @@
 void	mpdiv(mpint *dividend, mpint *divisor,  mpint *quotient, mpint *remainder);
 
 /* return neg, 0, pos as b1-b2 is neg, 0, pos */
-int	mpcmp(mpint *b1, mpint *b2) fl_purefn;
+int	mpcmp(mpint *b1, mpint *b2) sl_purefn;
 
 /* res = s != 0 ? b1 : b2 */
 void	mpsel(int s, mpint *b1, mpint *b2, mpint *res);
@@ -130,7 +130,7 @@
 void	mpinvert(mpint *b, mpint *m, mpint *res);
 
 /* bit counting */
-uint32_t	mpsignif(mpint*) fl_purefn;	/* number of sigificant bits in mantissa */
+uint32_t	mpsignif(mpint*) sl_purefn;	/* number of sigificant bits in mantissa */
 uint32_t	mplowbits0(mpint*);	/* k, where n = 2**k * q for odd q */
 
 /* well known constants */
@@ -158,11 +158,11 @@
 void	mpvectsmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p);
 
 /* sign of a - b or zero if the same */
-int	mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen) fl_purefn;
-int	mpvectscmp(mpdigit *a, int alen, mpdigit *b, int blen) fl_purefn;
+int	mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen) sl_purefn;
+int	mpvectscmp(mpdigit *a, int alen, mpdigit *b, int blen) sl_purefn;
 
 /* playing with magnitudes */
-int	mpmagcmp(mpint *b1, mpint *b2) fl_purefn;
+int	mpmagcmp(mpint *b1, mpint *b2) sl_purefn;
 void	mpmagadd(mpint *b1, mpint *b2, mpint *sum);	/* sum = b1+b2 */
 void	mpmagsub(mpint *b1, mpint *b2, mpint *sum);	/* sum = b1+b2 */
 
--- a/3rd/mp/test/fns.h
+++ b/3rd/mp/test/fns.h
@@ -1,5 +1,5 @@
 ldint* ldnew(int);
-int ldcmp(ldint *, ldint *) fl_purefn;
+int ldcmp(ldint *, ldint *) sl_purefn;
 int ldmagcmp(ldint *, ldint *);
 void ldadd(ldint *, ldint *, ldint *);
 void ldsub(ldint *, ldint *, ldint *);
@@ -16,7 +16,7 @@
 void lddiv_(ldint *, ldint *, ldint *, ldint *);
 void ldfree(ldint *);
 void testgen(int, ldint *);
-int ldmpeq(ldint *, mpint *) fl_purefn;
+int ldmpeq(ldint *, mpint *) sl_purefn;
 mpint* ldtomp(ldint *, mpint *);
 void mptarget(mpint *);
 void tests(void);
--- a/3rd/spooky.c
+++ b/3rd/spooky.c
@@ -53,7 +53,7 @@
 //
 // Read uint64_t in little-endian order.
 //
-fl_purefn
+sl_purefn
 static inline uint64_t
 spooky_read_le64(const uint64_t *s)
 {
--- a/3rd/utf/utf.h
+++ b/3rd/utf/utf.h
@@ -11,17 +11,17 @@
 
 int chartorune(Rune *rune, const char *str);
 int runetochar(char *str, const Rune *rune);
-int runenlen(const Rune *r, int nrune) fl_purefn;
-int fullrune(const char *str, int n) fl_purefn;
-int runelen(Rune c) fl_constfn;
-Rune tolowerrune(Rune c) fl_constfn;
-Rune toupperrune(Rune c) fl_constfn;
-Rune totitlerune(Rune c) fl_constfn;
-int islowerrune(Rune c) fl_constfn;
-int isupperrune(Rune c) fl_constfn;
-int isalpharune(Rune c) fl_constfn;
-int istitlerune(Rune c) fl_constfn;
-int isspacerune(Rune c) fl_constfn;
-int isdigitrune(Rune c) fl_constfn;
+int runenlen(const Rune *r, int nrune) sl_purefn;
+int fullrune(const char *str, int n) sl_purefn;
+int runelen(Rune c) sl_constfn;
+Rune tolowerrune(Rune c) sl_constfn;
+Rune toupperrune(Rune c) sl_constfn;
+Rune totitlerune(Rune c) sl_constfn;
+int islowerrune(Rune c) sl_constfn;
+int isupperrune(Rune c) sl_constfn;
+int isalpharune(Rune c) sl_constfn;
+int istitlerune(Rune c) sl_constfn;
+int isspacerune(Rune c) sl_constfn;
+int isdigitrune(Rune c) sl_constfn;
 
 int utfnlen(const char *s, long m);
--- a/3rd/wcwidth.c
+++ b/3rd/wcwidth.c
@@ -15,7 +15,7 @@
  * https://github.com/termux/termux-packages/tree/master/packages/libandroid-support
  */
 
-#include "flisp.h"
+#include "sl.h"
 
 struct width_interval {
 	int start;
@@ -498,7 +498,7 @@
 	{0x30000, 0x3fffd},  // Cjk Unified Ideograph-30..(nil)
 };
 
-fl_constfn
+sl_constfn
 static bool
 intable(const struct width_interval* table, int table_length, int c)
 {
@@ -523,7 +523,7 @@
 }
 
 int
-fl_wcwidth(Rune ucs)
+sl_wcwidth(Rune ucs)
 {
 	// NOTE: created by hand, there isn't anything identifiable other than
 	// general Cf category code to identify these, and some characters in Cf
--- a/README.md
+++ b/README.md
@@ -1,11 +1,15 @@
-# femtolisp
+# StreetLISP
 
-[![builds.sr.ht status](https://builds.sr.ht/~ft/femtolisp/commits/main/.build.yml.svg)](https://builds.sr.ht/~ft/femtolisp/commits/main/.build.yml?)
+	< cinap_lenrek> maybe thats all you need
+	< cinap_lenrek> a street lisp
+	< cinap_lenrek> sl(1)
 
-[Coverage report](https://ftrv.se/_/femtolisp/index.html)
+[![builds.sr.ht status](https://builds.sr.ht/~ft/sl/commits/main/.build.yml.svg)](https://builds.sr.ht/~ft/sl/commits/main/.build.yml?)
 
-A compact interpreter for a minimal lisp/scheme dialect.
+[Coverage report](https://ftrv.se/_/sl/index.html)
 
+A compact interpreter for a minimal lisp/scheme dialect. A street lisp.
+
 This is a reanimation of
 https://github.com/lambdaconservatory/femtolisp with bigger plans.
 
@@ -38,8 +42,8 @@
 
 Two ways to learn about more changes:
 
- * https://todo.sr.ht/~ft/femtolisp?search=status:closed
- * https://git.sr.ht/~ft/femtolisp/log
+ * https://todo.sr.ht/~ft/sl?search=status:closed
+ * https://git.sr.ht/~ft/sl/log
 
 ## Building
 
@@ -63,9 +67,9 @@
 	../retro68/build-toolchain.bash --ninja
 	# wait until everything builds, make sure it did not error out
 
-Now build femtolisp:
+Now build `sl`:
 
-	cd femtolisp
+	cd sl
 	export PATH="$PATH:$(pwd)/../retro68-build/toolchain/bin"
 	# for PowerPC:
 	meson setup build . -Dbuildtype=minsize --cross-file cross/powerpc-apple.txt
@@ -73,7 +77,7 @@
 	meson setup build . -Dbuildtype=minsize --cross-file cross/m68k-apple.txt
 	ninja -C build
 
-Either `build/flisp.dsk` or `build/flisp.bin` is the file to get on your Mac.
+Either `build/sl.dsk` or `build/sl.bin` is the file to get on your Mac.
 
 NOTE: this isn't a full-fledged port and is going to stay low priority unless somebody
 wants to spend time polishing it.
@@ -86,7 +90,7 @@
 	meson setup build . -Dbuildtype=minsize --cross-file cross/djgpp.txt
 	ninja -C build
 
-Result is `build/flisp.exe`.
+Result is `build/sl.exe`.
 
 ## Characteristics
 
binary files a/boot/flisp.boot.builtin /dev/null differ
binary files /dev/null b/boot/sl.boot.builtin differ
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
 project(
-	'femtolisp',
+	'sl',
 	'c',
 	version: '0.999',
 	meson_version: '>=1.1.0',
@@ -39,7 +39,7 @@
 	language: 'c',
 )
 
-src_flisp = [
+src_sl = [
 	'3rd/fn.c',
 	'3rd/iswprint.c',
 	'3rd/mt19937-64.c',
@@ -52,8 +52,8 @@
 	'src/cvalues.c',
 	'src/equal.c',
 	'src/equalhash.c',
-	'src/flisp.c',
-	'src/flmain.c',
+	'src/sl.c',
+	'src/slmain.c',
 	'src/hashing.c',
 	'src/htable.c',
 	'src/ios.c',
@@ -104,7 +104,7 @@
 
 if sys == 'macos'
 	platform = sys
-	flisp_exe_name = 'flisp.code.bin'
+	sl_exe_name = 'sl.code.bin'
 	add_languages(
 		'cpp',
 		native: false,
@@ -128,14 +128,14 @@
 	]
 elif sys == 'dos'
 	platform = sys
-	flisp_exe_name = 'flisp.exe'
+	sl_exe_name = 'sl.exe'
 else
 	platform = 'posix'
-	flisp_exe_name = 'flisp'
+	sl_exe_name = 'sl'
 endif
 
 inc += [include_directories('src'/platform)]
-src_flisp += ['src'/platform/'sys.c']
+src_sl += ['src'/platform/'sys.c']
 
 common = static_library(
 	'common',
@@ -151,10 +151,10 @@
 	'boot',
 	capture: true,
 	input: [
-		'boot/flisp.boot.builtin',
+		'boot/sl.boot.builtin',
 	],
 	output: [
-		'flisp.boot.h',
+		'sl.boot.h',
 	],
 	command: [
 		'tools/boot2h.sh', '@INPUT@',
@@ -165,7 +165,7 @@
 	'builtins',
 	capture: true,
 	input: [
-		src_flisp,
+		src_sl,
 	],
 	output: [
 		'builtin_fns.h',
@@ -253,10 +253,10 @@
 	prelink: false,
 )
 
-flisp = executable(
-	flisp_exe_name,
+sl = executable(
+	sl_exe_name,
 	sources: [
-		src_flisp,
+		src_sl,
 		boot,
 		builtins,
 		ops,
@@ -289,22 +289,22 @@
 	rincludes = fs.parent(fs.parent(rez.full_path()))/'RIncludes'
 
 	if cpu == 'm68k'
-		template = 'femtolispm68k.r'
+		template = 'm68k.r'
 		rez_data = '--copy'
 		rezflags = []
-		flisp_code = flisp
+		sl_code = sl
 	else
 		assert(cpu == 'ppc', 'unexpected cpu setting')
-		template = 'femtolispppc.r'
+		template = 'ppc.r'
 		rez_data = '--data'
 		rezflags = ['-DTARGET_API_MAC_CARBON=0']
-		flisp_code = custom_target(
-			'flisp.pef',
+		sl_code = custom_target(
+			'sl.pef',
 			input: [
-				flisp
+				sl
 			],
 			output: [
-				'flisp.pef',
+				'sl.pef',
 			],
 			command: [
 				makepef,
@@ -315,15 +315,15 @@
 	endif
 	template = meson.global_source_root()/'src/macos'/template
 
-	flisp_bin = custom_target(
-		'flisp.bin',
+	sl_bin = custom_target(
+		'sl.bin',
 		input: [
-			flisp_code,
+			sl_code,
 			template,
 		],
 		output: [
-			'flisp.bin',
-			'flisp.dsk',
+			'sl.bin',
+			'sl.dsk',
 		],
 		command: [
 			rez,
@@ -330,12 +330,12 @@
 			'-I' + rincludes,
 		] + rezflags + [
 			template,
-			'-DCFRAG_NAME="flisp"',
-			'-o', 'flisp.bin',
+			'-DCFRAG_NAME="sl"',
+			'-o', 'sl.bin',
 			'-t', 'APPL',
 			'-c', '????',
-			rez_data, flisp_code,
-			'--cc', 'flisp.dsk',
+			rez_data, sl_code,
+			'--cc', 'sl.dsk',
 		],
 		build_by_default: true,
 	)
@@ -375,18 +375,18 @@
 src_dir = meson.current_source_dir()
 tests_dir = join_paths(src_dir, 'test')
 
-test('100x100.lsp', flisp, args: ['100x100.lsp'], workdir: tests_dir)
-test('argv.lsp', flisp, args: ['argv.lsp'], workdir: tests_dir)
-test('exit0.lsp', flisp, args: ['exit0.lsp'], workdir: tests_dir)
-test('exit1.lsp', flisp, args: ['exit1.lsp'], workdir: tests_dir, should_fail: true)
-test('bench.lsp', flisp, args: ['bench.lsp'], workdir: tests_dir)
-test('hashtest.lsp', flisp, args: ['hashtest.lsp'], workdir: tests_dir)
-test('mp.lsp', flisp, args: ['mp.lsp'], workdir: tests_dir)
-test('perf.lsp', flisp, args: ['perf.lsp'], workdir: tests_dir, timeout: -1)
-test('tme.lsp', flisp, args: ['tme.lsp'], workdir: tests_dir)
-test('torture.lsp', flisp, args: ['-S', '8m', 'torture.lsp'], workdir: tests_dir, timeout: -1)
-test('torus.lsp', flisp, args: ['torus.lsp'], workdir: tests_dir)
-test('unit.lsp', flisp, args: ['-S', '1m', 'unittest.lsp'], workdir: tests_dir)
+test('100x100.lsp', sl, args: ['100x100.lsp'], workdir: tests_dir)
+test('argv.lsp', sl, args: ['argv.lsp'], workdir: tests_dir)
+test('exit0.lsp', sl, args: ['exit0.lsp'], workdir: tests_dir)
+test('exit1.lsp', sl, args: ['exit1.lsp'], workdir: tests_dir, should_fail: true)
+test('bench.lsp', sl, args: ['bench.lsp'], workdir: tests_dir)
+test('hashtest.lsp', sl, args: ['hashtest.lsp'], workdir: tests_dir)
+test('mp.lsp', sl, args: ['mp.lsp'], workdir: tests_dir)
+test('perf.lsp', sl, args: ['perf.lsp'], workdir: tests_dir, timeout: -1)
+test('tme.lsp', sl, args: ['tme.lsp'], workdir: tests_dir)
+test('torture.lsp', sl, args: ['-S', '8m', 'torture.lsp'], workdir: tests_dir, timeout: -1)
+test('torus.lsp', sl, args: ['torus.lsp'], workdir: tests_dir)
+test('unit.lsp', sl, args: ['-S', '1m', 'unittest.lsp'], workdir: tests_dir)
 
 bootstrap = find_program(
 	'bootstrap.sh',
--- a/mkfile
+++ b/mkfile
@@ -1,16 +1,16 @@
 </$objtype/mkfile
 
 BIN=/$objtype/bin
-TARG=flisp
+TARG=sl
 CFLAGS=$CFLAGS -p -Isrc -I3rd -I3rd/brieflz -Isrc/plan9 \
 	-D__plan9__ -D__${objtype}__ \
 	-DNDEBUG \
 
-CLEANFILES=src/plan9/flisp.boot.s src/plan9/builtin_fns.h
+CLEANFILES=src/plan9/sl.boot.s src/plan9/builtin_fns.h
 
 HFILES=\
 	src/equalhash.h\
-	src/flisp.h\
+	src/sl.h\
 	src/opcodes.h\
 	src/plan9/platform.h\
 
@@ -29,8 +29,8 @@
 	src/cvalues.$O\
 	src/equal.$O\
 	src/equalhash.$O\
-	src/flisp.$O\
-	src/flmain.$O\
+	src/sl.$O\
+	src/slmain.$O\
 	src/hashing.$O\
 	src/htable.$O\
 	src/ios.$O\
@@ -40,7 +40,7 @@
 	src/opcodes.$O\
 	src/operators.$O\
 	src/plan9/clz`{test -f src/plan9/clz_$objtype.s && echo -n _$objtype}.$O\
-	src/plan9/flisp.boot.$O\
+	src/plan9/sl.boot.$O\
 	src/plan9/popcount`{test -f src/plan9/popcount_$objtype.s && echo -n _$objtype}.$O\
 	src/plan9/sys.$O\
 	src/print.$O\
@@ -58,18 +58,18 @@
 
 src/plan9/builtin_fns.h:D:
 	awk -F '[()]' '\
-		/^fl_.*fn/     {attr=$1; next} \
+		/^sl_.*fn/     {attr=$1; next} \
 		/^_Noreturn/   {attr=$1; next} \
 		/^BUILTIN[_]?/ {printf "BUILTIN_FN(%s, %s)\n", $2, attr} \
 		{attr=""}' \
 	`{ls `{echo $OFILES | sed 's/\.'$O'/.c/g'} >[2]/dev/null} | sort >$target
 
-src/cvalues.$O: src/fl_arith_any.inc
-src/flisp.$O: src/vm.inc
+src/cvalues.$O: src/sl_arith_any.inc
+src/sl.$O: src/vm.inc
 src/equalhash.$O: src/htable.inc
 src/ptrhash.$O: src/htable.inc
 
-src/plan9/flisp.boot.s:D: boot/flisp.boot.builtin
+src/plan9/sl.boot.s:D: boot/sl.boot.builtin
 	aux/data2s boot <$prereq >$target
 
 %.$O: %.c
@@ -83,10 +83,10 @@
 bootstrap:V: $O.out
 	cd src && \
 	../$O.out ../tools/gen.lsp && \
-	cp ../boot/flisp.boot ../boot/flisp.boot.bak && \
-	../$O.out ../tools/mkboot0.lsp builtins.lsp instructions.lsp system.lsp compiler.lsp > ../boot/flisp.boot.new && \
-	mv ../boot/flisp.boot.new ../boot/flisp.boot && \
-	cp ../boot/flisp.boot ../boot/flisp.boot.builtin && \
+	cp ../boot/sl.boot ../boot/sl.boot.bak && \
+	../$O.out ../tools/mkboot0.lsp builtins.lsp instructions.lsp system.lsp compiler.lsp > ../boot/sl.boot.new && \
+	mv ../boot/sl.boot.new ../boot/sl.boot && \
+	cp ../boot/sl.boot ../boot/sl.boot.builtin && \
 	cd .. && \
 	mk && \
 	cd boot && \
--- a/src/bitvector.c
+++ b/src/bitvector.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 
 uint32_t *
 bitvector_resize(uint32_t *b, uint64_t oldsz, uint64_t newsz, bool zero)
--- a/src/builtins.c
+++ b/src/builtins.c
@@ -1,8 +1,4 @@
-/*
-  Extra femtoLisp builtin functions
-*/
-
-#include "flisp.h"
+#include "sl.h"
 #include "operators.h"
 #include "cvalues.h"
 #include "timefuncs.h"
@@ -26,9 +22,9 @@
 BUILTIN("nconc", nconc)
 {
 	if(nargs == 0)
-		return FL_nil;
+		return SL_nil;
 
-	value_t lst, first = FL_nil;
+	value_t lst, first = SL_nil;
 	value_t *pcdr = &first;
 	cons_t *c;
 	int i = 0;
@@ -43,7 +39,7 @@
 			while(iscons(c->cdr))
 				c = ptr(c->cdr);
 			pcdr = &c->cdr;
-		}else if(lst != FL_nil)
+		}else if(lst != SL_nil)
 			type_error("cons", lst);
 	}
 	*pcdr = lst;
@@ -50,7 +46,7 @@
 	return first;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("assq", assq)
 {
 	argcount(nargs, 2);
@@ -65,10 +61,10 @@
 			return bind;
 		v = cdr_(v);
 	}
-	return FL_nil;
+	return SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("memq", memq)
 {
 	argcount(nargs, 2);
@@ -79,7 +75,7 @@
 		if((c = ptr(v))->car == args[0])
 			return v;
 	}
-	return FL_nil;
+	return SL_nil;
 }
 
 BUILTIN("length", length)
@@ -106,9 +102,9 @@
 	}
 	if(iscprim(a)){
 		cv = ptr(a);
-		if(cp_class(cv) == FL(bytetype))
+		if(cp_class(cv) == SL(bytetype))
 			return fixnum(1);
-		if(cp_class(cv) == FL(runetype))
+		if(cp_class(cv) == SL(runetype))
 			return fixnum(runelen(*(Rune*)cp_data(cv)));
 	}
 	if(iscvalue(a) && cv_class(ptr(a))->eltype != nil)
@@ -126,7 +122,7 @@
 		}
 		return size_wrap(n);
 	}
-	if(a == FL_nil)
+	if(a == SL_nil)
 		return fixnum(0);
 	type_error("sequence", a);
 }
@@ -135,7 +131,7 @@
 BUILTIN("raise", raise)
 {
 	argcount(nargs, 1);
-	fl_raise(args[0]);
+	sl_raise(args[0]);
 }
 
 _Noreturn
@@ -143,25 +139,25 @@
 {
 	if(nargs > 1)
 		argcount(nargs, 1);
-	fl_exit(nargs > 0 ? tofixnum(args[0]) : 0);
+	sl_exit(nargs > 0 ? tofixnum(args[0]) : 0);
 }
 
 BUILTIN("symbol", symbol)
 {
 	argcount(nargs, 1);
-	if(fl_unlikely(!fl_isstring(args[0])))
+	if(sl_unlikely(!sl_isstring(args[0])))
 		type_error("string", args[0]);
 	return symbol(cvalue_data(args[0]), true);
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("keyword?", keywordp)
 {
 	argcount(nargs, 1);
-	return (issymbol(args[0]) && iskeyword((symbol_t*)ptr(args[0]))) ? FL_t : FL_nil;
+	return (issymbol(args[0]) && iskeyword((symbol_t*)ptr(args[0]))) ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("top-level-value", top_level_value)
 {
 	argcount(nargs, 1);
@@ -186,7 +182,7 @@
 	symbol_t *sym = tosymbol(args[0]);
 	if(!isconstant(sym))
 		sym->binding = UNBOUND;
-	return FL_void;
+	return SL_void;
 }
 
 BUILTIN("environment", environment)
@@ -193,43 +189,43 @@
 {
 	USED(args);
 	argcount(nargs, 0);
-	value_t lst = FL_nil;
-	fl_gc_handle(&lst);
+	value_t lst = SL_nil;
+	sl_gc_handle(&lst);
 	const char *k = nil;
 	symbol_t *v;
-	while(Tnext(FL(symtab), &k, (void**)&v)){
+	while(Tnext(SL(symtab), &k, (void**)&v)){
 		if(v->binding != UNBOUND && (v->flags & FLAG_KEYWORD) == 0)
-			lst = fl_cons(tagptr(v, TAG_SYM), lst);
+			lst = sl_cons(tagptr(v, TAG_SYM), lst);
 	}
-	fl_free_gc_handles(1);
+	sl_free_gc_handles(1);
 	return lst;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("constant?", constantp)
 {
 	argcount(nargs, 1);
 	if(issymbol(args[0]))
-		return isconstant((symbol_t*)ptr(args[0])) ? FL_t : FL_nil;
+		return isconstant((symbol_t*)ptr(args[0])) ? SL_t : SL_nil;
 	if(iscons(args[0])){
-		if(car_(args[0]) == FL_quote)
-			return FL_t;
-		return FL_nil;
+		if(car_(args[0]) == SL_quote)
+			return SL_t;
+		return SL_nil;
 	}
-	return FL_t;
+	return SL_t;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("integer-valued?", integer_valuedp)
 {
 	argcount(nargs, 1);
 	value_t v = args[0];
 	if(isfixnum(v) || ismpint(v))
-		return FL_t;
+		return SL_t;
 	if(iscprim(v)){
 		numerictype_t nt = cp_numtype(ptr(v));
 		if(nt < T_FLOAT)
-			return FL_t;
+			return SL_t;
 		void *data = cp_data(ptr(v));
 		if(nt == T_FLOAT){
 			float f = *(float*)data;
@@ -236,7 +232,7 @@
 			if(f < 0)
 				f = -f;
 			if(f <= FLT_MAXINT && (float)(int32_t)f == f)
-				return FL_t;
+				return SL_t;
 		}else{
 			assert(nt == T_DOUBLE);
 			double d = *(double*)data;
@@ -243,13 +239,13 @@
 			if(d < 0)
 				d = -d;
 			if(d <= DBL_MAXINT && (double)(int64_t)d == d)
-				return FL_t;
+				return SL_t;
 		}
 	}
-	return FL_nil;
+	return SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("integer?", integerp)
 {
 	argcount(nargs, 1);
@@ -256,14 +252,14 @@
 	value_t v = args[0];
 	return (isfixnum(v) || ismpint(v) ||
 			(iscprim(v) && cp_numtype(ptr(v)) < T_FLOAT)) ?
-		FL_t : FL_nil;
+		SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("bignum?", bignump)
 {
 	argcount(nargs, 1);
-	return ismpint(args[0]) ? FL_t : FL_nil;
+	return ismpint(args[0]) ? SL_t : SL_nil;
 }
 
 BUILTIN("fixnum", fixnum)
@@ -323,7 +319,7 @@
 	value_t v = alloc_vector(i, 0);
 	int a = 1;
 	for(size_t k = 0; k < i; k++){
-		value_t f = a < nargs ? args[a] : FL_void;
+		value_t f = a < nargs ? args[a] : SL_void;
 		vector_elt(v, k) = f;
 		if((a = (a + 1) % nargs) < 1)
 			a = 1;
@@ -387,13 +383,13 @@
 	if(nargs == 0){
 		char buf[4096];
 		if(getcwd(buf, sizeof(buf)) == nil)
-			lerrorf(FL_IOError, "could not get current dir");
+			lerrorf(SL_IOError, "could not get current dir");
 		return string_from_cstr(buf);
 	}
 	char *ptr = tostring(args[0]);
 	if(chdir(ptr) != 0)
-		lerrorf(FL_IOError, "could not cd to %s", ptr);
-	return FL_void;
+		lerrorf(SL_IOError, "could not cd to %s", ptr);
+	return SL_void;
 }
 
 BUILTIN("path-exists?", path_existsp)
@@ -400,7 +396,7 @@
 {
 	argcount(nargs, 1);
 	const char *path = tostring(args[0]);
-	return access(path, F_OK) == 0 ? FL_t : FL_nil;
+	return access(path, F_OK) == 0 ? SL_t : SL_nil;
 }
 
 BUILTIN("delete-file", delete_file)
@@ -408,8 +404,8 @@
 	argcount(nargs, 1);
 	const char *path = tostring(args[0]);
 	if(remove(path) != 0)
-		lerrorf(FL_IOError, "could not remove %s", path);
-	return FL_void;
+		lerrorf(SL_IOError, "could not remove %s", path);
+	return SL_void;
 }
 
 BUILTIN("os-getenv", os_getenv)
@@ -418,7 +414,7 @@
 	char *name = tostring(args[0]);
 	char *val = getenv(name);
 	if(val == nil)
-		return FL_nil;
+		return SL_nil;
 	return cvalue_static_cstring(val);
 }
 
@@ -427,7 +423,7 @@
 	argcount(nargs, 2);
 	char *name = tostring(args[0]);
 	int result;
-	if(args[1] == FL_nil)
+	if(args[1] == SL_nil)
 		result = unsetenv(name);
 	else{
 		char *val = tostring(args[1]);
@@ -434,6 +430,6 @@
 		result = setenv(name, val, 1);
 	}
 	if(result != 0)
-		lerrorf(FL_ArgError, "invalid environment variable");
-	return FL_t;
+		lerrorf(SL_ArgError, "invalid environment variable");
+	return SL_t;
 }
--- a/src/cc.h
+++ b/src/cc.h
@@ -2,21 +2,21 @@
 
 #ifdef __GNUC__
 
-#define fl_unlikely(x) __builtin_expect(!!(x), 0)
-#define fl_likely(x) __builtin_expect(!!(x), 1)
-#define fl_printfmt(x, y) __attribute__((format(printf, x, y)))
+#define sl_unlikely(x) __builtin_expect(!!(x), 0)
+#define sl_likely(x) __builtin_expect(!!(x), 1)
+#define sl_printfmt(x, y) __attribute__((format(printf, x, y)))
 #if defined(NDEBUG) && !defined(__macos__) && !defined(__dos__)
-#define fl_thread(x) __thread x
+#define sl_thread(x) __thread x
 #else
-#define fl_thread(x) x
+#define sl_thread(x) x
 #endif
-#define fl_prefetch(x) __builtin_prefetch(x)
-#define fl_constfn __attribute__((const))
-#define fl_purefn __attribute__((pure))
-#define fl_hotfn __attribute__((hot))
-#define fl_aligned(x) __attribute__((aligned(x)))
-#define fl_popcount(x) __builtin_popcount(x)
-#define fl_clz(x) __builtin_clz(x)
+#define sl_prefetch(x) __builtin_prefetch(x)
+#define sl_constfn __attribute__((const))
+#define sl_purefn __attribute__((pure))
+#define sl_hotfn __attribute__((hot))
+#define sl_aligned(x) __attribute__((aligned(x)))
+#define sl_popcount(x) __builtin_popcount(x)
+#define sl_clz(x) __builtin_clz(x)
 #define sadd_overflow __builtin_add_overflow
 #define sadd_overflow_64 __builtin_add_overflow
 #define smul_overflow_64 __builtin_mul_overflow
@@ -23,15 +23,15 @@
 
 #else
 
-#define fl_unlikely(x) (x)
-#define fl_likely(x) (x)
-#define fl_printfmt(x, y)
-#define fl_thread(x) x
-#define fl_prefetch(x)
-#define fl_constfn
-#define fl_purefn
-#define fl_hotfn
-#define fl_aligned(x)
+#define sl_unlikely(x) (x)
+#define sl_likely(x) (x)
+#define sl_printfmt(x, y)
+#define sl_thread(x) x
+#define sl_prefetch(x)
+#define sl_constfn
+#define sl_purefn
+#define sl_hotfn
+#define sl_aligned(x)
 
 /* FIXME(sigrid): s*_overflow_* can be more optimal */
 #define sadd_overflow_64(a, b, c) ( \
--- a/src/compress.c
+++ b/src/compress.c
@@ -1,10 +1,10 @@
-#include "flisp.h"
+#include "sl.h"
 #include "compress.h"
 #include "cvalues.h"
 #include "types.h"
 #include "brieflz.h"
 
-static value_t FL_sizesym, FL_tosym;
+static value_t SL_sizesym, SL_tosym;
 
 BUILTIN("lz-pack", lz_pack)
 {
@@ -36,7 +36,7 @@
 		: blz_pack(in, out, insz, work);
 	MEM_FREE(work);
 	if(n == BLZ_ERROR)
-		lerrorf(FL_ArgError, "blz error");
+		lerrorf(SL_ArgError, "blz error");
 	cvalue_len(v) = n;
 	return v;
 }
@@ -53,19 +53,19 @@
 	size_t outsz;
 	uint8_t *out;
 	value_t v;
-	if(args[1] == FL_sizesym){
+	if(args[1] == SL_sizesym){
 		outsz = tosize(args[2]);
 		v = cvalue(cv_class(ptr(args[0])), outsz);
 		out = cvalue_data(v);
-	}else if(args[1] == FL_tosym){
+	}else if(args[1] == SL_tosym){
 		v = args[2];
 		to_sized_ptr(v, &out, &outsz);
 	}else{
-		lerrorf(FL_ArgError, "either :size or :to must be specified");
+		lerrorf(SL_ArgError, "either :size or :to must be specified");
 	}
 	unsigned long n = blz_depack_safe(in, insz, out, outsz);
 	if(n == BLZ_ERROR)
-		lerrorf(FL_ArgError, "blz error");
+		lerrorf(SL_ArgError, "blz error");
 	cvalue_len(v) = n;
 	return v;
 }
@@ -73,6 +73,6 @@
 void
 compress_init(void)
 {
-	FL_sizesym = csymbol(":size");
-	FL_tosym = csymbol(":to");
+	SL_sizesym = csymbol(":size");
+	SL_tosym = csymbol(":to");
 }
--- a/src/cvalues.c
+++ b/src/cvalues.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "operators.h"
 #include "cvalues.h"
 #include "types.h"
@@ -15,17 +15,17 @@
 #define owned(cv) ((uintptr_t)(cv)->type & CV_OWNED)
 #define isinlined(cv) ((cv)->data == (cv)->_space)
 
-static void cvalue_init(fltype_t *type, value_t v, void *dest);
+static void cvalue_init(sltype_t *type, value_t v, void *dest);
 
 void
 add_finalizer(cvalue_t *cv)
 {
-	if(FL(nfinalizers) == FL(maxfinalizers)){
-		FL(maxfinalizers) *= 2;
-		FL(finalizers) = MEM_REALLOC(FL(finalizers), FL(maxfinalizers)*sizeof(FL(finalizers)));
-		assert(FL(finalizers) != nil);
+	if(SL(nfinalizers) == SL(maxfinalizers)){
+		SL(maxfinalizers) *= 2;
+		SL(finalizers) = MEM_REALLOC(SL(finalizers), SL(maxfinalizers)*sizeof(SL(finalizers)));
+		assert(SL(finalizers) != nil);
 	}
-	FL(finalizers)[FL(nfinalizers)++] = cv;
+	SL(finalizers)[SL(nfinalizers)++] = cv;
 }
 
 // remove dead objects from finalization list in-place
@@ -32,13 +32,13 @@
 void
 sweep_finalizers(void)
 {
-	cvalue_t **lst = FL(finalizers);
-	size_t n = 0, ndel = 0, l = FL(nfinalizers);
+	cvalue_t **lst = SL(finalizers);
+	size_t n = 0, ndel = 0, l = SL(nfinalizers);
 	cvalue_t *tmp;
 #define SWAP_sf(a, b) (tmp = a, a = b, b = tmp, 1)
 	if(l == 0)
 		return;
-	bool exiting = FL(exiting);
+	bool exiting = SL(exiting);
 	do{
 		tmp = lst[n];
 		if(isforwarded((value_t)tmp)){
@@ -46,7 +46,7 @@
 			lst[n] = ptr(forwardloc((value_t)tmp));
 			n++;
 		}else{
-			fltype_t *t = cv_class(tmp);
+			sltype_t *t = cv_class(tmp);
 			if(t->vtable != nil && t->vtable->finalize != nil)
 				t->vtable->finalize(tagptr(tmp, TAG_CVALUE));
 			if(!isinlined(tmp) && owned(tmp) && !exiting)
@@ -55,9 +55,9 @@
 		}
 	}while((n < l-ndel) && SWAP_sf(lst[n], lst[n+ndel]));
 
-	FL(nfinalizers) -= ndel;
+	SL(nfinalizers) -= ndel;
 
-	FL(malloc_pressure) = 0;
+	SL(malloc_pressure) = 0;
 }
 
 // compute the size of the metadata object for a cvalue
@@ -75,12 +75,12 @@
 void
 cv_autorelease(cvalue_t *cv)
 {
-	cv->type = (fltype_t*)(((uintptr_t)cv->type) | CV_OWNED);
+	cv->type = (sltype_t*)(((uintptr_t)cv->type) | CV_OWNED);
 	add_finalizer(cv);
 }
 
 static value_t
-cprim(fltype_t *type, size_t sz)
+cprim(sltype_t *type, size_t sz)
 {
 	assert(!ismanaged((uintptr_t)type));
 	assert(sz == type->size);
@@ -90,7 +90,7 @@
 }
 
 value_t
-cvalue_(fltype_t *type, size_t sz, bool nofinalize)
+cvalue_(sltype_t *type, size_t sz, bool nofinalize)
 {
 	assert(type != nil);
 	if(valid_numtype(type->numtype) && type->numtype != T_MPINT)
@@ -97,9 +97,9 @@
 		return cprim(type, sz);
 
 	bool str = false;
-	if(type->eltype == FL(bytetype)){
+	if(type->eltype == SL(bytetype)){
 		if(sz == 0)
-			return FL(the_empty_string);
+			return SL(the_empty_string);
 		sz++;
 		str = true;
 	}
@@ -112,13 +112,13 @@
 		if(!nofinalize && type->vtable != nil && type->vtable->finalize != nil)
 			add_finalizer(pcv);
 	}else{
-		if(FL(malloc_pressure) > ALLOC_LIMIT_TRIGGER)
-			fl_gc(false);
+		if(SL(malloc_pressure) > ALLOC_LIMIT_TRIGGER)
+			sl_gc(false);
 		pcv = alloc_words(CVALUE_NWORDS);
 		pcv->type = type;
 		pcv->data = MEM_ALLOC(sz);
 		cv_autorelease(pcv);
-		FL(malloc_pressure) += sz;
+		SL(malloc_pressure) += sz;
 	}
 	if(str)
 		((char*)pcv->data)[--sz] = '\0';
@@ -135,7 +135,7 @@
 // 'parent' is an optional cvalue that this pointer is known to point
 // into; NIL if none.
 value_t
-cvalue_from_ref(fltype_t *type, void *ptr, size_t sz)
+cvalue_from_ref(sltype_t *type, void *ptr, size_t sz)
 {
 	cvalue_t *pcv;
 
@@ -152,8 +152,8 @@
 cvalue_string(size_t sz)
 {
 	if(sz == 0)
-		return FL(the_empty_string);
-	return cvalue(FL(stringtype), sz);
+		return SL(the_empty_string);
+	return cvalue(SL(stringtype), sz);
 }
 
 value_t
@@ -160,8 +160,8 @@
 cvalue_static_cstring(const char *str)
 {
 	if(*str == 0)
-		return FL(the_empty_string);
-	return cvalue_from_ref(FL(stringtype), (char*)str, strlen(str));
+		return SL(the_empty_string);
+	return cvalue_from_ref(SL(stringtype), (char*)str, strlen(str));
 }
 
 value_t
@@ -179,7 +179,7 @@
 }
 
 bool
-fl_isstring(value_t v)
+sl_isstring(value_t v)
 {
 	return iscvalue(v) && cv_isstr(ptr(v));
 }
@@ -201,7 +201,7 @@
 
 #define num_init(ctype, cnvt, tag) \
 	static void \
-	cvalue_##ctype##_init(fltype_t *type, value_t arg, void *dest) \
+	cvalue_##ctype##_init(sltype_t *type, value_t arg, void *dest) \
 	{ \
 		ctype n; \
 		USED(type); \
@@ -236,10 +236,10 @@
 	{ \
 		if(nargs == 0){ \
 			PUSH(fixnum(0)); \
-			args = FL(sp)-1; \
+			args = SL(sp)-1; \
 		} \
-		value_t cp = cprim(FL(typenam##type), sizeof(ctype)); \
-		cvalue_##ctype##_init(FL(typenam##type), args[0], cp_data(ptr(cp))); \
+		value_t cp = cprim(SL(typenam##type), sizeof(ctype)); \
+		cvalue_##ctype##_init(SL(typenam##type), args[0], cp_data(ptr(cp))); \
 		return cp; \
 	}
 
@@ -246,7 +246,7 @@
 #define num_ctor_ctor(typenam, ctype, tag) \
 	value_t mk_##typenam(ctype n) \
 	{ \
-		value_t cp = cprim(FL(typenam##type), sizeof(ctype)); \
+		value_t cp = cprim(SL(typenam##type), sizeof(ctype)); \
 		*(ctype*)cp_data(ptr(cp)) = n; \
 		return cp; \
 	}
@@ -269,7 +269,7 @@
 num_ctor(rune, uint32_t, T_UINT32)
 
 static void
-cvalue_mpint_init(fltype_t *type, value_t arg, void *dest)
+cvalue_mpint_init(sltype_t *type, value_t arg, void *dest)
 {
 	mpint *n;
 	USED(type);
@@ -292,10 +292,10 @@
 {
 	if(nargs == 0){
 		PUSH(fixnum(0));
-		args = FL(sp)-1;
+		args = SL(sp)-1;
 	}
-	value_t cv = cvalue(FL(mpinttype), sizeof(mpint*));
-	cvalue_mpint_init(FL(mpinttype), args[0], cvalue_data(cv));
+	value_t cv = cvalue(SL(mpinttype), sizeof(mpint*));
+	cvalue_mpint_init(SL(mpinttype), args[0], cvalue_data(cv));
 	return cv;
 }
 
@@ -303,7 +303,7 @@
 value_t
 mk_mpint(mpint *n)
 {
-	value_t cv = cvalue(FL(mpinttype), sizeof(mpint*));
+	value_t cv = cvalue(SL(mpinttype), sizeof(mpint*));
 	*(mpint**)cvalue_data(cv) = n;
 	return cv;
 }
@@ -366,7 +366,7 @@
 		return vector_size(arg);
 	if(iscons(arg))
 		return llength(arg);
-	if(arg == FL_nil)
+	if(arg == SL_nil)
 		return 0;
 	if(isarray(arg))
 		return cvalue_arraylen(arg);
@@ -374,11 +374,11 @@
 }
 
 void
-cvalue_array_init(fltype_t *ft, value_t arg, void *dest)
+cvalue_array_init(sltype_t *ft, value_t arg, void *dest)
 {
 	value_t type = ft->type;
 	size_t elsize, i, cnt, sz;
-	fltype_t *eltype = ft->eltype;
+	sltype_t *eltype = ft->eltype;
 
 	elsize = ft->elsz;
 	cnt = predict_arraylen(arg);
@@ -386,7 +386,7 @@
 	if(iscons(cdr_(cdr_(type)))){
 		size_t tc = tosize(car_(cdr_(cdr_(type))));
 		if(tc != cnt)
-			lerrorf(FL_ArgError, "size mismatch");
+			lerrorf(SL_ArgError, "size mismatch");
 	}
 
 	sz = elsize * cnt;
@@ -399,7 +399,7 @@
 		}
 		return;
 	}
-	if(iscons(arg) || arg == FL_nil){
+	if(iscons(arg) || arg == SL_nil){
 		i = 0;
 		while(iscons(arg)){
 			if(i == cnt){
@@ -412,22 +412,22 @@
 			arg = cdr_(arg);
 		}
 		if(i != cnt)
-			lerrorf(FL_ArgError, "size mismatch");
+			lerrorf(SL_ArgError, "size mismatch");
 		return;
 	}
 	if(iscvalue(arg)){
 		cvalue_t *cv = ptr(arg);
 		if(isarray(arg)){
-			fltype_t *aet = cv_class(cv)->eltype;
+			sltype_t *aet = cv_class(cv)->eltype;
 			if(aet == eltype){
 				if(cv_len(cv) == sz)
 					memcpy(dest, cv_data(cv), sz);
 				else
-					lerrorf(FL_ArgError, "size mismatch");
+					lerrorf(SL_ArgError, "size mismatch");
 				return;
 			}else{
 				// TODO: initialize array from different type elements
-				lerrorf(FL_ArgError, "element type mismatch");
+				lerrorf(SL_ArgError, "element type mismatch");
 			}
 		}
 	}
@@ -445,7 +445,7 @@
 		argcount(nargs, 1);
 
 	cnt = nargs - 1;
-	fltype_t *type = get_array_type(args[0]);
+	sltype_t *type = get_array_type(args[0]);
 	elsize = type->elsz;
 	sz = elsize * cnt;
 
@@ -453,7 +453,7 @@
 	char *dest = cvalue_data(cv);
 	int i;
 	FOR_ARGS(i, 1, arg, args){
-		if(!fl_isnumber(arg))
+		if(!sl_isnumber(arg))
 			type_error("number", arg);
 		cvalue_init(type->eltype, arg, dest);
 		dest += elsize;
@@ -470,9 +470,9 @@
 		argcount(nargs, 3);
 	cnt = tosize(args[1]);
 	if(cnt < 0)
-		lerrorf(FL_ArgError, "invalid size: %"PRIu64, (uint64_t)cnt);
+		lerrorf(SL_ArgError, "invalid size: %"PRIu64, (uint64_t)cnt);
 
-	fltype_t *type = get_array_type(args[0]);
+	sltype_t *type = get_array_type(args[0]);
 	elsize = type->elsz;
 	sz = elsize * cnt;
 
@@ -481,7 +481,7 @@
 	a = 2;
 	for(i = 0; i < cnt; i++){
 		value_t arg = args[a];
-		if(!fl_isnumber(arg))
+		if(!sl_isnumber(arg))
 			type_error("number", arg);
 		cvalue_init(type->eltype, arg, dest);
 		dest += elsize;
@@ -509,10 +509,10 @@
 
 	if(iscons(type)){
 		value_t hed = car_(type);
-		if(hed == FL_arraysym){
+		if(hed == SL_arraysym){
 			value_t t = car(cdr_(type));
 			if(!iscons(cdr_(cdr_(type))))
-				lerrorf(FL_ArgError, "incomplete type");
+				lerrorf(SL_ArgError, "incomplete type");
 			value_t n = car_(cdr_(cdr_(type)));
 			size_t sz = tosize(n);
 			return sz * ctype_sizeof(t);
@@ -519,7 +519,7 @@
 		}
 	}
 
-	lerrorf(FL_ArgError, "invalid c type");
+	lerrorf(SL_ArgError, "invalid c type");
 }
 
 // get pointer and size for any plain-old-data value
@@ -529,7 +529,7 @@
 	if(iscvalue(v)){
 		cvalue_t *pcv = ptr(v);
 		ios_t *x = value2c(ios_t*, v);
-		if(cv_class(pcv) == FL(iostreamtype) && x->bm == bm_mem){
+		if(cv_class(pcv) == SL(iostreamtype) && x->bm == bm_mem){
 			*pdata = x->buf;
 			*psz = x->size;
 			return;
@@ -560,27 +560,27 @@
 	return size_wrap(n);
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("typeof", typeof)
 {
 	argcount(nargs, 1);
 	switch(tag(args[0])){
-	case TAG_CONS: return FL_conssym;
-	case TAG_NUM1: case TAG_NUM: return FL_fixnumsym;
-	case TAG_SYM: return FL_symbolsym;
-	case TAG_VECTOR: return FL_vectorsym;
+	case TAG_CONS: return SL_conssym;
+	case TAG_NUM1: case TAG_NUM: return SL_fixnumsym;
+	case TAG_SYM: return SL_symbolsym;
+	case TAG_VECTOR: return SL_vectorsym;
 	case TAG_FUNCTION:
-		if(args[0] == FL_t)
-			return FL_booleansym;
-		if(args[0] == FL_nil)
-			return FL_nullsym;
-		if(args[0] == FL_eof)
-			return FL_eof;
-		if(args[0] == FL_void)
-			return FL_void;
+		if(args[0] == SL_t)
+			return SL_booleansym;
+		if(args[0] == SL_nil)
+			return SL_nullsym;
+		if(args[0] == SL_eof)
+			return SL_eof;
+		if(args[0] == SL_void)
+			return SL_void;
 		if(isbuiltin(args[0]))
-			return FL_builtinsym;
-		return FL_function;
+			return SL_builtinsym;
+		return SL_function;
 	}
 	return cv_type(ptr(args[0]));
 }
@@ -599,11 +599,11 @@
 	if(isinlined(cv))
 		nv->data = nv->_space;
 	ncv = tagptr(nv, TAG_CVALUE);
-	fltype_t *t = cv_class(cv);
+	sltype_t *t = cv_class(cv);
 	if(t->vtable != nil && t->vtable->relocate != nil)
 		t->vtable->relocate(v, ncv);
 	forward(v, ncv);
-	if(FL(exiting))
+	if(SL(exiting))
 		cv_autorelease(ptr(ncv));
 	return ncv;
 }
@@ -637,29 +637,29 @@
 {
 	argcount(nargs, 1);
 	if(iscons(args[0]) || isvector(args[0]))
-		lerrorf(FL_ArgError, "argument must be a leaf atom");
+		lerrorf(SL_ArgError, "argument must be a leaf atom");
 	if(!iscvalue(args[0]))
 		return args[0];
 	if(!cv_isPOD(ptr(args[0])))
-		lerrorf(FL_ArgError, "argument must be a plain-old-data type");
+		lerrorf(SL_ArgError, "argument must be a plain-old-data type");
 	return cvalue_copy(args[0]);
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("plain-old-data?", plain_old_datap)
 {
 	argcount(nargs, 1);
 	return (iscprim(args[0]) ||
 			(iscvalue(args[0]) && cv_isPOD(ptr(args[0])))) ?
-		FL_t : FL_nil;
+		SL_t : SL_nil;
 }
 
 static void
-cvalue_init(fltype_t *type, value_t v, void *dest)
+cvalue_init(sltype_t *type, value_t v, void *dest)
 {
 	cvinitfunc_t f = type->init;
 	if(f == nil)
-		lerrorf(FL_ArgError, "invalid c type");
+		lerrorf(SL_ArgError, "invalid c type");
 	f(type, v, dest);
 }
 
@@ -672,7 +672,7 @@
 	if(nargs < 1 || nargs > 2)
 		argcount(nargs, 2);
 	value_t type = args[0];
-	fltype_t *ft = get_type(type);
+	sltype_t *ft = get_type(type);
 	value_t cv;
 	if(ft->eltype != nil){
 		// special case to handle incomplete array types bla[]
@@ -734,7 +734,7 @@
 {
 	uint8_t *data;
 	int index;
-	fltype_t *eltype = cv_class(ptr(args[0]))->eltype;
+	sltype_t *eltype = cv_class(ptr(args[0]))->eltype;
 	value_t el = 0;
 	numerictype_t nt = eltype->numtype;
 	if(nt >= T_INT32)
@@ -768,7 +768,7 @@
 cvalue_array_aset(value_t *args)
 {
 	uint8_t *data; int index;
-	fltype_t *eltype = cv_class(ptr(args[0]))->eltype;
+	sltype_t *eltype = cv_class(ptr(args[0]))->eltype;
 	check_addr_args(args[0], args[1], &data, &index);
 	uint8_t *dest = data + index*eltype->size;
 	cvalue_init(eltype, args[2], dest);
@@ -775,13 +775,13 @@
 	return args[2];
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("builtin", builtin)
 {
 	argcount(nargs, 1);
 	symbol_t *s = tosymbol(args[0]);
 	if(!iscbuiltin(s->binding))
-		lerrorf(FL_ArgError, "function \"%s\" not found", s->name);
+		lerrorf(SL_ArgError, "function \"%s\" not found", s->name);
 	return s->binding;
 }
 
@@ -791,13 +791,13 @@
 	cvalue_t *cv;
 	cv = MEM_CALLOC(CVALUE_NWORDS-1, sizeof(*cv));
 	assert(cv != nil);
-	cv->type = FL(builtintype);
+	cv->type = SL(builtintype);
 	cv->cbuiltin = f;
 
 	value_t sym = symbol(name, false);
 	symbol_t *s = ptr(sym);
 	s->binding = tagptr(cv, TAG_CVALUE);
-	ptrhash_put(&FL(reverse_dlsym_lookup_table), cv, (void*)sym);
+	ptrhash_put(&SL(reverse_dlsym_lookup_table), cv, (void*)sym);
 
 	return s->binding;
 }
@@ -804,7 +804,7 @@
 
 #define cv_intern(tok) \
 	do{ \
-		FL_##tok##sym = csymbol(#tok); \
+		SL_##tok##sym = csymbol(#tok); \
 	}while(0)
 
 #define ctor_cv_intern(tok, nt, ctype) \
@@ -811,9 +811,9 @@
 	do{ \
 		symbol_t *s; \
 		cv_intern(tok); \
-		set(FL_##tok##sym, cbuiltin(#tok, fn_builtin_##tok)); \
+		set(SL_##tok##sym, cbuiltin(#tok, fn_builtin_##tok)); \
 		if(valid_numtype(nt)){ \
-			s = ptr(FL_##tok##sym); \
+			s = ptr(SL_##tok##sym); \
 			s->numtype = nt; \
 			s->size = sizeof(ctype); \
 		} \
@@ -821,8 +821,8 @@
 
 #define mk_primtype(name, ctype) \
 	do{ \
-		FL(name##type) = get_type(FL_##name##sym); \
-		FL(name##type)->init = cvalue_##ctype##_init; \
+		SL(name##type) = get_type(SL_##name##sym); \
+		SL(name##type)->init = cvalue_##ctype##_init; \
 	}while(0)
 
 #define RETURN_NUM_AS(var, type) return(mk_##type(var))
@@ -854,9 +854,9 @@
 #define MP_OP mpadd
 #define ARITH_OVERFLOW sadd_overflow_64
 value_t
-fl_add_any(value_t *args, uint32_t nargs)
+sl_add_any(value_t *args, uint32_t nargs)
 {
-#include "fl_arith_any.inc"
+#include "sl_arith_any.inc"
 }
 
 #define ACCUM_DEFAULT 1
@@ -864,13 +864,13 @@
 #define MP_OP mpmul
 #define ARITH_OVERFLOW smul_overflow_64
 value_t
-fl_mul_any(value_t *args, uint32_t nargs)
+sl_mul_any(value_t *args, uint32_t nargs)
 {
-#include "fl_arith_any.inc"
+#include "sl_arith_any.inc"
 }
 
 value_t
-fl_neg(value_t n)
+sl_neg(value_t n)
 {
 	int64_t i64;
 	uint64_t ui64;
@@ -989,11 +989,11 @@
 _Noreturn void
 divide_by_0_error(void)
 {
-	lerrorf(FL_DivideError, "/: division by zero");
+	lerrorf(SL_DivideError, "/: division by zero");
 }
 
 value_t
-fl_div2(value_t a, value_t b)
+sl_div2(value_t a, value_t b)
 {
 	double da, db;
 	fixnum_t ai, bi;
@@ -1019,7 +1019,7 @@
 }
 
 value_t
-fl_idiv2(value_t a, value_t b)
+sl_idiv2(value_t a, value_t b)
 {
 	fixnum_t ai, bi;
 	numerictype_t ta, tb;
@@ -1080,7 +1080,7 @@
 }
 
 static value_t
-fl_bitwise_op(value_t a, value_t b, int opcode)
+sl_bitwise_op(value_t a, value_t b, int opcode)
 {
 	fixnum_t ai, bi;
 	numerictype_t ta, tb, itmp;
@@ -1156,7 +1156,7 @@
 	}
 	}
 	assert(0);
-	return FL_nil;
+	return SL_nil;
 }
 
 BUILTIN("logand", logand)
@@ -1170,7 +1170,7 @@
 		if(bothfixnums(v, e))
 			v = v & e;
 		else
-			v = fl_bitwise_op(v, e, 0);
+			v = sl_bitwise_op(v, e, 0);
 	}
 	return v;
 }
@@ -1186,7 +1186,7 @@
 		if(bothfixnums(v, e))
 			v = v | e;
 		else
-			v = fl_bitwise_op(v, e, 1);
+			v = sl_bitwise_op(v, e, 1);
 	}
 	return v;
 }
@@ -1202,7 +1202,7 @@
 		if(bothfixnums(v, e))
 			v = fixnum(numval(v) ^ numval(e));
 		else
-			v = fl_bitwise_op(v, e, 2);
+			v = sl_bitwise_op(v, e, 2);
 	}
 	return v;
 }
@@ -1304,10 +1304,10 @@
 void
 cvalues_init(void)
 {
-	htable_new(&FL(TypeTable), 256);
-	htable_new(&FL(reverse_dlsym_lookup_table), 256);
+	htable_new(&SL(TypeTable), 256);
+	htable_new(&SL(reverse_dlsym_lookup_table), 256);
 
-	FL(builtintype) = define_opaque_type(FL_builtinsym, sizeof(builtin_t), nil, nil);
+	SL(builtintype) = define_opaque_type(SL_builtinsym, sizeof(builtin_t), nil, nil);
 
 	ctor_cv_intern(int8, T_INT8, int8_t);
 	ctor_cv_intern(uint8, T_UINT8, uint8_t);
@@ -1324,11 +1324,11 @@
 
 	ctor_cv_intern(array, NONNUMERIC, int);
 
-	FL_stringtypesym = csymbol("*string-type*");
-	setc(FL_stringtypesym, fl_list2(FL_arraysym, FL_bytesym));
+	SL_stringtypesym = csymbol("*string-type*");
+	setc(SL_stringtypesym, sl_list2(SL_arraysym, SL_bytesym));
 
-	FL_runestringtypesym = csymbol("*runestring-type*");
-	setc(FL_runestringtypesym, fl_list2(FL_arraysym, FL_runesym));
+	SL_runestringtypesym = csymbol("*runestring-type*");
+	setc(SL_runestringtypesym, sl_list2(SL_arraysym, SL_runesym));
 
 	mk_primtype(int8, int8_t);
 	mk_primtype(uint8, uint8_t);
@@ -1344,11 +1344,11 @@
 	mk_primtype(double, double);
 
 	ctor_cv_intern(bignum, T_MPINT, mpint*);
-	FL(mpinttype) = get_type(FL_bignumsym);
-	FL(mpinttype)->init = cvalue_mpint_init;
-	FL(mpinttype)->vtable = &mpint_vtable;
+	SL(mpinttype) = get_type(SL_bignumsym);
+	SL(mpinttype)->init = cvalue_mpint_init;
+	SL(mpinttype)->vtable = &mpint_vtable;
 
-	FL(stringtype) = get_type(symbol_value(FL_stringtypesym));
-	FL(the_empty_string) = cvalue_from_ref(FL(stringtype), (char*)"", 0);
-	FL(runestringtype) = get_type(symbol_value(FL_runestringtypesym));
+	SL(stringtype) = get_type(symbol_value(SL_stringtypesym));
+	SL(the_empty_string) = cvalue_from_ref(SL(stringtype), (char*)"", 0);
+	SL(runestringtype) = get_type(symbol_value(SL_runestringtypesym));
 }
--- a/src/cvalues.h
+++ b/src/cvalues.h
@@ -9,39 +9,39 @@
 void add_finalizer(cvalue_t *cv);
 void sweep_finalizers(void);
 void cv_autorelease(cvalue_t *cv);
-value_t cvalue_(fltype_t *type, size_t sz, bool nofinalizer);
+value_t cvalue_(sltype_t *type, size_t sz, bool nofinalizer);
 #define cvalue(type, sz) cvalue_(type, sz, false)
 #define cvalue_nofinalizer(type, sz) cvalue_(type, sz, true)
-value_t cvalue_from_ref(fltype_t *type, void *ptr, size_t sz);
+value_t cvalue_from_ref(sltype_t *type, void *ptr, size_t sz);
 value_t cvalue_string(size_t sz);
 value_t cvalue_static_cstring(const char *str);
 value_t string_from_cstrn(char *str, size_t n);
 value_t string_from_cstr(char *str);
-bool fl_isstring(value_t v) fl_purefn;
+bool sl_isstring(value_t v) sl_purefn;
 void cv_pin(cvalue_t *cv);
 value_t size_wrap(size_t sz);
 size_t tosize(value_t n);
 off_t tooffset(value_t n);
-bool isarray(value_t v) fl_purefn;
-void cvalue_array_init(fltype_t *ft, value_t arg, void *dest);
-size_t cvalue_arraylen(value_t v) fl_purefn;
+bool isarray(value_t v) sl_purefn;
+void cvalue_array_init(sltype_t *ft, value_t arg, void *dest);
+size_t cvalue_arraylen(value_t v) sl_purefn;
 size_t ctype_sizeof(value_t type);
 void to_sized_ptr(value_t v, uint8_t **pdata, size_t *psz);
 value_t cvalue_relocate(value_t v);
 value_t cvalue_copy(value_t v);
-value_t cvalue_compare(value_t a, value_t b) fl_purefn;
+value_t cvalue_compare(value_t a, value_t b) sl_purefn;
 value_t cvalue_array_aref(value_t *args);
 value_t cvalue_array_aset(value_t *args);
 value_t cbuiltin(const char *name, builtin_t f);
 value_t return_from_uint64(uint64_t Uaccum);
 value_t return_from_int64(int64_t Saccum);
-value_t fl_add_any(value_t *args, uint32_t nargs);
-value_t fl_neg(value_t n);
-value_t fl_mul_any(value_t *args, uint32_t nargs);
+value_t sl_add_any(value_t *args, uint32_t nargs);
+value_t sl_neg(value_t n);
+value_t sl_mul_any(value_t *args, uint32_t nargs);
 bool num_to_ptr(value_t a, fixnum_t *pi, numerictype_t *pt, void **pp);
 _Noreturn void divide_by_0_error(void);
-value_t fl_div2(value_t a, value_t b);
-value_t fl_idiv2(value_t a, value_t b);
+value_t sl_div2(value_t a, value_t b);
+value_t sl_idiv2(value_t a, value_t b);
 void cvalues_init(void);
 
 value_t mk_double(double n);
@@ -53,4 +53,4 @@
 value_t mk_rune(Rune n);
 value_t mk_mpint(mpint *n);
 
-size_t llength(value_t v) fl_purefn;
+size_t llength(value_t v) sl_purefn;
--- a/src/dos/platform.h
+++ b/src/dos/platform.h
@@ -32,8 +32,8 @@
 #define USED(x) ((void)(x))
 #define nelem(x) (int)(sizeof(x)/sizeof((x)[0]))
 
-#define fl_setjmp(e) setjmp((e))
-#define fl_longjmp(e, v) longjmp((e), (v))
+#define sl_setjmp(e) setjmp((e))
+#define sl_longjmp(e, v) longjmp((e), (v))
 
 #define PATHSEP '\\'
 #define PATHSEPSTRING "\\"
--- a/src/dos/sys.c
+++ b/src/dos/sys.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "timefuncs.h"
 
 double
@@ -42,7 +42,7 @@
 }
 
 static const uint8_t boot[] = {
-#include "flisp.boot.h"
+#include "sl.boot.h"
 };
 
 int
@@ -50,5 +50,5 @@
 {
 	setlocale(LC_NUMERIC, "C");
 	setlocale(LC_CTYPE, "");
-	flmain(boot, sizeof(boot), argc, argv);
+	slmain(boot, sizeof(boot), argc, argv);
 }
--- a/src/equal.c
+++ b/src/equal.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "operators.h"
 #include "cvalues.h"
 #include "equal.h"
@@ -23,7 +23,7 @@
 {
 	value_t c = (value_t)ptrhash_get(table, (void*)key);
 	if(c == (value_t)HT_NOTFOUND)
-		return FL_nil;
+		return SL_nil;
 	if(c == key)
 		return c;
 	return eq_class(table, c);
@@ -32,8 +32,8 @@
 static void
 eq_union(htable_t *table, value_t a, value_t b, value_t c, value_t cb)
 {
-	value_t ca = c == FL_nil ? a : c;
-	if(cb != FL_nil)
+	value_t ca = c == SL_nil ? a : c;
+	if(cb != SL_nil)
 		ptrhash_put(table, (void*)cb, (void*)ca);
 	ptrhash_put(table, (void*)a, (void*)ca);
 	ptrhash_put(table, (void*)b, (void*)ca);
@@ -53,7 +53,7 @@
 	m = la < lb ? la : lb;
 	for(i = 0; i < m; i++){
 		value_t d = bounded_compare(vector_elt(a, i), vector_elt(b, i), bound-1, eq);
-		if(d == FL_nil || numval(d) != 0)
+		if(d == SL_nil || numval(d) != 0)
 			return d;
 	}
 	if(la < lb)
@@ -75,7 +75,7 @@
 	if(a == b)
 		return fixnum(0);
 	if(bound <= 0)
-		return FL_nil;
+		return SL_nil;
 	int taga = tag(a);
 	int tagb = cmptag(b);
 	int c;
@@ -85,7 +85,7 @@
 		if(isfixnum(b))
 			return (fixnum_t)a < (fixnum_t)b ? fixnum(-1) : fixnum(1);
 		if(iscprim(b)){
-			if(cp_class(ptr(b)) == FL(runetype))
+			if(cp_class(ptr(b)) == SL(runetype))
 				return fixnum(1);
 			return fixnum(numeric_compare(a, b, eq, true, false));
 		}
@@ -106,10 +106,10 @@
 			return bounded_vector_compare(a, b, bound, eq);
 		break;
 	case TAG_CPRIM:
-		if(cp_class(ptr(a)) == FL(runetype)){
-			if(!iscprim(b) || cp_class(ptr(b)) != FL(runetype))
+		if(cp_class(ptr(a)) == SL(runetype)){
+			if(!iscprim(b) || cp_class(ptr(b)) != SL(runetype))
 				return fixnum(-1);
-		}else if(iscprim(b) && cp_class(ptr(b)) == FL(runetype))
+		}else if(iscprim(b) && cp_class(ptr(b)) == SL(runetype))
 			return fixnum(1);
 		c = numeric_compare(a, b, eq, true, false);
 		if(c != 2)
@@ -133,13 +133,13 @@
 				function_t *fa = ptr(a);
 				function_t *fb = ptr(b);
 				d = bounded_compare(fa->bcode, fb->bcode, bound-1, eq);
-				if(d == FL_nil || numval(d) != 0)
+				if(d == SL_nil || numval(d) != 0)
 					return d;
 				d = bounded_compare(fa->vals, fb->vals, bound-1, eq);
-				if(d == FL_nil || numval(d) != 0)
+				if(d == SL_nil || numval(d) != 0)
 					return d;
 				d = bounded_compare(fa->env, fb->env, bound-1, eq);
-				if(d == FL_nil || numval(d) != 0)
+				if(d == SL_nil || numval(d) != 0)
 					return d;
 				return fixnum(0);
 			}
@@ -150,7 +150,7 @@
 		if(tagb < TAG_CONS)
 			return fixnum(1);
 		d = bounded_compare(car_(a), car_(b), bound-1, eq);
-		if(d == FL_nil || numval(d) != 0)
+		if(d == SL_nil || numval(d) != 0)
 			return d;
 		a = cdr_(a); b = cdr_(b);
 		bound--;
@@ -176,7 +176,7 @@
 		xb = vector_elt(b, i);
 		if(leafp(xa) || leafp(xb)){
 			d = bounded_compare(xa, xb, 1, eq);
-			if(d != FL_nil && numval(d) != 0)
+			if(d != SL_nil && numval(d) != 0)
 				return d;
 		}else if(tag(xa) < tag(xb))
 			return fixnum(-1);
@@ -186,7 +186,7 @@
 
 	ca = eq_class(table, a);
 	cb = eq_class(table, b);
-	if(ca != FL_nil && ca == cb)
+	if(ca != SL_nil && ca == cb)
 		return fixnum(0);
 
 	eq_union(table, a, b, ca, cb);
@@ -227,7 +227,7 @@
 			int tagdb = tag(db);
 			if(leafp(aa) || leafp(ab)){
 				d = bounded_compare(aa, ab, 1, eq);
-				if(d != FL_nil && numval(d) != 0)
+				if(d != SL_nil && numval(d) != 0)
 					return d;
 			}
 			if(tagaa < tagab)
@@ -236,7 +236,7 @@
 				return fixnum(1);
 			if(leafp(da) || leafp(db)){
 				d = bounded_compare(da, db, 1, eq);
-				if(d != FL_nil && numval(d) != 0)
+				if(d != SL_nil && numval(d) != 0)
 					return d;
 			}
 			if(tagda < tagdb)
@@ -246,7 +246,7 @@
 
 			ca = eq_class(table, a);
 			cb = eq_class(table, b);
-			if(ca != FL_nil && ca == cb)
+			if(ca != SL_nil && ca == cb)
 				return fixnum(0);
 
 			eq_union(table, a, b, ca, cb);
@@ -271,7 +271,7 @@
 
 		ca = eq_class(table, a);
 		cb = eq_class(table, b);
-		if(ca != FL_nil && ca == cb)
+		if(ca != SL_nil && ca == cb)
 			return fixnum(0);
 
 		eq_union(table, a, b, ca, cb);
@@ -295,10 +295,10 @@
 
 // 'eq' means unordered comparison is sufficient
 value_t
-fl_compare(value_t a, value_t b, bool eq)
+sl_compare(value_t a, value_t b, bool eq)
 {
 	value_t guess = bounded_compare(a, b, BOUNDED_COMPARE_BOUND, eq);
-	if(guess == FL_nil){
+	if(guess == SL_nil){
 		guess = cyc_compare(a, b, &equal_eq_hashtable, eq);
 		htable_reset(&equal_eq_hashtable, 512);
 	}
@@ -345,7 +345,7 @@
 	case TAG_CPRIM:
 		cp = ptr(a);
 		data = cp_data(cp);
-		if(cp_class(cp) == FL(runetype))
+		if(cp_class(cp) == SL(runetype))
 			return inthash(*(Rune*)data);
 		nt = cp_numtype(cp);
 		u.d = conv_to_double(data, nt);
@@ -353,7 +353,7 @@
 	case TAG_CVALUE:
 		cv = ptr(a);
 		data = cv_data(cv);
-		if(cv->type == FL(mpinttype)){
+		if(cv->type == SL(mpinttype)){
 			len = mptobe(*(mpint**)data, nil, 0, (uint8_t**)&data);
 			h = memhash(data, len);
 			MEM_FREE(data);
@@ -406,7 +406,7 @@
 {
 	if(eq_comparable(a, b))
 		return a == b;
-	return numval(fl_compare(a, b, true)) == 0;
+	return numval(sl_compare(a, b, true)) == 0;
 }
 
 uintptr_t
--- a/src/equal.h
+++ b/src/equal.h
@@ -6,6 +6,6 @@
 
 int equal_lispvalue(value_t a, value_t b);
 uintptr_t hash_lispvalue(value_t a);
-value_t fl_compare(value_t a, value_t b, bool eq);
+value_t sl_compare(value_t a, value_t b, bool eq);
 int numeric_compare(value_t a, value_t b, bool eq, bool eqnans, bool typeerr);
 void comparehash_init(void);
--- a/src/equalhash.c
+++ b/src/equalhash.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "equalhash.h"
 #include "equal.h"
 
--- a/src/fl_arith_any.inc
+++ /dev/null
@@ -1,158 +1,0 @@
-//value_t
-//fl_*_any(value_t *args, uint32_t nargs)
-// input: ACCUM_DEFAULT ARITH_OP(a,b)   MP_OP   ARITH_OVERFLOW
-// add:   0             a+b             mpadd   sadd_overflow_64
-// mul:   1             a*b             mpmul   smul_overflow_64
-
-	mpint *Maccum = nil, *m = nil;
-	int64_t Saccum = ACCUM_DEFAULT, x;
-	uint64_t u64;
-	double Faccum = ACCUM_DEFAULT;
-	bool inexact = false;
-	value_t arg;
-	numerictype_t pt;
-	void *a;
-	cprim_t *cp;
-	cvalue_t *cv;
-
-	uint32_t i, j;
-	FOR_ARGS(i, 0, arg, args){
-		if(isfixnum(arg))
-			x = numval(arg);
-		else{
-			if(iscprim(arg)){
-				cp = ptr(arg);
-				a = cp_data(cp);
-				pt = cp_numtype(cp);
-			}else if(iscvalue(arg)){
-				cv = ptr(arg);
-				a = cv_data(cv);
-				pt = cv_class(cv)->numtype;
-			}else{
-typeerr:
-				mpfree(Maccum);
-				mpfree(m);
-				type_error("number", arg);
-			}
-			switch(pt){
-			case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
-			case T_FLOAT:  Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue;
-			case T_INT8:   x = *(int8_t*)a; break;
-			case T_UINT8:  x = *(uint8_t*)a; break;
-			case T_INT16:  x = *(int16_t*)a; break;
-			case T_UINT16: x = *(uint16_t*)a; break;
-			case T_INT32:  x = *(int32_t*)a; break;
-			case T_UINT32: x = *(uint32_t*)a; break;
-			case T_INT64:  x = *(int64_t*)a; break;
-			case T_UINT64:
-				u64 = *(uint64_t*)a;
-				if(u64 > INT64_MAX){
-					x = ACCUM_DEFAULT;
-					goto overflow;
-				}
-				x = u64;
-				break;
-			case T_MPINT:
-				x = ACCUM_DEFAULT;
-				u64 = ACCUM_DEFAULT;
-				m = mpcopy(*(mpint**)a);
-				goto overflow;
-			default:
-				goto typeerr;
-			}
-		}
-
-		int64_t accu;
-		if(ARITH_OVERFLOW(Saccum, x, &accu)){
-			u64 = ACCUM_DEFAULT;
-			goto overflow;
-		}
-		Saccum = accu;
-	}
-
-	if(inexact)
-		return mk_double(ARITH_OP(Faccum, Saccum));
-	if(fits_fixnum(Saccum))
-		return fixnum((fixnum_t)Saccum);
-	u64 = ACCUM_DEFAULT;
-	x = ACCUM_DEFAULT;
-
-overflow:
-	i++;
-	if(Maccum == nil)
-		Maccum = vtomp(Saccum, nil);
-	if(m == nil)
-		m = u64 != ACCUM_DEFAULT ? uvtomp(u64, nil) : vtomp(x, nil);
-
-	MP_OP(Maccum, m, Maccum);
-
-	FOR_ARGS(j, i, arg, args){
-		if(isfixnum(arg)){
-			vtomp(numval(arg), m);
-			MP_OP(Maccum, m, Maccum);
-			continue;
-		}
-
-		if(iscprim(arg)){
-			cp = ptr(arg);
-			a = cp_data(cp);
-			pt = cp_numtype(cp);
-		}else if(iscvalue(arg)){
-			cv = ptr(arg);
-			a = cv_data(cv);
-			pt = cv_class(cv)->numtype;
-		}else{
-			goto typeerr;
-		}
-		switch(pt){
-		case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
-		case T_FLOAT:  Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue;
-		case T_INT8:   x = *(int8_t*)a; break;
-		case T_UINT8:  x = *(uint8_t*)a; break;
-		case T_INT16:  x = *(int16_t*)a; break;
-		case T_UINT16: x = *(uint16_t*)a; break;
-		case T_INT32:  x = *(int32_t*)a; break;
-		case T_UINT32: x = *(uint32_t*)a; break;
-		case T_INT64:  x = *(int64_t*)a; break;
-		case T_UINT64:
-			uvtomp(*(uint64_t*)a, m);
-			MP_OP(Maccum, m, Maccum);
-			continue;
-		case T_MPINT:
-			MP_OP(Maccum, *(mpint**)a, Maccum);
-			continue;
-		default:
-			goto typeerr;
-		}
-		vtomp(x, m);
-		MP_OP(Maccum, m, Maccum);
-	}
-
-	int n = mpsignif(Maccum);
-	if(n >= FIXNUM_BITS){
-		if(inexact){
-			dtomp(Faccum, m);
-			MP_OP(Maccum, m, Maccum);
-			n = mpsignif(Maccum);
-			if(n < FIXNUM_BITS){
-				inexact = false;
-				goto down;
-			}
-		}
-		mpfree(m);
-		return mk_mpint(Maccum);
-	}
-
-down:
-	mpfree(m);
-	Saccum = mptov(Maccum);
-	mpfree(Maccum);
-	if(inexact)
-		return mk_double(ARITH_OP(Faccum, Saccum));
-	assert(fits_fixnum(Saccum));
-	return fixnum((fixnum_t)Saccum);
-
-#undef ACCUM_DEFAULT
-#undef ARITH_OP
-#undef MP_OP
-#undef ARITH_OVERFLOW
--- a/src/flisp.c
+++ /dev/null
@@ -1,1355 +1,0 @@
-/*
-  femtoLisp
-
-  by Jeff Bezanson (C) 2009
-  Distributed under the BSD License
-*/
-
-#include "flisp.h"
-#include "operators.h"
-#include "cvalues.h"
-#include "types.h"
-#include "print.h"
-#include "read.h"
-#include "timefuncs.h"
-#include "equal.h"
-#include "hashing.h"
-#include "table.h"
-#include "iostream.h"
-#include "compress.h"
-
-value_t FL_builtins_table_sym, FL_quote, FL_lambda, FL_function, FL_comma, FL_commaat;
-value_t FL_commadot, FL_trycatch, FL_backquote;
-value_t FL_conssym, FL_symbolsym, FL_fixnumsym, FL_vectorsym, FL_builtinsym, FL_vu8sym;
-value_t FL_defsym, FL_defmacrosym, FL_forsym, FL_setqsym;
-value_t FL_booleansym, FL_nullsym, FL_evalsym, FL_fnsym;
-value_t FL_nulsym, FL_alarmsym, FL_backspacesym, FL_tabsym, FL_linefeedsym, FL_newlinesym;
-value_t FL_vtabsym, FL_pagesym, FL_returnsym, FL_escsym, FL_spacesym, FL_deletesym;
-value_t FL_IOError, FL_ParseError, FL_TypeError, FL_ArgError, FL_MemoryError;
-value_t FL_DivideError, FL_BoundsError, FL_Error, FL_KeyError, FL_UnboundError;
-
-value_t FL_printwidthsym, FL_printreadablysym, FL_printprettysym, FL_printlengthsym;
-value_t FL_printlevelsym;
-value_t FL_tablesym, FL_arraysym;
-value_t FL_iostreamsym, FL_rdsym, FL_wrsym, FL_apsym, FL_crsym, FL_truncsym;
-value_t FL_instrsym, FL_outstrsym;
-value_t FL_int8sym, FL_uint8sym, FL_int16sym, FL_uint16sym, FL_int32sym, FL_uint32sym;
-value_t FL_int64sym, FL_uint64sym, FL_bignumsym;
-value_t FL_bytesym, FL_runesym, FL_floatsym, FL_doublesym;
-value_t FL_stringtypesym, FL_runestringtypesym;
-
-fl_thread(Fl *fl);
-
-typedef struct {
-	const char *name;
-	builtin_t fptr;
-}builtinspec_t;
-
-bool
-isbuiltin(value_t x)
-{
-	int i;
-	return tag(x) == TAG_FUNCTION && (i = uintval(x)) < nelem(builtins) && builtins[i].name != nil;
-}
-
-static value_t apply_cl(int nargs) fl_hotfn;
-
-// error utilities ------------------------------------------------------------
-
-void
-free_readstate(fl_readstate_t *rs)
-{
-	htable_free(&rs->backrefs);
-	htable_free(&rs->gensyms);
-}
-
-_Noreturn void
-fl_exit(int status)
-{
-	FL(exiting) = true;
-	fl_gc(false);
-	exit(status);
-}
-
-#define FL_TRY \
-	fl_exception_context_t _ctx; int l__tr, l__ca; \
-	_ctx.sp = FL(sp); _ctx.frame = FL(curr_frame); _ctx.rdst = FL(readstate); _ctx.prev = FL(exctx); \
-	_ctx.ngchnd = FL(ngchandles); FL(exctx) = &_ctx; \
-	if(!fl_setjmp(_ctx.buf)) \
-		for(l__tr = 1; l__tr; l__tr = 0, (void)(FL(exctx) = FL(exctx)->prev))
-
-#define FL_CATCH_INC \
-	l__ca = 0, FL(lasterror) = FL_nil, FL(throwing_frame) = 0, FL(sp) = _ctx.sp, FL(curr_frame) = _ctx.frame
-
-#define FL_CATCH \
-	else \
-		for(l__ca = 1; l__ca; FL_CATCH_INC)
-
-#define FL_CATCH_NO_INC \
-	else \
-		for(l__ca = 1; l__ca;)
-
-void
-fl_savestate(fl_exception_context_t *_ctx)
-{
-	_ctx->sp = FL(sp);
-	_ctx->frame = FL(curr_frame);
-	_ctx->rdst = FL(readstate);
-	_ctx->prev = FL(exctx);
-	_ctx->ngchnd = FL(ngchandles);
-}
-
-void
-fl_restorestate(fl_exception_context_t *_ctx)
-{
-	FL(lasterror) = FL_nil;
-	FL(throwing_frame) = 0;
-	FL(sp) = _ctx->sp;
-	FL(curr_frame) = _ctx->frame;
-}
-
-_Noreturn void
-fl_raise(value_t e)
-{
-	ios_flush(ios_stdout);
-	ios_flush(ios_stderr);
-
-	FL(lasterror) = e;
-	// unwind read state
-	while(FL(readstate) != FL(exctx)->rdst){
-		free_readstate(FL(readstate));
-		FL(readstate) = FL(readstate)->prev;
-	}
-	if(FL(throwing_frame) == 0)
-		FL(throwing_frame) = FL(curr_frame);
-	FL(ngchandles) = FL(exctx)->ngchnd;
-	fl_exception_context_t *thisctx = FL(exctx);
-	if(FL(exctx)->prev)   // don't throw past toplevel
-		FL(exctx) = FL(exctx)->prev;
-	fl_longjmp(thisctx->buf, 1);
-}
-
-_Noreturn void
-lerrorf(value_t e, const char *format, ...)
-{
-	char msgbuf[256];
-	va_list args;
-
-	PUSH(e);
-	va_start(args, format);
-	vsnprintf(msgbuf, sizeof(msgbuf), format, args);
-	value_t msg = string_from_cstr(msgbuf);
-	va_end(args);
-
-	e = POP();
-	fl_raise(fl_list2(e, msg));
-}
-
-_Noreturn void
-type_error(const char *expected, value_t got)
-{
-	fl_raise(fl_listn(3, FL_TypeError, symbol(expected, false), got));
-}
-
-_Noreturn void
-bounds_error(value_t arr, value_t ind)
-{
-	fl_raise(fl_listn(3, FL_BoundsError, arr, ind));
-}
-
-_Noreturn void
-unbound_error(value_t sym)
-{
-	fl_raise(fl_listn(2, FL_UnboundError, sym));
-}
-
-_Noreturn void
-arity_error(int nargs, int c)
-{
-	lerrorf(FL_ArgError, "arity mismatch: wanted %"PRId32", got %"PRId32, c, nargs);
-}
-
-// safe cast operators --------------------------------------------------------
-
-#define isstring fl_isstring
-#define SAFECAST_OP(type, ctype, cnvt) \
-	ctype to##type(value_t v) \
-	{ \
-		if(fl_likely(is##type(v))) \
-			return (ctype)cnvt(v); \
-		type_error(#type, v); \
-	}
-SAFECAST_OP(cons, cons_t*, ptr)
-SAFECAST_OP(symbol, symbol_t*, ptr)
-SAFECAST_OP(fixnum, fixnum_t, numval)
-//SAFECAST_OP(cvalue, cvalue_t*, ptr)
-SAFECAST_OP(string, char*, cvalue_data)
-#undef isstring
-
-// symbol table ---------------------------------------------------------------
-
-static symbol_t *
-mk_symbol(const char *str, int len, bool copy)
-{
-	symbol_t *sym = MEM_ALLOC(sizeof(*sym) + (copy ? len+1 : 0));
-	sym->numtype = NONNUMERIC;
-	if(str[0] == ':' && str[1] != 0){
-		value_t s = tagptr(sym, TAG_SYM);
-		sym->flags = FLAG_KEYWORD;
-		setc(s, s);
-	}else{
-		sym->binding = UNBOUND;
-		sym->flags = 0;
-	}
-	sym->type = nil;
-	sym->hash = memhash(str, len)^0xAAAAAAAAAAAAAAAAULL;
-	if(copy){
-		memcpy((char*)(sym+1), str, len+1);
-		sym->name = (const char*)(sym+1);
-	}else{
-		sym->name = str;
-	}
-	sym->size = 0;
-	return sym;
-}
-
-value_t
-symbol(const char *str, bool copy)
-{
-	int len = strlen(str);
-	symbol_t *v;
-	const char *k;
-	if(!Tgetkv(FL(symtab), str, len, &k, (void**)&v)){
-		v = mk_symbol(str, len, copy);
-		FL(symtab) = Tsetl(FL(symtab), v->name, len, v);
-	}
-	return tagptr(v, TAG_SYM);
-}
-
-value_t
-csymbol_(const char *str, int len)
-{
-	symbol_t *v = mk_symbol(str, len, false);
-	FL(symtab) = Tsetl(FL(symtab), str, len, v);
-	return tagptr(v, TAG_SYM);
-}
-
-BUILTIN("gensym", gensym)
-{
-	argcount(nargs, 0);
-	USED(args);
-	gensym_t *gs = alloc_words(sizeof(gensym_t)/sizeof(value_t));
-	gs->id = FL(gensym_ctr)++;
-	gs->binding = UNBOUND;
-	gs->type = nil;
-	return tagptr(gs, TAG_SYM);
-}
-
-value_t
-gensym(void)
-{
-	return fn_builtin_gensym(nil, 0);
-}
-
-fl_purefn
-BUILTIN("gensym?", gensymp)
-{
-	argcount(nargs, 1);
-	return isgensym(args[0]) ? FL_t : FL_nil;
-}
-
-char *
-uint2str(char *dest, size_t len, uint64_t num, int base)
-{
-	int i = len-1;
-	uint64_t b = (uint64_t)base;
-	char ch;
-	dest[i--] = '\0';
-	while(i >= 0){
-		ch = (char)(num % b);
-		if(ch < 10)
-			ch += '0';
-		else
-			ch = ch-10+'a';
-		dest[i--] = ch;
-		num /= b;
-		if(num == 0)
-			break;
-	}
-	return &dest[i+1];
-}
-
-const char *
-symbol_name(value_t v)
-{
-	if(ismanaged(v)){
-		gensym_t *gs = ptr(v);
-		FL(gsnameno) = 1-FL(gsnameno);
-		char *n = uint2str(FL(gsname)[FL(gsnameno)]+1, sizeof(FL(gsname)[0])-1, gs->id, 10);
-		*(--n) = 'g';
-		return n;
-	}
-	return ((symbol_t*)ptr(v))->name;
-}
-
-// conses ---------------------------------------------------------------------
-
-value_t
-mk_cons(void)
-{
-	cons_t *c;
-
-	if(fl_unlikely(FL(curheap) > FL(lim)))
-		fl_gc(false);
-	c = (cons_t*)FL(curheap);
-	FL(curheap) += sizeof(cons_t);
-	return tagptr(c, TAG_CONS);
-}
-
-void *
-alloc_words(int n)
-{
-	value_t *first;
-
-#if !defined(BITS64)
-	// force 8-byte alignment
-	if(n & 1)
-		n++;
-#endif
-	if(fl_unlikely((value_t*)FL(curheap) > (value_t*)FL(lim)+2-n)){
-		fl_gc(false);
-		while(fl_unlikely((value_t*)FL(curheap) > ((value_t*)FL(lim))+2-n))
-			fl_gc(true);
-	}
-	first = (value_t*)FL(curheap);
-	FL(curheap) += n*sizeof(value_t);
-	return first;
-}
-
-value_t
-alloc_vector(size_t n, bool init)
-{
-	if(n == 0)
-		return FL(the_empty_vector);
-	value_t *c = alloc_words(n+1);
-	value_t v = tagptr(c, TAG_VECTOR);
-	vector_setsize(v, n);
-	if(init){
-		for(size_t i = 0; i < n; i++)
-			vector_elt(v, i) = FL_void;
-	}
-	return v;
-}
-
-// collector ------------------------------------------------------------------
-
-void
-fl_gc_handle(value_t *pv)
-{
-	if(fl_unlikely(FL(ngchandles) >= N_GC_HANDLES))
-		lerrorf(FL_MemoryError, "out of gc handles");
-	FL(gchandles)[FL(ngchandles)++] = pv;
-}
-
-void
-fl_free_gc_handles(int n)
-{
-	assert(FL(ngchandles) >= n);
-	FL(ngchandles) -= n;
-}
-
-value_t
-relocate(value_t v)
-{
-	value_t a, d, nc, first, *pcdr;
-
-	if(isfixnum(v))
-		return v;
-
-	uintptr_t t = tag(v);
-	if(t == TAG_CONS){
-		// iterative implementation allows arbitrarily long cons chains
-		pcdr = &first;
-		do{
-			a = car_(v);
-			if(isforwarded(v)){
-				*pcdr = forwardloc(v);
-				return first;
-			}
-			d = cdr_(v);
-			*pcdr = nc = tagptr((cons_t*)FL(curheap), TAG_CONS);
-			FL(curheap) += sizeof(cons_t);
-			forward(v, nc);
-			car_(nc) = ismanaged(a) ? relocate(a) : a;
-			pcdr = &cdr_(nc);
-			v = d;
-		}while(iscons(v));
-		*pcdr = d == FL_nil ? FL_nil : relocate(d);
-		return first;
-	}
-
-	if(!ismanaged(v))
-		return v;
-	if(isforwarded(v))
-		return forwardloc(v);
-
-	if(t == TAG_CVALUE)
-		return cvalue_relocate(v);
-	if(t == TAG_VECTOR){
-		// N.B.: 0-length vectors secretly have space for a first element
-		size_t i, sz = vector_size(v);
-		if(vector_elt(v, -1) & 0x1){
-			// grown vector
-			nc = relocate(vector_elt(v, 0));
-			forward(v, nc);
-		}else{
-			nc = tagptr(alloc_words(sz+1), TAG_VECTOR);
-			vector_setsize(nc, sz);
-			a = vector_elt(v, 0);
-			forward(v, nc);
-			if(sz > 0){
-				vector_elt(nc, 0) = relocate(a);
-				for(i = 1; i < sz; i++)
-					vector_elt(nc, i) = relocate(vector_elt(v, i));
-			}
-		}
-		return nc;
-	}
-	if(t == TAG_FUNCTION){
-		function_t *fn = ptr(v);
-		function_t *nfn = alloc_words(sizeof(function_t)/sizeof(value_t));
-		nfn->bcode = fn->bcode;
-		nfn->vals = fn->vals;
-		nc = tagptr(nfn, TAG_FUNCTION);
-		forward(v, nc);
-		nfn->env = relocate(fn->env);
-		nfn->vals = relocate(nfn->vals);
-		nfn->bcode = relocate(nfn->bcode);
-		assert(!ismanaged(fn->name));
-		nfn->name = fn->name;
-		return nc;
-	}
-	if(t == TAG_SYM){
-		gensym_t *gs = ptr(v);
-		gensym_t *ng = alloc_words(sizeof(gensym_t)/sizeof(value_t));
-		ng->id = gs->id;
-		ng->binding = gs->binding;
-		ng->type = gs->type;
-		nc = tagptr(ng, TAG_SYM);
-		forward(v, nc);
-		if(fl_likely(ng->binding != UNBOUND))
-			ng->binding = relocate(ng->binding);
-		return nc;
-	}
-	if(t == TAG_CPRIM){
-		cprim_t *pcp = ptr(v);
-		size_t nw = CPRIM_NWORDS+NWORDS(cp_class(pcp)->size);
-		cprim_t *ncp = alloc_words(nw);
-		while(nw--)
-			((value_t*)ncp)[nw] = ((value_t*)pcp)[nw];
-		nc = tagptr(ncp, TAG_CPRIM);
-		forward(v, nc);
-		return nc;
-	}
-	return v;
-}
-
-static void
-trace_globals(void)
-{
-	const char *k = nil;
-	symbol_t *v;
-	while(Tnext(FL(symtab), &k, (void**)&v)){
-		if(v->binding != UNBOUND)
-			v->binding = relocate(v->binding);
-	}
-}
-
-void
-fl_gc(bool mustgrow)
-{
-	FL(gccalls)++;
-	FL(curheap) = FL(tospace);
-	if(FL(grew))
-		FL(lim) = FL(curheap)+FL(heapsize)*2-sizeof(cons_t);
-	else
-		FL(lim) = FL(curheap)+FL(heapsize)-sizeof(cons_t);
-
-	value_t *top, *f;
-	if(FL(throwing_frame) > FL(curr_frame)){
-		top = FL(throwing_frame) - 3;
-		f = (value_t*)*top;
-	}else{
-		top = FL(sp);
-		f = FL(curr_frame);
-	}
-	for(;;){
-		for(value_t *p = f; p < top; p++)
-			*p = relocate(*p);
-		if(f == FL(stack))
-			break;
-		top = f - 3;
-		f = (value_t*)*top;
-	}
-	for(int i = 0; i < FL(ngchandles); i++)
-		*FL(gchandles)[i] = relocate(*FL(gchandles)[i]);
-	trace_globals();
-	relocate_typetable();
-	fl_readstate_t *rs = FL(readstate);
-	while(rs){
-		value_t ent;
-		for(int i = 0; i < rs->backrefs.size; i++){
-			ent = (value_t)rs->backrefs.table[i];
-			if(ent != (value_t)HT_NOTFOUND)
-				rs->backrefs.table[i] = (void*)relocate(ent);
-		}
-		for(int i = 0; i < rs->gensyms.size; i++){
-			ent = (value_t)rs->gensyms.table[i];
-			if(ent != (value_t)HT_NOTFOUND)
-				rs->gensyms.table[i] = (void*)relocate(ent);
-		}
-		rs->source = relocate(rs->source);
-		rs = rs->prev;
-	}
-	FL(lasterror) = relocate(FL(lasterror));
-	FL(memory_exception_value) = relocate(FL(memory_exception_value));
-	FL(the_empty_vector) = relocate(FL(the_empty_vector));
-	FL(the_empty_string) = relocate(FL(the_empty_string));
-
-	sweep_finalizers();
-
-	void *temp = FL(tospace);
-	FL(tospace) = FL(fromspace);
-	FL(fromspace) = temp;
-
-	// if we're using > 80% of the space, resize tospace so we have
-	// more space to fill next time. if we grew tospace last time,
-	// grow the other half of the heap this time to catch up.
-	if(FL(grew) || ((intptr_t)(FL(lim)-FL(curheap)) < (intptr_t)FL(heapsize)/5) || mustgrow){
-		temp = MEM_REALLOC(FL(tospace), FL(heapsize)*2);
-		if(fl_unlikely(temp == nil))
-			fl_raise(FL(memory_exception_value));
-		FL(tospace) = temp;
-		if(FL(grew)){
-			FL(heapsize) *= 2;
-			temp = bitvector_resize(FL(consflags), 0, FL(heapsize)/sizeof(cons_t), 1);
-			if(fl_unlikely(temp == nil))
-				fl_raise(FL(memory_exception_value));
-			FL(consflags) = (uint32_t*)temp;
-		}
-		FL(grew) = !FL(grew);
-	}
-	if(fl_unlikely((value_t*)FL(curheap) > (value_t*)FL(lim)-2)){
-		// all data was live; gc again and grow heap.
-		// but also always leave at least 4 words available, so a closure
-		// can be allocated without an extra check.
-		fl_gc(false);
-	}
-}
-
-// utils ----------------------------------------------------------------------
-
-// apply function with n args on the stack
-fl_hotfn
-static value_t
-_applyn(int n)
-{
-	value_t *saveSP = FL(sp);
-	value_t f = saveSP[-n-1];
-	value_t v;
-	if(iscbuiltin(f))
-		v = ((cvalue_t*)ptr(f))->cbuiltin(saveSP-n, n);
-	else if(isfunction(f))
-		v = apply_cl(n);
-	else if(fl_likely(isbuiltin(f))){
-		value_t tab = symbol_value(FL_builtins_table_sym);
-		if(fl_unlikely(ptr(tab) == nil))
-			unbound_error(tab);
-		saveSP[-n-1] = vector_elt(tab, uintval(f));
-		v = apply_cl(n);
-	}else{
-		type_error("function", f);
-	}
-	FL(sp) = saveSP;
-	return v;
-}
-
-value_t
-fl_apply(value_t f, value_t v)
-{
-	value_t *saveSP = FL(sp);
-
-	PUSH(f);
-	int n;
-	for(n = 0; iscons(v); n++){
-		PUSH(car_(v));
-		v = cdr_(v);
-	}
-	if(v != FL_nil)
-		lerrorf(FL_ArgError, "apply: last argument: not a list");
-	v = _applyn(n);
-	FL(sp) = saveSP;
-	return v;
-}
-
-value_t
-fl_applyn(int n, value_t f, ...)
-{
-	va_list ap;
-	va_start(ap, f);
-
-	PUSH(f);
-	for(int i = 0; i < n; i++){
-		value_t a = va_arg(ap, value_t);
-		PUSH(a);
-	}
-	value_t v = _applyn(n);
-	POPN(n+1);
-	va_end(ap);
-	return v;
-}
-
-value_t
-fl_listn(int n, ...)
-{
-	va_list ap;
-	va_start(ap, n);
-	value_t *si = FL(sp);
-
-	for(int i = 0; i < n; i++){
-		value_t a = va_arg(ap, value_t);
-		PUSH(a);
-	}
-	cons_t *c = alloc_words(n*2);
-	cons_t *l = c;
-	for(int i = 0; i < n; i++){
-		c->car = *si++;
-		c->cdr = tagptr(c+1, TAG_CONS);
-		c++;
-	}
-	c[-1].cdr = FL_nil;
-
-	POPN(n);
-	va_end(ap);
-	return tagptr(l, TAG_CONS);
-}
-
-value_t
-fl_list2(value_t a, value_t b)
-{
-	PUSH(a);
-	PUSH(b);
-	cons_t *c = alloc_words(4);
-	b = POP();
-	a = POP();
-	c[0].car = a;
-	c[0].cdr = tagptr(c+1, TAG_CONS);
-	c[1].car = b;
-	c[1].cdr = FL_nil;
-	return tagptr(c, TAG_CONS);
-}
-
-value_t
-fl_cons(value_t a, value_t b)
-{
-	PUSH(a);
-	PUSH(b);
-	value_t c = mk_cons();
-	cdr_(c) = POP();
-	car_(c) = POP();
-	return c;
-}
-
-bool
-fl_isnumber(value_t v)
-{
-	if(isfixnum(v) || ismpint(v))
-		return true;
-	if(iscprim(v)){
-		cprim_t *c = ptr(v);
-		return c->type != FL(runetype) && valid_numtype(c->type->numtype);
-	}
-	return false;
-}
-
-// eval -----------------------------------------------------------------------
-
-fl_hotfn
-static value_t
-list(value_t *args, int nargs, bool star)
-{
-	if(fl_unlikely(nargs == 0))
-		return FL_nil;
-	value_t v = cons_reserve(nargs);
-	cons_t *c = ptr(v);
-	for(int i = 0; i < nargs; i++){
-		c->car = args[i];
-		c->cdr = tagptr(c+1, TAG_CONS);
-		c++;
-	}
-	if(star)
-		c[-2].cdr = c[-1].car;
-	else
-		c[-1].cdr = FL_nil;
-	return v;
-}
-
-static value_t
-copy_list(value_t L)
-{
-	if(!iscons(L))
-		return FL_nil;
-	value_t *plcons = FL(sp);
-	value_t *pL = plcons+1;
-	PUSH(FL_nil);
-	PUSH(L);
-	value_t c;
-	c = mk_cons(); PUSH(c);  // save first cons
-	car_(c) = car_(*pL);
-	cdr_(c) = FL_nil;
-	*plcons = c;
-	*pL = cdr_(*pL);
-	while(iscons(*pL)){
-		c = mk_cons();
-		car_(c) = car_(*pL);
-		cdr_(c) = FL_nil;
-		cdr_(*plcons) = c;
-		*plcons = c;
-		*pL = cdr_(*pL);
-	}
-	c = POP();  // first cons
-	POPN(2);
-	return c;
-}
-
-static value_t
-do_trycatch(void)
-{
-	value_t *saveSP = FL(sp);
-	value_t v = FL_nil;
-	value_t thunk = saveSP[-2];
-	FL(sp)[-2] = saveSP[-1];
-	FL(sp)[-1] = thunk;
-
-	FL_TRY{
-		v = apply_cl(0);
-	}
-	FL_CATCH{
-		v = saveSP[-2];
-		PUSH(v);
-		PUSH(FL(lasterror));
-		v = apply_cl(1);
-	}
-	FL(sp) = saveSP;
-	return v;
-}
-
-/*
-  argument layout on stack is
-  |--required args--|--opt args--|--kw args--|--rest args...
-*/
-static int
-process_keys(value_t kwtable, int nreq, int nkw, int nopt, value_t *bp, int nargs, int va)
-{
-	int extr = nopt+nkw;
-	int ntot = nreq+extr;
-	value_t args[64], v = FL_nil;
-	int i, a = 0, nrestargs;
-	value_t s1 = FL(sp)[-1];
-	value_t s3 = FL(sp)[-3];
-	value_t s4 = FL(sp)[-4];
-	if(fl_unlikely(nargs < nreq))
-		lerrorf(FL_ArgError, "too few arguments");
-	if(fl_unlikely(extr > nelem(args)))
-		lerrorf(FL_ArgError, "too many arguments");
-	for(i = 0; i < extr; i++)
-		args[i] = UNBOUND;
-	for(i = nreq; i < nargs; i++){
-		v = bp[i];
-		if(issymbol(v) && iskeyword((symbol_t*)ptr(v)))
-			break;
-		if(a >= nopt)
-			goto no_kw;
-		args[a++] = v;
-	}
-	if(i >= nargs)
-		goto no_kw;
-	// now process keywords
-	uintptr_t n = vector_size(kwtable)/2;
-	do{
-		i++;
-		if(fl_unlikely(i >= nargs))
-			lerrorf(FL_ArgError, "keyword %s requires an argument", symbol_name(v));
-		value_t hv = fixnum(((symbol_t*)ptr(v))->hash);
-		fixnum_t lx = numval(hv);
-		uintptr_t x = 2*((lx < 0 ? -lx : lx) % n);
-		if(fl_likely(vector_elt(kwtable, x) == v)){
-			intptr_t idx = numval(vector_elt(kwtable, x+1));
-			assert(idx < nkw);
-			idx += nopt;
-			if(args[idx] == UNBOUND){
-				// if duplicate key, keep first value
-				args[idx] = bp[i];
-			}
-		}else{
-			lerrorf(FL_ArgError, "unsupported keyword %s", symbol_name(v));
-		}
-		i++;
-		if(i >= nargs)
-			break;
-		v = bp[i];
-	}while(issymbol(v) && iskeyword((symbol_t*)ptr(v)));
-no_kw:
-	nrestargs = nargs - i;
-	if(fl_unlikely(!va && nrestargs > 0))
-		lerrorf(FL_ArgError, "too many arguments");
-	nargs = ntot + nrestargs;
-	if(nrestargs)
-		memmove(bp+ntot, bp+i, nrestargs*sizeof(value_t));
-	memmove(bp+nreq, args, extr*sizeof(value_t));
-	FL(sp) = bp + nargs;
-	assert((intptr_t)(FL(sp)-FL(stack)) < (intptr_t)FL(nstack)-4);
-	PUSH(s4);
-	PUSH(s3);
-	PUSH(nargs);
-	PUSH(s1);
-	FL(curr_frame) = FL(sp);
-	return nargs;
-}
-
-#if BYTE_ORDER == LITTLE_ENDIAN && defined(MEM_UNALIGNED_ACCESS)
-#define GET_INT32(a) *(const int32_t*)(a)
-#define GET_INT16(a) *(const int16_t*)(a)
-#else
-#define GET_INT32(a) (int32_t)((a)[0]<<0 | (a)[1]<<8 | (a)[2]<<16 | (uint32_t)(a)[3]<<24)
-#define GET_INT16(a) (int16_t)((a)[0]<<0 | (a)[1]<<8)
-#endif
-
-/*
-  stack on entry: <func>  <nargs args...>
-  caller's responsibility:
-  - put the stack in this state
-  - provide arg count
-  - respect tail position
-  - restore SP
-
-  callee's responsibility:
-  - check arg counts
-  - allocate vararg array
-  - push closed env, set up new environment
-*/
-static value_t
-apply_cl(int nargs)
-{
-	value_t *top_frame = FL(curr_frame), *bp, *ipd;
-	register value_t *sp = FL(sp);
-	const uint8_t *ip;
-	bool tail;
-	int n;
-
-	goto apply_func;
-
-#if defined(COMPUTED_GOTO)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpedantic"
-	static const void * const ops[] = {
-#define GOTO_OP_OFFSET(op) [op] = &&op_##op
-#include "vm_goto.inc"
-#undef GOTO_OP_OFFSET
-	};
-#define NEXT_OP goto *ops[*ip++]
-#define LABEL(x) x
-#define OP(x) op_##x:
-#include "vm.inc"
-#undef OP
-#undef LABEL
-#undef NEXT_OP
-#pragma GCC diagnostic pop
-#else /* just a usual (portable) switch/case */
-	uint8_t op;
-	while(1){
-		switch(op){
-#define NEXT_OP break
-#define LABEL(x) x
-#define OP(x) case x:
-#include "vm.inc"
-#undef OP
-#undef LABEL
-#undef NEXT_OP
-		}
-		op = *ip++;
-	}
-#endif
-}
-
-// top = top frame pointer to start at
-static value_t
-_stacktrace(value_t *top)
-{
-	value_t lst = FL_nil;
-	value_t *stack = FL(stack);
-
-	fl_gc_handle(&lst);
-	while(top > stack){
-		const uint8_t *ip1 = (void*)top[-1];
-		int sz = top[-2]+1;
-		value_t *bp = top-4-sz;
-		value_t func = bp[0];
-		const uint8_t *ip0 = cvalue_data(fn_bcode(func));
-		intptr_t ip = ip1 - ip0 - 1; /* -1: ip1 is *after* the one that was being executed */
-		value_t v = alloc_vector(sz+1, 0);
-		vector_elt(v, 0) = fixnum(ip);
-		vector_elt(v, 1) = func;
-		for(int i = 1; i < sz; i++){
-			value_t si = bp[i];
-			// if there's an error evaluating argument defaults some slots
-			// might be left set to UNBOUND
-			vector_elt(v, i+1) = si == UNBOUND ? FL_void : si;
-		}
-		lst = fl_cons(v, lst);
-		top = (value_t*)top[-3];
-	}
-	fl_free_gc_handles(1);
-	return lst;
-}
-
-// builtins -------------------------------------------------------------------
-
-BUILTIN("gc", gc)
-{
-	USED(args);
-	argcount(nargs, 0);
-	fl_gc(false);
-	return FL_void;
-}
-
-BUILTIN("function", function)
-{
-	if(nargs == 1 && issymbol(args[0]))
-		return fn_builtin_builtin(args, nargs);
-	if(nargs < 2 || nargs > 4)
-		argcount(nargs, 2);
-	if(fl_unlikely(!fl_isstring(args[0])))
-		type_error("string", args[0]);
-	if(fl_unlikely(!isvector(args[1])))
-		type_error("vector", args[1]);
-	cvalue_t *arr = ptr(args[0]);
-	cv_pin(arr);
-	uint8_t *data = cv_data(arr);
-	if(FL(loading)){
-		// read syntax, shifted 48 for compact text representation
-		size_t i, sz = cv_len(arr);
-		for(i = 0; i < sz; i++)
-			data[i] -= 48;
-	}
-	function_t *fn = alloc_words(sizeof(function_t)/sizeof(value_t));
-	value_t fv = tagptr(fn, TAG_FUNCTION);
-	fn->bcode = args[0];
-	fn->vals = args[1];
-	fn->env = FL_nil;
-	fn->name = FL_lambda;
-	if(nargs > 2){
-		if(issymbol(args[2])){
-			fn->name = args[2];
-			if(nargs > 3)
-				fn->env = args[3];
-		}else{
-			fn->env = args[2];
-			if(nargs > 3){
-				if(fl_unlikely(!issymbol(args[3])))
-					type_error("symbol", args[3]);
-				fn->name = args[3];
-			}
-		}
-		if(fl_unlikely(isgensym(fn->name)))
-			lerrorf(FL_ArgError, "name should not be a gensym");
-	}
-	return fv;
-}
-
-fl_purefn
-BUILTIN("function:code", function_code)
-{
-	argcount(nargs, 1);
-	value_t v = args[0];
-	if(fl_unlikely(!isfunction(v)))
-		type_error("function", v);
-	return fn_bcode(v);
-}
-
-fl_purefn
-BUILTIN("function:vals", function_vals)
-{
-	argcount(nargs, 1);
-	value_t v = args[0];
-	if(fl_unlikely(!isfunction(v)))
-		type_error("function", v);
-	return fn_vals(v);
-}
-
-fl_purefn
-BUILTIN("function:env", function_env)
-{
-	argcount(nargs, 1);
-	value_t v = args[0];
-	if(fl_unlikely(!isfunction(v)))
-		type_error("function", v);
-	return fn_env(v);
-}
-
-BUILTIN("function:name", function_name)
-{
-	argcount(nargs, 1);
-	value_t v = args[0];
-	if(isfunction(v))
-		return fn_name(v);
-	if(isbuiltin(v))
-		return symbol(builtins[uintval(v)].name, false);
-	if(iscbuiltin(v)){
-		v = (value_t)ptrhash_get(&FL(reverse_dlsym_lookup_table), ptr(v));
-		if(v == (value_t)HT_NOTFOUND)
-			return FL_nil;
-		return v;
-	}
-	type_error("function", v);
-}
-
-BUILTIN("copy-list", copy_list)
-{
-	argcount(nargs, 1);
-	return copy_list(args[0]);
-}
-
-BUILTIN("append", append)
-{
-	value_t first = FL_nil, lst, lastcons = FL_nil;
-	int i;
-	if(nargs == 0)
-		return FL_nil;
-	fl_gc_handle(&first);
-	fl_gc_handle(&lastcons);
-	for(i = 0; i < nargs; i++){
-		lst = args[i];
-		if(iscons(lst)){
-			lst = copy_list(lst);
-			if(first == FL_nil)
-				first = lst;
-			else
-				cdr_(lastcons) = lst;
-			lastcons = tagptr((((cons_t*)FL(curheap))-1), TAG_CONS);
-		}else if(lst != FL_nil){
-			type_error("cons", lst);
-		}
-	}
-	fl_free_gc_handles(2);
-	return first;
-}
-
-BUILTIN("list*", liststar)
-{
-	if(nargs == 1)
-		return args[0];
-	if(nargs == 0)
-		argcount(nargs, 1);
-	return list(args, nargs, true);
-}
-
-BUILTIN("stacktrace", stacktrace)
-{
-	USED(args);
-	argcount(nargs, 0);
-	return _stacktrace(FL(throwing_frame) ? FL(throwing_frame) : FL(curr_frame));
-}
-
-BUILTIN("map", map)
-{
-	if(fl_unlikely(nargs < 2))
-		lerrorf(FL_ArgError, "too few arguments");
-	value_t *k = FL(sp);
-	PUSH(FL_nil);
-	PUSH(FL_nil);
-	for(bool first = true;;){
-		PUSH(args[0]);
-		for(int i = 1; i < nargs; i++){
-			if(!iscons(args[i])){
-				POPN(2+i);
-				return k[1];
-			}
-			PUSH(car(args[i]));
-			args[i] = cdr_(args[i]);
-		}
-		value_t v = _applyn(nargs-1);
-		POPN(nargs);
-		PUSH(v);
-		value_t c = mk_cons();
-		car_(c) = POP(); cdr_(c) = FL_nil;
-		if(first)
-			k[1] = c;
-		else
-			cdr_(k[0]) = c;
-		k[0] = c;
-		first = false;
-	}
-}
-
-BUILTIN("for-each", for_each)
-{
-	if(fl_unlikely(nargs < 2))
-		lerrorf(FL_ArgError, "too few arguments");
-	for(size_t n = 0;; n++){
-		PUSH(args[0]);
-		int pargs = 0;
-		for(int i = 1; i < nargs; i++, pargs++){
-			value_t v = args[i];
-			if(iscons(v)){
-				PUSH(car_(v));
-				args[i] = cdr_(v);
-				continue;
-			}
-			if(isvector(v)){
-				size_t sz = vector_size(v);
-				if(n < sz){
-					PUSH(vector_elt(v, n));
-					continue;
-				}
-			}
-			if(isarray(v)){
-				size_t sz = cvalue_arraylen(v);
-				if(n < sz){
-					value_t a[2];
-					a[0] = v;
-					a[1] = fixnum(n);
-					PUSH(cvalue_array_aref(a));
-					continue;
-				}
-			}
-			if(ishashtable(v)){
-				htable_t *h = totable(v);
-				assert(n != 0 || h->i == 0);
-				void **table = h->table;
-				for(; h->i < h->size; h->i += 2){
-					if(table[h->i+1] != HT_NOTFOUND)
-						break;
-				}
-				if(h->i < h->size){
-					PUSH((value_t)table[h->i]);
-					pargs++;
-					PUSH((value_t)table[h->i+1]);
-					h->i += 2;
-					continue;
-				}
-				h->i = 0;
-			}
-			POPN(pargs+1);
-			return FL_void;
-		}
-		_applyn(pargs);
-		POPN(pargs+1);
-	}
-}
-
-BUILTIN("sleep", fl_sleep)
-{
-	if(nargs > 1)
-		argcount(nargs, 1);
-	double s = nargs > 0 ? todouble(args[0]) : 0;
-	sleep_ms(s * 1000.0);
-	return FL_void;
-}
-
-BUILTIN("vm-stats", vm_stats)
-{
-	USED(args);
-	argcount(nargs, 0);
-	ios_printf(ios_stderr, "heap total     %10"PRIuPTR" bytes\n", FL(heapsize));
-	ios_printf(ios_stderr, "heap free      %10"PRIuPTR" bytes\n", (uintptr_t)(FL(lim)-FL(curheap)));
-	ios_printf(ios_stderr, "heap used      %10"PRIuPTR" bytes\n", (uintptr_t)(FL(curheap)-FL(fromspace)));
-	ios_printf(ios_stderr, "stack          %10"PRIu64" bytes\n", (uint64_t)FL(nstack)*sizeof(value_t));
-	ios_printf(ios_stderr, "finalizers     %10"PRIu32"\n", (uint32_t)FL(nfinalizers));
-	ios_printf(ios_stderr, "max finalizers %10"PRIu32"\n", (uint32_t)FL(maxfinalizers));
-	ios_printf(ios_stderr, "gc handles     %10"PRIu32"\n", (uint32_t)FL(ngchandles));
-	ios_printf(ios_stderr, "gc calls       %10"PRIu64"\n", (uint64_t)FL(gccalls));
-	ios_printf(ios_stderr, "opcodes        %10d\n", N_OPCODES);
-	return FL_void;
-}
-
-static const builtinspec_t builtin_fns[] = {
-#define BUILTIN_FN(l, c, attr){l, (builtin_t)fn_builtin_##c},
-#include "builtin_fns.h"
-#undef BUILTIN_FN
-};
-
-// initialization -------------------------------------------------------------
-
-int
-fl_init(size_t heapsize, size_t stacksize)
-{
-	int i;
-
-	if((fl = MEM_CALLOC(1, sizeof(*fl))) == nil)
-		return -1;
-	FL(scr_width) = 100;
-
-	FL(heapsize) = heapsize*sizeof(value_t);
-
-	if((FL(fromspace) = MEM_ALLOC(FL(heapsize))) == nil){
-failed:
-		MEM_FREE(FL(fromspace));
-		MEM_FREE(FL(tospace));
-		MEM_FREE(FL(consflags));
-		MEM_FREE(FL(finalizers));
-		fl_segfree(FL(stack), stacksize*sizeof(value_t));
-		htable_free(&FL(printconses));
-		MEM_FREE(fl);
-		return -1;
-	}
-
-	if((FL(tospace) = MEM_ALLOC(FL(heapsize))) == nil)
-		goto failed;
-	FL(curheap) = FL(fromspace);
-	FL(lim) = FL(curheap)+FL(heapsize)-sizeof(cons_t);
-
-	if((FL(stack) = fl_segalloc(stacksize*sizeof(value_t))) == nil)
-		goto failed;
-	FL(curr_frame) = FL(sp) = FL(stack);
-	FL(nstack) = stacksize;
-
-	FL(maxfinalizers) = 512;
-	if((FL(finalizers) = MEM_ALLOC(FL(maxfinalizers) * sizeof(*FL(finalizers)))) == nil)
-		goto failed;
-
-	if((FL(consflags) = bitvector_new(FL(heapsize)/sizeof(cons_t), 1)) == nil)
-		goto failed;
-	if((htable_new(&FL(printconses), 32)) == nil)
-		goto failed;
-
-	comparehash_init();
-
-	FL_lambda = csymbol("λ");
-	FL_function = csymbol("function");
-	FL_quote = csymbol("quote");
-	FL_trycatch = csymbol("trycatch");
-	FL_backquote = csymbol("quasiquote");
-	FL_comma = csymbol("unquote");
-	FL_commaat = csymbol("unquote-splicing");
-	FL_commadot = csymbol("unquote-nsplicing");
-	FL_IOError = csymbol("io-error");
-	FL_ParseError = csymbol("parse-error");
-	FL_TypeError = csymbol("type-error");
-	FL_ArgError = csymbol("arg-error");
-	FL_UnboundError = csymbol("unbound-error");
-	FL_KeyError = csymbol("key-error");
-	FL_MemoryError = csymbol("memory-error");
-	FL_BoundsError = csymbol("bounds-error");
-	FL_DivideError = csymbol("divide-error");
-	FL_Error = csymbol("error");
-	FL_conssym = csymbol("cons");
-	FL_symbolsym = csymbol("symbol");
-	FL_fixnumsym = csymbol("fixnum");
-	FL_vectorsym = csymbol("vector");
-	FL_builtinsym = csymbol("builtin");
-	FL_booleansym = csymbol("boolean");
-	FL_nullsym = csymbol("null");
-	FL_defsym = csymbol("def");
-	FL_defmacrosym = csymbol("defmacro");
-	FL_forsym = csymbol("for");
-	FL_setqsym = csymbol("set!");
-	FL_evalsym = csymbol("eval");
-	FL_vu8sym = csymbol("vu8");
-	FL_fnsym = csymbol("fn");
-	FL_nulsym = csymbol("nul");
-	FL_alarmsym = csymbol("alarm");
-	FL_backspacesym = csymbol("backspace");
-	FL_tabsym = csymbol("tab");
-	FL_linefeedsym = csymbol("linefeed");
-	FL_vtabsym = csymbol("vtab");
-	FL_pagesym = csymbol("page");
-	FL_returnsym = csymbol("return");
-	FL_escsym = csymbol("esc");
-	FL_spacesym = csymbol("space");
-	FL_deletesym = csymbol("delete");
-	FL_newlinesym = csymbol("newline");
-	FL_builtins_table_sym = csymbol("*builtins*");
-
-	set(FL_printprettysym = csymbol("*print-pretty*"), FL_t);
-	set(FL_printreadablysym = csymbol("*print-readably*"), FL_t);
-	set(FL_printwidthsym = csymbol("*print-width*"), fixnum(FL(scr_width)));
-	set(FL_printlengthsym = csymbol("*print-length*"), FL_nil);
-	set(FL_printlevelsym = csymbol("*print-level*"), FL_nil);
-	FL(lasterror) = FL_nil;
-
-	for(i = 0; i < nelem(builtins); i++){
-		if(builtins[i].name)
-			set(symbol(builtins[i].name, false), builtin(i));
-	}
-	setc(csymbol("procedure?"), builtin(OP_FUNCTIONP));
-	setc(csymbol("top-level-bound?"), builtin(OP_BOUNDP));
-
-	FL(the_empty_vector) = tagptr(alloc_words(1), TAG_VECTOR);
-	vector_setsize(FL(the_empty_vector), 0);
-
-	cvalues_init();
-
-	set(csymbol("*os-name*"), cvalue_static_cstring(__os_name__));
-#if defined(__os_version__)
-	set(csymbol("*os-version*"), cvalue_static_cstring(__os_version__));
-#endif
-	FL(memory_exception_value) = fl_list2(FL_MemoryError, cvalue_static_cstring("out of memory"));
-
-	const builtinspec_t *b;
-	for(i = 0, b = builtin_fns; i < nelem(builtin_fns); i++, b++)
-		cbuiltin(b->name, b->fptr);
-	table_init();
-	iostream_init();
-	compress_init();
-	return 0;
-}
-
-// top level ------------------------------------------------------------------
-
-value_t
-fl_toplevel_eval(value_t expr)
-{
-	return fl_applyn(1, symbol_value(FL_evalsym), expr);
-}
-
-int
-fl_load_system_image(value_t sys_image_iostream)
-{
-	FL(loading) = true;
-	PUSH(sys_image_iostream);
-	value_t *saveSP = FL(sp);
-	FL_TRY{
-		while(1){
-			FL(sp) = saveSP;
-			value_t e = fl_read_sexpr(FL(sp)[-1]);
-			if(ios_eof(value2c(ios_t*, FL(sp)[-1])))
-				break;
-			if(isfunction(e)){
-				// stage 0 format: series of thunks
-				PUSH(e);
-				(void)_applyn(0);
-			}else{
-				// stage 1 format: list alternating symbol/value
-				while(iscons(e)){
-					symbol_t *sym = tosymbol(car_(e));
-					e = cdr_(e);
-					if(sym->binding != UNBOUND)
-						ios_printf(ios_stderr, "%s redefined on boot\n", sym->name);
-					sym->binding = car_(e);
-					e = cdr_(e);
-				}
-				break;
-			}
-		}
-	}
-	FL_CATCH_NO_INC{
-		ios_puts(ios_stderr, "fatal error during bootstrap: ");
-		fl_print(ios_stderr, FL(lasterror));
-		ios_putc(ios_stderr, '\n');
-		return -1;
-	}
-	FL(sp) = saveSP-1;
-	FL(loading) = false;
-	return 0;
-}
--- a/src/flisp.h
+++ /dev/null
@@ -1,452 +1,0 @@
-#pragma once
-
-#include "platform.h"
-#include "utf8.h"
-#include "ios.h"
-#include "tbl.h"
-#include "bitvector.h"
-#include "htableh.inc"
-HTPROT(ptrhash)
-
-typedef struct fltype_t fltype_t;
-
-enum {
-	TAG_NUM,
-	TAG_CPRIM,
-	TAG_FUNCTION,
-	TAG_VECTOR,
-	TAG_NUM1,
-	TAG_CVALUE,
-	TAG_SYM,
-	TAG_CONS,
-
-	/* those were set to 7 and 3 strategically on purpose */
-	TAG_NONLEAF_MASK = TAG_CONS & TAG_VECTOR,
-};
-
-enum {
-	FLAG_CONST = 1<<0,
-	FLAG_KEYWORD = 1<<1,
-};
-
-typedef enum {
-	T_INT8, T_UINT8,
-	T_INT16, T_UINT16,
-	T_INT32, T_UINT32,
-	T_INT64, T_UINT64,
-	T_MPINT,
-	T_FLOAT,
-	T_DOUBLE,
-}numerictype_t;
-
-typedef uintptr_t value_t;
-
-#if defined(BITS64)
-typedef int64_t fixnum_t;
-#define FIXNUM_BITS 62
-#define TOP_BIT (1ULL<<63)
-#define T_FIXNUM T_INT64
-#define PRIdFIXNUM PRId64
-#else
-typedef int32_t fixnum_t;
-#define FIXNUM_BITS 30
-#define TOP_BIT (1U<<31)
-#define T_FIXNUM T_INT32
-#define PRIdFIXNUM PRId32
-#endif
-
-#if !defined(FWD_BIT)
-#define FWD_BIT TOP_BIT
-#endif
-
-typedef struct {
-	value_t car;
-	value_t cdr;
-}fl_aligned(8) cons_t;
-
-// NOTE: symbol_t MUST have the same fields as gensym_t first
-// there are places where gensyms are treated as normal symbols
-typedef struct {
-	uint64_t hash;
-	fltype_t *type;
-	value_t binding;   // global value binding
-	uint8_t numtype;
-	uint8_t size;
-	uint8_t flags;
-	uint8_t _dummy;
-	const char *name;
-}fl_aligned(8) symbol_t;
-
-typedef struct {
-	uint64_t id;
-	fltype_t *type;
-	value_t binding;
-}fl_aligned(8) gensym_t;
-
-typedef struct Builtin Builtin;
-
-struct Builtin {
-	const char *name;
-	int nargs;
-};
-
-typedef value_t (*builtin_t)(value_t*, int);
-
-#define fits_bits(x, b) (((x)>>(b-1)) == 0 || (~((x)>>(b-1))) == 0)
-#define fits_fixnum(x) fits_bits(x, FIXNUM_BITS)
-
-#define ANYARGS -10000
-#define NONNUMERIC (0xff)
-#define valid_numtype(v) ((v) <= T_DOUBLE)
-#define UNBOUND ((value_t)1) // an invalid value
-#define tag(x) ((x) & 7)
-#define ptr(x) ((void*)((uintptr_t)(x) & (~(uintptr_t)7)))
-#define tagptr(p, t) ((value_t)(p) | (t))
-#define fixnum(x) ((value_t)(x)<<2)
-#define numval(x)  ((fixnum_t)(x)>>2)
-#define uintval(x) (((unsigned int)(x))>>3)
-#define builtin(n) tagptr(((value_t)n<<3), TAG_FUNCTION)
-#define iscons(x) (tag(x) == TAG_CONS)
-#define issymbol(x) (tag(x) == TAG_SYM)
-#define isfixnum(x) (((x)&3) == TAG_NUM)
-#define bothfixnums(x, y) (isfixnum(x) && isfixnum(y))
-#define isvector(x) (tag(x) == TAG_VECTOR)
-#define iscvalue(x) (tag(x) == TAG_CVALUE)
-#define iscprim(x) (tag(x) == TAG_CPRIM)
-// doesn't lead to other values
-#define leafp(a) (((a)&TAG_NONLEAF_MASK) != TAG_NONLEAF_MASK)
-
-// allocate n consecutive conses
-#define cons_reserve(n) tagptr(alloc_words((n)*2), TAG_CONS)
-#define cons_index(c) (((cons_t*)ptr(c))-((cons_t*)FL(fromspace)))
-#define ismarked(c) bitvector_get(FL(consflags), cons_index(c))
-#define mark_cons(c) bitvector_set(FL(consflags), cons_index(c))
-#define unmark_cons(c) bitvector_reset(FL(consflags), cons_index(c))
-
-#define isforwarded(v) (*(value_t*)ptr(v) & FWD_BIT)
-#define forwardloc(v) (*(value_t*)ptr(v) ^ FWD_BIT)
-#define forward(v, to) \
-	do{ \
-		*(value_t*)ptr(v) = (value_t)(to) | FWD_BIT; \
-	}while(0)
-
-#define vector_size(v) (((size_t*)ptr(v))[0]>>2)
-#define vector_setsize(v, n) (((size_t*)ptr(v))[0] = ((n)<<2))
-#define vector_elt(v, i) (((value_t*)ptr(v))[1+(i)])
-#define vector_grow_amt(x) ((x)<8 ? 5 : 6*((x)>>3))
-// functions ending in _ are unsafe, faster versions
-#define car_(v) (((cons_t*)ptr(v))->car)
-#define cdr_(v) (((cons_t*)ptr(v))->cdr)
-#define car(v) (tocons(v)->car)
-#define cdr(v) (tocons(v)->cdr)
-#define fn_bcode(f) (((function_t*)ptr(f))->bcode)
-#define fn_vals(f) (((function_t*)ptr(f))->vals)
-#define fn_env(f) (((function_t*)ptr(f))->env)
-#define fn_name(f) (((function_t*)ptr(f))->name)
-#define set(s, v) (((symbol_t*)ptr(s))->binding = (v))
-#define setc(s, v) \
-	do{ \
-		symbol_t *sy = (symbol_t*)ptr(s); \
-		sy->flags |= FLAG_CONST; \
-		sy->binding = (v); \
-	}while(0)
-#define isconstant(s) ((s)->flags & FLAG_CONST)
-#define iskeyword(s) ((s)->flags & FLAG_KEYWORD)
-#define symbol_value(s) (((symbol_t*)ptr(s))->binding)
-#define sym_to_numtype(s) (((symbol_t*)ptr(s))->numtype)
-#define ismanaged(v) ((((uint8_t*)ptr(v)) >= FL(fromspace)) && (((uint8_t*)ptr(v)) < FL(fromspace)+FL(heapsize)))
-#define isgensym(x)  (issymbol(x) && ismanaged(x))
-#define isfunction(x) (tag(x) == TAG_FUNCTION && (x) > (N_BUILTINS<<3))
-#define iscbuiltin(x) (iscvalue(x) && cv_class(ptr(x)) == FL(builtintype))
-// utility for iterating over all arguments in a builtin
-// i=index, i0=start index, arg = var for each arg, args = arg array
-// assumes "nargs" is the argument count
-#define FOR_ARGS(i, i0, arg, args) for(i=i0; i<nargs && ((arg=args[i]) || 1); i++)
-#define N_BUILTINS ((int)N_OPCODES)
-
-#define PUSH(v) \
-	do{ \
-		*FL(sp)++ = (v); \
-	}while(0)
-#define POPN(n) \
-	do{ \
-		FL(sp) -= (n); \
-	}while(0)
-#define POP() *(--FL(sp))
-
-bool isbuiltin(value_t x) fl_constfn fl_hotfn;
-int fl_init(size_t heapsize, size_t stacksize);
-int fl_load_system_image(value_t ios);
-
-_Noreturn void fl_exit(int status);
-
-/* collector */
-value_t relocate(value_t v) fl_hotfn;
-void fl_gc(bool mustgrow);
-void fl_gc_handle(value_t *pv);
-void fl_free_gc_handles(int n);
-
-/* symbol table */
-value_t gensym(void);
-value_t symbol(const char *str, bool copy) fl_hotfn;
-value_t csymbol_(const char *str, int len);
-#define csymbol(str) csymbol_(str, sizeof(str)-1)
-const char *symbol_name(value_t v);
-
-/* read, eval, print main entry points */
-value_t fl_toplevel_eval(value_t expr);
-value_t fl_apply(value_t f, value_t l);
-value_t fl_applyn(int n, value_t f, ...);
-
-/* object model manipulation */
-value_t fl_cons(value_t a, value_t b);
-value_t fl_list2(value_t a, value_t b);
-value_t fl_listn(int n, ...);
-bool fl_isnumber(value_t v) fl_purefn;
-value_t alloc_vector(size_t n, bool init);
-
-/* consistent iswprint and wcwidth */
-int fl_iswprint(Rune c) fl_constfn;
-int fl_wcwidth(Rune c) fl_constfn;
-
-/* safe casts */
-cons_t *tocons(value_t v) fl_purefn;
-symbol_t *tosymbol(value_t v) fl_purefn;
-fixnum_t tofixnum(value_t v) fl_purefn;
-char *tostring(value_t v) fl_purefn;
-double todouble(value_t a) fl_purefn;
-
-/* conses */
-value_t mk_cons(void) fl_hotfn;
-void *alloc_words(int n) fl_hotfn;
-
-char *uint2str(char *dest, size_t len, uint64_t num, int base);
-
-/* error handling */
-typedef struct _fl_readstate_t {
-	htable_t backrefs;
-	htable_t gensyms;
-	value_t source;
-	struct _fl_readstate_t *prev;
-}fl_readstate_t;
-
-typedef struct _ectx_t {
-	fl_readstate_t *rdst;
-	struct _ectx_t *prev;
-	jmp_buf buf;
-	value_t *sp;
-	value_t *frame;
-	int ngchnd;
-}fl_exception_context_t;
-
-void free_readstate(fl_readstate_t *rs);
-
-#define FL_TRY_EXTERN \
-	fl_exception_context_t _ctx; int l__tr, l__ca; \
-	fl_savestate(&_ctx); FL(exctx) = &_ctx; \
-	if(!fl_setjmp(_ctx.buf)) \
-		for(l__tr = 1; l__tr; l__tr = 0, (void)(FL(exctx) = FL(exctx)->prev))
-
-#define FL_CATCH_EXTERN_NO_RESTORE \
-	else \
-		for(l__ca=1; l__ca;)
-
-#define FL_CATCH_EXTERN \
-	else \
-		for(l__ca=1; l__ca; l__ca=0, fl_restorestate(&_ctx))
-
-_Noreturn void lerrorf(value_t e, const char *format, ...) fl_printfmt(2, 3);
-void fl_savestate(fl_exception_context_t *_ctx);
-void fl_restorestate(fl_exception_context_t *_ctx);
-_Noreturn void fl_raise(value_t e);
-_Noreturn void type_error(const char *expected, value_t got);
-_Noreturn void bounds_error(value_t arr, value_t ind);
-_Noreturn void unbound_error(value_t sym);
-_Noreturn void arity_error(int nargs, int c);
-
-#define argcount(nargs, c) \
-	do{ \
-		if(fl_unlikely(nargs != c)) \
-			arity_error(nargs, c); \
-	}while(0)
-
-typedef struct {
-	void (*print)(value_t self, ios_t *f);
-	void (*relocate)(value_t oldv, value_t newv);
-	void (*finalize)(value_t self);
-	void (*print_traverse)(value_t self);
-} cvtable_t;
-
-typedef void (*cvinitfunc_t)(fltype_t*, value_t, void*);
-
-struct fltype_t {
-	value_t type;
-	cvtable_t *vtable;
-	fltype_t *eltype;  // for arrays
-	fltype_t *artype;  // (array this)
-	cvinitfunc_t init;
-	size_t size;
-	size_t elsz;
-	numerictype_t numtype;
-};
-
-typedef struct {
-	fltype_t *type;
-	union {
-		void *data;
-		builtin_t cbuiltin;
-	};
-	size_t len; // length of *data in bytes
-	uint8_t _space[]; // variable size
-}fl_aligned(8) cvalue_t;
-
-typedef struct {
-	fltype_t *type;
-	uint8_t _space[];
-}fl_aligned(8) cprim_t;
-
-typedef struct {
-	value_t bcode;
-	value_t vals;
-	value_t env;
-	value_t name;
-}fl_aligned(8) function_t;
-
-#define CPRIM_NWORDS sizeof(cprim_t)/sizeof(value_t)
-#define cv_class(cv) ((fltype_t*)(((uintptr_t)((cvalue_t*)cv)->type)&~(uintptr_t)3))
-#define cv_len(cv) (((cvalue_t*)(cv))->len)
-#define cv_type(cv) (cv_class(cv)->type)
-#define cv_data(cv) (((cvalue_t*)(cv))->data)
-#define cv_isstr(cv) (cv_class(cv)->eltype == FL(bytetype))
-#define cv_isPOD(cv) (cv_class(cv)->init != nil)
-#define cvalue_data(v) cv_data((cvalue_t*)ptr(v))
-#define cvalue_len(v) cv_len((cvalue_t*)ptr(v))
-#define value2c(type, v) ((type)cvalue_data(v))
-#define cp_class(cp) (((cprim_t*)(cp))->type)
-#define cp_type(cp)	(cp_class(cp)->type)
-#define cp_numtype(cp) (cp_class(cp)->numtype)
-#define cp_data(cp)	(((cprim_t*)(cp))->_space)
-// WARNING: multiple evaluation!
-#define cptr(v) (iscprim(v) ? cp_data(ptr(v)) : cvalue_data(v))
-
-#define ismpint(v) (iscvalue(v) && cp_numtype(ptr(v)) == T_MPINT)
-#define tompint(v) (*(mpint**)cv_data(ptr(v)))
-
-#define BUILTIN(lname, cname) \
-	value_t fn_builtin_##cname(value_t *args, int nargs)
-
-#define BUILTIN_FN(l, c, attr) attr BUILTIN(l, c);
-#include "builtin_fns.h"
-#undef BUILTIN_FN
-
-#include "opcodes.h"
-
-enum {
-	FL_nil = builtin(OP_LOADNIL),
-	FL_t = builtin(OP_LOADT),
-	FL_void = builtin(OP_LOADVOID),
-	FL_eof = builtin(OP_EOF_OBJECT),
-};
-
-#define N_GC_HANDLES 1024
-
-typedef struct Fl Fl;
-
-struct Fl {
-	value_t *sp;
-	uint8_t *curheap;
-	value_t *curr_frame;
-
-	uint8_t *fromspace;
-	uint8_t *tospace;
-	uint8_t *lim;
-
-	value_t *stack;
-
-	uintptr_t heapsize;//bytes
-	size_t malloc_pressure;
-	uint32_t nstack;
-
-	cvalue_t **finalizers;
-	size_t nfinalizers;
-	size_t maxfinalizers;
-
-	fl_readstate_t *readstate;
-	Tbl *symtab;
-
-	// saved execution state for an unwind target
-	fl_exception_context_t *exctx;
-	value_t *throwing_frame;  // active frame when exception was thrown
-	value_t lasterror;
-
-	fltype_t *tabletype;
-
-	fltype_t *iostreamtype;
-
-	value_t the_empty_vector;
-	value_t the_empty_string;
-	value_t memory_exception_value;
-
-	fltype_t *mpinttype;
-	fltype_t *int8type, *uint8type;
-	fltype_t *int16type, *uint16type;
-	fltype_t *int32type, *uint32type;
-	fltype_t *int64type, *uint64type;
-	fltype_t *floattype, *doubletype;
-	fltype_t *bytetype, *runetype;
-	fltype_t *stringtype, *runestringtype;
-	fltype_t *builtintype;
-
-	uint32_t gensym_ctr;
-	// two static buffers for gensym printing so there can be two
-	// gensym names available at a time, mostly for compare()
-	char gsname[2][16];
-	int gsnameno;
-
-	bool loading;
-	bool exiting;
-	bool grew;
-
-	uint32_t *consflags;
-	size_t gccalls;
-
-	htable_t printconses;
-	uint32_t printlabel;
-	int print_pretty;
-	int print_princ;
-	fixnum_t print_length;
-	fixnum_t print_level;
-	fixnum_t p_level;
-	int scr_width;
-	ssize_t hpos, vpos;
-
-	htable_t reverse_dlsym_lookup_table;
-	htable_t TypeTable;
-	int ngchandles;
-	value_t *gchandles[N_GC_HANDLES];
-};
-
-extern fl_thread(Fl *fl);
-#define FL(f) fl->f
-
-extern value_t FL_builtins_table_sym, FL_quote, FL_lambda, FL_function, FL_comma, FL_commaat;
-extern value_t FL_commadot, FL_trycatch, FL_backquote;
-extern value_t FL_conssym, FL_symbolsym, FL_fixnumsym, FL_vectorsym, FL_builtinsym, FL_vu8sym;
-extern value_t FL_defsym, FL_defmacrosym, FL_forsym, FL_setqsym;
-extern value_t FL_booleansym, FL_nullsym, FL_evalsym, FL_fnsym;
-extern value_t FL_nulsym, FL_alarmsym, FL_backspacesym, FL_tabsym, FL_linefeedsym, FL_newlinesym;
-extern value_t FL_vtabsym, FL_pagesym, FL_returnsym, FL_escsym, FL_spacesym, FL_deletesym;
-extern value_t FL_IOError, FL_ParseError, FL_TypeError, FL_ArgError, FL_MemoryError;
-extern value_t FL_DivideError, FL_BoundsError, FL_Error, FL_KeyError, FL_UnboundError;
-
-extern value_t FL_printwidthsym, FL_printreadablysym, FL_printprettysym, FL_printlengthsym;
-extern value_t FL_printlevelsym;
-extern value_t FL_arraysym;
-extern value_t FL_iostreamsym, FL_rdsym, FL_wrsym, FL_apsym, FL_crsym, FL_truncsym;
-extern value_t FL_instrsym, FL_outstrsym;
-extern value_t FL_int8sym, FL_uint8sym, FL_int16sym, FL_uint16sym, FL_int32sym, FL_uint32sym;
-extern value_t FL_int64sym, FL_uint64sym, FL_bignumsym;
-extern value_t FL_bytesym, FL_runesym, FL_floatsym, FL_doublesym;
-extern value_t FL_stringtypesym, FL_runestringtypesym;
-
-_Noreturn void flmain(const uint8_t *boot, int bootsz, int argc, char **argv);
--- a/src/flmain.c
+++ /dev/null
@@ -1,145 +1,0 @@
-#include "flisp.h"
-#include "cvalues.h"
-#include "print.h"
-#include "iostream.h"
-#include "random.h"
-#include "brieflz.h"
-#include "nan.h"
-
-#if !defined(ARGBEGIN)
-/* straight from 9front */
-static char *argv0 = nil;
-#define	ARGBEGIN \
-	for((argv0 ? 0 : (argv0=*argv)), argv++, argc--; argv[0] && argv[0][0]=='-' && argv[0][1]; argc--, argv++){ \
-		const char *_args, *_argt; \
-		Rune _argc; \
-		_args = &argv[0][1]; \
-		if(_args[0]=='-' && _args[1]==0){ \
-			argc--; \
-			argv++; \
-			break; \
-		}\
-		_argc = 0; \
-		while(*_args && (_args += chartorune(&_argc, _args))) \
-			switch(_argc)
-#define	ARGEND USED(_argt); USED(_argc); USED(_args);}USED(argv); USED(argc);
-#define	ARGF() (_argt=_args, _args="", (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
-#define	ARGC() _argc
-#define	EARGF(x) (_argt=_args, _args="", (*_argt? _argt: argv[1]? (argc--, *++argv): (x, (char*)0)))
-#endif
-
-static value_t
-argv_list(int argc, char **argv)
-{
-	int i;
-	value_t lst = FL_nil, temp;
-	fl_gc_handle(&lst);
-	fl_gc_handle(&temp);
-	for(i = argc-1; i >= 0; i--){
-		temp = cvalue_static_cstring(argv[i]);
-		lst = fl_cons(temp, lst);
-	}
-	lst = fl_cons(cvalue_static_cstring(argv0), lst);
-	fl_free_gc_handles(2);
-	return lst;
-}
-
-static void
-sizesuffix(size_t *sz, char su)
-{
-	switch(tolower(su)){
-	case 'k':
-		*sz *= 1024;
-		break;
-	case 'm':
-		*sz *= 1024*1024;
-		break;
-	case 0:
-		break;
-	default:
-		ios_printf(ios_stderr, "invalid size suffix '%c'\n", su);
-		exit(1);
-	}
-}
-
-_Noreturn static void
-usage(void)
-{
-	ios_printf(ios_stderr, "%s: [-H heapsize] [-S stacksize] ...\n", argv0);
-	exit(0);
-}
-
-
-_Noreturn void
-flmain(const uint8_t *boot, int bootsz, int argc, char **argv)
-{
-	size_t heapsize = HEAP_SIZE0, stacksize = STACK_SIZE0;
-	char *e;
-
-	nan_init();
-	randomize();
-	ios_init_stdstreams();
-	mpsetminbits(sizeof(fixnum_t)*8);
-
-	ARGBEGIN{
-	case 'H':
-		heapsize = strtoull(EARGF(usage()), &e, 0);
-		sizesuffix(&heapsize, *e);
-		break;
-	case 'S':
-		stacksize = strtoull(EARGF(usage()), &e, 0);
-		sizesuffix(&stacksize, *e);
-		break;
-	case 'h':
-		usage();
-	default:
-		break;
-	}ARGEND
-
-	if(fl_init(heapsize, stacksize) != 0){
-		ios_puts(ios_stderr, "init failed\n");
-		exit(1);
-	}
-
-	value_t f = cvalue(FL(iostreamtype), (int)sizeof(ios_t));
-	fl_gc_handle(&f);
-	value_t args = argv_list(argc, argv);
-	fl_gc_handle(&args);
-	ios_t *s = value2c(ios_t*, f);
-	uint8_t *unpacked = nil;
-	if(boot[0] == 0){
-		uint32_t unpackedsz =
-			boot[1]<<0 |
-			boot[2]<<8 |
-			boot[3]<<16|
-			boot[4]<<24;
-		unpacked = MEM_ALLOC(unpackedsz);
-		unsigned long n = blz_depack_safe(boot+5, bootsz-5, unpacked, unpackedsz);
-		if(n == BLZ_ERROR){
-			ios_puts(ios_stderr, "failed to unpack boot image\n");
-			fl_exit(1);
-		}
-		boot = unpacked;
-		bootsz = n;
-	}
-	ios_static_buffer(s, boot, bootsz);
-
-	int r = 1;
-	FL_TRY_EXTERN{
-		if(fl_load_system_image(f) == 0){
-			MEM_FREE(unpacked);
-			s = value2c(ios_t*, f);
-			fl_free_gc_handles(2);
-			ios_close(s);
-			fl_applyn(1, symbol_value(symbol("__start", false)), args);
-			r = 0;
-		}
-	}
-	FL_CATCH_EXTERN_NO_RESTORE{
-		ios_puts(ios_stderr, "fatal error:\n");
-		fl_print(ios_stderr, FL(lasterror));
-		ios_putc(ios_stderr, '\n');
-		break;
-	}
-	fl_exit(r);
-}
--- a/src/hashing.c
+++ b/src/hashing.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "hashing.h"
 #include "spooky.h"
 
--- a/src/hashing.h
+++ b/src/hashing.h
@@ -1,5 +1,5 @@
 #pragma once
 
-value_t inthash(value_t a) fl_constfn;
-uint32_t int64to32hash(uint64_t key) fl_constfn;
+value_t inthash(value_t a) sl_constfn;
+uint32_t int64to32hash(uint64_t key) sl_constfn;
 uint64_t memhash(const char* buf, size_t n);
--- a/src/htable.c
+++ b/src/htable.c
@@ -2,11 +2,11 @@
   functions common to all hash table instantiations
 */
 
-#include "flisp.h"
+#include "sl.h"
 #include "htable.h"
 #include "hashing.h"
 
-static fl_constfn value_t
+static sl_constfn value_t
 nextipow2(value_t i)
 {
 	if(i == 0)
--- a/src/htable.h
+++ b/src/htable.h
@@ -9,7 +9,7 @@
 	// FIXME(sigrid): in a multithreaded environment this isn't enough
 	int i;
 	void *_space[HT_N_INLINE];
-}fl_aligned(8) htable_t;
+}sl_aligned(8) htable_t;
 
 // define this to be an invalid key/value
 #define HT_NOTFOUND ((void*)1)
--- a/src/htableh.inc
+++ b/src/htableh.inc
@@ -3,9 +3,9 @@
 #include "htable.h"
 
 #define HTPROT(HTNAME) \
-void *HTNAME##_get(htable_t *h, void *key) fl_purefn; \
+void *HTNAME##_get(htable_t *h, void *key) sl_purefn; \
 void HTNAME##_put(htable_t *h, void *key, void *val); \
-bool HTNAME##_has(htable_t *h, void *key) fl_purefn; \
+bool HTNAME##_has(htable_t *h, void *key) sl_purefn; \
 bool HTNAME##_remove(htable_t *h, void *key); \
 void **HTNAME##_bp(htable_t *h, void *key);
 
--- a/src/ios.c
+++ b/src/ios.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "timefuncs.h"
 
 #define MOST_OF(x) ((x) - ((x)>>4))
--- a/src/ios.h
+++ b/src/ios.h
@@ -54,7 +54,7 @@
 	uint8_t local[IOS_INLSIZE];
 }ios_t;
 
-void *llt_memrchr(const void *s, int c, size_t n) fl_purefn;
+void *llt_memrchr(const void *s, int c, size_t n) sl_purefn;
 
 /* low-level interface functions */
 size_t ios_read(ios_t *s, void *dest, size_t n);
@@ -64,7 +64,7 @@
 off_t ios_skip(ios_t *s, off_t offs);  // relative seek
 off_t ios_pos(ios_t *s);  // get current position
 int ios_trunc(ios_t *s, off_t size);
-bool ios_eof(ios_t *s) fl_purefn;
+bool ios_eof(ios_t *s) sl_purefn;
 int ios_flush(ios_t *s);
 void ios_close(ios_t *s);
 void ios_free(ios_t *s);
@@ -92,8 +92,8 @@
 
 /* high-level functions - output */
 int ios_pututf8(ios_t *s, Rune r);
-int ios_printf(ios_t *s, const char *format, ...) fl_printfmt(2, 3);
-int ios_vprintf(ios_t *s, const char *format, va_list args) fl_printfmt(2, 0);
+int ios_printf(ios_t *s, const char *format, ...) sl_printfmt(2, 3);
+int ios_vprintf(ios_t *s, const char *format, va_list args) sl_printfmt(2, 0);
 
 void hexdump(ios_t *dest, const uint8_t *buffer, size_t len, size_t startoffs);
 
--- a/src/iostream.c
+++ b/src/iostream.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "cvalues.h"
 #include "types.h"
 #include "print.h"
@@ -9,12 +9,12 @@
 print_iostream(value_t v, ios_t *f)
 {
 	ios_t *s = value2c(ios_t*, v);
-	fl_print_str(f, "#<io stream");
+	sl_print_str(f, "#<io stream");
 	if(*s->loc.filename){
-		fl_print_chr(f, ' ');
-		fl_print_str(f, s->loc.filename);
+		sl_print_chr(f, ' ');
+		sl_print_str(f, s->loc.filename);
 	}
-	fl_print_chr(f, '>');
+	sl_print_chr(f, '>');
 }
 
 static void
@@ -44,28 +44,28 @@
 static int
 isiostream(value_t v)
 {
-	return iscvalue(v) && cv_class(ptr(v)) == FL(iostreamtype);
+	return iscvalue(v) && cv_class(ptr(v)) == SL(iostreamtype);
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("iostream?", iostreamp)
 {
 	argcount(nargs, 1);
-	return isiostream(args[0]) ? FL_t : FL_nil;
+	return isiostream(args[0]) ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("eof-object?", eof_objectp)
 {
 	argcount(nargs, 1);
-	return args[0] == FL_eof ? FL_t : FL_nil;
+	return args[0] == SL_eof ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 ios_t *
 toiostream(value_t v)
 {
-	if(fl_unlikely(!isiostream(v)))
+	if(sl_unlikely(!isiostream(v)))
 		type_error("iostream", v);
 	return value2c(ios_t*, v);
 }
@@ -76,24 +76,24 @@
 		argcount(nargs, 1);
 	bool r = false, w = false, c = false, t = false, a = false;
 	for(int i = 1; i < nargs; i++){
-		if(args[i] == FL_rdsym)
+		if(args[i] == SL_rdsym)
 			r = 1;
-		else if(args[i] == FL_wrsym)
+		else if(args[i] == SL_wrsym)
 			w = 1;
-		else if(args[i] == FL_apsym)
+		else if(args[i] == SL_apsym)
 			a = w = 1;
-		else if(args[i] == FL_crsym)
+		else if(args[i] == SL_crsym)
 			c = w = 1;
-		else if(args[i] == FL_truncsym)
+		else if(args[i] == SL_truncsym)
 			t = w = 1;
 	}
 	if(!r && !w && !c && !t && !a)
 		r = true;  // default to reading
-	value_t f = cvalue(FL(iostreamtype), sizeof(ios_t));
+	value_t f = cvalue(SL(iostreamtype), sizeof(ios_t));
 	char *fname = tostring(args[0]);
 	ios_t *s = value2c(ios_t*, f);
 	if(ios_file(s, fname, r, w, c, t) == nil)
-		lerrorf(FL_IOError, "could not open \"%s\"", fname);
+		lerrorf(SL_IOError, "could not open \"%s\"", fname);
 	if(a)
 		ios_seek_end(s);
 	return f;
@@ -103,10 +103,10 @@
 {
 	argcount(nargs, 0);
 	USED(args);
-	value_t f = cvalue(FL(iostreamtype), sizeof(ios_t));
+	value_t f = cvalue(SL(iostreamtype), sizeof(ios_t));
 	ios_t *s = value2c(ios_t*, f);
 	if(ios_mem(s, 0) == nil)
-		lerrorf(FL_MemoryError, "could not allocate stream");
+		lerrorf(SL_MemoryError, "could not allocate stream");
 	return f;
 }
 
@@ -114,11 +114,11 @@
 {
 	if(nargs > 1)
 		argcount(nargs, 1);
-	value_t a = nargs == 0 ? symbol_value(FL_instrsym) : args[0];
-	fl_gc_handle(&a);
-	value_t v = fl_read_sexpr(a);
-	fl_free_gc_handles(1);
-	return ios_eof(toiostream(a)) ? FL_eof : v;
+	value_t a = nargs == 0 ? symbol_value(SL_instrsym) : args[0];
+	sl_gc_handle(&a);
+	value_t v = sl_read_sexpr(a);
+	sl_free_gc_handles(1);
+	return ios_eof(toiostream(a)) ? SL_eof : v;
 }
 
 BUILTIN("io-getc", io_getc)
@@ -128,10 +128,10 @@
 	Rune r;
 	int res;
 	if((res = ios_getutf8(s, &r)) == IOS_EOF)
-		//lerrorf(FL_IOError, "end of file reached");
-		return FL_eof;
+		//lerrorf(SL_IOError, "end of file reached");
+		return SL_eof;
 	if(res == 0)
-		lerrorf(FL_IOError, "invalid UTF-8 sequence");
+		lerrorf(SL_IOError, "invalid UTF-8 sequence");
 	return mk_rune(r);
 }
 
@@ -142,10 +142,10 @@
 	ios_t *s = toiostream(args[0]);
 	int r = ios_wait(s, nargs > 1 ? todouble(args[1]) : -1);
 	if(r >= 0)
-		return r ? FL_t : FL_nil;
+		return r ? SL_t : SL_nil;
 	if(r == IOS_EOF)
-		return FL_eof;
-	lerrorf(FL_IOError, "i/o error");
+		return SL_eof;
+	lerrorf(SL_IOError, "i/o error");
 }
 
 BUILTIN("io-putc", io_putc)
@@ -153,7 +153,7 @@
 	argcount(nargs, 2);
 	ios_t *s = toiostream(args[0]);
 	cprim_t *cp = ptr(args[1]);
-	if(!iscprim(args[1]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[1]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[1]);
 	Rune r = *(Rune*)cp_data(cp);
 	return fixnum(ios_pututf8(s, r));
@@ -166,7 +166,7 @@
 	off_t off = tooffset(args[1]);
 	off_t res = ios_skip(s, off);
 	if(res < 0)
-		return FL_nil;
+		return SL_nil;
 	return sizeof(res) == sizeof(int64_t) ? mk_int64(res) : mk_int32(res);
 }
 
@@ -173,7 +173,7 @@
 BUILTIN("io-flush", io_flush)
 {
 	argcount(nargs, 1);
-	return ios_flush(toiostream(args[0])) == 0 ? FL_t : FL_nil;
+	return ios_flush(toiostream(args[0])) == 0 ? SL_t : SL_nil;
 }
 
 BUILTIN("io-close", io_close)
@@ -180,7 +180,7 @@
 {
 	argcount(nargs, 1);
 	ios_close(toiostream(args[0]));
-	return FL_void;
+	return SL_void;
 }
 
 BUILTIN("io-truncate", io_truncate)
@@ -188,8 +188,8 @@
 	argcount(nargs, 2);
 	ios_t *s = toiostream(args[0]);
 	if(ios_trunc(s, tooffset(args[1])) < 0)
-		lerrorf(FL_IOError, "truncation failed");
-	return FL_void;
+		lerrorf(SL_IOError, "truncation failed");
+	return SL_void;
 }
 
 BUILTIN("io-discardbuffer", io_discardbuffer)
@@ -196,14 +196,14 @@
 {
 	argcount(nargs, 1);
 	ios_purge(toiostream(args[0]));
-	return FL_void;
+	return SL_void;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("io-eof?", io_eofp)
 {
 	argcount(nargs, 1);
-	return ios_eof(toiostream(args[0])) ? FL_t : FL_nil;
+	return ios_eof(toiostream(args[0])) ? SL_t : SL_nil;
 }
 
 BUILTIN("io-seek", io_seek)
@@ -213,8 +213,8 @@
 	size_t pos = tosize(args[1]);
 	off_t res = ios_seek(s, (off_t)pos);
 	if(res < 0)
-		return FL_nil;
-	return FL_t;
+		return SL_nil;
+	return SL_t;
 }
 
 BUILTIN("io-pos", io_pos)
@@ -223,7 +223,7 @@
 	ios_t *s = toiostream(args[0]);
 	off_t res = ios_pos(s);
 	if(res < 0)
-		return FL_nil;
+		return SL_nil;
 	return size_wrap((size_t)res);
 }
 
@@ -232,8 +232,8 @@
 	if(nargs < 1 || nargs > 2)
 		argcount(nargs, 1);
 	ios_t *s;
-	s = nargs == 2 ? toiostream(args[1]) : toiostream(symbol_value(FL_outstrsym));
-	fl_print(s, args[0]);
+	s = nargs == 2 ? toiostream(args[1]) : toiostream(symbol_value(SL_outstrsym));
+	sl_print(s, args[0]);
 	return args[0];
 }
 
@@ -243,7 +243,7 @@
 		argcount(nargs, 2);
 	ios_t *s = toiostream(args[0]);
 	size_t n;
-	fltype_t *ft;
+	sltype_t *ft;
 	if(nargs == 3){
 		// form (io.read s type count)
 		ft = get_array_type(args[1]);
@@ -251,7 +251,7 @@
 	}else{
 		ft = get_type(args[1]);
 		if(ft->eltype != nil && !iscons(cdr_(cdr_(args[1]))))
-			lerrorf(FL_ArgError, "incomplete type");
+			lerrorf(SL_ArgError, "incomplete type");
 		n = ft->size;
 	}
 	value_t cv = cvalue(ft, n);
@@ -258,8 +258,8 @@
 	uint8_t *data = cptr(cv);
 	size_t got = ios_read(s, data, n);
 	if(got < n)
-		//lerrorf(FL_IOError, "end of input reached");
-		return FL_eof;
+		//lerrorf(SL_IOError, "end of input reached");
+		return SL_eof;
 	return cv;
 }
 
@@ -282,9 +282,9 @@
 	ios_t *s = toiostream(args[0]);
 	value_t v = args[1];
 	cprim_t *cp = ptr(v);
-	if(iscprim(args[1]) && cp_class(cp) == FL(runetype)){
+	if(iscprim(args[1]) && cp_class(cp) == SL(runetype)){
 		if(nargs > 2)
-			lerrorf(FL_ArgError, "offset argument not supported for characters");
+			lerrorf(SL_ArgError, "offset argument not supported for characters");
 		Rune r = *(Rune*)cp_data(ptr(args[1]));
 		return fixnum(ios_pututf8(s, r));
 	}
@@ -305,8 +305,8 @@
 	size_t uldelim = tosize(arg);
 	if(uldelim > 0x7f){
 		// runes > 0x7f, or anything else > 0xff, are out of range
-		if((iscprim(arg) && cp_class(ptr(arg)) == FL(runetype)) || uldelim > 0xff)
-			lerrorf(FL_ArgError, "delimiter out of range");
+		if((iscprim(arg) && cp_class(ptr(arg)) == SL(runetype)) || uldelim > 0xff)
+			lerrorf(SL_ArgError, "delimiter out of range");
 	}
 	return (uint8_t)uldelim;
 }
@@ -333,7 +333,7 @@
 		((uint8_t*)cv->data)[n] = 0;
 	}
 	if(n == 0 && ios_eof(src))
-		return FL_eof;
+		return SL_eof;
 	return str;
 }
 
@@ -413,9 +413,9 @@
 	}else{
 		uint8_t *b = ios_takebuf(st, &n); n--;
 		if(n == 0)
-			return FL(the_empty_string);
+			return SL(the_empty_string);
 		b[n] = '\0';
-		str = cvalue_from_ref(FL(stringtype), b, n);
+		str = cvalue_from_ref(SL(stringtype), b, n);
 		cv_autorelease(ptr(str));
 	}
 	return str;
@@ -426,11 +426,11 @@
 	argcount(nargs, 1);
 	ios_t *src = toiostream(args[0]);
 	if(src->bm != bm_mem)
-		lerrorf(FL_ArgError, "requires memory stream");
+		lerrorf(SL_ArgError, "requires memory stream");
 	bool eof = ios_eof(src);
 	value_t v = stream_to_string(&args[0]);
-	if(eof && v == FL(the_empty_string))
-		v = FL_eof;
+	if(eof && v == SL(the_empty_string))
+		v = SL_eof;
 	return v;
 }
 
@@ -437,16 +437,16 @@
 void
 iostream_init(void)
 {
-	FL_iostreamsym = csymbol("iostream");
-	FL_rdsym = csymbol(":read");
-	FL_wrsym = csymbol(":write");
-	FL_apsym = csymbol(":append");
-	FL_crsym = csymbol(":create");
-	FL_truncsym = csymbol(":truncate");
-	FL_instrsym = csymbol("*input-stream*");
-	FL_outstrsym = csymbol("*output-stream*");
-	FL(iostreamtype) = define_opaque_type(FL_iostreamsym, sizeof(ios_t), &iostream_vtable, nil);
-	set(csymbol("*stdout*"), cvalue_from_ref(FL(iostreamtype), ios_stdout, sizeof(ios_t)));
-	set(csymbol("*stderr*"), cvalue_from_ref(FL(iostreamtype), ios_stderr, sizeof(ios_t)));
-	set(csymbol("*stdin*"), cvalue_from_ref(FL(iostreamtype), ios_stdin, sizeof(ios_t)));
+	SL_iostreamsym = csymbol("iostream");
+	SL_rdsym = csymbol(":read");
+	SL_wrsym = csymbol(":write");
+	SL_apsym = csymbol(":append");
+	SL_crsym = csymbol(":create");
+	SL_truncsym = csymbol(":truncate");
+	SL_instrsym = csymbol("*input-stream*");
+	SL_outstrsym = csymbol("*output-stream*");
+	SL(iostreamtype) = define_opaque_type(SL_iostreamsym, sizeof(ios_t), &iostream_vtable, nil);
+	set(csymbol("*stdout*"), cvalue_from_ref(SL(iostreamtype), ios_stdout, sizeof(ios_t)));
+	set(csymbol("*stderr*"), cvalue_from_ref(SL(iostreamtype), ios_stderr, sizeof(ios_t)));
+	set(csymbol("*stdin*"), cvalue_from_ref(SL(iostreamtype), ios_stdin, sizeof(ios_t)));
 }
--- a/src/macos/femtolispm68k.r
+++ /dev/null
@@ -1,22 +1,0 @@
-#include "Retro68APPL.r"
-
-resource 'SIZE' (-1) {
-	reserved,
-	ignoreSuspendResumeEvents,
-	reserved,
-	cannotBackground,
-	needsActivateOnFGSwitch,
-	backgroundAndForeground,
-	dontGetFrontClicks,
-	ignoreChildDiedEvents,
-	is32BitCompatible,
-	notHighLevelEventAware,
-	onlyLocalHLEvents,
-	notStationeryAware,
-	dontUseTextEditServices,
-	reserved,
-	reserved,
-	reserved,
-	4 * 1024 * 1024,
-	1 * 1024 * 1024
-};
--- a/src/macos/femtolispppc.r
+++ /dev/null
@@ -1,22 +1,0 @@
-#include "RetroPPCAPPL.r"
-
-resource 'SIZE' (-1) {
-	reserved,
-	ignoreSuspendResumeEvents,
-	reserved,
-	cannotBackground,
-	needsActivateOnFGSwitch,
-	backgroundAndForeground,
-	dontGetFrontClicks,
-	ignoreChildDiedEvents,
-	is32BitCompatible,
-	notHighLevelEventAware,
-	onlyLocalHLEvents,
-	notStationeryAware,
-	dontUseTextEditServices,
-	reserved,
-	reserved,
-	reserved,
-	16 * 1024 * 1024,
-	8 * 1024 * 1024
-};
--- /dev/null
+++ b/src/macos/m68k.r
@@ -1,0 +1,22 @@
+#include "Retro68APPL.r"
+
+resource 'SIZE' (-1) {
+	reserved,
+	ignoreSuspendResumeEvents,
+	reserved,
+	cannotBackground,
+	needsActivateOnFGSwitch,
+	backgroundAndForeground,
+	dontGetFrontClicks,
+	ignoreChildDiedEvents,
+	is32BitCompatible,
+	notHighLevelEventAware,
+	onlyLocalHLEvents,
+	notStationeryAware,
+	dontUseTextEditServices,
+	reserved,
+	reserved,
+	reserved,
+	4 * 1024 * 1024,
+	1 * 1024 * 1024
+};
--- a/src/macos/platform.h
+++ b/src/macos/platform.h
@@ -34,8 +34,8 @@
 #define USED(x) ((void)(x))
 #define nelem(x) (int)(sizeof(x)/sizeof((x)[0]))
 
-#define fl_setjmp(e) setjmp((e))
-#define fl_longjmp(e, v) longjmp((e), (v))
+#define sl_setjmp(e) setjmp((e))
+#define sl_longjmp(e, v) longjmp((e), (v))
 
 #define PATHSEP '/'
 #define PATHSEPSTRING "/"
--- /dev/null
+++ b/src/macos/ppc.r
@@ -1,0 +1,22 @@
+#include "RetroPPCAPPL.r"
+
+resource 'SIZE' (-1) {
+	reserved,
+	ignoreSuspendResumeEvents,
+	reserved,
+	cannotBackground,
+	needsActivateOnFGSwitch,
+	backgroundAndForeground,
+	dontGetFrontClicks,
+	ignoreChildDiedEvents,
+	is32BitCompatible,
+	notHighLevelEventAware,
+	onlyLocalHLEvents,
+	notStationeryAware,
+	dontUseTextEditServices,
+	reserved,
+	reserved,
+	reserved,
+	16 * 1024 * 1024,
+	8 * 1024 * 1024
+};
--- a/src/macos/sys.c
+++ b/src/macos/sys.c
@@ -1,5 +1,5 @@
 #include <OSUtils.h>
-#include "flisp.h"
+#include "sl.h"
 #include "timefuncs.h"
 
 double
@@ -74,7 +74,7 @@
 char os_version[10];
 
 static const uint8_t boot[] = {
-#include "flisp.boot.h"
+#include "sl.boot.h"
 };
 
 int
@@ -90,5 +90,5 @@
 		(r.systemVersion>>4)&0xf,
 		(r.systemVersion>>0)&0xf
 	);
-	flmain(boot, sizeof(boot), argc, argv);
+	slmain(boot, sizeof(boot), argc, argv);
 }
--- a/src/math.c
+++ b/src/math.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "cvalues.h"
 
 #define BUILTIN_(lname, cname) \
--- a/src/mem.c
+++ b/src/mem.c
@@ -4,8 +4,8 @@
 #include "platform.h"
 
 #define HAVE_MORECORE 1
-#define MORECORE fl_sbrk
-static void *fl_sbrk(intptr_t increment);
+#define MORECORE sl_sbrk
+static void *sl_sbrk(intptr_t increment);
 #define MORECORE_CONTIGUOUS 0
 #define MORECORE_CANNOT_TRIM 1
 #define NO_SEGMENT_TRAVERSAL 1
@@ -26,31 +26,31 @@
 #include "dlmalloc.inc"
 
 void *
-fl_malloc(size_t size)
+sl_malloc(size_t size)
 {
 	return dlmalloc(size);
 }
 
 void
-fl_free(void *p)
+sl_free(void *p)
 {
 	dlfree(p);
 }
 
 void *
-fl_calloc(size_t n, size_t size)
+sl_calloc(size_t n, size_t size)
 {
 	return dlcalloc(n, size);
 }
 
 void *
-fl_realloc(void *p, size_t size)
+sl_realloc(void *p, size_t size)
 {
 	return dlrealloc(p, size);
 }
 
 char *
-fl_strdup(const char *s)
+sl_strdup(const char *s)
 {
 	size_t sz = strlen(s)+1;
 	char *p = dlmalloc(sz);
@@ -60,7 +60,7 @@
 
 #if defined(__macos__)
 static void *
-fl_sbrk(intptr_t increment)
+sl_sbrk(intptr_t increment)
 {
 	static char *e = nil;
 	if(increment == 0)
@@ -74,7 +74,7 @@
 }
 #else
 static void *
-fl_sbrk(intptr_t increment)
+sl_sbrk(intptr_t increment)
 {
 	return sbrk(increment);
 }
--- a/src/mem.h
+++ b/src/mem.h
@@ -11,18 +11,18 @@
 #endif
 
 #if defined(USE_DLMALLOC)
-void *fl_malloc(size_t);
-void fl_free(void *);
-void *fl_calloc(size_t, size_t);
-void *fl_realloc(void *, size_t);
-char *fl_strdup(const char *s);
-#define MEM_CALLOC(n, sz) fl_calloc((size_t)(n), (size_t)(sz))
-#define MEM_ALLOC(n) fl_malloc((size_t)(n))
-#define MEM_REALLOC(p, n) fl_realloc((p), (size_t)(n))
-#define MEM_FREE(x) fl_free(x)
-#define MEM_STRDUP(s) fl_strdup(s)
-#define fl_segalloc(sz) MEM_ALLOC((size_t)sz)
-#define fl_segfree(s, sz) MEM_FREE(s)
+void *sl_malloc(size_t);
+void sl_free(void *);
+void *sl_calloc(size_t, size_t);
+void *sl_realloc(void *, size_t);
+char *sl_strdup(const char *s);
+#define MEM_CALLOC(n, sz) sl_calloc((size_t)(n), (size_t)(sz))
+#define MEM_ALLOC(n) sl_malloc((size_t)(n))
+#define MEM_REALLOC(p, n) sl_realloc((p), (size_t)(n))
+#define MEM_FREE(x) sl_free(x)
+#define MEM_STRDUP(s) sl_strdup(s)
+#define sl_segalloc(sz) MEM_ALLOC((size_t)sz)
+#define sl_segfree(s, sz) MEM_FREE(s)
 #else
 #define MEM_CALLOC(n, sz) calloc((size_t)(n), (size_t)(sz))
 #define MEM_ALLOC(n) malloc((size_t)(n))
@@ -29,6 +29,6 @@
 #define MEM_REALLOC(p, n) realloc((p), (size_t)(n))
 #define MEM_FREE(x) free(x)
 #define MEM_STRDUP(s) strdup(s)
-void *fl_segalloc(size_t sz);
-void fl_segfree(void *s, size_t sz);
+void *sl_segalloc(size_t sz);
+void sl_segfree(void *s, size_t sz);
 #endif
--- a/src/opcodes.c
+++ b/src/opcodes.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 
 const Builtin builtins[N_OPCODES] = {
 	[OP_NANP] = {"nan?", 1},
--- a/src/operators.c
+++ b/src/operators.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "operators.h"
 
 mpint *
@@ -20,7 +20,7 @@
 	return mpzero;
 }
 
-fl_purefn
+sl_purefn
 double
 conv_to_double(void *data, numerictype_t tag)
 {
@@ -47,7 +47,7 @@
 
 // FIXME sign with mpint
 #define CONV_TO_INTTYPE(name, ctype) \
-fl_purefn \
+sl_purefn \
 ctype \
 conv_to_##name(void *data, numerictype_t tag) \
 { \
@@ -74,7 +74,7 @@
 // this is needed to work around an UB casting negative
 // floats and doubles to uint64. you need to cast to int64
 // first.
-fl_purefn
+sl_purefn
 uint64_t
 conv_to_uint64(void *data, numerictype_t tag)
 {
@@ -103,7 +103,7 @@
 	return 0;
 }
 
-fl_purefn
+sl_purefn
 bool
 cmp_same_lt(void *a, void *b, numerictype_t tag)
 {
@@ -123,7 +123,7 @@
 	return false;
 }
 
-fl_purefn
+sl_purefn
 bool
 cmp_same_eq(void *a, void *b, numerictype_t tag)
 {
--- a/src/plan9/clz.c
+++ b/src/plan9/clz.c
@@ -1,7 +1,7 @@
 #include "platform.h"
 
 int
-fl_clz(uint32_t x)
+sl_clz(uint32_t x)
 {
 	uint32_t r;
 	if(x == 0)
--- a/src/plan9/clz_amd64.s
+++ b/src/plan9/clz_amd64.s
@@ -1,4 +1,4 @@
-TEXT fl_clz(SB),1,$0
+TEXT sl_clz(SB),1,$0
 	BYTE $0x0F; BYTE $0xBD; BYTE $0xC5 /* BSRL RARG, AX */
 	XORL $31, AX
 	RET
--- a/src/plan9/clz_arm64.s
+++ b/src/plan9/clz_arm64.s
@@ -1,3 +1,3 @@
-TEXT fl_clz(SB),1,$0
+TEXT sl_clz(SB),1,$0
 	CLZW R0, R0
 	RETURN
--- a/src/plan9/platform.h
+++ b/src/plan9/platform.h
@@ -22,11 +22,11 @@
 
 #define __os_name__ "plan9"
 
-int fl_popcount(unsigned int w);
-int fl_clz(unsigned int x);
+int sl_popcount(unsigned int w);
+int sl_clz(unsigned int x);
 
-#define fl_setjmp(e) setjmp((e))
-#define fl_longjmp(e, v) longjmp((e), (v))
+#define sl_setjmp(e) setjmp((e))
+#define sl_longjmp(e, v) longjmp((e), (v))
 
 extern double D_PNAN, D_PINF;
 
--- a/src/plan9/popcount.c
+++ b/src/plan9/popcount.c
@@ -1,7 +1,7 @@
 #include "platform.h"
 
 int
-fl_popcount(unsigned int w)
+sl_popcount(unsigned int w)
 {
 	w -= (w >> 1) & 0x55555555U;
 	w = (w & 0x33333333U) + ((w >> 2) & 0x33333333U);
--- a/src/plan9/sys.c
+++ b/src/plan9/sys.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "timefuncs.h"
 #include <tos.h>
 
@@ -16,13 +16,13 @@
 }
 
 void *
-fl_segalloc(size_t sz)
+sl_segalloc(size_t sz)
 {
 	return segattach(SG_CEXEC, "memory", nil, sz);
 }
 
 void
-fl_segfree(void *s, size_t sz)
+sl_segfree(void *s, size_t sz)
 {
 	USED(sz);
 	segdetach(s);
@@ -105,5 +105,5 @@
 	tmfmtinstall();
 	D_PNAN = strtod("+NaN", nil);
 	D_PINF = strtod("+Inf", nil);
-	flmain(bootcode, bootlen, argc, argv);
+	slmain(bootcode, bootlen, argc, argv);
 }
--- a/src/posix/platform.h
+++ b/src/posix/platform.h
@@ -61,8 +61,8 @@
 #endif
 #endif
 
-#define fl_setjmp(e) sigsetjmp((e), 0)
-#define fl_longjmp(e, v) siglongjmp((e), (v))
+#define sl_setjmp(e) sigsetjmp((e), 0)
+#define sl_longjmp(e, v) siglongjmp((e), (v))
 
 #define nil NULL
 #define USED(x) ((void)(x))
--- a/src/posix/sys.c
+++ b/src/posix/sys.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "timefuncs.h"
 #include <sys/mman.h>
 
@@ -6,7 +6,7 @@
 #define PAGEALIGNED(x) (((x) + pagesize-1) & ~(pagesize-1))
 
 void *
-fl_segalloc(size_t sz)
+sl_segalloc(size_t sz)
 {
 	sz = PAGEALIGNED(sz);
 	void *s = mmap(nil, sz, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
@@ -16,7 +16,7 @@
 }
 
 void
-fl_segfree(void *s, size_t sz)
+sl_segfree(void *s, size_t sz)
 {
 	sz = PAGEALIGNED(sz);
 	if(munmap(s, sz) != 0)
@@ -91,7 +91,7 @@
 }
 
 static const uint8_t boot[] = {
-#include "flisp.boot.h"
+#include "sl.boot.h"
 };
 
 char *os_version;
@@ -106,5 +106,5 @@
 	long p = sysconf(_SC_PAGE_SIZE);
 	if(p > 0)
 		pagesize = p;
-	flmain(boot, sizeof(boot), argc, argv);
+	slmain(boot, sizeof(boot), argc, argv);
 }
--- a/src/print.c
+++ b/src/print.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "operators.h"
 #include "cvalues.h"
 #include "ieee754.h"
@@ -12,9 +12,9 @@
 {
 	ios_putc(f, c);
 	if(c == '\n')
-		FL(hpos) = 0;
+		SL(hpos) = 0;
 	else
-		FL(hpos)++;
+		SL(hpos)++;
 }
 
 static inline void
@@ -23,7 +23,7 @@
 	ios_write(f, s, n);
 	ssize_t w = u8_strwidth(s, n);
 	if(w > 0)
-		FL(hpos) += w;
+		SL(hpos) += w;
 }
 
 static inline void
@@ -36,12 +36,12 @@
 outindent(ios_t *f, int n)
 {
 	// move back to left margin if we get too indented
-	if(n > FL(scr_width)-12)
+	if(n > SL(scr_width)-12)
 		n = 2;
 	int n0 = n;
 	ios_putc(f, '\n');
-	FL(vpos)++;
-	FL(hpos) = n;
+	SL(vpos)++;
+	SL(hpos) = n;
 	while(n >= 8){
 		ios_putc(f, '\t');
 		n -= 8;
@@ -54,13 +54,13 @@
 }
 
 void
-fl_print_chr(ios_t *f, char c)
+sl_print_chr(ios_t *f, char c)
 {
 	outc(f, c);
 }
 
 void
-fl_print_str(ios_t *f, const char *s)
+sl_print_str(ios_t *f, const char *s)
 {
 	outs(f, s);
 }
@@ -71,9 +71,9 @@
 	value_t *bp;
 	while(iscons(v)){
 		if(ismarked(v)){
-			bp = (value_t*)ptrhash_bp(&FL(printconses), (void*)v);
+			bp = (value_t*)ptrhash_bp(&SL(printconses), (void*)v);
 			if(*bp == (value_t)HT_NOTFOUND)
-				*bp = fixnum(FL(printlabel)++);
+				*bp = fixnum(SL(printlabel)++);
 			return;
 		}
 		mark_cons(v);
@@ -83,9 +83,9 @@
 	if(!ismanaged(v) || issymbol(v))
 		return;
 	if(ismarked(v)){
-		bp = (value_t*)ptrhash_bp(&FL(printconses), (void*)v);
+		bp = (value_t*)ptrhash_bp(&SL(printconses), (void*)v);
 		if(*bp == (value_t)HT_NOTFOUND)
-			*bp = fixnum(FL(printlabel)++);
+			*bp = fixnum(SL(printlabel)++);
 		return;
 	}
 	if(isvector(v)){
@@ -107,7 +107,7 @@
 		// don't consider shared references to ""
 		if(!cv_isstr(cv) || cv_len(cv) != 0)
 			mark_cons(v);
-		fltype_t *t = cv_class(cv);
+		sltype_t *t = cv_class(cv);
 		if(t->vtable != nil && t->vtable->print_traverse != nil)
 			t->vtable->print_traverse(v);
 	}
@@ -122,7 +122,7 @@
 	if((name[0] == '\0') ||
 		(name[0] == '.' && name[1] == '\0') ||
 		(name[0] == '#') ||
-		fl_read_numtok(name, nil, 0))
+		sl_read_numtok(name, nil, 0))
 		escape = true;
 	i = 0;
 	while(name[i]){
@@ -173,11 +173,11 @@
 		const char *s = symbol_name(v);
 		return u8_strwidth(s, strlen(s)) < SMALL_STR_LEN;
 	}
-	if(fl_isstring(v))
+	if(sl_isstring(v))
 		return cv_len(ptr(v)) < SMALL_STR_LEN;
 	return (
 		isfixnum(v) || isbuiltin(v) || iscprim(v) ||
-		v == FL_t || v == FL_nil || v == FL_eof || v == FL_void
+		v == SL_t || v == SL_nil || v == SL_eof || v == SL_void
 	);
 }
 
@@ -186,11 +186,11 @@
 {
 	if(tinyp(v))
 		return true;
-	if(fl_isnumber(v))
+	if(sl_isnumber(v))
 		return true;
 	if(iscons(v)){
 		if(tinyp(car_(v)) &&
-		   (tinyp(cdr_(v)) || (iscons(cdr_(v)) && tinyp(car_(cdr_(v))) && cdr_(cdr_(v)) == FL_nil)))
+		   (tinyp(cdr_(v)) || (iscons(cdr_(v)) && tinyp(car_(cdr_(v))) && cdr_(cdr_(v)) == SL_nil)))
 			return true;
 		return false;
 	}
@@ -208,8 +208,8 @@
 specialindent(value_t head)
 {
 	// indent these forms 2 spaces, not lined up with the first argument
-	if(head == FL_lambda || head == FL_trycatch || head == FL_defsym ||
-		head == FL_defmacrosym || head == FL_forsym)
+	if(head == SL_lambda || head == SL_trycatch || head == SL_defsym ||
+		head == SL_defmacrosym || head == SL_forsym)
 		return 2;
 	return -1;
 }
@@ -222,7 +222,7 @@
 		const char *s = symbol_name(v);
 		return u8_strwidth(s, strlen(s));
 	}
-	if(iscprim(v) && ptr(v) != nil && cp_class(ptr(v)) == FL(runetype))
+	if(iscprim(v) && ptr(v) != nil && cp_class(ptr(v)) == SL(runetype))
 		return 4;
 	return -1;
 }
@@ -246,7 +246,7 @@
 indentafter3(value_t head, value_t v)
 {
 	// for certain X always indent (X a b c) after b
-	return head == FL_forsym && !allsmallp(cdr_(v));
+	return head == SL_forsym && !allsmallp(cdr_(v));
 }
 
 static int
@@ -253,7 +253,7 @@
 indentafter2(value_t head, value_t v)
 {
 	// for certain X always indent (X a b) after a
-	return (head == FL_defsym || head == FL_defmacrosym) && !allsmallp(cdr_(v));
+	return (head == SL_defsym || head == SL_defmacrosym) && !allsmallp(cdr_(v));
 }
 
 static bool
@@ -262,9 +262,9 @@
 	// indent before every subform of a special form, unless every
 	// subform is "small"
 	value_t c = car_(v);
-	if(c == FL_lambda || c == FL_setqsym)
+	if(c == SL_lambda || c == SL_setqsym)
 		return false;
-	//if(c == FL(IF)) // TODO: others
+	//if(c == SL(IF)) // TODO: others
 	//	return !allsmallp(cdr_(v));
 	return false;
 }
@@ -284,23 +284,23 @@
 {
 	value_t cd;
 	const char *op;
-	if(iscons(cdr_(v)) && cdr_(cdr_(v)) == FL_nil &&
-		!ptrhash_has(&FL(printconses), (void*)cdr_(v)) &&
-		((car_(v) == FL_quote     && (op = "'"))  ||
-		 (car_(v) == FL_backquote && (op = "`"))  ||
-		 (car_(v) == FL_comma     && (op = ","))  ||
-		 (car_(v) == FL_commaat   && (op = ",@")) ||
-		 (car_(v) == FL_commadot  && (op = ",.")))){
+	if(iscons(cdr_(v)) && cdr_(cdr_(v)) == SL_nil &&
+		!ptrhash_has(&SL(printconses), (void*)cdr_(v)) &&
+		((car_(v) == SL_quote     && (op = "'"))  ||
+		 (car_(v) == SL_backquote && (op = "`"))  ||
+		 (car_(v) == SL_comma     && (op = ","))  ||
+		 (car_(v) == SL_commaat   && (op = ",@")) ||
+		 (car_(v) == SL_commadot  && (op = ",.")))){
 		// special prefix syntax
 		unmark_cons(v);
 		unmark_cons(cdr_(v));
 		outs(f, op);
-		fl_print_child(f, car_(cdr_(v)));
+		sl_print_child(f, car_(cdr_(v)));
 		return;
 	}
-	int startpos = FL(hpos);
+	int startpos = SL(hpos);
 	outc(f, '(');
-	int newindent = FL(hpos);
+	int newindent = SL(hpos);
 	int lastv, n = 0, si, ind, est, nextsmall, thistiny;
 	bool always = false, blk = blockindent(v);
 	if(!blk)
@@ -311,24 +311,24 @@
 	int n_unindented = 1;
 	while(1){
 		cd = cdr_(v);
-		if(FL(print_length) >= 0 && n >= FL(print_length) && cd != FL_nil){
+		if(SL(print_length) >= 0 && n >= SL(print_length) && cd != SL_nil){
 			outsn(f, "...)", 4);
 			break;
 		}
-		lastv = FL(vpos);
+		lastv = SL(vpos);
 		unmark_cons(v);
-		fl_print_child(f, car_(v));
-		if(!iscons(cd) || ptrhash_has(&FL(printconses), (void*)cd)){
-			if(cd != FL_nil){
+		sl_print_child(f, car_(v));
+		if(!iscons(cd) || ptrhash_has(&SL(printconses), (void*)cd)){
+			if(cd != SL_nil){
 				outsn(f, " . ", 3);
-				fl_print_child(f, cd);
+				sl_print_child(f, cd);
 			}
 			outc(f, ')');
 			break;
 		}
 
-		if(!FL(print_pretty) ||
-			(head == FL_lambda && n == 0)){
+		if(!SL(print_pretty) ||
+			(head == SL_lambda && n == 0)){
 			// never break line before lambda-list
 			ind = 0;
 		}else{
@@ -335,14 +335,14 @@
 			est = lengthestimate(car_(cd));
 			nextsmall = smallp(car_(cd));
 			thistiny = tinyp(car_(v));
-			ind = ((FL(vpos) > lastv ||
-					(FL(hpos)>FL(scr_width)/2 && !nextsmall && !thistiny && n>0)) ||
+			ind = ((SL(vpos) > lastv ||
+					(SL(hpos)>SL(scr_width)/2 && !nextsmall && !thistiny && n>0)) ||
 
-				   (FL(hpos) > FL(scr_width)-4) ||
+				   (SL(hpos) > SL(scr_width)-4) ||
 
-				   (est != -1 && FL(hpos)+est > FL(scr_width)-2) ||
+				   (est != -1 && SL(hpos)+est > SL(scr_width)-2) ||
 
-				   (head == FL_lambda && !nextsmall) ||
+				   (head == SL_lambda && !nextsmall) ||
 
 				   (n > 0 && always) ||
 
@@ -366,7 +366,7 @@
 				if(si != -1)
 					newindent = startpos + si;
 				else if(!blk)
-					newindent = FL(hpos);
+					newindent = SL(hpos);
 			}
 		}
 		n++;
@@ -380,12 +380,12 @@
 print_circle_prefix(ios_t *f, value_t v)
 {
 	value_t label;
-	if((label = (value_t)ptrhash_get(&FL(printconses), (void*)v)) != (value_t)HT_NOTFOUND){
+	if((label = (value_t)ptrhash_get(&SL(printconses), (void*)v)) != (value_t)HT_NOTFOUND){
 		if(!ismarked(v)){
-			FL(hpos) += ios_printf(f, "#%"PRIdPTR"#", (intptr_t)numval(label));
+			SL(hpos) += ios_printf(f, "#%"PRIdPTR"#", (intptr_t)numval(label));
 			return true;
 		}
-		FL(hpos) += ios_printf(f, "#%"PRIdPTR"=", (intptr_t)numval(label));
+		SL(hpos) += ios_printf(f, "#%"PRIdPTR"=", (intptr_t)numval(label));
 	}
 	if(ismanaged(v))
 		unmark_cons(v);
@@ -393,22 +393,22 @@
 }
 
 void
-fl_print_child(ios_t *f, value_t v)
+sl_print_child(ios_t *f, value_t v)
 {
 	const char *name;
-	if(FL(print_level) >= 0 && FL(p_level) >= FL(print_level) && (iscons(v) || isvector(v) || isfunction(v))){
+	if(SL(print_level) >= 0 && SL(p_level) >= SL(print_level) && (iscons(v) || isvector(v) || isfunction(v))){
 		outc(f, '#');
 		return;
 	}
-	FL(p_level)++;
+	SL(p_level)++;
 
 	switch(tag(v)){
 	case TAG_NUM: case TAG_NUM1:
-		FL(hpos) += ios_printf(f, "%"PRIdFIXNUM, numval(v));
+		SL(hpos) += ios_printf(f, "%"PRIdFIXNUM, numval(v));
 		break;
 	case TAG_SYM:
 		name = symbol_name(v);
-		if(FL(print_princ))
+		if(SL(print_princ))
 			outs(f, name);
 		else if(ismanaged(v)){
 			outsn(f, "#:", 2);
@@ -417,21 +417,21 @@
 			print_symbol_name(f, name);
 		break;
 	case TAG_FUNCTION:
-		if(v == FL_t)
+		if(v == SL_t)
 			outc(f, 'T');
-		else if(v == FL_nil)
+		else if(v == SL_nil)
 			outsn(f, "NIL", 3);
-		else if(v == FL_eof)
+		else if(v == SL_eof)
 			outsn(f, "#<eof>", 6);
-		else if(v == FL_void){
+		else if(v == SL_void){
 			outsn(f, "#<void>", 7);
 		}else if(isbuiltin(v)){
-			if(!FL(print_princ))
+			if(!SL(print_princ))
 				outsn(f, "#.", 2);
 			outs(f, builtins[uintval(v)].name);
 		}else{
 			assert(isfunction(v));
-			if(!FL(print_princ)){
+			if(!SL(print_princ)){
 				if(print_circle_prefix(f, v))
 					break;
 				function_t *fn = ptr(v);
@@ -440,18 +440,18 @@
 				size_t i, sz = cvalue_len(fn->bcode);
 				for(i = 0; i < sz; i++)
 					data[i] += 48;
-				fl_print_child(f, fn->bcode);
+				sl_print_child(f, fn->bcode);
 				for(i = 0; i < sz; i++)
 					data[i] -= 48;
 				outc(f, ' ');
-				fl_print_child(f, fn->vals);
-				if(fn->env != FL_nil){
+				sl_print_child(f, fn->vals);
+				if(fn->env != SL_nil){
 					outc(f, ' ');
-					fl_print_child(f, fn->env);
+					sl_print_child(f, fn->env);
 				}
-				if(fn->name != FL_lambda){
+				if(fn->name != SL_lambda){
 					outc(f, ' ');
-					fl_print_child(f, fn->name);
+					sl_print_child(f, fn->name);
 				}
 				outc(f, ')');
 			}else{
@@ -468,26 +468,26 @@
 	case TAG_CVALUE:
 	case TAG_VECTOR:
 	case TAG_CONS:
-		if(!FL(print_princ) && print_circle_prefix(f, v))
+		if(!SL(print_princ) && print_circle_prefix(f, v))
 			break;
 		if(isvector(v)){
 			outs(f, "#(");
-			int newindent = FL(hpos), est;
+			int newindent = SL(hpos), est;
 			int i, sz = vector_size(v);
 			for(i = 0; i < sz; i++){
-				if(FL(print_length) >= 0 && i >= FL(print_length) && i < sz-1){
+				if(SL(print_length) >= 0 && i >= SL(print_length) && i < sz-1){
 					outsn(f, "...", 3);
 					break;
 				}
-				fl_print_child(f, vector_elt(v, i));
+				sl_print_child(f, vector_elt(v, i));
 				if(i < sz-1){
-					if(!FL(print_pretty))
+					if(!SL(print_pretty))
 						outc(f, ' ');
 					else{
 						est = lengthestimate(vector_elt(v, i+1));
-						if(FL(hpos) > FL(scr_width)-4 ||
-						   (est != -1 && (FL(hpos)+est > FL(scr_width)-2)) ||
-						   (FL(hpos) > FL(scr_width)/2 && !smallp(vector_elt(v, i+1)) && !tinyp(vector_elt(v, i))))
+						if(SL(hpos) > SL(scr_width)-4 ||
+						   (est != -1 && (SL(hpos)+est > SL(scr_width)-2)) ||
+						   (SL(hpos) > SL(scr_width)/2 && !smallp(vector_elt(v, i+1)) && !tinyp(vector_elt(v, i))))
 							newindent = outindent(f, newindent);
 						else
 							outc(f, ' ');
@@ -503,7 +503,7 @@
 			print_cons(f, v);
 		break;
 	}
-	FL(p_level)--;
+	SL(p_level)--;
 }
 
 static void
@@ -641,20 +641,20 @@
 static void
 cvalue_printdata(ios_t *f, void *data, size_t len, value_t type, int weak)
 {
-	if(type == FL_bytesym){
+	if(type == SL_bytesym){
 		uint8_t ch = *(uint8_t*)data;
-		if(FL(print_princ))
+		if(SL(print_princ))
 			outc(f, ch);
 		else if(weak)
-			FL(hpos) += ios_printf(f, "0x%hhx", ch);
+			SL(hpos) += ios_printf(f, "0x%hhx", ch);
 		else
-			FL(hpos) += ios_printf(f, "#byte(0x%hhx)", ch);
-	}else if(type == FL_runesym){
+			SL(hpos) += ios_printf(f, "#byte(0x%hhx)", ch);
+	}else if(type == SL_runesym){
 		Rune r = *(Rune*)data;
 		char seq[UTFmax+1];
 		int nb = runetochar(seq, &r);
 		seq[nb] = '\0';
-		if(FL(print_princ)){
+		if(SL(print_princ)){
 			outsn(f, seq, nb);
 		}else{
 			outsn(f, "#\\", 2);
@@ -671,18 +671,18 @@
 			case ' ':  outsn(f, "space", 5); break;
 			case 0x7f: outsn(f, "delete", 6); break;
 			default:
-				if(fl_iswprint(r))
+				if(sl_iswprint(r))
 					outs(f, seq);
 				else
-					FL(hpos) += ios_printf(f, "x%04"PRIx32, r);
+					SL(hpos) += ios_printf(f, "x%04"PRIx32, r);
 				break;
 			}
 		}
-	}else if(type == FL_floatsym || type == FL_doublesym){
+	}else if(type == SL_floatsym || type == SL_doublesym){
 		char buf[64];
 		double d;
 		int ndec;
-		if(type == FL_floatsym){
+		if(type == SL_floatsym){
 			d = (double)*(float*)data;
 			ndec = 8;
 		}else{
@@ -697,8 +697,8 @@
 				rep = signbit(d) ? "-nan.0" : "+nan.0";
 			else
 				rep = signbit(d) ? "-wtf.0" : "+wtf.0";
-			if(type == FL_floatsym && !FL(print_princ) && !weak)
-				FL(hpos) += ios_printf(f, "#%s(%s)", symbol_name(type), rep);
+			if(type == SL_floatsym && !SL(print_princ) && !weak)
+				SL(hpos) += ios_printf(f, "#%s(%s)", symbol_name(type), rep);
 			else
 				outs(f, rep);
 		}else if(d == 0){
@@ -706,7 +706,7 @@
 				outsn(f, "-0.0", 4);
 			else
 				outsn(f, "0.0", 3);
-			if(type == FL_floatsym && !FL(print_princ) && !weak)
+			if(type == SL_floatsym && !SL(print_princ) && !weak)
 				outc(f, 'f');
 		}else{
 			snprint_real(buf, sizeof(buf), d, 0, ndec, 3, 10);
@@ -714,19 +714,19 @@
 			outs(f, buf);
 			if(!hasdec)
 				outsn(f, ".0", 2);
-			if(type == FL_floatsym && !FL(print_princ) && !weak)
+			if(type == SL_floatsym && !SL(print_princ) && !weak)
 				outc(f, 'f');
 		}
-	}else if(type == FL_uint64sym){
+	}else if(type == SL_uint64sym){
 		uint64_t ui64 = *(uint64_t*)data;
-		if(weak || FL(print_princ))
-			FL(hpos) += ios_printf(f, "%"PRIu64, ui64);
+		if(weak || SL(print_princ))
+			SL(hpos) += ios_printf(f, "%"PRIu64, ui64);
 		else
-			FL(hpos) += ios_printf(f, "#%s(%"PRIu64")", symbol_name(type), ui64);
-	}else if(type == FL_bignumsym){
+			SL(hpos) += ios_printf(f, "#%s(%"PRIu64")", symbol_name(type), ui64);
+	}else if(type == SL_bignumsym){
 		mpint *i = *(mpint**)data;
 		char *s = mptoa(i, 10, nil, 0);
-		FL(hpos) += ios_printf(f, "%s", s);
+		SL(hpos) += ios_printf(f, "%s", s);
 		MEM_FREE(s);
 	}else if(issymbol(type)){
 		// handle other integer prims. we know it's smaller than uint64
@@ -734,15 +734,15 @@
 		numerictype_t nt = sym_to_numtype(type);
 		if(valid_numtype(nt)){
 			int64_t i64 = conv_to_int64(data, nt);
-			if(weak || FL(print_princ))
-				FL(hpos) += ios_printf(f, "%"PRId64, i64);
+			if(weak || SL(print_princ))
+				SL(hpos) += ios_printf(f, "%"PRId64, i64);
 			else
-				FL(hpos) += ios_printf(f, "#%s(%"PRId64")", symbol_name(type), i64);
+				SL(hpos) += ios_printf(f, "#%s(%"PRId64")", symbol_name(type), i64);
 		}else{
-			FL(hpos) += ios_printf(f, "#<%s>", symbol_name(type));
+			SL(hpos) += ios_printf(f, "#<%s>", symbol_name(type));
 		}
 	}else if(iscons(type)){
-		if(car_(type) == FL_arraysym){
+		if(car_(type) == SL_arraysym){
 			size_t i;
 			value_t eltype = car(cdr_(type));
 			size_t cnt, elsize;
@@ -754,15 +754,15 @@
 				elsize = ctype_sizeof(eltype);
 				cnt = elsize ? len/elsize : 0;
 			}
-			if(eltype == FL_bytesym){
-				if(FL(print_princ)){
+			if(eltype == SL_bytesym){
+				if(SL(print_princ)){
 					ios_write(f, data, len);
 					/*
 					char *nl = llt_memrchr(data, '\n', len);
 					if(nl)
-						FL(hpos) = u8_strwidth(nl+1);
+						SL(hpos) = u8_strwidth(nl+1);
 					else
-						FL(hpos) += u8_strwidth(data);
+						SL(hpos) += u8_strwidth(data);
 					*/
 				}else{
 					outc(f, '"');
@@ -770,28 +770,28 @@
 					outc(f, '"');
 				}
 				return;
-			}else if(eltype == FL_runesym){
+			}else if(eltype == SL_runesym){
 				char buf[UTFmax+1];
-				if(!FL(print_princ))
+				if(!SL(print_princ))
 					outc(f, '"');
 				for(i = 0; i < cnt; i++, data = (char*)data + elsize){
 					int n = runetochar(buf, (Rune*)data);
 					buf[n] = 0;
-					if(FL(print_princ))
+					if(SL(print_princ))
 						ios_write(f, buf, n);
 					else
 						print_string(f, buf, n);
 				}
-				if(!FL(print_princ))
+				if(!SL(print_princ))
 					outc(f, '"');
 				return;
 			}
 			if(!weak){
-				if(eltype == FL_uint8sym){
+				if(eltype == SL_uint8sym){
 					outsn(f, "#vu8(", 5);
 				}else{
 					outsn(f, "#array(", 7);
-					fl_print_child(f, eltype);
+					sl_print_child(f, eltype);
 					if(cnt > 0)
 						outc(f, ' ');
 				}
@@ -816,10 +816,10 @@
 	void *data = cptr(v);
 	value_t label;
 
-	if(cv_class(cv) == FL(builtintype)){
-		label = (value_t)ptrhash_get(&FL(reverse_dlsym_lookup_table), cv);
+	if(cv_class(cv) == SL(builtintype)){
+		label = (value_t)ptrhash_get(&SL(reverse_dlsym_lookup_table), cv);
 		assert(label != (value_t)HT_NOTFOUND);
-		if(FL(print_princ)){
+		if(SL(print_princ)){
 			outs(f, symbol_name(label));
 		}else{
 			outsn(f, "#fn(", 4);
@@ -838,36 +838,36 @@
 static void
 set_print_width(void)
 {
-	value_t pw = symbol_value(FL_printwidthsym);
+	value_t pw = symbol_value(SL_printwidthsym);
 	if(!isfixnum(pw))
 		return;
-	FL(scr_width) = numval(pw);
+	SL(scr_width) = numval(pw);
 }
 
 void
-fl_print(ios_t *f, value_t v)
+sl_print(ios_t *f, value_t v)
 {
-	FL(print_pretty) = symbol_value(FL_printprettysym) != FL_nil;
-	if(FL(print_pretty))
+	SL(print_pretty) = symbol_value(SL_printprettysym) != SL_nil;
+	if(SL(print_pretty))
 		set_print_width();
-	FL(print_princ) = symbol_value(FL_printreadablysym) == FL_nil;
-	value_t pl = symbol_value(FL_printlengthsym);
-	FL(print_length) = isfixnum(pl) ? numval(pl) : -1;
-	pl = symbol_value(FL_printlevelsym);
-	FL(print_level) = isfixnum(pl) ? numval(pl) : -1;
-	FL(p_level) = 0;
+	SL(print_princ) = symbol_value(SL_printreadablysym) == SL_nil;
+	value_t pl = symbol_value(SL_printlengthsym);
+	SL(print_length) = isfixnum(pl) ? numval(pl) : -1;
+	pl = symbol_value(SL_printlevelsym);
+	SL(print_level) = isfixnum(pl) ? numval(pl) : -1;
+	SL(p_level) = 0;
 
-	FL(printlabel) = 0;
-	if(!FL(print_princ))
+	SL(printlabel) = 0;
+	if(!SL(print_princ))
 		print_traverse(v);
-	FL(hpos) = FL(vpos) = 0;
+	SL(hpos) = SL(vpos) = 0;
 
-	fl_print_child(f, v);
+	sl_print_child(f, v);
 
-	if(FL(print_level) >= 0 || FL(print_length) >= 0)
-		memset(FL(consflags), 0, 4*bitvector_nwords(FL(heapsize)/sizeof(cons_t)));
+	if(SL(print_level) >= 0 || SL(print_length) >= 0)
+		memset(SL(consflags), 0, 4*bitvector_nwords(SL(heapsize)/sizeof(cons_t)));
 
 	if((iscons(v) || isvector(v) || isfunction(v) || iscvalue(v)) &&
-		!fl_isstring(v) && v != FL_t && v != FL_nil && v != FL_void)
-		htable_reset(&FL(printconses), 32);
+		!sl_isstring(v) && v != SL_t && v != SL_nil && v != SL_void)
+		htable_reset(&SL(printconses), 32);
 }
--- a/src/print.h
+++ b/src/print.h
@@ -1,7 +1,7 @@
 #pragma once
 
-void fl_print(ios_t *f, value_t v);
+void sl_print(ios_t *f, value_t v);
 void print_traverse(value_t v);
-void fl_print_chr(ios_t *f, char c);
-void fl_print_str(ios_t *f, const char *s);
-void fl_print_child(ios_t *f, value_t v);
+void sl_print_chr(ios_t *f, char c);
+void sl_print_str(ios_t *f, const char *s);
+void sl_print_child(ios_t *f, value_t v);
--- a/src/ptrhash.c
+++ b/src/ptrhash.c
@@ -3,7 +3,7 @@
   optimized for storing info about particular values
 */
 
-#include "flisp.h"
+#include "sl.h"
 
 #if defined(BITS64)
 static uint64_t
--- a/src/random.c
+++ b/src/random.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "cvalues.h"
 #include "mt19937-64.h"
 #include "timefuncs.h"
--- a/src/read.c
+++ b/src/read.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "cvalues.h"
 #include "read.h"
 #include "nan.h"
@@ -24,10 +24,10 @@
 
 static value_t do_read_sexpr(Rctx *ctx, value_t label);
 
-#define RS value2c(ios_t*, FL(readstate)->source)
+#define RS value2c(ios_t*, SL(readstate)->source)
 
 bool
-fl_read_numtok(const char *tok, value_t *pval, int base)
+sl_read_numtok(const char *tok, value_t *pval, int base)
 {
 	char *end;
 	int64_t i64;
@@ -121,7 +121,7 @@
 	ctx->toktype = TOK_NONE;
 }
 
-static _Noreturn void fl_printfmt(2, 3)
+static _Noreturn void sl_printfmt(2, 3)
 parse_error(ios_loc_t *loc, const char *format, ...)
 {
 	char msgbuf[512];
@@ -137,7 +137,7 @@
 	value_t msg = string_from_cstr(msgbuf);
 	va_end(args);
 
-	fl_raise(fl_list2(FL_ParseError, msg));
+	sl_raise(sl_list2(SL_ParseError, msg));
 }
 
 static void
@@ -242,7 +242,7 @@
 			if(cval == 'u' || cval == 'U' || cval == 'x'){
 				read_token(ctx, 'u', 0);
 				if(ctx->buf[1] != '\0'){ // not a solitary 'u','U','x'
-					if(!fl_read_numtok(&ctx->buf[1], &ctx->tokval, 16))
+					if(!sl_read_numtok(&ctx->buf[1], &ctx->tokval, 16))
 						parse_error(&ctx->loc, "invalid hex character constant");
 					cval = numval(ctx->tokval);
 				}
@@ -250,18 +250,18 @@
 				read_token(ctx, (char)cval, 0);
 				ctx->tokval = symbol(ctx->buf, true);
 				if(ctx->buf[1] == '\0') USED(cval); /* one character */
-				else if(ctx->tokval == FL_nulsym)       cval = 0x00;
-				else if(ctx->tokval == FL_alarmsym)     cval = 0x07;
-				else if(ctx->tokval == FL_backspacesym) cval = 0x08;
-				else if(ctx->tokval == FL_tabsym)       cval = 0x09;
-				else if(ctx->tokval == FL_linefeedsym)  cval = 0x0A;
-				else if(ctx->tokval == FL_newlinesym)   cval = 0x0A;
-				else if(ctx->tokval == FL_vtabsym)      cval = 0x0B;
-				else if(ctx->tokval == FL_pagesym)      cval = 0x0C;
-				else if(ctx->tokval == FL_returnsym)    cval = 0x0D;
-				else if(ctx->tokval == FL_escsym)       cval = 0x1B;
-				else if(ctx->tokval == FL_spacesym)     cval = 0x20;
-				else if(ctx->tokval == FL_deletesym)    cval = 0x7F;
+				else if(ctx->tokval == SL_nulsym)       cval = 0x00;
+				else if(ctx->tokval == SL_alarmsym)     cval = 0x07;
+				else if(ctx->tokval == SL_backspacesym) cval = 0x08;
+				else if(ctx->tokval == SL_tabsym)       cval = 0x09;
+				else if(ctx->tokval == SL_linefeedsym)  cval = 0x0A;
+				else if(ctx->tokval == SL_newlinesym)   cval = 0x0A;
+				else if(ctx->tokval == SL_vtabsym)      cval = 0x0B;
+				else if(ctx->tokval == SL_pagesym)      cval = 0x0C;
+				else if(ctx->tokval == SL_returnsym)    cval = 0x0D;
+				else if(ctx->tokval == SL_escsym)       cval = 0x1B;
+				else if(ctx->tokval == SL_spacesym)     cval = 0x20;
+				else if(ctx->tokval == SL_deletesym)    cval = 0x7F;
 				else
 					parse_error(&ctx->loc, "unknown character #\\%s", ctx->buf);
 			}
@@ -340,7 +340,7 @@
 			    (c == 'o' && (base = 8)) ||
 			    (c == 'd' && (base = 10)) ||
 			    (c == 'x' && (base = 16))) && (isdigit_base(ctx->buf[1], base) || ctx->buf[1] == '-')){
-				if(!fl_read_numtok(&ctx->buf[1], &ctx->tokval, base))
+				if(!sl_read_numtok(&ctx->buf[1], &ctx->tokval, base))
 					parse_error(&ctx->loc, "invalid base %d constant", base);
 				return (ctx->toktype = TOK_NUM);
 			}
@@ -368,16 +368,16 @@
 		if(!ok){
 			if(s[0] == '.' && s[1] == '\0')
 				return (ctx->toktype = TOK_DOT);
-			if(fl_read_numtok(s, &ctx->tokval, 0))
+			if(sl_read_numtok(s, &ctx->tokval, 0))
 				return (ctx->toktype = TOK_NUM);
 		}
 		ctx->toktype = TOK_SYM;
 		if(strcasecmp(s, "nil") == 0)
-			ctx->tokval = FL_nil;
+			ctx->tokval = SL_nil;
 		else if(s[1] == 0 && (s[0] == 't' || s[0] == 'T'))
-			ctx->tokval = FL_t;
+			ctx->tokval = SL_t;
 		else if(strcmp(s, "λ") == 0 || strcmp(s, "lambda") == 0)
-			ctx->tokval = FL_lambda;
+			ctx->tokval = SL_lambda;
 		else{
 			ctx->tokval = symbol(s, true);
 			if(s[strlen(s)-1] == '#')
@@ -397,15 +397,15 @@
 	PUSH(v);
 	assert(s+d > s);
 	value_t newv = alloc_vector(s+d, 1);
-	v = FL(sp)[-1];
+	v = SL(sp)[-1];
 	for(i = 0; i < s; i++)
 		vector_elt(newv, i) = vector_elt(v, i);
 	// use gc to rewrite references from the old vector to the new
-	FL(sp)[-1] = newv;
+	SL(sp)[-1] = newv;
 	if(s > 0 && rewrite_refs){
 		((size_t*)ptr(v))[0] |= 0x1;
 		vector_elt(v, 0) = newv;
-		fl_gc(false);
+		sl_gc(false);
 	}
 	return POP();
 }
@@ -413,22 +413,22 @@
 static value_t
 read_vector(Rctx *ctx, value_t label, uint32_t closer)
 {
-	value_t v = FL(the_empty_vector), elt;
+	value_t v = SL(the_empty_vector), elt;
 	uint32_t i = 0;
 	PUSH(v);
 	if(label != UNBOUND)
-		ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)v);
+		ptrhash_put(&SL(readstate)->backrefs, (void*)label, (void*)v);
 	while(peek(ctx) != closer){
 		if(ios_eof(RS))
 			parse_error(&ctx->loc, "unexpected end of input");
-		v = FL(sp)[-1]; // reload after possible alloc in peek()
+		v = SL(sp)[-1]; // reload after possible alloc in peek()
 		if(i >= vector_size(v)){
-			v = FL(sp)[-1] = vector_grow(v, label != UNBOUND);
+			v = SL(sp)[-1] = vector_grow(v, label != UNBOUND);
 			if(label != UNBOUND)
-				ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)v);
+				ptrhash_put(&SL(readstate)->backrefs, (void*)label, (void*)v);
 		}
 		elt = do_read_sexpr(ctx, UNBOUND);
-		v = FL(sp)[-1];
+		v = SL(sp)[-1];
 		assert(i < vector_size(v));
 		vector_elt(v, i) = elt;
 		i++;
@@ -555,14 +555,14 @@
 
 	loc0 = RS->loc;
 	loc0.colno--;
-	ipval = FL(sp)-1;
-	PUSH(FL_nil);
-	ipc = FL(sp)-1; // to keep track of current cons cell
+	ipval = SL(sp)-1;
+	PUSH(SL_nil);
+	ipc = SL(sp)-1; // to keep track of current cons cell
 	t = peek(ctx);
 	while(t != closer){
 		if(ios_eof(RS))
 			parse_error(&loc0, "not closed: unexpected EOI "PAtLoc, ctx->loc.lineno, ctx->loc.colno);
-		c = mk_cons(); car_(c) = cdr_(c) = FL_nil;
+		c = mk_cons(); car_(c) = cdr_(c) = SL_nil;
 		pc = ipc;
 		if(iscons(*pc))
 			cdr_(*pc) = c;
@@ -570,7 +570,7 @@
 			pval = ipval;
 			*pval = c;
 			if(label != UNBOUND)
-				ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)c);
+				ptrhash_put(&SL(readstate)->backrefs, (void*)label, (void*)c);
 		}
 		*pc = c;
 		c = do_read_sexpr(ctx, UNBOUND);
@@ -614,7 +614,7 @@
 	take(ctx);
 	switch(t){
 	case TOK_OPEN:
-		PUSH(FL_nil);
+		PUSH(SL_nil);
 		read_list(ctx, label, TOK_CLOSE);
 		return POP();
 	case TOK_SYM:
@@ -621,36 +621,36 @@
 	case TOK_NUM:
 		return ctx->tokval;
 	case TOK_OPENB:
-		PUSH(FL_nil);
+		PUSH(SL_nil);
 		read_list(ctx, label, TOK_CLOSEB);
 		return POP();
 	case TOK_OPENC:
-		PUSH(FL_nil);
+		PUSH(SL_nil);
 		read_list(ctx, label, TOK_CLOSEC);
 		return POP();
 	case TOK_COMMA:
-		head = &FL_comma; goto listwith;
+		head = &SL_comma; goto listwith;
 	case TOK_COMMAAT:
-		head = &FL_commaat; goto listwith;
+		head = &SL_commaat; goto listwith;
 	case TOK_COMMADOT:
-		head = &FL_commadot; goto listwith;
+		head = &SL_commadot; goto listwith;
 	case TOK_BQ:
-		head = &FL_backquote; goto listwith;
+		head = &SL_backquote; goto listwith;
 	case TOK_QUOTE:
-		head = &FL_quote;
+		head = &SL_quote;
 	listwith:
 		v = cons_reserve(2);
 		car_(v) = *head;
 		cdr_(v) = tagptr((cons_t*)ptr(v)+1, TAG_CONS);
-		car_(cdr_(v)) = cdr_(cdr_(v)) = FL_nil;
+		car_(cdr_(v)) = cdr_(cdr_(v)) = SL_nil;
 		PUSH(v);
 		if(label != UNBOUND)
-			ptrhash_put(&FL(readstate)->backrefs, (void*)label, (void*)v);
+			ptrhash_put(&SL(readstate)->backrefs, (void*)label, (void*)v);
 		v = do_read_sexpr(ctx, UNBOUND);
-		car_(cdr_(FL(sp)[-1])) = v;
+		car_(cdr_(SL(sp)[-1])) = v;
 		return POP();
 	case TOK_SHARPQUOTE:
-		// femtoLisp doesn't need symbol-function, so #' does nothing
+		// StreetLISP doesn't need symbol-function, so #' does nothing
 		return do_read_sexpr(ctx, label);
 	case TOK_SHARPSYM:
 		sym = ctx->tokval;
@@ -661,18 +661,18 @@
 			take(ctx);
 			parse_error(&ctx->loc, "expected argument list for %s", symbol_name(ctx->tokval));
 		}
-		PUSH(FL_nil);
+		PUSH(SL_nil);
 		read_list(ctx, UNBOUND, TOK_CLOSE);
-		if(sym == FL_vu8sym){
-			sym = FL_arraysym;
-			FL(sp)[-1] = fl_cons(FL_uint8sym, FL(sp)[-1]);
-		}else if(sym == FL_fnsym){
-			sym = FL_function;
+		if(sym == SL_vu8sym){
+			sym = SL_arraysym;
+			SL(sp)[-1] = sl_cons(SL_uint8sym, SL(sp)[-1]);
+		}else if(sym == SL_fnsym){
+			sym = SL_function;
 		}
 		v = symbol_value(sym);
 		if(v == UNBOUND)
 			unbound_error(sym);
-		return fl_apply(v, POP());
+		return sl_apply(v, POP());
 	case TOK_SHARPOPEN:
 		return read_vector(ctx, label, TOK_CLOSE);
 	case TOK_SHARPDOT:
@@ -688,23 +688,23 @@
 				unbound_error(sym);
 			return v;
 		}
-		return fl_toplevel_eval(sym);
+		return sl_toplevel_eval(sym);
 	case TOK_LABEL:
 		// create backreference label
-		if(ptrhash_has(&FL(readstate)->backrefs, (void*)ctx->tokval))
+		if(ptrhash_has(&SL(readstate)->backrefs, (void*)ctx->tokval))
 			parse_error(&ctx->loc, "label %"PRIdPTR" redefined", (intptr_t)numval(ctx->tokval));
 		oldtokval = ctx->tokval;
 		v = do_read_sexpr(ctx, ctx->tokval);
-		ptrhash_put(&FL(readstate)->backrefs, (void*)oldtokval, (void*)v);
+		ptrhash_put(&SL(readstate)->backrefs, (void*)oldtokval, (void*)v);
 		return v;
 	case TOK_BACKREF:
 		// look up backreference
-		v = (value_t)ptrhash_get(&FL(readstate)->backrefs, (void*)ctx->tokval);
+		v = (value_t)ptrhash_get(&SL(readstate)->backrefs, (void*)ctx->tokval);
 		if(v == (value_t)HT_NOTFOUND)
 			parse_error(&ctx->loc, "undefined label %"PRIdPTR, (intptr_t)numval(ctx->tokval));
 		return v;
 	case TOK_GENSYM:
-		pv = (value_t*)ptrhash_bp(&FL(readstate)->gensyms, (void*)ctx->tokval);
+		pv = (value_t*)ptrhash_bp(&SL(readstate)->gensyms, (void*)ctx->tokval);
 		if(*pv == (value_t)HT_NOTFOUND)
 			*pv = gensym();
 		return *pv;
@@ -719,26 +719,26 @@
 	case TOK_DOT:
 		parse_error(&ctx->loc, "unexpected '.'");
 	}
-	return FL_void;
+	return SL_void;
 }
 
 value_t
-fl_read_sexpr(value_t f)
+sl_read_sexpr(value_t f)
 {
-	fl_readstate_t state;
-	state.prev = FL(readstate);
+	sl_readstate_t state;
+	state.prev = SL(readstate);
 	htable_new(&state.backrefs, 8);
 	htable_new(&state.gensyms, 8);
 	state.source = f;
-	FL(readstate) = &state;
+	SL(readstate) = &state;
 	Rctx ctx;
 	ctx.toktype = TOK_NONE;
-	fl_gc_handle(&ctx.tokval);
+	sl_gc_handle(&ctx.tokval);
 
 	value_t v = do_read_sexpr(&ctx, UNBOUND);
 
-	fl_free_gc_handles(1);
-	FL(readstate) = state.prev;
+	sl_free_gc_handles(1);
+	SL(readstate) = state.prev;
 	free_readstate(&state);
 	return v;
 }
--- a/src/read.h
+++ b/src/read.h
@@ -1,7 +1,7 @@
 #pragma once
 
-value_t fl_read_sexpr(value_t f);
-bool fl_read_numtok(const char *tok, value_t *pval, int base);
+value_t sl_read_sexpr(value_t f);
+bool sl_read_numtok(const char *tok, value_t *pval, int base);
 
 // defines which characters are ordinary symbol characters.
 // exceptions are '.', which is an ordinary symbol character
--- /dev/null
+++ b/src/sl.c
@@ -1,0 +1,1348 @@
+#include "sl.h"
+#include "operators.h"
+#include "cvalues.h"
+#include "types.h"
+#include "print.h"
+#include "read.h"
+#include "timefuncs.h"
+#include "equal.h"
+#include "hashing.h"
+#include "table.h"
+#include "iostream.h"
+#include "compress.h"
+
+value_t SL_builtins_table_sym, SL_quote, SL_lambda, SL_function, SL_comma, SL_commaat;
+value_t SL_commadot, SL_trycatch, SL_backquote;
+value_t SL_conssym, SL_symbolsym, SL_fixnumsym, SL_vectorsym, SL_builtinsym, SL_vu8sym;
+value_t SL_defsym, SL_defmacrosym, SL_forsym, SL_setqsym;
+value_t SL_booleansym, SL_nullsym, SL_evalsym, SL_fnsym;
+value_t SL_nulsym, SL_alarmsym, SL_backspacesym, SL_tabsym, SL_linefeedsym, SL_newlinesym;
+value_t SL_vtabsym, SL_pagesym, SL_returnsym, SL_escsym, SL_spacesym, SL_deletesym;
+value_t SL_IOError, SL_ParseError, SL_TypeError, SL_ArgError, SL_MemoryError;
+value_t SL_DivideError, SL_BoundsError, SL_Error, SL_KeyError, SL_UnboundError;
+
+value_t SL_printwidthsym, SL_printreadablysym, SL_printprettysym, SL_printlengthsym;
+value_t SL_printlevelsym;
+value_t SL_tablesym, SL_arraysym;
+value_t SL_iostreamsym, SL_rdsym, SL_wrsym, SL_apsym, SL_crsym, SL_truncsym;
+value_t SL_instrsym, SL_outstrsym;
+value_t SL_int8sym, SL_uint8sym, SL_int16sym, SL_uint16sym, SL_int32sym, SL_uint32sym;
+value_t SL_int64sym, SL_uint64sym, SL_bignumsym;
+value_t SL_bytesym, SL_runesym, SL_floatsym, SL_doublesym;
+value_t SL_stringtypesym, SL_runestringtypesym;
+
+sl_thread(Sl *sl);
+
+typedef struct {
+	const char *name;
+	builtin_t fptr;
+}builtinspec_t;
+
+bool
+isbuiltin(value_t x)
+{
+	int i;
+	return tag(x) == TAG_FUNCTION && (i = uintval(x)) < nelem(builtins) && builtins[i].name != nil;
+}
+
+static value_t apply_cl(int nargs) sl_hotfn;
+
+// error utilities ------------------------------------------------------------
+
+void
+free_readstate(sl_readstate_t *rs)
+{
+	htable_free(&rs->backrefs);
+	htable_free(&rs->gensyms);
+}
+
+_Noreturn void
+sl_exit(int status)
+{
+	SL(exiting) = true;
+	sl_gc(false);
+	exit(status);
+}
+
+#define SL_TRY \
+	sl_exception_context_t _ctx; int l__tr, l__ca; \
+	_ctx.sp = SL(sp); _ctx.frame = SL(curr_frame); _ctx.rdst = SL(readstate); _ctx.prev = SL(exctx); \
+	_ctx.ngchnd = SL(ngchandles); SL(exctx) = &_ctx; \
+	if(!sl_setjmp(_ctx.buf)) \
+		for(l__tr = 1; l__tr; l__tr = 0, (void)(SL(exctx) = SL(exctx)->prev))
+
+#define SL_CATCH_INC \
+	l__ca = 0, SL(lasterror) = SL_nil, SL(throwing_frame) = 0, SL(sp) = _ctx.sp, SL(curr_frame) = _ctx.frame
+
+#define SL_CATCH \
+	else \
+		for(l__ca = 1; l__ca; SL_CATCH_INC)
+
+#define SL_CATCH_NO_INC \
+	else \
+		for(l__ca = 1; l__ca;)
+
+void
+sl_savestate(sl_exception_context_t *_ctx)
+{
+	_ctx->sp = SL(sp);
+	_ctx->frame = SL(curr_frame);
+	_ctx->rdst = SL(readstate);
+	_ctx->prev = SL(exctx);
+	_ctx->ngchnd = SL(ngchandles);
+}
+
+void
+sl_restorestate(sl_exception_context_t *_ctx)
+{
+	SL(lasterror) = SL_nil;
+	SL(throwing_frame) = 0;
+	SL(sp) = _ctx->sp;
+	SL(curr_frame) = _ctx->frame;
+}
+
+_Noreturn void
+sl_raise(value_t e)
+{
+	ios_flush(ios_stdout);
+	ios_flush(ios_stderr);
+
+	SL(lasterror) = e;
+	// unwind read state
+	while(SL(readstate) != SL(exctx)->rdst){
+		free_readstate(SL(readstate));
+		SL(readstate) = SL(readstate)->prev;
+	}
+	if(SL(throwing_frame) == 0)
+		SL(throwing_frame) = SL(curr_frame);
+	SL(ngchandles) = SL(exctx)->ngchnd;
+	sl_exception_context_t *thisctx = SL(exctx);
+	if(SL(exctx)->prev)   // don't throw past toplevel
+		SL(exctx) = SL(exctx)->prev;
+	sl_longjmp(thisctx->buf, 1);
+}
+
+_Noreturn void
+lerrorf(value_t e, const char *format, ...)
+{
+	char msgbuf[256];
+	va_list args;
+
+	PUSH(e);
+	va_start(args, format);
+	vsnprintf(msgbuf, sizeof(msgbuf), format, args);
+	value_t msg = string_from_cstr(msgbuf);
+	va_end(args);
+
+	e = POP();
+	sl_raise(sl_list2(e, msg));
+}
+
+_Noreturn void
+type_error(const char *expected, value_t got)
+{
+	sl_raise(sl_listn(3, SL_TypeError, symbol(expected, false), got));
+}
+
+_Noreturn void
+bounds_error(value_t arr, value_t ind)
+{
+	sl_raise(sl_listn(3, SL_BoundsError, arr, ind));
+}
+
+_Noreturn void
+unbound_error(value_t sym)
+{
+	sl_raise(sl_listn(2, SL_UnboundError, sym));
+}
+
+_Noreturn void
+arity_error(int nargs, int c)
+{
+	lerrorf(SL_ArgError, "arity mismatch: wanted %"PRId32", got %"PRId32, c, nargs);
+}
+
+// safe cast operators --------------------------------------------------------
+
+#define isstring sl_isstring
+#define SAFECAST_OP(type, ctype, cnvt) \
+	ctype to##type(value_t v) \
+	{ \
+		if(sl_likely(is##type(v))) \
+			return (ctype)cnvt(v); \
+		type_error(#type, v); \
+	}
+SAFECAST_OP(cons, cons_t*, ptr)
+SAFECAST_OP(symbol, symbol_t*, ptr)
+SAFECAST_OP(fixnum, fixnum_t, numval)
+//SAFECAST_OP(cvalue, cvalue_t*, ptr)
+SAFECAST_OP(string, char*, cvalue_data)
+#undef isstring
+
+// symbol table ---------------------------------------------------------------
+
+static symbol_t *
+mk_symbol(const char *str, int len, bool copy)
+{
+	symbol_t *sym = MEM_ALLOC(sizeof(*sym) + (copy ? len+1 : 0));
+	sym->numtype = NONNUMERIC;
+	if(str[0] == ':' && str[1] != 0){
+		value_t s = tagptr(sym, TAG_SYM);
+		sym->flags = FLAG_KEYWORD;
+		setc(s, s);
+	}else{
+		sym->binding = UNBOUND;
+		sym->flags = 0;
+	}
+	sym->type = nil;
+	sym->hash = memhash(str, len)^0xAAAAAAAAAAAAAAAAULL;
+	if(copy){
+		memcpy((char*)(sym+1), str, len+1);
+		sym->name = (const char*)(sym+1);
+	}else{
+		sym->name = str;
+	}
+	sym->size = 0;
+	return sym;
+}
+
+value_t
+symbol(const char *str, bool copy)
+{
+	int len = strlen(str);
+	symbol_t *v;
+	const char *k;
+	if(!Tgetkv(SL(symtab), str, len, &k, (void**)&v)){
+		v = mk_symbol(str, len, copy);
+		SL(symtab) = Tsetl(SL(symtab), v->name, len, v);
+	}
+	return tagptr(v, TAG_SYM);
+}
+
+value_t
+csymbol_(const char *str, int len)
+{
+	symbol_t *v = mk_symbol(str, len, false);
+	SL(symtab) = Tsetl(SL(symtab), str, len, v);
+	return tagptr(v, TAG_SYM);
+}
+
+BUILTIN("gensym", gensym)
+{
+	argcount(nargs, 0);
+	USED(args);
+	gensym_t *gs = alloc_words(sizeof(gensym_t)/sizeof(value_t));
+	gs->id = SL(gensym_ctr)++;
+	gs->binding = UNBOUND;
+	gs->type = nil;
+	return tagptr(gs, TAG_SYM);
+}
+
+value_t
+gensym(void)
+{
+	return fn_builtin_gensym(nil, 0);
+}
+
+sl_purefn
+BUILTIN("gensym?", gensymp)
+{
+	argcount(nargs, 1);
+	return isgensym(args[0]) ? SL_t : SL_nil;
+}
+
+char *
+uint2str(char *dest, size_t len, uint64_t num, int base)
+{
+	int i = len-1;
+	uint64_t b = (uint64_t)base;
+	char ch;
+	dest[i--] = '\0';
+	while(i >= 0){
+		ch = (char)(num % b);
+		if(ch < 10)
+			ch += '0';
+		else
+			ch = ch-10+'a';
+		dest[i--] = ch;
+		num /= b;
+		if(num == 0)
+			break;
+	}
+	return &dest[i+1];
+}
+
+const char *
+symbol_name(value_t v)
+{
+	if(ismanaged(v)){
+		gensym_t *gs = ptr(v);
+		SL(gsnameno) = 1-SL(gsnameno);
+		char *n = uint2str(SL(gsname)[SL(gsnameno)]+1, sizeof(SL(gsname)[0])-1, gs->id, 10);
+		*(--n) = 'g';
+		return n;
+	}
+	return ((symbol_t*)ptr(v))->name;
+}
+
+// conses ---------------------------------------------------------------------
+
+value_t
+mk_cons(void)
+{
+	cons_t *c;
+
+	if(sl_unlikely(SL(curheap) > SL(lim)))
+		sl_gc(false);
+	c = (cons_t*)SL(curheap);
+	SL(curheap) += sizeof(cons_t);
+	return tagptr(c, TAG_CONS);
+}
+
+void *
+alloc_words(int n)
+{
+	value_t *first;
+
+#if !defined(BITS64)
+	// force 8-byte alignment
+	if(n & 1)
+		n++;
+#endif
+	if(sl_unlikely((value_t*)SL(curheap) > (value_t*)SL(lim)+2-n)){
+		sl_gc(false);
+		while(sl_unlikely((value_t*)SL(curheap) > ((value_t*)SL(lim))+2-n))
+			sl_gc(true);
+	}
+	first = (value_t*)SL(curheap);
+	SL(curheap) += n*sizeof(value_t);
+	return first;
+}
+
+value_t
+alloc_vector(size_t n, bool init)
+{
+	if(n == 0)
+		return SL(the_empty_vector);
+	value_t *c = alloc_words(n+1);
+	value_t v = tagptr(c, TAG_VECTOR);
+	vector_setsize(v, n);
+	if(init){
+		for(size_t i = 0; i < n; i++)
+			vector_elt(v, i) = SL_void;
+	}
+	return v;
+}
+
+// collector ------------------------------------------------------------------
+
+void
+sl_gc_handle(value_t *pv)
+{
+	if(sl_unlikely(SL(ngchandles) >= N_GC_HANDLES))
+		lerrorf(SL_MemoryError, "out of gc handles");
+	SL(gchandles)[SL(ngchandles)++] = pv;
+}
+
+void
+sl_free_gc_handles(int n)
+{
+	assert(SL(ngchandles) >= n);
+	SL(ngchandles) -= n;
+}
+
+value_t
+relocate(value_t v)
+{
+	value_t a, d, nc, first, *pcdr;
+
+	if(isfixnum(v))
+		return v;
+
+	uintptr_t t = tag(v);
+	if(t == TAG_CONS){
+		// iterative implementation allows arbitrarily long cons chains
+		pcdr = &first;
+		do{
+			a = car_(v);
+			if(isforwarded(v)){
+				*pcdr = forwardloc(v);
+				return first;
+			}
+			d = cdr_(v);
+			*pcdr = nc = tagptr((cons_t*)SL(curheap), TAG_CONS);
+			SL(curheap) += sizeof(cons_t);
+			forward(v, nc);
+			car_(nc) = ismanaged(a) ? relocate(a) : a;
+			pcdr = &cdr_(nc);
+			v = d;
+		}while(iscons(v));
+		*pcdr = d == SL_nil ? SL_nil : relocate(d);
+		return first;
+	}
+
+	if(!ismanaged(v))
+		return v;
+	if(isforwarded(v))
+		return forwardloc(v);
+
+	if(t == TAG_CVALUE)
+		return cvalue_relocate(v);
+	if(t == TAG_VECTOR){
+		// N.B.: 0-length vectors secretly have space for a first element
+		size_t i, sz = vector_size(v);
+		if(vector_elt(v, -1) & 0x1){
+			// grown vector
+			nc = relocate(vector_elt(v, 0));
+			forward(v, nc);
+		}else{
+			nc = tagptr(alloc_words(sz+1), TAG_VECTOR);
+			vector_setsize(nc, sz);
+			a = vector_elt(v, 0);
+			forward(v, nc);
+			if(sz > 0){
+				vector_elt(nc, 0) = relocate(a);
+				for(i = 1; i < sz; i++)
+					vector_elt(nc, i) = relocate(vector_elt(v, i));
+			}
+		}
+		return nc;
+	}
+	if(t == TAG_FUNCTION){
+		function_t *fn = ptr(v);
+		function_t *nfn = alloc_words(sizeof(function_t)/sizeof(value_t));
+		nfn->bcode = fn->bcode;
+		nfn->vals = fn->vals;
+		nc = tagptr(nfn, TAG_FUNCTION);
+		forward(v, nc);
+		nfn->env = relocate(fn->env);
+		nfn->vals = relocate(nfn->vals);
+		nfn->bcode = relocate(nfn->bcode);
+		assert(!ismanaged(fn->name));
+		nfn->name = fn->name;
+		return nc;
+	}
+	if(t == TAG_SYM){
+		gensym_t *gs = ptr(v);
+		gensym_t *ng = alloc_words(sizeof(gensym_t)/sizeof(value_t));
+		ng->id = gs->id;
+		ng->binding = gs->binding;
+		ng->type = gs->type;
+		nc = tagptr(ng, TAG_SYM);
+		forward(v, nc);
+		if(sl_likely(ng->binding != UNBOUND))
+			ng->binding = relocate(ng->binding);
+		return nc;
+	}
+	if(t == TAG_CPRIM){
+		cprim_t *pcp = ptr(v);
+		size_t nw = CPRIM_NWORDS+NWORDS(cp_class(pcp)->size);
+		cprim_t *ncp = alloc_words(nw);
+		while(nw--)
+			((value_t*)ncp)[nw] = ((value_t*)pcp)[nw];
+		nc = tagptr(ncp, TAG_CPRIM);
+		forward(v, nc);
+		return nc;
+	}
+	return v;
+}
+
+static void
+trace_globals(void)
+{
+	const char *k = nil;
+	symbol_t *v;
+	while(Tnext(SL(symtab), &k, (void**)&v)){
+		if(v->binding != UNBOUND)
+			v->binding = relocate(v->binding);
+	}
+}
+
+void
+sl_gc(bool mustgrow)
+{
+	SL(gccalls)++;
+	SL(curheap) = SL(tospace);
+	if(SL(grew))
+		SL(lim) = SL(curheap)+SL(heapsize)*2-sizeof(cons_t);
+	else
+		SL(lim) = SL(curheap)+SL(heapsize)-sizeof(cons_t);
+
+	value_t *top, *f;
+	if(SL(throwing_frame) > SL(curr_frame)){
+		top = SL(throwing_frame) - 3;
+		f = (value_t*)*top;
+	}else{
+		top = SL(sp);
+		f = SL(curr_frame);
+	}
+	for(;;){
+		for(value_t *p = f; p < top; p++)
+			*p = relocate(*p);
+		if(f == SL(stack))
+			break;
+		top = f - 3;
+		f = (value_t*)*top;
+	}
+	for(int i = 0; i < SL(ngchandles); i++)
+		*SL(gchandles)[i] = relocate(*SL(gchandles)[i]);
+	trace_globals();
+	relocate_typetable();
+	sl_readstate_t *rs = SL(readstate);
+	while(rs){
+		value_t ent;
+		for(int i = 0; i < rs->backrefs.size; i++){
+			ent = (value_t)rs->backrefs.table[i];
+			if(ent != (value_t)HT_NOTFOUND)
+				rs->backrefs.table[i] = (void*)relocate(ent);
+		}
+		for(int i = 0; i < rs->gensyms.size; i++){
+			ent = (value_t)rs->gensyms.table[i];
+			if(ent != (value_t)HT_NOTFOUND)
+				rs->gensyms.table[i] = (void*)relocate(ent);
+		}
+		rs->source = relocate(rs->source);
+		rs = rs->prev;
+	}
+	SL(lasterror) = relocate(SL(lasterror));
+	SL(memory_exception_value) = relocate(SL(memory_exception_value));
+	SL(the_empty_vector) = relocate(SL(the_empty_vector));
+	SL(the_empty_string) = relocate(SL(the_empty_string));
+
+	sweep_finalizers();
+
+	void *temp = SL(tospace);
+	SL(tospace) = SL(fromspace);
+	SL(fromspace) = temp;
+
+	// if we're using > 80% of the space, resize tospace so we have
+	// more space to fill next time. if we grew tospace last time,
+	// grow the other half of the heap this time to catch up.
+	if(SL(grew) || ((intptr_t)(SL(lim)-SL(curheap)) < (intptr_t)SL(heapsize)/5) || mustgrow){
+		temp = MEM_REALLOC(SL(tospace), SL(heapsize)*2);
+		if(sl_unlikely(temp == nil))
+			sl_raise(SL(memory_exception_value));
+		SL(tospace) = temp;
+		if(SL(grew)){
+			SL(heapsize) *= 2;
+			temp = bitvector_resize(SL(consflags), 0, SL(heapsize)/sizeof(cons_t), 1);
+			if(sl_unlikely(temp == nil))
+				sl_raise(SL(memory_exception_value));
+			SL(consflags) = (uint32_t*)temp;
+		}
+		SL(grew) = !SL(grew);
+	}
+	if(sl_unlikely((value_t*)SL(curheap) > (value_t*)SL(lim)-2)){
+		// all data was live; gc again and grow heap.
+		// but also always leave at least 4 words available, so a closure
+		// can be allocated without an extra check.
+		sl_gc(false);
+	}
+}
+
+// utils ----------------------------------------------------------------------
+
+// apply function with n args on the stack
+sl_hotfn
+static value_t
+_applyn(int n)
+{
+	value_t *saveSP = SL(sp);
+	value_t f = saveSP[-n-1];
+	value_t v;
+	if(iscbuiltin(f))
+		v = ((cvalue_t*)ptr(f))->cbuiltin(saveSP-n, n);
+	else if(isfunction(f))
+		v = apply_cl(n);
+	else if(sl_likely(isbuiltin(f))){
+		value_t tab = symbol_value(SL_builtins_table_sym);
+		if(sl_unlikely(ptr(tab) == nil))
+			unbound_error(tab);
+		saveSP[-n-1] = vector_elt(tab, uintval(f));
+		v = apply_cl(n);
+	}else{
+		type_error("function", f);
+	}
+	SL(sp) = saveSP;
+	return v;
+}
+
+value_t
+sl_apply(value_t f, value_t v)
+{
+	value_t *saveSP = SL(sp);
+
+	PUSH(f);
+	int n;
+	for(n = 0; iscons(v); n++){
+		PUSH(car_(v));
+		v = cdr_(v);
+	}
+	if(v != SL_nil)
+		lerrorf(SL_ArgError, "apply: last argument: not a list");
+	v = _applyn(n);
+	SL(sp) = saveSP;
+	return v;
+}
+
+value_t
+sl_applyn(int n, value_t f, ...)
+{
+	va_list ap;
+	va_start(ap, f);
+
+	PUSH(f);
+	for(int i = 0; i < n; i++){
+		value_t a = va_arg(ap, value_t);
+		PUSH(a);
+	}
+	value_t v = _applyn(n);
+	POPN(n+1);
+	va_end(ap);
+	return v;
+}
+
+value_t
+sl_listn(int n, ...)
+{
+	va_list ap;
+	va_start(ap, n);
+	value_t *si = SL(sp);
+
+	for(int i = 0; i < n; i++){
+		value_t a = va_arg(ap, value_t);
+		PUSH(a);
+	}
+	cons_t *c = alloc_words(n*2);
+	cons_t *l = c;
+	for(int i = 0; i < n; i++){
+		c->car = *si++;
+		c->cdr = tagptr(c+1, TAG_CONS);
+		c++;
+	}
+	c[-1].cdr = SL_nil;
+
+	POPN(n);
+	va_end(ap);
+	return tagptr(l, TAG_CONS);
+}
+
+value_t
+sl_list2(value_t a, value_t b)
+{
+	PUSH(a);
+	PUSH(b);
+	cons_t *c = alloc_words(4);
+	b = POP();
+	a = POP();
+	c[0].car = a;
+	c[0].cdr = tagptr(c+1, TAG_CONS);
+	c[1].car = b;
+	c[1].cdr = SL_nil;
+	return tagptr(c, TAG_CONS);
+}
+
+value_t
+sl_cons(value_t a, value_t b)
+{
+	PUSH(a);
+	PUSH(b);
+	value_t c = mk_cons();
+	cdr_(c) = POP();
+	car_(c) = POP();
+	return c;
+}
+
+bool
+sl_isnumber(value_t v)
+{
+	if(isfixnum(v) || ismpint(v))
+		return true;
+	if(iscprim(v)){
+		cprim_t *c = ptr(v);
+		return c->type != SL(runetype) && valid_numtype(c->type->numtype);
+	}
+	return false;
+}
+
+// eval -----------------------------------------------------------------------
+
+sl_hotfn
+static value_t
+list(value_t *args, int nargs, bool star)
+{
+	if(sl_unlikely(nargs == 0))
+		return SL_nil;
+	value_t v = cons_reserve(nargs);
+	cons_t *c = ptr(v);
+	for(int i = 0; i < nargs; i++){
+		c->car = args[i];
+		c->cdr = tagptr(c+1, TAG_CONS);
+		c++;
+	}
+	if(star)
+		c[-2].cdr = c[-1].car;
+	else
+		c[-1].cdr = SL_nil;
+	return v;
+}
+
+static value_t
+copy_list(value_t L)
+{
+	if(!iscons(L))
+		return SL_nil;
+	value_t *plcons = SL(sp);
+	value_t *pL = plcons+1;
+	PUSH(SL_nil);
+	PUSH(L);
+	value_t c;
+	c = mk_cons(); PUSH(c);  // save first cons
+	car_(c) = car_(*pL);
+	cdr_(c) = SL_nil;
+	*plcons = c;
+	*pL = cdr_(*pL);
+	while(iscons(*pL)){
+		c = mk_cons();
+		car_(c) = car_(*pL);
+		cdr_(c) = SL_nil;
+		cdr_(*plcons) = c;
+		*plcons = c;
+		*pL = cdr_(*pL);
+	}
+	c = POP();  // first cons
+	POPN(2);
+	return c;
+}
+
+static value_t
+do_trycatch(void)
+{
+	value_t *saveSP = SL(sp);
+	value_t v = SL_nil;
+	value_t thunk = saveSP[-2];
+	SL(sp)[-2] = saveSP[-1];
+	SL(sp)[-1] = thunk;
+
+	SL_TRY{
+		v = apply_cl(0);
+	}
+	SL_CATCH{
+		v = saveSP[-2];
+		PUSH(v);
+		PUSH(SL(lasterror));
+		v = apply_cl(1);
+	}
+	SL(sp) = saveSP;
+	return v;
+}
+
+/*
+  argument layout on stack is
+  |--required args--|--opt args--|--kw args--|--rest args...
+*/
+static int
+process_keys(value_t kwtable, int nreq, int nkw, int nopt, value_t *bp, int nargs, int va)
+{
+	int extr = nopt+nkw;
+	int ntot = nreq+extr;
+	value_t args[64], v = SL_nil;
+	int i, a = 0, nrestargs;
+	value_t s1 = SL(sp)[-1];
+	value_t s3 = SL(sp)[-3];
+	value_t s4 = SL(sp)[-4];
+	if(sl_unlikely(nargs < nreq))
+		lerrorf(SL_ArgError, "too few arguments");
+	if(sl_unlikely(extr > nelem(args)))
+		lerrorf(SL_ArgError, "too many arguments");
+	for(i = 0; i < extr; i++)
+		args[i] = UNBOUND;
+	for(i = nreq; i < nargs; i++){
+		v = bp[i];
+		if(issymbol(v) && iskeyword((symbol_t*)ptr(v)))
+			break;
+		if(a >= nopt)
+			goto no_kw;
+		args[a++] = v;
+	}
+	if(i >= nargs)
+		goto no_kw;
+	// now process keywords
+	uintptr_t n = vector_size(kwtable)/2;
+	do{
+		i++;
+		if(sl_unlikely(i >= nargs))
+			lerrorf(SL_ArgError, "keyword %s requires an argument", symbol_name(v));
+		value_t hv = fixnum(((symbol_t*)ptr(v))->hash);
+		fixnum_t lx = numval(hv);
+		uintptr_t x = 2*((lx < 0 ? -lx : lx) % n);
+		if(sl_likely(vector_elt(kwtable, x) == v)){
+			intptr_t idx = numval(vector_elt(kwtable, x+1));
+			assert(idx < nkw);
+			idx += nopt;
+			if(args[idx] == UNBOUND){
+				// if duplicate key, keep first value
+				args[idx] = bp[i];
+			}
+		}else{
+			lerrorf(SL_ArgError, "unsupported keyword %s", symbol_name(v));
+		}
+		i++;
+		if(i >= nargs)
+			break;
+		v = bp[i];
+	}while(issymbol(v) && iskeyword((symbol_t*)ptr(v)));
+no_kw:
+	nrestargs = nargs - i;
+	if(sl_unlikely(!va && nrestargs > 0))
+		lerrorf(SL_ArgError, "too many arguments");
+	nargs = ntot + nrestargs;
+	if(nrestargs)
+		memmove(bp+ntot, bp+i, nrestargs*sizeof(value_t));
+	memmove(bp+nreq, args, extr*sizeof(value_t));
+	SL(sp) = bp + nargs;
+	assert((intptr_t)(SL(sp)-SL(stack)) < (intptr_t)SL(nstack)-4);
+	PUSH(s4);
+	PUSH(s3);
+	PUSH(nargs);
+	PUSH(s1);
+	SL(curr_frame) = SL(sp);
+	return nargs;
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN && defined(MEM_UNALIGNED_ACCESS)
+#define GET_INT32(a) *(const int32_t*)(a)
+#define GET_INT16(a) *(const int16_t*)(a)
+#else
+#define GET_INT32(a) (int32_t)((a)[0]<<0 | (a)[1]<<8 | (a)[2]<<16 | (uint32_t)(a)[3]<<24)
+#define GET_INT16(a) (int16_t)((a)[0]<<0 | (a)[1]<<8)
+#endif
+
+/*
+  stack on entry: <func>  <nargs args...>
+  caller's responsibility:
+  - put the stack in this state
+  - provide arg count
+  - respect tail position
+  - restore SP
+
+  callee's responsibility:
+  - check arg counts
+  - allocate vararg array
+  - push closed env, set up new environment
+*/
+static value_t
+apply_cl(int nargs)
+{
+	value_t *top_frame = SL(curr_frame), *bp, *ipd;
+	register value_t *sp = SL(sp);
+	const uint8_t *ip;
+	bool tail;
+	int n;
+
+	goto apply_func;
+
+#if defined(COMPUTED_GOTO)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+	static const void * const ops[] = {
+#define GOTO_OP_OFFSET(op) [op] = &&op_##op
+#include "vm_goto.inc"
+#undef GOTO_OP_OFFSET
+	};
+#define NEXT_OP goto *ops[*ip++]
+#define LABEL(x) x
+#define OP(x) op_##x:
+#include "vm.inc"
+#undef OP
+#undef LABEL
+#undef NEXT_OP
+#pragma GCC diagnostic pop
+#else /* just a usual (portable) switch/case */
+	uint8_t op;
+	while(1){
+		switch(op){
+#define NEXT_OP break
+#define LABEL(x) x
+#define OP(x) case x:
+#include "vm.inc"
+#undef OP
+#undef LABEL
+#undef NEXT_OP
+		}
+		op = *ip++;
+	}
+#endif
+}
+
+// top = top frame pointer to start at
+static value_t
+_stacktrace(value_t *top)
+{
+	value_t lst = SL_nil;
+	value_t *stack = SL(stack);
+
+	sl_gc_handle(&lst);
+	while(top > stack){
+		const uint8_t *ip1 = (void*)top[-1];
+		int sz = top[-2]+1;
+		value_t *bp = top-4-sz;
+		value_t func = bp[0];
+		const uint8_t *ip0 = cvalue_data(fn_bcode(func));
+		intptr_t ip = ip1 - ip0 - 1; /* -1: ip1 is *after* the one that was being executed */
+		value_t v = alloc_vector(sz+1, 0);
+		vector_elt(v, 0) = fixnum(ip);
+		vector_elt(v, 1) = func;
+		for(int i = 1; i < sz; i++){
+			value_t si = bp[i];
+			// if there's an error evaluating argument defaults some slots
+			// might be left set to UNBOUND
+			vector_elt(v, i+1) = si == UNBOUND ? SL_void : si;
+		}
+		lst = sl_cons(v, lst);
+		top = (value_t*)top[-3];
+	}
+	sl_free_gc_handles(1);
+	return lst;
+}
+
+// builtins -------------------------------------------------------------------
+
+BUILTIN("gc", gc)
+{
+	USED(args);
+	argcount(nargs, 0);
+	sl_gc(false);
+	return SL_void;
+}
+
+BUILTIN("function", function)
+{
+	if(nargs == 1 && issymbol(args[0]))
+		return fn_builtin_builtin(args, nargs);
+	if(nargs < 2 || nargs > 4)
+		argcount(nargs, 2);
+	if(sl_unlikely(!sl_isstring(args[0])))
+		type_error("string", args[0]);
+	if(sl_unlikely(!isvector(args[1])))
+		type_error("vector", args[1]);
+	cvalue_t *arr = ptr(args[0]);
+	cv_pin(arr);
+	uint8_t *data = cv_data(arr);
+	if(SL(loading)){
+		// read syntax, shifted 48 for compact text representation
+		size_t i, sz = cv_len(arr);
+		for(i = 0; i < sz; i++)
+			data[i] -= 48;
+	}
+	function_t *fn = alloc_words(sizeof(function_t)/sizeof(value_t));
+	value_t fv = tagptr(fn, TAG_FUNCTION);
+	fn->bcode = args[0];
+	fn->vals = args[1];
+	fn->env = SL_nil;
+	fn->name = SL_lambda;
+	if(nargs > 2){
+		if(issymbol(args[2])){
+			fn->name = args[2];
+			if(nargs > 3)
+				fn->env = args[3];
+		}else{
+			fn->env = args[2];
+			if(nargs > 3){
+				if(sl_unlikely(!issymbol(args[3])))
+					type_error("symbol", args[3]);
+				fn->name = args[3];
+			}
+		}
+		if(sl_unlikely(isgensym(fn->name)))
+			lerrorf(SL_ArgError, "name should not be a gensym");
+	}
+	return fv;
+}
+
+sl_purefn
+BUILTIN("function:code", function_code)
+{
+	argcount(nargs, 1);
+	value_t v = args[0];
+	if(sl_unlikely(!isfunction(v)))
+		type_error("function", v);
+	return fn_bcode(v);
+}
+
+sl_purefn
+BUILTIN("function:vals", function_vals)
+{
+	argcount(nargs, 1);
+	value_t v = args[0];
+	if(sl_unlikely(!isfunction(v)))
+		type_error("function", v);
+	return fn_vals(v);
+}
+
+sl_purefn
+BUILTIN("function:env", function_env)
+{
+	argcount(nargs, 1);
+	value_t v = args[0];
+	if(sl_unlikely(!isfunction(v)))
+		type_error("function", v);
+	return fn_env(v);
+}
+
+BUILTIN("function:name", function_name)
+{
+	argcount(nargs, 1);
+	value_t v = args[0];
+	if(isfunction(v))
+		return fn_name(v);
+	if(isbuiltin(v))
+		return symbol(builtins[uintval(v)].name, false);
+	if(iscbuiltin(v)){
+		v = (value_t)ptrhash_get(&SL(reverse_dlsym_lookup_table), ptr(v));
+		if(v == (value_t)HT_NOTFOUND)
+			return SL_nil;
+		return v;
+	}
+	type_error("function", v);
+}
+
+BUILTIN("copy-list", copy_list)
+{
+	argcount(nargs, 1);
+	return copy_list(args[0]);
+}
+
+BUILTIN("append", append)
+{
+	value_t first = SL_nil, lst, lastcons = SL_nil;
+	int i;
+	if(nargs == 0)
+		return SL_nil;
+	sl_gc_handle(&first);
+	sl_gc_handle(&lastcons);
+	for(i = 0; i < nargs; i++){
+		lst = args[i];
+		if(iscons(lst)){
+			lst = copy_list(lst);
+			if(first == SL_nil)
+				first = lst;
+			else
+				cdr_(lastcons) = lst;
+			lastcons = tagptr((((cons_t*)SL(curheap))-1), TAG_CONS);
+		}else if(lst != SL_nil){
+			type_error("cons", lst);
+		}
+	}
+	sl_free_gc_handles(2);
+	return first;
+}
+
+BUILTIN("list*", liststar)
+{
+	if(nargs == 1)
+		return args[0];
+	if(nargs == 0)
+		argcount(nargs, 1);
+	return list(args, nargs, true);
+}
+
+BUILTIN("stacktrace", stacktrace)
+{
+	USED(args);
+	argcount(nargs, 0);
+	return _stacktrace(SL(throwing_frame) ? SL(throwing_frame) : SL(curr_frame));
+}
+
+BUILTIN("map", map)
+{
+	if(sl_unlikely(nargs < 2))
+		lerrorf(SL_ArgError, "too few arguments");
+	value_t *k = SL(sp);
+	PUSH(SL_nil);
+	PUSH(SL_nil);
+	for(bool first = true;;){
+		PUSH(args[0]);
+		for(int i = 1; i < nargs; i++){
+			if(!iscons(args[i])){
+				POPN(2+i);
+				return k[1];
+			}
+			PUSH(car(args[i]));
+			args[i] = cdr_(args[i]);
+		}
+		value_t v = _applyn(nargs-1);
+		POPN(nargs);
+		PUSH(v);
+		value_t c = mk_cons();
+		car_(c) = POP(); cdr_(c) = SL_nil;
+		if(first)
+			k[1] = c;
+		else
+			cdr_(k[0]) = c;
+		k[0] = c;
+		first = false;
+	}
+}
+
+BUILTIN("for-each", for_each)
+{
+	if(sl_unlikely(nargs < 2))
+		lerrorf(SL_ArgError, "too few arguments");
+	for(size_t n = 0;; n++){
+		PUSH(args[0]);
+		int pargs = 0;
+		for(int i = 1; i < nargs; i++, pargs++){
+			value_t v = args[i];
+			if(iscons(v)){
+				PUSH(car_(v));
+				args[i] = cdr_(v);
+				continue;
+			}
+			if(isvector(v)){
+				size_t sz = vector_size(v);
+				if(n < sz){
+					PUSH(vector_elt(v, n));
+					continue;
+				}
+			}
+			if(isarray(v)){
+				size_t sz = cvalue_arraylen(v);
+				if(n < sz){
+					value_t a[2];
+					a[0] = v;
+					a[1] = fixnum(n);
+					PUSH(cvalue_array_aref(a));
+					continue;
+				}
+			}
+			if(ishashtable(v)){
+				htable_t *h = totable(v);
+				assert(n != 0 || h->i == 0);
+				void **table = h->table;
+				for(; h->i < h->size; h->i += 2){
+					if(table[h->i+1] != HT_NOTFOUND)
+						break;
+				}
+				if(h->i < h->size){
+					PUSH((value_t)table[h->i]);
+					pargs++;
+					PUSH((value_t)table[h->i+1]);
+					h->i += 2;
+					continue;
+				}
+				h->i = 0;
+			}
+			POPN(pargs+1);
+			return SL_void;
+		}
+		_applyn(pargs);
+		POPN(pargs+1);
+	}
+}
+
+BUILTIN("sleep", sl_sleep)
+{
+	if(nargs > 1)
+		argcount(nargs, 1);
+	double s = nargs > 0 ? todouble(args[0]) : 0;
+	sleep_ms(s * 1000.0);
+	return SL_void;
+}
+
+BUILTIN("vm-stats", vm_stats)
+{
+	USED(args);
+	argcount(nargs, 0);
+	ios_printf(ios_stderr, "heap total     %10"PRIuPTR" bytes\n", SL(heapsize));
+	ios_printf(ios_stderr, "heap free      %10"PRIuPTR" bytes\n", (uintptr_t)(SL(lim)-SL(curheap)));
+	ios_printf(ios_stderr, "heap used      %10"PRIuPTR" bytes\n", (uintptr_t)(SL(curheap)-SL(fromspace)));
+	ios_printf(ios_stderr, "stack          %10"PRIu64" bytes\n", (uint64_t)SL(nstack)*sizeof(value_t));
+	ios_printf(ios_stderr, "finalizers     %10"PRIu32"\n", (uint32_t)SL(nfinalizers));
+	ios_printf(ios_stderr, "max finalizers %10"PRIu32"\n", (uint32_t)SL(maxfinalizers));
+	ios_printf(ios_stderr, "gc handles     %10"PRIu32"\n", (uint32_t)SL(ngchandles));
+	ios_printf(ios_stderr, "gc calls       %10"PRIu64"\n", (uint64_t)SL(gccalls));
+	ios_printf(ios_stderr, "opcodes        %10d\n", N_OPCODES);
+	return SL_void;
+}
+
+static const builtinspec_t builtin_fns[] = {
+#define BUILTIN_FN(l, c, attr){l, (builtin_t)fn_builtin_##c},
+#include "builtin_fns.h"
+#undef BUILTIN_FN
+};
+
+// initialization -------------------------------------------------------------
+
+int
+sl_init(size_t heapsize, size_t stacksize)
+{
+	int i;
+
+	if((sl = MEM_CALLOC(1, sizeof(*sl))) == nil)
+		return -1;
+	SL(scr_width) = 100;
+
+	SL(heapsize) = heapsize*sizeof(value_t);
+
+	if((SL(fromspace) = MEM_ALLOC(SL(heapsize))) == nil){
+failed:
+		MEM_FREE(SL(fromspace));
+		MEM_FREE(SL(tospace));
+		MEM_FREE(SL(consflags));
+		MEM_FREE(SL(finalizers));
+		sl_segfree(SL(stack), stacksize*sizeof(value_t));
+		htable_free(&SL(printconses));
+		MEM_FREE(sl);
+		return -1;
+	}
+
+	if((SL(tospace) = MEM_ALLOC(SL(heapsize))) == nil)
+		goto failed;
+	SL(curheap) = SL(fromspace);
+	SL(lim) = SL(curheap)+SL(heapsize)-sizeof(cons_t);
+
+	if((SL(stack) = sl_segalloc(stacksize*sizeof(value_t))) == nil)
+		goto failed;
+	SL(curr_frame) = SL(sp) = SL(stack);
+	SL(nstack) = stacksize;
+
+	SL(maxfinalizers) = 512;
+	if((SL(finalizers) = MEM_ALLOC(SL(maxfinalizers) * sizeof(*SL(finalizers)))) == nil)
+		goto failed;
+
+	if((SL(consflags) = bitvector_new(SL(heapsize)/sizeof(cons_t), 1)) == nil)
+		goto failed;
+	if((htable_new(&SL(printconses), 32)) == nil)
+		goto failed;
+
+	comparehash_init();
+
+	SL_lambda = csymbol("λ");
+	SL_function = csymbol("function");
+	SL_quote = csymbol("quote");
+	SL_trycatch = csymbol("trycatch");
+	SL_backquote = csymbol("quasiquote");
+	SL_comma = csymbol("unquote");
+	SL_commaat = csymbol("unquote-splicing");
+	SL_commadot = csymbol("unquote-nsplicing");
+	SL_IOError = csymbol("io-error");
+	SL_ParseError = csymbol("parse-error");
+	SL_TypeError = csymbol("type-error");
+	SL_ArgError = csymbol("arg-error");
+	SL_UnboundError = csymbol("unbound-error");
+	SL_KeyError = csymbol("key-error");
+	SL_MemoryError = csymbol("memory-error");
+	SL_BoundsError = csymbol("bounds-error");
+	SL_DivideError = csymbol("divide-error");
+	SL_Error = csymbol("error");
+	SL_conssym = csymbol("cons");
+	SL_symbolsym = csymbol("symbol");
+	SL_fixnumsym = csymbol("fixnum");
+	SL_vectorsym = csymbol("vector");
+	SL_builtinsym = csymbol("builtin");
+	SL_booleansym = csymbol("boolean");
+	SL_nullsym = csymbol("null");
+	SL_defsym = csymbol("def");
+	SL_defmacrosym = csymbol("defmacro");
+	SL_forsym = csymbol("for");
+	SL_setqsym = csymbol("set!");
+	SL_evalsym = csymbol("eval");
+	SL_vu8sym = csymbol("vu8");
+	SL_fnsym = csymbol("fn");
+	SL_nulsym = csymbol("nul");
+	SL_alarmsym = csymbol("alarm");
+	SL_backspacesym = csymbol("backspace");
+	SL_tabsym = csymbol("tab");
+	SL_linefeedsym = csymbol("linefeed");
+	SL_vtabsym = csymbol("vtab");
+	SL_pagesym = csymbol("page");
+	SL_returnsym = csymbol("return");
+	SL_escsym = csymbol("esc");
+	SL_spacesym = csymbol("space");
+	SL_deletesym = csymbol("delete");
+	SL_newlinesym = csymbol("newline");
+	SL_builtins_table_sym = csymbol("*builtins*");
+
+	set(SL_printprettysym = csymbol("*print-pretty*"), SL_t);
+	set(SL_printreadablysym = csymbol("*print-readably*"), SL_t);
+	set(SL_printwidthsym = csymbol("*print-width*"), fixnum(SL(scr_width)));
+	set(SL_printlengthsym = csymbol("*print-length*"), SL_nil);
+	set(SL_printlevelsym = csymbol("*print-level*"), SL_nil);
+	SL(lasterror) = SL_nil;
+
+	for(i = 0; i < nelem(builtins); i++){
+		if(builtins[i].name)
+			set(symbol(builtins[i].name, false), builtin(i));
+	}
+	setc(csymbol("procedure?"), builtin(OP_FUNCTIONP));
+	setc(csymbol("top-level-bound?"), builtin(OP_BOUNDP));
+
+	SL(the_empty_vector) = tagptr(alloc_words(1), TAG_VECTOR);
+	vector_setsize(SL(the_empty_vector), 0);
+
+	cvalues_init();
+
+	set(csymbol("*os-name*"), cvalue_static_cstring(__os_name__));
+#if defined(__os_version__)
+	set(csymbol("*os-version*"), cvalue_static_cstring(__os_version__));
+#endif
+	SL(memory_exception_value) = sl_list2(SL_MemoryError, cvalue_static_cstring("out of memory"));
+
+	const builtinspec_t *b;
+	for(i = 0, b = builtin_fns; i < nelem(builtin_fns); i++, b++)
+		cbuiltin(b->name, b->fptr);
+	table_init();
+	iostream_init();
+	compress_init();
+	return 0;
+}
+
+// top level ------------------------------------------------------------------
+
+value_t
+sl_toplevel_eval(value_t expr)
+{
+	return sl_applyn(1, symbol_value(SL_evalsym), expr);
+}
+
+int
+sl_load_system_image(value_t sys_image_iostream)
+{
+	SL(loading) = true;
+	PUSH(sys_image_iostream);
+	value_t *saveSP = SL(sp);
+	SL_TRY{
+		while(1){
+			SL(sp) = saveSP;
+			value_t e = sl_read_sexpr(SL(sp)[-1]);
+			if(ios_eof(value2c(ios_t*, SL(sp)[-1])))
+				break;
+			if(isfunction(e)){
+				// stage 0 format: series of thunks
+				PUSH(e);
+				(void)_applyn(0);
+			}else{
+				// stage 1 format: list alternating symbol/value
+				while(iscons(e)){
+					symbol_t *sym = tosymbol(car_(e));
+					e = cdr_(e);
+					if(sym->binding != UNBOUND)
+						ios_printf(ios_stderr, "%s redefined on boot\n", sym->name);
+					sym->binding = car_(e);
+					e = cdr_(e);
+				}
+				break;
+			}
+		}
+	}
+	SL_CATCH_NO_INC{
+		ios_puts(ios_stderr, "fatal error during bootstrap: ");
+		sl_print(ios_stderr, SL(lasterror));
+		ios_putc(ios_stderr, '\n');
+		return -1;
+	}
+	SL(sp) = saveSP-1;
+	SL(loading) = false;
+	return 0;
+}
--- /dev/null
+++ b/src/sl.h
@@ -1,0 +1,452 @@
+#pragma once
+
+#include "platform.h"
+#include "utf8.h"
+#include "ios.h"
+#include "tbl.h"
+#include "bitvector.h"
+#include "htableh.inc"
+HTPROT(ptrhash)
+
+typedef struct sltype_t sltype_t;
+
+enum {
+	TAG_NUM,
+	TAG_CPRIM,
+	TAG_FUNCTION,
+	TAG_VECTOR,
+	TAG_NUM1,
+	TAG_CVALUE,
+	TAG_SYM,
+	TAG_CONS,
+
+	/* those were set to 7 and 3 strategically on purpose */
+	TAG_NONLEAF_MASK = TAG_CONS & TAG_VECTOR,
+};
+
+enum {
+	FLAG_CONST = 1<<0,
+	FLAG_KEYWORD = 1<<1,
+};
+
+typedef enum {
+	T_INT8, T_UINT8,
+	T_INT16, T_UINT16,
+	T_INT32, T_UINT32,
+	T_INT64, T_UINT64,
+	T_MPINT,
+	T_FLOAT,
+	T_DOUBLE,
+}numerictype_t;
+
+typedef uintptr_t value_t;
+
+#if defined(BITS64)
+typedef int64_t fixnum_t;
+#define FIXNUM_BITS 62
+#define TOP_BIT (1ULL<<63)
+#define T_FIXNUM T_INT64
+#define PRIdFIXNUM PRId64
+#else
+typedef int32_t fixnum_t;
+#define FIXNUM_BITS 30
+#define TOP_BIT (1U<<31)
+#define T_FIXNUM T_INT32
+#define PRIdFIXNUM PRId32
+#endif
+
+#if !defined(FWD_BIT)
+#define FWD_BIT TOP_BIT
+#endif
+
+typedef struct {
+	value_t car;
+	value_t cdr;
+}sl_aligned(8) cons_t;
+
+// NOTE: symbol_t MUST have the same fields as gensym_t first
+// there are places where gensyms are treated as normal symbols
+typedef struct {
+	uint64_t hash;
+	sltype_t *type;
+	value_t binding;   // global value binding
+	uint8_t numtype;
+	uint8_t size;
+	uint8_t flags;
+	uint8_t _dummy;
+	const char *name;
+}sl_aligned(8) symbol_t;
+
+typedef struct {
+	uint64_t id;
+	sltype_t *type;
+	value_t binding;
+}sl_aligned(8) gensym_t;
+
+typedef struct Builtin Builtin;
+
+struct Builtin {
+	const char *name;
+	int nargs;
+};
+
+typedef value_t (*builtin_t)(value_t*, int);
+
+#define fits_bits(x, b) (((x)>>(b-1)) == 0 || (~((x)>>(b-1))) == 0)
+#define fits_fixnum(x) fits_bits(x, FIXNUM_BITS)
+
+#define ANYARGS -10000
+#define NONNUMERIC (0xff)
+#define valid_numtype(v) ((v) <= T_DOUBLE)
+#define UNBOUND ((value_t)1) // an invalid value
+#define tag(x) ((x) & 7)
+#define ptr(x) ((void*)((uintptr_t)(x) & (~(uintptr_t)7)))
+#define tagptr(p, t) ((value_t)(p) | (t))
+#define fixnum(x) ((value_t)(x)<<2)
+#define numval(x)  ((fixnum_t)(x)>>2)
+#define uintval(x) (((unsigned int)(x))>>3)
+#define builtin(n) tagptr(((value_t)n<<3), TAG_FUNCTION)
+#define iscons(x) (tag(x) == TAG_CONS)
+#define issymbol(x) (tag(x) == TAG_SYM)
+#define isfixnum(x) (((x)&3) == TAG_NUM)
+#define bothfixnums(x, y) (isfixnum(x) && isfixnum(y))
+#define isvector(x) (tag(x) == TAG_VECTOR)
+#define iscvalue(x) (tag(x) == TAG_CVALUE)
+#define iscprim(x) (tag(x) == TAG_CPRIM)
+// doesn't lead to other values
+#define leafp(a) (((a)&TAG_NONLEAF_MASK) != TAG_NONLEAF_MASK)
+
+// allocate n consecutive conses
+#define cons_reserve(n) tagptr(alloc_words((n)*2), TAG_CONS)
+#define cons_index(c) (((cons_t*)ptr(c))-((cons_t*)SL(fromspace)))
+#define ismarked(c) bitvector_get(SL(consflags), cons_index(c))
+#define mark_cons(c) bitvector_set(SL(consflags), cons_index(c))
+#define unmark_cons(c) bitvector_reset(SL(consflags), cons_index(c))
+
+#define isforwarded(v) (*(value_t*)ptr(v) & FWD_BIT)
+#define forwardloc(v) (*(value_t*)ptr(v) ^ FWD_BIT)
+#define forward(v, to) \
+	do{ \
+		*(value_t*)ptr(v) = (value_t)(to) | FWD_BIT; \
+	}while(0)
+
+#define vector_size(v) (((size_t*)ptr(v))[0]>>2)
+#define vector_setsize(v, n) (((size_t*)ptr(v))[0] = ((n)<<2))
+#define vector_elt(v, i) (((value_t*)ptr(v))[1+(i)])
+#define vector_grow_amt(x) ((x)<8 ? 5 : 6*((x)>>3))
+// functions ending in _ are unsafe, faster versions
+#define car_(v) (((cons_t*)ptr(v))->car)
+#define cdr_(v) (((cons_t*)ptr(v))->cdr)
+#define car(v) (tocons(v)->car)
+#define cdr(v) (tocons(v)->cdr)
+#define fn_bcode(f) (((function_t*)ptr(f))->bcode)
+#define fn_vals(f) (((function_t*)ptr(f))->vals)
+#define fn_env(f) (((function_t*)ptr(f))->env)
+#define fn_name(f) (((function_t*)ptr(f))->name)
+#define set(s, v) (((symbol_t*)ptr(s))->binding = (v))
+#define setc(s, v) \
+	do{ \
+		symbol_t *sy = (symbol_t*)ptr(s); \
+		sy->flags |= FLAG_CONST; \
+		sy->binding = (v); \
+	}while(0)
+#define isconstant(s) ((s)->flags & FLAG_CONST)
+#define iskeyword(s) ((s)->flags & FLAG_KEYWORD)
+#define symbol_value(s) (((symbol_t*)ptr(s))->binding)
+#define sym_to_numtype(s) (((symbol_t*)ptr(s))->numtype)
+#define ismanaged(v) ((((uint8_t*)ptr(v)) >= SL(fromspace)) && (((uint8_t*)ptr(v)) < SL(fromspace)+SL(heapsize)))
+#define isgensym(x)  (issymbol(x) && ismanaged(x))
+#define isfunction(x) (tag(x) == TAG_FUNCTION && (x) > (N_BUILTINS<<3))
+#define iscbuiltin(x) (iscvalue(x) && cv_class(ptr(x)) == SL(builtintype))
+// utility for iterating over all arguments in a builtin
+// i=index, i0=start index, arg = var for each arg, args = arg array
+// assumes "nargs" is the argument count
+#define FOR_ARGS(i, i0, arg, args) for(i=i0; i<nargs && ((arg=args[i]) || 1); i++)
+#define N_BUILTINS ((int)N_OPCODES)
+
+#define PUSH(v) \
+	do{ \
+		*SL(sp)++ = (v); \
+	}while(0)
+#define POPN(n) \
+	do{ \
+		SL(sp) -= (n); \
+	}while(0)
+#define POP() *(--SL(sp))
+
+bool isbuiltin(value_t x) sl_constfn sl_hotfn;
+int sl_init(size_t heapsize, size_t stacksize);
+int sl_load_system_image(value_t ios);
+
+_Noreturn void sl_exit(int status);
+
+/* collector */
+value_t relocate(value_t v) sl_hotfn;
+void sl_gc(bool mustgrow);
+void sl_gc_handle(value_t *pv);
+void sl_free_gc_handles(int n);
+
+/* symbol table */
+value_t gensym(void);
+value_t symbol(const char *str, bool copy) sl_hotfn;
+value_t csymbol_(const char *str, int len);
+#define csymbol(str) csymbol_(str, sizeof(str)-1)
+const char *symbol_name(value_t v);
+
+/* read, eval, print main entry points */
+value_t sl_toplevel_eval(value_t expr);
+value_t sl_apply(value_t f, value_t l);
+value_t sl_applyn(int n, value_t f, ...);
+
+/* object model manipulation */
+value_t sl_cons(value_t a, value_t b);
+value_t sl_list2(value_t a, value_t b);
+value_t sl_listn(int n, ...);
+bool sl_isnumber(value_t v) sl_purefn;
+value_t alloc_vector(size_t n, bool init);
+
+/* consistent iswprint and wcwidth */
+int sl_iswprint(Rune c) sl_constfn;
+int sl_wcwidth(Rune c) sl_constfn;
+
+/* safe casts */
+cons_t *tocons(value_t v) sl_purefn;
+symbol_t *tosymbol(value_t v) sl_purefn;
+fixnum_t tofixnum(value_t v) sl_purefn;
+char *tostring(value_t v) sl_purefn;
+double todouble(value_t a) sl_purefn;
+
+/* conses */
+value_t mk_cons(void) sl_hotfn;
+void *alloc_words(int n) sl_hotfn;
+
+char *uint2str(char *dest, size_t len, uint64_t num, int base);
+
+/* error handling */
+typedef struct _sl_readstate_t {
+	htable_t backrefs;
+	htable_t gensyms;
+	value_t source;
+	struct _sl_readstate_t *prev;
+}sl_readstate_t;
+
+typedef struct _ectx_t {
+	sl_readstate_t *rdst;
+	struct _ectx_t *prev;
+	jmp_buf buf;
+	value_t *sp;
+	value_t *frame;
+	int ngchnd;
+}sl_exception_context_t;
+
+void free_readstate(sl_readstate_t *rs);
+
+#define SL_TRY_EXTERN \
+	sl_exception_context_t _ctx; int l__tr, l__ca; \
+	sl_savestate(&_ctx); SL(exctx) = &_ctx; \
+	if(!sl_setjmp(_ctx.buf)) \
+		for(l__tr = 1; l__tr; l__tr = 0, (void)(SL(exctx) = SL(exctx)->prev))
+
+#define SL_CATCH_EXTERN_NO_RESTORE \
+	else \
+		for(l__ca=1; l__ca;)
+
+#define SL_CATCH_EXTERN \
+	else \
+		for(l__ca=1; l__ca; l__ca=0, sl_restorestate(&_ctx))
+
+_Noreturn void lerrorf(value_t e, const char *format, ...) sl_printfmt(2, 3);
+void sl_savestate(sl_exception_context_t *_ctx);
+void sl_restorestate(sl_exception_context_t *_ctx);
+_Noreturn void sl_raise(value_t e);
+_Noreturn void type_error(const char *expected, value_t got);
+_Noreturn void bounds_error(value_t arr, value_t ind);
+_Noreturn void unbound_error(value_t sym);
+_Noreturn void arity_error(int nargs, int c);
+
+#define argcount(nargs, c) \
+	do{ \
+		if(sl_unlikely(nargs != c)) \
+			arity_error(nargs, c); \
+	}while(0)
+
+typedef struct {
+	void (*print)(value_t self, ios_t *f);
+	void (*relocate)(value_t oldv, value_t newv);
+	void (*finalize)(value_t self);
+	void (*print_traverse)(value_t self);
+} cvtable_t;
+
+typedef void (*cvinitfunc_t)(sltype_t*, value_t, void*);
+
+struct sltype_t {
+	value_t type;
+	cvtable_t *vtable;
+	sltype_t *eltype;  // for arrays
+	sltype_t *artype;  // (array this)
+	cvinitfunc_t init;
+	size_t size;
+	size_t elsz;
+	numerictype_t numtype;
+};
+
+typedef struct {
+	sltype_t *type;
+	union {
+		void *data;
+		builtin_t cbuiltin;
+	};
+	size_t len; // length of *data in bytes
+	uint8_t _space[]; // variable size
+}sl_aligned(8) cvalue_t;
+
+typedef struct {
+	sltype_t *type;
+	uint8_t _space[];
+}sl_aligned(8) cprim_t;
+
+typedef struct {
+	value_t bcode;
+	value_t vals;
+	value_t env;
+	value_t name;
+}sl_aligned(8) function_t;
+
+#define CPRIM_NWORDS sizeof(cprim_t)/sizeof(value_t)
+#define cv_class(cv) ((sltype_t*)(((uintptr_t)((cvalue_t*)cv)->type)&~(uintptr_t)3))
+#define cv_len(cv) (((cvalue_t*)(cv))->len)
+#define cv_type(cv) (cv_class(cv)->type)
+#define cv_data(cv) (((cvalue_t*)(cv))->data)
+#define cv_isstr(cv) (cv_class(cv)->eltype == SL(bytetype))
+#define cv_isPOD(cv) (cv_class(cv)->init != nil)
+#define cvalue_data(v) cv_data((cvalue_t*)ptr(v))
+#define cvalue_len(v) cv_len((cvalue_t*)ptr(v))
+#define value2c(type, v) ((type)cvalue_data(v))
+#define cp_class(cp) (((cprim_t*)(cp))->type)
+#define cp_type(cp)	(cp_class(cp)->type)
+#define cp_numtype(cp) (cp_class(cp)->numtype)
+#define cp_data(cp)	(((cprim_t*)(cp))->_space)
+// WARNING: multiple evaluation!
+#define cptr(v) (iscprim(v) ? cp_data(ptr(v)) : cvalue_data(v))
+
+#define ismpint(v) (iscvalue(v) && cp_numtype(ptr(v)) == T_MPINT)
+#define tompint(v) (*(mpint**)cv_data(ptr(v)))
+
+#define BUILTIN(lname, cname) \
+	value_t fn_builtin_##cname(value_t *args, int nargs)
+
+#define BUILTIN_FN(l, c, attr) attr BUILTIN(l, c);
+#include "builtin_fns.h"
+#undef BUILTIN_FN
+
+#include "opcodes.h"
+
+enum {
+	SL_nil = builtin(OP_LOADNIL),
+	SL_t = builtin(OP_LOADT),
+	SL_void = builtin(OP_LOADVOID),
+	SL_eof = builtin(OP_EOF_OBJECT),
+};
+
+#define N_GC_HANDLES 1024
+
+typedef struct Sl Sl;
+
+struct Sl {
+	value_t *sp;
+	uint8_t *curheap;
+	value_t *curr_frame;
+
+	uint8_t *fromspace;
+	uint8_t *tospace;
+	uint8_t *lim;
+
+	value_t *stack;
+
+	uintptr_t heapsize;//bytes
+	size_t malloc_pressure;
+	uint32_t nstack;
+
+	cvalue_t **finalizers;
+	size_t nfinalizers;
+	size_t maxfinalizers;
+
+	sl_readstate_t *readstate;
+	Tbl *symtab;
+
+	// saved execution state for an unwind target
+	sl_exception_context_t *exctx;
+	value_t *throwing_frame;  // active frame when exception was thrown
+	value_t lasterror;
+
+	sltype_t *tabletype;
+
+	sltype_t *iostreamtype;
+
+	value_t the_empty_vector;
+	value_t the_empty_string;
+	value_t memory_exception_value;
+
+	sltype_t *mpinttype;
+	sltype_t *int8type, *uint8type;
+	sltype_t *int16type, *uint16type;
+	sltype_t *int32type, *uint32type;
+	sltype_t *int64type, *uint64type;
+	sltype_t *floattype, *doubletype;
+	sltype_t *bytetype, *runetype;
+	sltype_t *stringtype, *runestringtype;
+	sltype_t *builtintype;
+
+	uint32_t gensym_ctr;
+	// two static buffers for gensym printing so there can be two
+	// gensym names available at a time, mostly for compare()
+	char gsname[2][16];
+	int gsnameno;
+
+	bool loading;
+	bool exiting;
+	bool grew;
+
+	uint32_t *consflags;
+	size_t gccalls;
+
+	htable_t printconses;
+	uint32_t printlabel;
+	int print_pretty;
+	int print_princ;
+	fixnum_t print_length;
+	fixnum_t print_level;
+	fixnum_t p_level;
+	int scr_width;
+	ssize_t hpos, vpos;
+
+	htable_t reverse_dlsym_lookup_table;
+	htable_t TypeTable;
+	int ngchandles;
+	value_t *gchandles[N_GC_HANDLES];
+};
+
+extern sl_thread(Sl *sl);
+#define SL(f) sl->f
+
+extern value_t SL_builtins_table_sym, SL_quote, SL_lambda, SL_function, SL_comma, SL_commaat;
+extern value_t SL_commadot, SL_trycatch, SL_backquote;
+extern value_t SL_conssym, SL_symbolsym, SL_fixnumsym, SL_vectorsym, SL_builtinsym, SL_vu8sym;
+extern value_t SL_defsym, SL_defmacrosym, SL_forsym, SL_setqsym;
+extern value_t SL_booleansym, SL_nullsym, SL_evalsym, SL_fnsym;
+extern value_t SL_nulsym, SL_alarmsym, SL_backspacesym, SL_tabsym, SL_linefeedsym, SL_newlinesym;
+extern value_t SL_vtabsym, SL_pagesym, SL_returnsym, SL_escsym, SL_spacesym, SL_deletesym;
+extern value_t SL_IOError, SL_ParseError, SL_TypeError, SL_ArgError, SL_MemoryError;
+extern value_t SL_DivideError, SL_BoundsError, SL_Error, SL_KeyError, SL_UnboundError;
+
+extern value_t SL_printwidthsym, SL_printreadablysym, SL_printprettysym, SL_printlengthsym;
+extern value_t SL_printlevelsym;
+extern value_t SL_arraysym;
+extern value_t SL_iostreamsym, SL_rdsym, SL_wrsym, SL_apsym, SL_crsym, SL_truncsym;
+extern value_t SL_instrsym, SL_outstrsym;
+extern value_t SL_int8sym, SL_uint8sym, SL_int16sym, SL_uint16sym, SL_int32sym, SL_uint32sym;
+extern value_t SL_int64sym, SL_uint64sym, SL_bignumsym;
+extern value_t SL_bytesym, SL_runesym, SL_floatsym, SL_doublesym;
+extern value_t SL_stringtypesym, SL_runestringtypesym;
+
+_Noreturn void slmain(const uint8_t *boot, int bootsz, int argc, char **argv);
--- /dev/null
+++ b/src/sl_arith_any.inc
@@ -1,0 +1,158 @@
+//value_t
+//sl_*_any(value_t *args, uint32_t nargs)
+// input: ACCUM_DEFAULT ARITH_OP(a,b)   MP_OP   ARITH_OVERFLOW
+// add:   0             a+b             mpadd   sadd_overflow_64
+// mul:   1             a*b             mpmul   smul_overflow_64
+
+	mpint *Maccum = nil, *m = nil;
+	int64_t Saccum = ACCUM_DEFAULT, x;
+	uint64_t u64;
+	double Faccum = ACCUM_DEFAULT;
+	bool inexact = false;
+	value_t arg;
+	numerictype_t pt;
+	void *a;
+	cprim_t *cp;
+	cvalue_t *cv;
+
+	uint32_t i, j;
+	FOR_ARGS(i, 0, arg, args){
+		if(isfixnum(arg))
+			x = numval(arg);
+		else{
+			if(iscprim(arg)){
+				cp = ptr(arg);
+				a = cp_data(cp);
+				pt = cp_numtype(cp);
+			}else if(iscvalue(arg)){
+				cv = ptr(arg);
+				a = cv_data(cv);
+				pt = cv_class(cv)->numtype;
+			}else{
+typeerr:
+				mpfree(Maccum);
+				mpfree(m);
+				type_error("number", arg);
+			}
+			switch(pt){
+			case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
+			case T_FLOAT:  Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue;
+			case T_INT8:   x = *(int8_t*)a; break;
+			case T_UINT8:  x = *(uint8_t*)a; break;
+			case T_INT16:  x = *(int16_t*)a; break;
+			case T_UINT16: x = *(uint16_t*)a; break;
+			case T_INT32:  x = *(int32_t*)a; break;
+			case T_UINT32: x = *(uint32_t*)a; break;
+			case T_INT64:  x = *(int64_t*)a; break;
+			case T_UINT64:
+				u64 = *(uint64_t*)a;
+				if(u64 > INT64_MAX){
+					x = ACCUM_DEFAULT;
+					goto overflow;
+				}
+				x = u64;
+				break;
+			case T_MPINT:
+				x = ACCUM_DEFAULT;
+				u64 = ACCUM_DEFAULT;
+				m = mpcopy(*(mpint**)a);
+				goto overflow;
+			default:
+				goto typeerr;
+			}
+		}
+
+		int64_t accu;
+		if(ARITH_OVERFLOW(Saccum, x, &accu)){
+			u64 = ACCUM_DEFAULT;
+			goto overflow;
+		}
+		Saccum = accu;
+	}
+
+	if(inexact)
+		return mk_double(ARITH_OP(Faccum, Saccum));
+	if(fits_fixnum(Saccum))
+		return fixnum((fixnum_t)Saccum);
+	u64 = ACCUM_DEFAULT;
+	x = ACCUM_DEFAULT;
+
+overflow:
+	i++;
+	if(Maccum == nil)
+		Maccum = vtomp(Saccum, nil);
+	if(m == nil)
+		m = u64 != ACCUM_DEFAULT ? uvtomp(u64, nil) : vtomp(x, nil);
+
+	MP_OP(Maccum, m, Maccum);
+
+	FOR_ARGS(j, i, arg, args){
+		if(isfixnum(arg)){
+			vtomp(numval(arg), m);
+			MP_OP(Maccum, m, Maccum);
+			continue;
+		}
+
+		if(iscprim(arg)){
+			cp = ptr(arg);
+			a = cp_data(cp);
+			pt = cp_numtype(cp);
+		}else if(iscvalue(arg)){
+			cv = ptr(arg);
+			a = cv_data(cv);
+			pt = cv_class(cv)->numtype;
+		}else{
+			goto typeerr;
+		}
+		switch(pt){
+		case T_DOUBLE: Faccum = ARITH_OP(Faccum, *(double*)a); inexact = true; continue;
+		case T_FLOAT:  Faccum = ARITH_OP(Faccum, *(float*)a); inexact = true; continue;
+		case T_INT8:   x = *(int8_t*)a; break;
+		case T_UINT8:  x = *(uint8_t*)a; break;
+		case T_INT16:  x = *(int16_t*)a; break;
+		case T_UINT16: x = *(uint16_t*)a; break;
+		case T_INT32:  x = *(int32_t*)a; break;
+		case T_UINT32: x = *(uint32_t*)a; break;
+		case T_INT64:  x = *(int64_t*)a; break;
+		case T_UINT64:
+			uvtomp(*(uint64_t*)a, m);
+			MP_OP(Maccum, m, Maccum);
+			continue;
+		case T_MPINT:
+			MP_OP(Maccum, *(mpint**)a, Maccum);
+			continue;
+		default:
+			goto typeerr;
+		}
+		vtomp(x, m);
+		MP_OP(Maccum, m, Maccum);
+	}
+
+	int n = mpsignif(Maccum);
+	if(n >= FIXNUM_BITS){
+		if(inexact){
+			dtomp(Faccum, m);
+			MP_OP(Maccum, m, Maccum);
+			n = mpsignif(Maccum);
+			if(n < FIXNUM_BITS){
+				inexact = false;
+				goto down;
+			}
+		}
+		mpfree(m);
+		return mk_mpint(Maccum);
+	}
+
+down:
+	mpfree(m);
+	Saccum = mptov(Maccum);
+	mpfree(Maccum);
+	if(inexact)
+		return mk_double(ARITH_OP(Faccum, Saccum));
+	assert(fits_fixnum(Saccum));
+	return fixnum((fixnum_t)Saccum);
+
+#undef ACCUM_DEFAULT
+#undef ARITH_OP
+#undef MP_OP
+#undef ARITH_OVERFLOW
--- /dev/null
+++ b/src/slmain.c
@@ -1,0 +1,145 @@
+#include "sl.h"
+#include "cvalues.h"
+#include "print.h"
+#include "iostream.h"
+#include "random.h"
+#include "brieflz.h"
+#include "nan.h"
+
+#if !defined(ARGBEGIN)
+/* straight from 9front */
+static char *argv0 = nil;
+#define	ARGBEGIN \
+	for((argv0 ? 0 : (argv0=*argv)), argv++, argc--; argv[0] && argv[0][0]=='-' && argv[0][1]; argc--, argv++){ \
+		const char *_args, *_argt; \
+		Rune _argc; \
+		_args = &argv[0][1]; \
+		if(_args[0]=='-' && _args[1]==0){ \
+			argc--; \
+			argv++; \
+			break; \
+		}\
+		_argc = 0; \
+		while(*_args && (_args += chartorune(&_argc, _args))) \
+			switch(_argc)
+#define	ARGEND USED(_argt); USED(_argc); USED(_args);}USED(argv); USED(argc);
+#define	ARGF() (_argt=_args, _args="", (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
+#define	ARGC() _argc
+#define	EARGF(x) (_argt=_args, _args="", (*_argt? _argt: argv[1]? (argc--, *++argv): (x, (char*)0)))
+#endif
+
+static value_t
+argv_list(int argc, char **argv)
+{
+	int i;
+	value_t lst = SL_nil, temp;
+	sl_gc_handle(&lst);
+	sl_gc_handle(&temp);
+	for(i = argc-1; i >= 0; i--){
+		temp = cvalue_static_cstring(argv[i]);
+		lst = sl_cons(temp, lst);
+	}
+	lst = sl_cons(cvalue_static_cstring(argv0), lst);
+	sl_free_gc_handles(2);
+	return lst;
+}
+
+static void
+sizesuffix(size_t *sz, char su)
+{
+	switch(tolower(su)){
+	case 'k':
+		*sz *= 1024;
+		break;
+	case 'm':
+		*sz *= 1024*1024;
+		break;
+	case 0:
+		break;
+	default:
+		ios_printf(ios_stderr, "invalid size suffix '%c'\n", su);
+		exit(1);
+	}
+}
+
+_Noreturn static void
+usage(void)
+{
+	ios_printf(ios_stderr, "%s: [-H heapsize] [-S stacksize] ...\n", argv0);
+	exit(0);
+}
+
+
+_Noreturn void
+slmain(const uint8_t *boot, int bootsz, int argc, char **argv)
+{
+	size_t heapsize = HEAP_SIZE0, stacksize = STACK_SIZE0;
+	char *e;
+
+	nan_init();
+	randomize();
+	ios_init_stdstreams();
+	mpsetminbits(sizeof(fixnum_t)*8);
+
+	ARGBEGIN{
+	case 'H':
+		heapsize = strtoull(EARGF(usage()), &e, 0);
+		sizesuffix(&heapsize, *e);
+		break;
+	case 'S':
+		stacksize = strtoull(EARGF(usage()), &e, 0);
+		sizesuffix(&stacksize, *e);
+		break;
+	case 'h':
+		usage();
+	default:
+		break;
+	}ARGEND
+
+	if(sl_init(heapsize, stacksize) != 0){
+		ios_puts(ios_stderr, "init failed\n");
+		exit(1);
+	}
+
+	value_t f = cvalue(SL(iostreamtype), (int)sizeof(ios_t));
+	sl_gc_handle(&f);
+	value_t args = argv_list(argc, argv);
+	sl_gc_handle(&args);
+	ios_t *s = value2c(ios_t*, f);
+	uint8_t *unpacked = nil;
+	if(boot[0] == 0){
+		uint32_t unpackedsz =
+			boot[1]<<0 |
+			boot[2]<<8 |
+			boot[3]<<16|
+			boot[4]<<24;
+		unpacked = MEM_ALLOC(unpackedsz);
+		unsigned long n = blz_depack_safe(boot+5, bootsz-5, unpacked, unpackedsz);
+		if(n == BLZ_ERROR){
+			ios_puts(ios_stderr, "failed to unpack boot image\n");
+			sl_exit(1);
+		}
+		boot = unpacked;
+		bootsz = n;
+	}
+	ios_static_buffer(s, boot, bootsz);
+
+	int r = 1;
+	SL_TRY_EXTERN{
+		if(sl_load_system_image(f) == 0){
+			MEM_FREE(unpacked);
+			s = value2c(ios_t*, f);
+			sl_free_gc_handles(2);
+			ios_close(s);
+			sl_applyn(1, symbol_value(symbol("__start", false)), args);
+			r = 0;
+		}
+	}
+	SL_CATCH_EXTERN_NO_RESTORE{
+		ios_puts(ios_stderr, "fatal error:\n");
+		sl_print(ios_stderr, SL(lasterror));
+		ios_putc(ios_stderr, '\n');
+		break;
+	}
+	sl_exit(r);
+}
--- a/src/string.c
+++ b/src/string.c
@@ -1,7 +1,7 @@
 /*
   string functions
 */
-#include "flisp.h"
+#include "sl.h"
 #include "operators.h"
 #include "cvalues.h"
 #include "print.h"
@@ -9,11 +9,11 @@
 #include "equal.h"
 #include "iostream.h"
 
-fl_purefn
+sl_purefn
 BUILTIN("string?", stringp)
 {
 	argcount(nargs, 1);
-	return fl_isstring(args[0]) ? FL_t : FL_nil;
+	return sl_isstring(args[0]) ? SL_t : SL_nil;
 }
 
 BUILTIN("string-length", string_length)
@@ -21,7 +21,7 @@
 	size_t start = 0;
 	if(nargs < 1 || nargs > 3)
 		argcount(nargs, 1);
-	if(!fl_isstring(args[0]))
+	if(!sl_isstring(args[0]))
 		type_error("string", args[0]);
 	size_t len = cv_len(ptr(args[0]));
 	size_t stop = len;
@@ -46,23 +46,23 @@
 	argcount(nargs, 1);
 	if(iscprim(args[0])){
 		cprim_t *cp = ptr(args[0]);
-		if(cp_class(cp) == FL(runetype)){
-			int w = fl_wcwidth(*(Rune*)cp_data(cp));
-			return w < 0 ? FL_nil : fixnum(w);
+		if(cp_class(cp) == SL(runetype)){
+			int w = sl_wcwidth(*(Rune*)cp_data(cp));
+			return w < 0 ? SL_nil : fixnum(w);
 		}
 	}
-	if(!fl_isstring(args[0]))
+	if(!sl_isstring(args[0]))
 		type_error("string", args[0]);
 	char *str = tostring(args[0]);
 	size_t len = cv_len(ptr(args[0]));
 	ssize_t w = u8_strwidth(str, len);
-	return w < 0 ? FL_nil : size_wrap(w);
+	return w < 0 ? SL_nil : size_wrap(w);
 }
 
 BUILTIN("string-reverse", string_reverse)
 {
 	argcount(nargs, 1);
-	if(!fl_isstring(args[0]))
+	if(!sl_isstring(args[0]))
 		type_error("string", args[0]);
 	size_t len = cv_len(ptr(args[0]));
 	value_t ns = cvalue_string(len);
@@ -75,8 +75,8 @@
 	argcount(nargs, 1);
 	if(iscvalue(args[0])){
 		cvalue_t *cv = ptr(args[0]);
-		fltype_t *t = cv_class(cv);
-		if(t->eltype == FL(runetype)){
+		sltype_t *t = cv_class(cv);
+		if(t->eltype == SL(runetype)){
 			size_t nr = cv_len(cv) / sizeof(Rune);
 			Rune *r = (Rune*)cv_data(cv);
 			size_t nb = runenlen(r, nr);
@@ -94,10 +94,10 @@
 {
 	bool term = false;
 	if(nargs == 2)
-		term = args[1] != FL_nil;
+		term = args[1] != SL_nil;
 	else
 		argcount(nargs, 1);
-	if(!fl_isstring(args[0]))
+	if(!sl_isstring(args[0]))
 		type_error("string", args[0]);
 	cvalue_t *cv = ptr(args[0]);
 	char *ptr = (char*)cv_data(cv);
@@ -106,7 +106,7 @@
 	size_t newsz = nc*sizeof(Rune);
 	if(term)
 		newsz += sizeof(Rune);
-	value_t runestr = cvalue(FL(runestringtype), newsz);
+	value_t runestr = cvalue(SL(runestringtype), newsz);
 	ptr = cvalue_data(args[0]);  // relocatable pointer
 	Rune *r = cvalue_data(runestr);
 	for(size_t i = 0; i < nb; i++)
@@ -118,24 +118,24 @@
 
 BUILTIN("string", string)
 {
-	if(nargs == 1 && fl_isstring(args[0]))
+	if(nargs == 1 && sl_isstring(args[0]))
 		return args[0];
 	value_t arg, buf = fn_builtin_buffer(nil, 0);
-	fl_gc_handle(&buf);
+	sl_gc_handle(&buf);
 	ios_t *s = value2c(ios_t*, buf);
-	value_t oldpr = symbol_value(FL_printreadablysym);
-	value_t oldpp = symbol_value(FL_printprettysym);
-	set(FL_printreadablysym, FL_nil);
-	set(FL_printprettysym, FL_nil);
+	value_t oldpr = symbol_value(SL_printreadablysym);
+	value_t oldpp = symbol_value(SL_printprettysym);
+	set(SL_printreadablysym, SL_nil);
+	set(SL_printprettysym, SL_nil);
 	int i;
 	FOR_ARGS(i, 0, arg, args){
 		USED(arg);
-		fl_print(s, args[i]);
+		sl_print(s, args[i]);
 	}
-	set(FL_printreadablysym, oldpr);
-	set(FL_printprettysym, oldpp);
+	set(SL_printreadablysym, oldpr);
+	set(SL_printprettysym, oldpp);
 	value_t outp = stream_to_string(&buf);
-	fl_free_gc_handles(1);
+	sl_free_gc_handles(1);
 	return outp;
 }
 
@@ -147,10 +147,10 @@
 	size_t len = cv_len(ptr(args[0]));
 	size_t dlen = cv_len(ptr(args[1]));
 	size_t ssz, tokend, tokstart, i = 0;
-	value_t first = FL_nil, c = FL_nil, last;
+	value_t first = SL_nil, c = SL_nil, last;
 	size_t junk;
-	fl_gc_handle(&first);
-	fl_gc_handle(&last);
+	sl_gc_handle(&first);
+	sl_gc_handle(&last);
 
 	do{
 		// find and allocate next token
@@ -159,7 +159,7 @@
 			tokend = i;
 		ssz = tokend - tokstart;
 		last = c; // save previous cons cell
-		c = fl_cons(cvalue_string(ssz), FL_nil);
+		c = sl_cons(cvalue_string(ssz), SL_nil);
 
 		// we've done allocation; reload movable pointers
 		s = cvalue_data(args[0]);
@@ -169,7 +169,7 @@
 			memmove(cvalue_data(car_(c)), &s[tokstart], ssz);
 
 		// link new cell
-		if(last == FL_nil)
+		if(last == SL_nil)
 			first = c;   // first time, save first cons
 		else
 			((cons_t*)ptr(last))->cdr = c;
@@ -178,7 +178,7 @@
 		// delimiter, we need to go around one more time to add an
 		// empty string. this happens when (i == len && tokend < i)
 	}while(i < len || (i == len && (tokend != i)));
-	fl_free_gc_handles(2);
+	sl_free_gc_handles(2);
 	return first;
 }
 
@@ -226,7 +226,7 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
 	return mk_rune(toupperrune(*(Rune*)cp_data(cp)));
 }
@@ -235,7 +235,7 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
 	return mk_rune(tolowerrune(*(Rune*)cp_data(cp)));
 }
@@ -244,69 +244,69 @@
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
 	return mk_rune(totitlerune(*(Rune*)cp_data(cp)));
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("char-alphabetic?", char_alphabeticp)
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
-	return isalpharune(*(Rune*)cp_data(cp)) ? FL_t : FL_nil;
+	return isalpharune(*(Rune*)cp_data(cp)) ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("char-lower-case?", char_lower_casep)
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
-	return islowerrune(*(Rune*)cp_data(cp)) ? FL_t : FL_nil;
+	return islowerrune(*(Rune*)cp_data(cp)) ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("char-upper-case?", char_upper_casep)
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
-	return isupperrune(*(Rune*)cp_data(cp)) ? FL_t : FL_nil;
+	return isupperrune(*(Rune*)cp_data(cp)) ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("char-title-case?", char_title_casep)
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
-	return istitlerune(*(Rune*)cp_data(cp)) ? FL_t : FL_nil;
+	return istitlerune(*(Rune*)cp_data(cp)) ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("char-numeric?", char_numericp)
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
-	return isdigitrune(*(Rune*)cp_data(cp)) ? FL_t : FL_nil;
+	return isdigitrune(*(Rune*)cp_data(cp)) ? SL_t : SL_nil;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("char-whitespace?", char_whitespacep)
 {
 	argcount(nargs, 1);
 	cprim_t *cp = ptr(args[0]);
-	if(!iscprim(args[0]) || cp_class(cp) != FL(runetype))
+	if(!iscprim(args[0]) || cp_class(cp) != SL(runetype))
 		type_error("rune", args[0]);
-	return isspacerune(*(Rune*)cp_data(cp)) ? FL_t : FL_nil;
+	return isspacerune(*(Rune*)cp_data(cp)) ? SL_t : SL_nil;
 }
 
 BUILTIN("string-find", string_find)
@@ -325,17 +325,17 @@
 
 	value_t v = args[1];
 	cprim_t *cp = ptr(v);
-	if(iscprim(v) && cp_class(cp) == FL(runetype)){
+	if(iscprim(v) && cp_class(cp) == SL(runetype)){
 		Rune r = *(Rune*)cp_data(cp);
 		needlesz = runetochar(cbuf, &r);
 		needle = cbuf;
 		needle[needlesz] = 0;
-	}else if(iscprim(v) && cp_class(cp) == FL(bytetype)){
+	}else if(iscprim(v) && cp_class(cp) == SL(bytetype)){
 		needlesz = 1;
 		needle = cbuf;
 		needle[0] = *(char*)cp_data(cp);
 		needle[needlesz] = 0;
-	}else if(fl_isstring(v)){
+	}else if(sl_isstring(v)){
 		cvalue_t *cv = ptr(v);
 		needlesz = cv_len(cv);
 		needle = (char*)cv_data(cv);
@@ -343,7 +343,7 @@
 		type_error("string", args[1]);
 	}
 	if(needlesz > len-start)
-		return FL_nil;
+		return SL_nil;
 	if(needlesz == 0)
 		return size_wrap(start);
 	size_t i;
@@ -351,7 +351,7 @@
 		if(s[i] == needle[0] && memcmp(&s[i+1], needle+1, needlesz-1) == 0)
 			return size_wrap(i);
 	}
-	return FL_nil;
+	return SL_nil;
 }
 
 static unsigned long
@@ -359,7 +359,7 @@
 {
 	unsigned long radix = tosize(arg);
 	if(radix < 2 || radix > 36)
-		lerrorf(FL_ArgError, "invalid radix");
+		lerrorf(SL_ArgError, "invalid radix");
 	return radix;
 }
 
@@ -380,12 +380,12 @@
 		if(cp_numtype(data) < T_FLOAT)
 			num = conv_to_uint64(cp_data(data), cp_numtype(data));
 		else if(radix != 10)
-			lerrorf(FL_ArgError, "invalid radix with floating point");
+			lerrorf(SL_ArgError, "invalid radix with floating point");
 		else
 			return fn_builtin_string(args, nargs);
 	}else if(ismpint(n)){
 		if(radix != 16 && radix != 10 && radix != 8 && radix != 4 && radix != 2)
-			lerrorf(FL_ArgError, "invalid radix with bignum");
+			lerrorf(SL_ArgError, "invalid radix with bignum");
 		mpint *i = tompint(n);
 		char *s = mptoa(i, radix, nil, 0);
 		assert(s != nil);
@@ -399,7 +399,7 @@
 	}else{
 		type_error("integer", n);
 	}
-	if(numval(fl_compare(args[0], fixnum(0), false)) < 0){
+	if(numval(sl_compare(args[0], fixnum(0), false)) < 0){
 		num = -num;
 		neg = true;
 	}
@@ -418,16 +418,16 @@
 	unsigned long radix = 0;
 	if(nargs == 2)
 		radix = get_radix_arg(args[1]);
-	if(!fl_read_numtok(str, &n, (int)radix))
-		return FL_nil;
+	if(!sl_read_numtok(str, &n, (int)radix))
+		return SL_nil;
 	return n;
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("string-utf8?", string_utf8p)
 {
 	argcount(nargs, 1);
 	char *s = tostring(args[0]);
 	size_t len = cv_len(ptr(args[0]));
-	return u8_isvalid(s, len) ? FL_t : FL_nil;
+	return u8_isvalid(s, len) ? SL_t : SL_nil;
 }
--- a/src/system.lsp
+++ b/src/system.lsp
@@ -1,4 +1,4 @@
-; femtoLisp standard library
+; StreetLISP standard library
 ; by Jeff Bezanson (C) 2009
 ; Distributed under the BSD License
 
@@ -1125,10 +1125,10 @@
   (let* ((homevar (case *os-name*
                     (("unknown") nil)
                     (("plan9") "home")
-                    (("macos") (princ "\x1b]0;femtolisp v0.999\007") nil)
+                    (("macos") (princ "\x1b]0;StreetLISP v0.999\007") nil)
                     (else "HOME")))
          (home (and homevar (os-getenv homevar)))
-         (fname (and home (string home *directory-separator* ".flisprc"))))
+         (fname (and home (string home *directory-separator* ".slrc"))))
     (when (and fname (path-exists? fname)) (load fname))))
 
 (def (__start argv)
--- a/src/table.c
+++ b/src/table.c
@@ -1,4 +1,4 @@
-#include "flisp.h"
+#include "sl.h"
 #include "equalhash.h"
 #include "cvalues.h"
 #include "types.h"
@@ -12,18 +12,18 @@
 {
 	htable_t *h = cvalue_data(v);
 	int first = 1;
-	fl_print_str(f, "#table(");
+	sl_print_str(f, "#table(");
 	for(int i = 0; i < h->size; i += 2){
 		if(h->table[i+1] != HT_NOTFOUND){
 			if(!first)
-				fl_print_str(f, "  ");
-			fl_print_child(f, (value_t)h->table[i]);
-			fl_print_chr(f, ' ');
-			fl_print_child(f, (value_t)h->table[i+1]);
+				sl_print_str(f, "  ");
+			sl_print_child(f, (value_t)h->table[i]);
+			sl_print_chr(f, ' ');
+			sl_print_child(f, (value_t)h->table[i+1]);
 			first = 0;
 		}
 	}
-	fl_print_chr(f, ')');
+	sl_print_chr(f, ')');
 }
 
 static void
@@ -69,14 +69,14 @@
 bool
 ishashtable(value_t v)
 {
-	return iscvalue(v) && cv_class(ptr(v)) == FL(tabletype);
+	return iscvalue(v) && cv_class(ptr(v)) == SL(tabletype);
 }
 
-fl_purefn
+sl_purefn
 BUILTIN("table?", tablep)
 {
 	argcount(nargs, 1);
-	return ishashtable(args[0]) ? FL_t : FL_nil;
+	return ishashtable(args[0]) ? SL_t : SL_nil;
 }
 
 htable_t *
@@ -91,16 +91,16 @@
 {
 	int cnt = nargs;
 	if(cnt & 1)
-		lerrorf(FL_ArgError, "arguments must come in pairs");
+		lerrorf(SL_ArgError, "arguments must come in pairs");
 	value_t nt;
 	// prevent small tables from being added to finalizer list
 	if(cnt <= HT_N_INLINE)
-		nt = cvalue_nofinalizer(FL(tabletype), sizeof(htable_t));
+		nt = cvalue_nofinalizer(SL(tabletype), sizeof(htable_t));
 	else
-		nt = cvalue(FL(tabletype), sizeof(htable_t)-inline_space);
+		nt = cvalue(SL(tabletype), sizeof(htable_t)-inline_space);
 	htable_t *h = cvalue_data(nt);
 	htable_new(h, cnt/2);
-	value_t k = FL_nil, arg;
+	value_t k = SL_nil, arg;
 	int i;
 	FOR_ARGS(i, 0, arg, args){
 		if(i & 1)
@@ -132,11 +132,11 @@
 static void
 key_error(value_t key)
 {
-	lerrorf(fl_list2(FL_KeyError, key), "key not found");
+	lerrorf(sl_list2(SL_KeyError, key), "key not found");
 }
 
 // (get table key [default])
-fl_purefn
+sl_purefn
 BUILTIN("get", get)
 {
 	if(nargs != 3)
@@ -152,12 +152,12 @@
 }
 
 // (has? table key)
-fl_purefn
+sl_purefn
 BUILTIN("has?", has)
 {
 	argcount(nargs, 2);
 	htable_t *h = totable(args[0]);
-	return equalhash_has(h, (void*)args[1]) ? FL_t : FL_nil;
+	return equalhash_has(h, (void*)args[1]) ? SL_t : SL_nil;
 }
 
 // (del! table key)
@@ -177,19 +177,19 @@
 	htable_t *h = totable(t);
 	int n = h->size;
 	void **table = h->table;
-	fl_gc_handle(&f);
-	fl_gc_handle(&zero);
-	fl_gc_handle(&t);
+	sl_gc_handle(&f);
+	sl_gc_handle(&zero);
+	sl_gc_handle(&t);
 	for(int i = 0; i < n; i += 2){
 		if(table[i+1] == HT_NOTFOUND)
 			continue;
-		zero = fl_applyn(3, f, (value_t)table[i], (value_t)table[i+1], zero);
+		zero = sl_applyn(3, f, (value_t)table[i], (value_t)table[i+1], zero);
 		// reload pointer
 		h = cvalue_data(t);
 		n = h->size;
 		table = h->table;
 	}
-	fl_free_gc_handles(3);
+	sl_free_gc_handles(3);
 	return zero;
 }
 
@@ -196,5 +196,5 @@
 void
 table_init(void)
 {
-	FL(tabletype) = define_opaque_type(symbol("table", false), sizeof(htable_t), &table_vtable, nil);
+	SL(tabletype) = define_opaque_type(symbol("table", false), sizeof(htable_t), &table_vtable, nil);
 }
--- a/src/table.h
+++ b/src/table.h
@@ -1,3 +1,3 @@
-bool ishashtable(value_t v) fl_purefn;
-htable_t *totable(value_t v) fl_purefn;
+bool ishashtable(value_t v) sl_purefn;
+htable_t *totable(value_t v) sl_purefn;
 void table_init(void);
--- a/src/types.c
+++ b/src/types.c
@@ -1,24 +1,24 @@
-#include "flisp.h"
+#include "sl.h"
 #include "cvalues.h"
 #include "equalhash.h"
 #include "types.h"
 
-fltype_t *
+sltype_t *
 get_type(value_t t)
 {
-	fltype_t *ft;
+	sltype_t *ft;
 	if(issymbol(t)){
 		ft = ((symbol_t*)ptr(t))->type;
 		if(ft != nil)
 			return ft;
 	}
-	void **bp = equalhash_bp(&FL(TypeTable), (void*)t);
+	void **bp = equalhash_bp(&SL(TypeTable), (void*)t);
 	if(*bp != HT_NOTFOUND){
 		assert(*bp != nil);
 		return *bp;
 	}
 
-	bool isarray = iscons(t) && car_(t) == FL_arraysym && iscons(cdr_(t));
+	bool isarray = iscons(t) && car_(t) == SL_arraysym && iscons(cdr_(t));
 	size_t sz;
 	if(isarray && !iscons(cdr_(cdr_(t)))){
 		// special case: incomplete array type
@@ -27,7 +27,7 @@
 		sz = ctype_sizeof(t);
 	}
 
-	ft = MEM_CALLOC(1, sizeof(fltype_t));
+	ft = MEM_CALLOC(1, sizeof(sltype_t));
 	assert(ft != nil);
 	ft->type = t;
 	ft->numtype = NONNUMERIC;
@@ -38,7 +38,7 @@
 	}
 	ft->size = sz;
 	if(isarray && iscons(t)){
-		fltype_t *eltype = get_type(car_(cdr_(t)));
+		sltype_t *eltype = get_type(car_(cdr_(t)));
 		assert(eltype != nil && eltype->size > 0);
 		ft->elsz = eltype->size;
 		ft->eltype = eltype;
@@ -49,19 +49,19 @@
 	return ft;
 }
 
-fltype_t *
+sltype_t *
 get_array_type(value_t eltype)
 {
-	fltype_t *et = get_type(eltype);
+	sltype_t *et = get_type(eltype);
 	if(et->artype == nil)
-		et->artype = get_type(fl_list2(FL_arraysym, eltype));
+		et->artype = get_type(sl_list2(SL_arraysym, eltype));
 	return et->artype;
 }
 
-fltype_t *
+sltype_t *
 define_opaque_type(value_t sym, size_t sz, cvtable_t *vtab, cvinitfunc_t init)
 {
-	fltype_t *ft = MEM_CALLOC(1, sizeof(fltype_t));
+	sltype_t *ft = MEM_CALLOC(1, sizeof(sltype_t));
 	assert(ft != nil);
 	ft->type = sym;
 	ft->numtype = NONNUMERIC;
@@ -74,13 +74,13 @@
 void
 relocate_typetable(void)
 {
-	htable_t *h = &FL(TypeTable);
+	htable_t *h = &SL(TypeTable);
 	for(int i = 0; i < h->size; i += 2){
 		if(h->table[i] != HT_NOTFOUND){
 			void *nv = (void*)relocate((value_t)h->table[i]);
 			h->table[i] = nv;
 			if(h->table[i+1] != HT_NOTFOUND)
-				((fltype_t*)h->table[i+1])->type = (value_t)nv;
+				((sltype_t*)h->table[i+1])->type = (value_t)nv;
 		}
 	}
 }
--- a/src/types.h
+++ b/src/types.h
@@ -1,6 +1,6 @@
 #pragma once
 
-fltype_t *get_type(value_t t);
-fltype_t *get_array_type(value_t eltype);
-fltype_t *define_opaque_type(value_t sym, size_t sz, cvtable_t *vtab, cvinitfunc_t init);
+sltype_t *get_type(value_t t);
+sltype_t *get_array_type(value_t eltype);
+sltype_t *define_opaque_type(value_t sym, size_t sz, cvtable_t *vtab, cvinitfunc_t init);
 void relocate_typetable(void);
--- a/src/utf8.c
+++ b/src/utf8.c
@@ -13,7 +13,7 @@
   A UTF-8 validation routine is included.
 */
 
-#include "flisp.h"
+#include "sl.h"
 
 static const uint32_t offsetsFromUTF8[6] = {
 	0x00000000U, 0x00003080U, 0x000E2080U,
@@ -70,7 +70,7 @@
 	assert(n >= 0);
 	for(i = w = 0; i < n;){
 		i += chartorune(&r, s+i);
-		ssize_t x = fl_wcwidth(r);
+		ssize_t x = sl_wcwidth(r);
 		if(x < 0)
 			return -1;
 		w += x;
@@ -176,7 +176,7 @@
 		}else{
 			i0 = i;
 			ch = u8_nextmemchar(src, &i);
-			if(ascii || !fl_iswprint(ch)){
+			if(ascii || !sl_iswprint(ch)){
 				buf += u8_escape_rune(buf, sz - (buf-start), ch);
 			}else{
 				i = i0;
--- a/src/utf8.h
+++ b/src/utf8.h
@@ -4,18 +4,18 @@
 #define isutf(c) (((c)&0xC0) != 0x80)
 
 /* byte offset to character number */
-size_t u8_charnum(const char *s, size_t offset) fl_purefn;
+size_t u8_charnum(const char *s, size_t offset) sl_purefn;
 
 /* next character without NUL character terminator */
 Rune u8_nextmemchar(const char *s, size_t *i);
 
 /* returns length of next utf-8 sequence */
-size_t u8_seqlen(const char *s) fl_purefn;
+size_t u8_seqlen(const char *s) sl_purefn;
 
 /* length of a utf-8 string in runes */
-size_t u8_runelen(const char *s, size_t nb) fl_purefn;
+size_t u8_runelen(const char *s, size_t nb) sl_purefn;
 
-char read_escape_control_char(char c) fl_constfn;
+char read_escape_control_char(char c) sl_constfn;
 
 /* given a wide character, convert it to an ASCII escape sequence stored in
    buf, where buf is "sz" bytes. returns the number of characters output.
@@ -41,8 +41,8 @@
                  bool escape_quotes, bool ascii);
 
 /* utility predicates used by the above */
-bool octal_digit(char c) fl_constfn;
-bool hex_digit(char c) fl_constfn;
+bool octal_digit(char c) sl_constfn;
+bool hex_digit(char c) sl_constfn;
 
 /* same as the above, but searches a buffer of a given size instead of
    a NUL-terminated string. */
@@ -49,10 +49,10 @@
 char *u8_memchr(char *s, Rune ch, size_t sz, size_t *charn);
 
 /* number of columns occupied by a string */
-ssize_t u8_strwidth(const char *s, ssize_t n) fl_purefn;
+ssize_t u8_strwidth(const char *s, ssize_t n) sl_purefn;
 
 /* determine whether a sequence of bytes is valid UTF-8. length is in bytes */
-bool u8_isvalid(const char *str, int length) fl_purefn;
+bool u8_isvalid(const char *str, int length) sl_purefn;
 
 /* reverse a UTF-8 string. len is length in bytes. dest and src must both
    be allocated to at least len+1 bytes. returns 1 for error, 0 otherwise */
--- a/src/vm.inc
+++ b/src/vm.inc
@@ -33,7 +33,7 @@
 		if(v > (N_BUILTINS<<3)){
 			nargs = n;
 			if(tail){
-				FL(curr_frame) = (value_t*)FL(curr_frame)[-3];
+				SL(curr_frame) = (value_t*)SL(curr_frame)[-3];
 				for(fixnum_t s = -1; s < (fixnum_t)n; s++)
 					bp[s] = sp[s-n];
 				sp = bp+n;
@@ -45,10 +45,10 @@
 			ip = cvalue_data(fn->bcode);
 			assert(!ismanaged((uintptr_t)ip));
 			*sp++ = fn->env;
-			*sp++ = (value_t)FL(curr_frame);
+			*sp++ = (value_t)SL(curr_frame);
 			*sp++ = nargs;
 			ipd = sp++;
-			FL(curr_frame) = sp;
+			SL(curr_frame) = sp;
 			NEXT_OP;
 		}
 		int i = uintval(v);
@@ -55,10 +55,10 @@
 		assert(isbuiltin(v));
 		fixnum_t s = builtins[i].nargs;
 		if(s >= 0){
-			FL(sp) = sp;
+			SL(sp) = sp;
 			argcount(n, s);
 		}else if(s != ANYARGS && n < -s){
-			FL(sp) = sp;
+			SL(sp) = sp;
 			argcount(n, -s);
 		}
 		// remove function arg
@@ -85,15 +85,15 @@
 			continue;
 #endif
 		}
-	}else if(fl_likely(iscbuiltin(v))){
+	}else if(sl_likely(iscbuiltin(v))){
 		value_t *p = sp - n;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		v = ((cvalue_t*)ptr(v))->cbuiltin(p, n);
 		sp = p;
 		p[-1] = v;
 		NEXT_OP;
 	}
-	FL(sp) = sp;
+	SL(sp) = sp;
 	type_error("function", v);
 }
 
@@ -104,9 +104,9 @@
 		na = GET_INT32(ip);
 		ip += 4;
 	}
-	if(fl_unlikely(nargs != na)){
+	if(sl_unlikely(nargs != na)){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		arity_error(nargs, na);
 	}
 	NEXT_OP;
@@ -118,17 +118,17 @@
 
 OP(OP_RET) {
 	value_t v = *(--sp);
-	sp = FL(curr_frame);
-	FL(curr_frame) = (value_t*)sp[-3];
-	if(FL(curr_frame) == top_frame){
-		FL(sp) = sp;
+	sp = SL(curr_frame);
+	SL(curr_frame) = (value_t*)sp[-3];
+	if(SL(curr_frame) == top_frame){
+		SL(sp) = sp;
 		return v;
 	}
 	sp -= 4+nargs;
-	ipd = FL(curr_frame)-1;
+	ipd = SL(curr_frame)-1;
 	ip = (uint8_t*)*ipd;
-	nargs = FL(curr_frame)[-2];
-	bp = FL(curr_frame) - 4 - nargs;
+	nargs = SL(curr_frame)[-2];
+	bp = SL(curr_frame) - 4 - nargs;
 	sp[-1] = v;
 	NEXT_OP;
 }
@@ -142,7 +142,7 @@
 	NEXT_OP;
 
 OP(OP_BRN)
-	ip += *(--sp) == FL_nil ? GET_INT16(ip) : 2;
+	ip += *(--sp) == SL_nil ? GET_INT16(ip) : 2;
 	NEXT_OP;
 
 OP(OP_LOADG) {
@@ -158,9 +158,9 @@
 	}
 	assert(issymbol(v));
 	symbol_t *sym = ptr(v);
-	if(fl_unlikely(sym->binding == UNBOUND)){
+	if(sl_unlikely(sym->binding == UNBOUND)){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		unbound_error(v);
 	}
 	*sp++ = sym->binding;
@@ -173,20 +173,20 @@
 	{
 		int i = n;
 		value_t a = sp[-i], b, v;
-		for(v = FL_t; i > 1; a = b){
+		for(v = SL_t; i > 1; a = b){
 			i--;
 			b = sp[-i];
 			if(bothfixnums(a, b)){
 				if((fixnum_t)a >= (fixnum_t)b){
-					v = FL_nil;
+					v = SL_nil;
 					break;
 				}
 			}else{
 				int x = numeric_compare(a, b, false, false, false);
 				if(x > 1)
-					x = numval(fl_compare(a, b, false));
+					x = numval(sl_compare(a, b, false));
 				if(x >= 0){
-					v = FL_nil;
+					v = SL_nil;
 					break;
 				}
 			}
@@ -214,7 +214,7 @@
 		*ipd = (uintptr_t)ip;
 		v = sp[-1];
 		int64_t i64;
-		b = isfixnum(v) ? fixnum_neg(v) : fl_neg(v);
+		b = isfixnum(v) ? fixnum_neg(v) : sl_neg(v);
 	}else{
 		b = sp[-1];
 	}
@@ -223,7 +223,7 @@
 		v = q;
 	else{
 		sp[-1] = b;
-		v = fl_add_any(sp-2, 2);
+		v = sl_add_any(sp-2, 2);
 	}
 	sp--;
 	sp[-1] = v;
@@ -239,7 +239,7 @@
 	NEXT_OP;
 
 OP(OP_BRNN)
-	ip += *(--sp) != FL_nil ? GET_INT16(ip) : 2;
+	ip += *(--sp) != SL_nil ? GET_INT16(ip) : 2;
 	NEXT_OP;
 
 OP(OP_DUP)
@@ -253,11 +253,11 @@
 
 OP(OP_CAR) {
 	value_t v = sp[-1];
-	if(fl_likely(iscons(v)))
+	if(sl_likely(iscons(v)))
 		v = car_(v);
-	else if(fl_unlikely(v != FL_nil)){
+	else if(sl_unlikely(v != SL_nil)){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		type_error("cons", v);
 	}
 	sp[-1] = v;
@@ -267,7 +267,7 @@
 OP(OP_CLOSURE) {
 	int x = *ip++;
 	assert(x > 0);
-	FL(sp) = sp;
+	SL(sp) = sp;
 	value_t *pv = alloc_words(
 		1+x+
 #if !defined(BITS64)
@@ -297,12 +297,12 @@
 }
 
 OP(OP_CONS) {
-	if(FL(curheap) > FL(lim)){
-		FL(sp) = sp;
-		fl_gc(0);
+	if(SL(curheap) > SL(lim)){
+		SL(sp) = sp;
+		sl_gc(0);
 	}
-	cons_t *c = (cons_t*)FL(curheap);
-	FL(curheap) += sizeof(cons_t);
+	cons_t *c = (cons_t*)SL(curheap);
+	SL(curheap) += sizeof(cons_t);
 	c->car = sp[-2];
 	c->cdr = sp[-1];
 	sp[-2] = tagptr(c, TAG_CONS);
@@ -317,11 +317,11 @@
 
 OP(OP_CDR) {
 	value_t v = sp[-1];
-	if(fl_likely(iscons(v)))
+	if(sl_likely(iscons(v)))
 		v = cdr_(v);
-	else if(fl_unlikely(v != FL_nil)){
+	else if(sl_unlikely(v != SL_nil)){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		type_error("cons", v);
 	}
 	sp[-1] = v;
@@ -329,11 +329,11 @@
 }
 
 OP(OP_LOADVOID)
-	*sp++ = FL_void;
+	*sp++ = SL_void;
 	NEXT_OP;
 
 OP(OP_NOT)
-	sp[-1] = sp[-1] == FL_nil ? FL_t : FL_nil;
+	sp[-1] = sp[-1] == SL_nil ? SL_t : SL_nil;
 	NEXT_OP;
 
 OP(OP_SETA)
@@ -357,19 +357,19 @@
 			bp[i+3] = i+1;
 			bp[i+4] = 0;
 			sp = bp+i+5;
-			FL(curr_frame) = sp;
+			SL(curr_frame) = sp;
 		}
-	}else if(fl_unlikely(s < 0)){
+	}else if(sl_unlikely(s < 0)){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
-		lerrorf(FL_ArgError, "too few arguments");
+		SL(sp) = sp;
+		lerrorf(SL_ArgError, "too few arguments");
 	}else{
 		sp++;
 		sp[-2] = i+1;
 		sp[-3] = sp[-4];
 		sp[-4] = sp[-5];
-		sp[-5] = FL_nil;
-		FL(curr_frame) = sp;
+		sp[-5] = SL_nil;
+		SL(curr_frame) = sp;
 	}
 	ipd = sp-1;
 	nargs = i+1;
@@ -385,9 +385,9 @@
 
 OP(OP_SETCAR) {
 	value_t v = sp[-2];
-	if(fl_unlikely(!iscons(v))){
+	if(sl_unlikely(!iscons(v))){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		type_error("cons", v);
 	}
 	car_(v) = sp[-1];
@@ -396,15 +396,15 @@
 }
 
 OP(OP_LOADNIL)
-	*sp++ = FL_nil;
+	*sp++ = SL_nil;
 	NEXT_OP;
 
 OP(OP_BOX) {
 	int i = *ip++;
-	FL(sp) = sp;
+	SL(sp) = sp;
 	value_t v = mk_cons();
 	car_(v) = bp[i];
-	cdr_(v) = FL_nil;
+	cdr_(v) = SL_nil;
 	bp[i] = v;
 	NEXT_OP;
 }
@@ -414,7 +414,7 @@
 	NEXT_OP;
 
 OP(OP_ATOMP)
-	sp[-1] = iscons(sp[-1]) ? FL_nil : FL_t;
+	sp[-1] = iscons(sp[-1]) ? SL_nil : SL_t;
 	NEXT_OP;
 
 OP(OP_AREF2) {
@@ -435,15 +435,15 @@
 		value_t e = sp[-i];
 		size_t isz = tosize(e);
 		if(isvector(v)){
-			if(fl_unlikely(isz >= vector_size(v))){
-				FL(sp) = sp;
+			if(sl_unlikely(isz >= vector_size(v))){
+				SL(sp) = sp;
 				bounds_error(v, e);
 			}
 			v = vector_elt(v, isz);
 			continue;
 		}
-		if(!iscons(v) && v != FL_nil){
-			FL(sp) = sp;
+		if(!iscons(v) && v != SL_nil){
+			SL(sp) = sp;
 			type_error("sequence", v);
 		}
 		for(value_t v0 = v;; isz--){
@@ -452,8 +452,8 @@
 				break;
 			}
 			v = cdr_(v);
-			if(fl_unlikely(!iscons(v))){
-				FL(sp) = sp;
+			if(sl_unlikely(!iscons(v))){
+				SL(sp) = sp;
 				bounds_error(v0, e);
 			}
 		}
@@ -466,18 +466,18 @@
 OP(OP_NANP) {
 	value_t v = sp[-1];
 	if(!iscprim(v))
-		v = FL_nil;
+		v = SL_nil;
 	else{
 		void *p = ptr(v);
 		switch(cp_numtype(p)){
 		case T_DOUBLE:
-			v = isnan(*(double*)cp_data(p)) ? FL_t : FL_nil;
+			v = isnan(*(double*)cp_data(p)) ? SL_t : SL_nil;
 			break;
 		case T_FLOAT:
-			v = isnan(*(float*)cp_data(p)) ? FL_t : FL_nil;
+			v = isnan(*(float*)cp_data(p)) ? SL_t : SL_nil;
 			break;
 		default:
-			v = FL_nil;
+			v = SL_nil;
 			break;
 		}
 	}
@@ -491,9 +491,9 @@
 
 OP(OP_SETCDR) {
 	value_t v = sp[-2];
-	if(fl_unlikely(!iscons(v))){
+	if(sl_unlikely(!iscons(v))){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		type_error("cons", v);
 	}
 	cdr_(v) = sp[-1];
@@ -521,15 +521,15 @@
 			value_t e = sp[-i];
 			size_t isz = tosize(e);
 			if(isvector(v)){
-				if(fl_unlikely(isz >= vector_size(v))){
-					FL(sp) = sp;
+				if(sl_unlikely(isz >= vector_size(v))){
+					SL(sp) = sp;
 					bounds_error(v, e);
 				}
 				v = vector_elt(v, isz);
 				continue;
 			}
-			if(!iscons(v) && v != FL_nil){
-				FL(sp) = sp;
+			if(!iscons(v) && v != SL_nil){
+				SL(sp) = sp;
 				type_error("sequence", v);
 			}
 			for(value_t v0 = v;; isz--){
@@ -538,8 +538,8 @@
 					break;
 				}
 				v = cdr_(v);
-				if(fl_unlikely(!iscons(v))){
-					FL(sp) = sp;
+				if(sl_unlikely(!iscons(v))){
+					SL(sp) = sp;
 					bounds_error(v0, e);
 				}
 			}
@@ -549,12 +549,12 @@
 	value_t e = sp[-2];
 	size_t isz = tosize(e);
 	if(isvector(v)){
-		if(fl_unlikely(isz >= vector_size(v))){
-			FL(sp) = sp;
+		if(sl_unlikely(isz >= vector_size(v))){
+			SL(sp) = sp;
 			bounds_error(v, e);
 		}
 		vector_elt(v, isz) = (e = sp[-1]);
-	}else if(iscons(v) || v == FL_nil){
+	}else if(iscons(v) || v == SL_nil){
 		for(value_t v0 = v;; isz--){
 			if(isz == 0){
 				car_(v) = (e = sp[-1]);
@@ -561,8 +561,8 @@
 				break;
 			}
 			v = cdr_(v);
-			if(fl_unlikely(!iscons(v))){
-				FL(sp) = sp;
+			if(sl_unlikely(!iscons(v))){
+				SL(sp) = sp;
 				bounds_error(v0, e);
 			}
 		}
@@ -569,7 +569,7 @@
 	}else if(isarray(v)){
 		e = cvalue_array_aset(sp-3);
 	}else{
-		FL(sp) = sp;
+		SL(sp) = sp;
 		type_error("sequence", v);
 	}
 	sp -= n;
@@ -580,9 +580,9 @@
 OP(OP_EQUAL) {
 	value_t v;
 	if(sp[-2] == sp[-1])
-		v = FL_t;
+		v = SL_t;
 	else
-		v = fl_compare(sp[-2], sp[-1], true) == 0 ? FL_t : FL_nil;
+		v = sl_compare(sp[-2], sp[-1], true) == 0 ? SL_t : SL_nil;
 	sp[-2] = v;
 	sp--;
 	NEXT_OP;
@@ -589,7 +589,7 @@
 }
 
 OP(OP_CONSP)
-	sp[-1] = iscons(sp[-1]) ? FL_t : FL_nil;
+	sp[-1] = iscons(sp[-1]) ? SL_t : SL_nil;
 	NEXT_OP;
 
 OP(OP_LOADC) {
@@ -602,15 +602,15 @@
 }
 
 OP(OP_SYMBOLP)
-	sp[-1] = issymbol(sp[-1]) ? FL_t : FL_nil;
+	sp[-1] = issymbol(sp[-1]) ? SL_t : SL_nil;
 	NEXT_OP;
 
 OP(OP_NUMBERP)
-	sp[-1] = fl_isnumber(sp[-1]) ? FL_t : FL_nil;
+	sp[-1] = sl_isnumber(sp[-1]) ? SL_t : SL_nil;
 	NEXT_OP;
 
 OP(OP_BRBOUND)
-	*sp++ = bp[GET_INT32(ip)] != UNBOUND ? FL_t : FL_nil;
+	*sp++ = bp[GET_INT32(ip)] != UNBOUND ? SL_t : SL_nil;
 	ip += 4;
 	NEXT_OP;
 
@@ -619,20 +619,20 @@
 	ip += 4;
 	int x = GET_INT32(ip);
 	ip += 4;
-	if(fl_unlikely(nargs < i)){
+	if(sl_unlikely(nargs < i)){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
-		lerrorf(FL_ArgError, "too few arguments");
+		SL(sp) = sp;
+		lerrorf(SL_ArgError, "too few arguments");
 	}
 	if(x > 0){
-		if(fl_unlikely(nargs > x)){
+		if(sl_unlikely(nargs > x)){
 			*ipd = (uintptr_t)ip;
-			FL(sp) = sp;
-			lerrorf(FL_ArgError, "too many arguments");
+			SL(sp) = sp;
+			lerrorf(SL_ArgError, "too many arguments");
 		}
 	}else
 		x = -x;
-	if(fl_likely(x > nargs)){
+	if(sl_likely(x > nargs)){
 		x -= nargs;
 		sp += x;
 		sp[-1] = sp[-x-1];
@@ -639,7 +639,7 @@
 		sp[-2] = nargs+x;
 		sp[-3] = sp[-x-3];
 		sp[-4] = sp[-x-4];
-		FL(curr_frame) = sp;
+		SL(curr_frame) = sp;
 		ipd = sp-1;
 		for(i = 0; i < x; i++)
 			bp[nargs+i] = UNBOUND;
@@ -649,7 +649,7 @@
 }
 
 OP(OP_EQ)
-	sp[-2] = sp[-2] == sp[-1] ? FL_t : FL_nil;
+	sp[-2] = sp[-2] == sp[-1] ? SL_t : SL_nil;
 	sp--;
 	NEXT_OP;
 
@@ -666,7 +666,7 @@
 OP(OP_BOUNDP) {
 	*ipd = (uintptr_t)ip;
 	symbol_t *sym = tosymbol(sp[-1]);
-	sp[-1] = sym->binding == UNBOUND ? FL_nil : FL_t;
+	sp[-1] = sym->binding == UNBOUND ? SL_nil : SL_t;
 	NEXT_OP;
 }
 
@@ -675,16 +675,16 @@
 LABEL(apply_numeq):;
 	int i = n;
 	value_t a = sp[-i], b, v;
-	for(v = FL_t; i > 1; a = b){
+	for(v = SL_t; i > 1; a = b){
 		i--;
 		b = sp[-i];
 		if(bothfixnums(a, b)){
 			if(a != b){
-				v = FL_nil;
+				v = SL_nil;
 				break;
 			}
 		}else if(numeric_compare(a, b, true, false, true) != 0){
-			v = FL_nil;
+			v = SL_nil;
 			break;
 		}
 	}
@@ -695,17 +695,17 @@
 
 OP(OP_CADR) {
 	value_t v = sp[-1];
-	if(fl_likely(iscons(v))){
+	if(sl_likely(iscons(v))){
 		v = cdr_(v);
-		if(fl_likely(iscons(v)))
+		if(sl_likely(iscons(v)))
 			v = car_(v);
 		else
 			goto LABEL(cadr_nil);
 	}else{
 LABEL(cadr_nil):
-		if(fl_unlikely(v != FL_nil)){
+		if(sl_unlikely(v != SL_nil)){
 			*ipd = (uintptr_t)ip;
-			FL(sp) = sp;
+			SL(sp) = sp;
 			type_error("cons", v);
 		}
 	}
@@ -727,10 +727,10 @@
 		*sp++ = car_(v);
 		v = cdr_(v);
 	}
-	if(v != FL_nil){
+	if(v != SL_nil){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
-		lerrorf(FL_ArgError, "apply: last argument: not a list");
+		SL(sp) = sp;
+		lerrorf(SL_ArgError, "apply: last argument: not a list");
 	}
 	n = sp-p;
 	goto LABEL(do_call);
@@ -737,12 +737,12 @@
 }
 
 OP(OP_LOADT)
-	*sp++ = FL_t;
+	*sp++ = SL_t;
 	NEXT_OP;
 
 OP(OP_BUILTINP) {
 	value_t v = sp[-1];
-	sp[-1] = (isbuiltin(v) || iscbuiltin(v)) ? FL_t : FL_nil;
+	sp[-1] = (isbuiltin(v) || iscbuiltin(v)) ? SL_t : SL_nil;
 	NEXT_OP;
 }
 
@@ -751,12 +751,12 @@
 	*ipd = (uintptr_t)ip;
 	value_t v = sp[-1];
 	int64_t i64;
-	sp[-1] = isfixnum(v) ? fixnum_neg(v) : fl_neg(v);
+	sp[-1] = isfixnum(v) ? fixnum_neg(v) : sl_neg(v);
 	NEXT_OP;
 }
 
 OP(OP_FIXNUMP)
-	sp[-1] = isfixnum(sp[-1]) ? FL_t : FL_nil;
+	sp[-1] = isfixnum(sp[-1]) ? SL_t : SL_nil;
 	NEXT_OP;
 
 OP(OP_MUL) {
@@ -763,7 +763,7 @@
 	n = *ip++;
 LABEL(apply_mul):
 	*ipd = (uintptr_t)ip;
-	value_t v = fl_mul_any(sp-n, n);
+	value_t v = sl_mul_any(sp-n, n);
 	sp -= n;
 	*sp++ = v;
 	NEXT_OP;
@@ -772,9 +772,9 @@
 OP(OP_IDIV) {
 	value_t a = sp[-2];
 	value_t b = sp[-1];
-	if(fl_unlikely(b == 0)){
+	if(sl_unlikely(b == 0)){
 		*ipd = (uintptr_t)ip;
-		FL(sp) = sp;
+		SL(sp) = sp;
 		divide_by_0_error();
 	}
 	value_t v;
@@ -782,7 +782,7 @@
 		v = fixnum((fixnum_t)a / (fixnum_t)b);
 	else{
 		*ipd = (uintptr_t)ip;
-		v = fl_idiv2(a, b);
+		v = sl_idiv2(a, b);
 	}
 	sp--;
 	sp[-1] = v;
@@ -795,15 +795,15 @@
 	*ipd = (uintptr_t)ip;
 	value_t *p = sp-n;
 	if(n == 1){
-		sp[-1] = fl_div2(fixnum(1), *p);
+		sp[-1] = sl_div2(fixnum(1), *p);
 	}else{
-		if(fl_unlikely(n > 2)){
+		if(sl_unlikely(n > 2)){
 			*sp++ = *p;
 			*p = fixnum(1);
-			p[1] = fl_mul_any(p, n);
+			p[1] = sl_mul_any(p, n);
 			*p = *(--sp);
 		}
-		value_t v = fl_div2(p[0], p[1]);
+		value_t v = sl_div2(p[0], p[1]);
 		sp -= n;
 		*sp++ = v;
 	}
@@ -813,7 +813,7 @@
 OP(OP_VECTOR) {
 	n = *ip++;
 LABEL(apply_vector):;
-	FL(sp) = sp;
+	SL(sp) = sp;
 	value_t v = alloc_vector(n, 0);
 	memcpy(&vector_elt(v, 0), sp-n, n*sizeof(value_t));
 	sp -= n;
@@ -822,7 +822,7 @@
 }
 
 OP(OP_COMPARE)
-	sp[-2] = fl_compare(sp[-2], sp[-1], false);
+	sp[-2] = sl_compare(sp[-2], sp[-1], false);
 	sp--;
 	NEXT_OP;
 
@@ -833,8 +833,8 @@
 	fixnum_t s = tofixnum(p[-3]);
 	fixnum_t hi = tofixnum(p[-2]);
 	sp += 2;
-	FL(sp) = sp;
-	for(v = FL_void; s <= hi; s++){
+	SL(sp) = sp;
+	for(v = SL_void; s <= hi; s++){
 		p[0] = p[-1];
 		p[1] = fixnum(s);
 		v = _applyn(1);
@@ -863,12 +863,12 @@
 }
 
 OP(OP_VECTORP)
-	sp[-1] = isvector(sp[-1]) ? FL_t : FL_nil;
+	sp[-1] = isvector(sp[-1]) ? SL_t : SL_nil;
 	NEXT_OP;
 
 OP(OP_TRYCATCH) {
 	*ipd = (uintptr_t)ip;
-	FL(sp) = sp;
+	SL(sp) = sp;
 	value_t v = do_trycatch();
 	sp--;
 	sp[-1] = v;
@@ -881,7 +881,7 @@
 		goto LABEL(do_add2);
 LABEL(apply_add):
 	*ipd = (uintptr_t)ip;
-	value_t v = fl_add_any(sp-n, n);
+	value_t v = sl_add_any(sp-n, n);
 	sp -= n;
 	*sp++ = v;
 	NEXT_OP;
@@ -896,11 +896,11 @@
 OP(OP_EQV) {
 	value_t v;
 	if(sp[-2] == sp[-1])
-		v = FL_t;
+		v = SL_t;
 	else if(!leafp(sp[-2]) || !leafp(sp[-1]))
-		v = FL_nil;
+		v = SL_nil;
 	else
-		v = fl_compare(sp[-2], sp[-1], true) == 0 ? FL_t : FL_nil;
+		v = sl_compare(sp[-2], sp[-1], true) == 0 ? SL_t : SL_nil;
 	sp[-2] = v;
 	sp--;
 	NEXT_OP;
@@ -916,9 +916,9 @@
 	fixnum_t s = GET_INT32(ip);
 	ip += 4;
 	*ipd = (uintptr_t)ip;
-	FL(sp) = sp;
+	SL(sp) = sp;
 	nargs = process_keys(v, i, x, labs(s)-(i+x), bp, nargs, s<0);
-	sp = FL(sp);
+	sp = SL(sp);
 	ipd = sp-1;
 	NEXT_OP;
 }
@@ -932,15 +932,15 @@
 		goto LABEL(do_neg);
 	*ipd = (uintptr_t)ip;
 	value_t *p = sp-n;
-	// we need to pass the full arglist on to fl_add_any
+	// we need to pass the full arglist on to sl_add_any
 	// so it can handle rest args properly
 	*sp++ = *p;
 	*p = fixnum(0);
-	value_t v = fl_add_any(p, n);
+	value_t v = sl_add_any(p, n);
 	int64_t i64;
-	p[1] = isfixnum(v) ? fixnum_neg(v) : fl_neg(v);
+	p[1] = isfixnum(v) ? fixnum_neg(v) : sl_neg(v);
 	p[0] = *(--sp);
-	v = fl_add_any(p, 2);
+	v = sl_add_any(p, 2);
 	sp -= n;
 	*sp++ = v;
 	NEXT_OP;
@@ -947,7 +947,7 @@
 }
 
 OP(OP_BRNL)
-	ip += *(--sp) == FL_nil ? GET_INT32(ip) : 4;
+	ip += *(--sp) == SL_nil ? GET_INT32(ip) : 4;
 	NEXT_OP;
 
 OP(OP_SETAL)
@@ -958,10 +958,10 @@
 OP(OP_BOXL) {
 	int i = GET_INT32(ip);
 	ip += 4;
-	FL(sp) = sp;
+	SL(sp) = sp;
 	value_t v = mk_cons();
 	car_(v) = bp[i];
-	cdr_(v) = FL_nil;
+	cdr_(v) = SL_nil;
 	bp[i] = v;
 	NEXT_OP;
 }
@@ -971,7 +971,7 @@
 	sp[-1] =
 		((tag(v) == TAG_FUNCTION &&
 		  (isbuiltin(v) || v>(N_BUILTINS<<3))) ||
-		 iscbuiltin(v)) ? FL_t : FL_nil;
+		 iscbuiltin(v)) ? SL_t : SL_nil;
 	NEXT_OP;
 }
 
@@ -985,7 +985,7 @@
 	NEXT_OP;
 
 OP(OP_BRNNL)
-	ip += *(--sp) != FL_nil ? GET_INT32(ip) : 4;
+	ip += *(--sp) != SL_nil ? GET_INT32(ip) : 4;
 	NEXT_OP;
 
 OP(OP_LOADCL)
--- a/test/torture.lsp
+++ b/test/torture.lsp
@@ -8,7 +8,7 @@
       0
       `(+ 1 1 1 1 1 1 1 1 1 1 ,(big (- n 1)))))
 
-; https://todo.sr.ht/~ft/femtolisp/2
+; https://todo.sr.ht/~ft/sl/2
 ;(def nst (big 100000))
 ;(write (eval nst))
 ;(newline)
--- a/tools/bootstrap.sh
+++ b/tools/bootstrap.sh
@@ -1,14 +1,14 @@
 #!/bin/sh
 test -e
-F="$(pwd)/build/flisp"
+F="$(pwd)/build/sl"
 test -x $F || { meson setup -Dbuildtype=debug build . && ninja -C build || exit 1; }
 test -x $F || { echo no $F found; exit 1; }
 cd src && \
 $F ../tools/gen.lsp && \
-cp ../boot/flisp.boot.builtin ../boot/flisp.boot.builtin.bak && \
-$F ../tools/mkboot0.lsp builtins.lsp instructions.lsp system.lsp compiler.lsp > ../boot/flisp.boot && \
-cp ../boot/flisp.boot ../boot/flisp.boot.builtin && \
+cp ../boot/sl.boot.builtin ../boot/sl.boot.builtin.bak && \
+$F ../tools/mkboot0.lsp builtins.lsp instructions.lsp system.lsp compiler.lsp > ../boot/sl.boot && \
+cp ../boot/sl.boot ../boot/sl.boot.builtin && \
 ninja -C ../build && \
 cd ../boot && \
 $F ../tools/mkboot1.lsp && \
-ninja -C ../build || { cp flisp.boot.builtin.bak flisp.boot.builtin; exit 1; }
+ninja -C ../build || { cp sl.boot.builtin.bak sl.boot.builtin; exit 1; }
--- a/tools/builtins2h.sh
+++ b/tools/builtins2h.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 set -e
 awk -F '[()]' '\
-	/^fl_.*fn/     {attr=$1; next} \
+	/^sl_.*fn/     {attr=$1; next} \
 	/^_Noreturn/   {attr=$1; next} \
 	/^BUILTIN[_]?/ {printf "BUILTIN_FN(%s, %s)\n", $2, attr} \
 	{attr=""}' $* | sort
--- a/tools/disenv.lsp
+++ b/tools/disenv.lsp
@@ -1,4 +1,4 @@
-#!/usr/bin/env flisp
+#!/usr/bin/env sl
 (for-each (lambda (e)
            (let ((v (top-level-value e)))
                 (when (and (function? v)
--- a/tools/gen.lsp
+++ b/tools/gen.lsp
@@ -138,7 +138,7 @@
     (io-write c-header "\tN_OPCODES\n}opcode_t;\n\n")
     (io-write c-header "extern const Builtin builtins[N_OPCODES];\n")
     (io-close c-header)
-    (io-write c-code "#include \"flisp.h\"\n\n")
+    (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[")
--- a/tools/mkboot1.lsp
+++ b/tools/mkboot1.lsp
@@ -4,4 +4,4 @@
 #.(load "../src/docs_extra.lsp")
 #.(load "../src/docs_ops.lsp")
 (load "../src/compiler.lsp")
-(make-system-image "flisp.boot")
+(make-system-image "sl.boot")
--