summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
...
* seq_iter: null list object if rewind not needed.Kaz Kylheku2020-06-041-6/+14
| | | | | | | | | | | | * lib.c (seq_iter_init_with_info): Take new Boolean argument indicating whether the iterator needs to support the rewind operation. If this is false, and the object is a list, then we clobber the object, in order to eliminate the GC root. (seq_iter_init, iter_begin, iter_reset): Pass 0 for the new Boolean parameter. (seq_iter_init_with_rewind): New function. (diff, isec): Use seq_iter_init_with_rewind to request an iterator with rewind support for the second sequence.
* mapping: rewrite loop using seq_info and args.Kaz Kylheku2020-06-041-19/+27
| | | | | | | | | | | | | | | * eval.c (map_common): Do not extract the arguments as a list. Do not produce a list of iterator objects. Instead, allocate an array of seq_iter_t objects on the stack using alloca, and use these for walking the input lists in parallel. Do not cons a list of the tuples coming from the lists, but rather store the tuples into a struct args, also on the stack, and invoke the function with that. Now, the only heap memory we allocate is the resulting list being accumulated. In the case of mapdo, no heap allocation takes place. However, if some of the inputs are hashes, then hash iterators get allocated in seq_iter_init. (mapcarv, mappendv, mapdov): Pass self argument to map_common, needed for seq_iter_init.
* mapcar, mappend, mapdo: merge implementations.Kaz Kylheku2020-06-041-60/+20
| | | | | | * eval.c (map_common): New static function. (mapcarv, mappendv, mapdov): Now one-line wrappers for map_common.
* maprod: bugfix: not reducing to mapcar.Kaz Kylheku2020-06-041-5/+6
| | | | | | | | | | | The one list case of maprod reduces to mappend rather than mapcar, so that [maprod identity '(1 2 3)] fails instead of producing (1 2 3). * eval.c (prod_common): Take pointer to mapping function to use in one-list case, and use it. (maprodv): Pass mapcarv to prod_common. (maprendv): Pass mappendv to prod_common.
* Convert mapping functions to new iterators.Kaz Kylheku2020-06-033-100/+91
| | | | | | | | | | | | | | | | | * eval.c (get_iter_f): Renamed to iter_from_binding_f. (iter_begin_f, iter_more_f, iter_item_f, iter_step_f): New global variables. (op_each): Follow rename of get_iter_f. (mapcarv, mappendv, lazy_mapcar_func, lazy_mapcar, lazy_mapcarv_func, lazy_mapcarv, mapdov, prod_common): Convert from car/cdr/null-test iteration to iter-begin. (eval_init): gc-protect and initialize new variables. * lib.c (mapcar_listout, mappend, mapdo): Convert to seq_iter iteration. List argument renamed to seq. (mapcar): List argument renamed to seq. * lib.h: Declarations updated with renamed arguments.
* seq_iter: integers and ranges become iterable.Kaz Kylheku2020-06-032-15/+176
| | | | | | | | | | | | | | | | | | | | | I think with the iter-begin API, we have the the "Maxwell's Equations of Iteration". This not only works well for conses, but it extends to numbers and ranges. * lib.h (seq_iter_t): New union member ul, containing a new member lim. existing len member moved into ul union. * lib.c (seq_iter_get_vec, seq_iter_peek_vec): Adjust access of len, now wrapped in union. (seq_iter_get_range_cnum, seq_iter_peek_range_cnum, seq_iter_get_range_chr, seq_iter_peek_range_chr, seq_iter_get_range_bignum, seq_iter_peek_range_bignum, seq_iter_get_chr, seq_iter_peek_chr, seq_iter_get_num, seq_iter_peek_num): New static functions. (seq_iter_init_with_info): Support RNG object, further classifying the iteration based on the type of the from element. Support numbers and characters as iterable. (iter_begin, iter_more, iter_item, iter_step, iter_reset): Support numbers directly as unencapsulated iterators.
* Convert each-family operators to use iter-begin.Kaz Kylheku2020-06-022-14/+16
| | | | | | | | | | | | | | | | | | | With this change we can do (each ((x vec)) ...) with reasonable efficiency, because we are no longer marching through the vector with cdr, copying the suffix. * eval.c (get_iter_f): New global variable. (op_each): Obtain iterators for all the objects with iter_begin, instead of treating them as lists. Probe the iterators for termination with iter_more, get the items with iter_item instead of car and step with iter_step instead of cdr. (eval_init): gc-protect the get_iter_f function and initialize it. * share/txr/stdlib/compiler.tl (expand-each): Replace the car/cdr and null testing with iter-init, iter-more, iter-item and iter-step.
* New style iteration functions.Kaz Kylheku2020-06-024-7/+276
| | | | | | | | | | | | | | | | | | | | | | | | iter-begin provides a paradigm for iteration that is more compatible with lists. If the sequence is a list, then the list itself is returned as the iterator, and the other functions are basicaly wrappers for car/cdr and null testing. Yet the API is defined in such a way that other objects can be iterated with good efficiency, at the cost of allocating a new iterator object (which can be re-used). * eval.c (eval_init): Register iter-begin, iter-more, iter-item, iter-step and iter-reset. * lib.c (seq_iter_init_with_info): New static function. (seq_iter_init): Now a thin wrapper for seq_iter_init_with_info. (iter_begin, iter_more, iter_item, iter_step, iter_reset): New functions. * lib.h (iter_begin, iter_more, iter_item, iter_step, iter_reset): New functions. * txr.1: Documented.
* Version 239.txr-239Kaz Kylheku2020-06-024-4/+31
| | | | | | | | * RELNOTES: Updated. * configure, txr.1: Bumped version and date. * share/txr/stdlib/ver.tl: Likewise.
* compiler: bugfix: missing block in dohash and each.Kaz Kylheku2020-05-311-16/+18
| | | | | | | | | | The compiler's expander for dohash, and for the each family of operators neglects to add the (block nil ...) around the forms that are expected to be in a block. * share/txr/stdlib/compiler.tl (expand-dohash, expand-each): Generate the (block nil ...) around the sys:for construct which doesn't produce one.
* vm: bugfix: bungled no-block-visible diagnosis.Kaz Kylheku2020-05-311-1/+1
| | | | | * vm.c (vm_no_block_err): Fix passing extra name argument to format that is not used in the format string.
* doc: constantp syntax formatting.Kaz Kylheku2020-05-311-1/+1
| | | | * txr.1: Fix extra whitespace around env parameter.
* streams: maintain integer format string detector.Kaz Kylheku2020-05-302-14/+30
| | | | | | | | | | | | | | | | | | | | | | | | | * configure: provide LONGLONG_TYPE and INTPTR_TYPE macros in config.h that expand to a string literal capturing the original tokens of the type that was probed. * stream.c (struct fmt): Removed size member, replaced with type string. We can match format strings to the textual type, which will work even if we cannot compile that type. So that is to say, for instance the "%I64d" entry in the table is associated with "int64", whereas an expression like sizeof (int64) won't compile where that type doesn't exist. (fmt_tab): Replace sizes with type names. Also fix an issue: %llx was replicated in three rows of the table. (detect_format_string): Determine the textual type of cnum. It is a typedef for intptr_t, and the new INPTR_TYPE macro gives the tokens that were used to typedef intptr_t. If INTPTR_TYPE happens to be "longlong_t", we use LONGLONG_TYPE in its place. Then using the determined type, we can search the table for an appropriate entry: one which matches the type and whose conversion specifier works. Also, we now test all four conversion specifiers rather than assuming that if the decimal one is okay, the others work. Plus, if a working format string is not found, we now abort.
* Replace trivial format(nil, ...) with simpler ops.Kaz Kylheku2020-05-309-53/+87
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * gencadr.txr (cadr_register): Use scat2 to glue two strings. * cadr.c: Regenerated. * lib.c (scat2, scat3): New functions. * lib.h (scat2, scat3): Declared. * liblib.c (place_instantiate, ver_instantiate, ifa_instantiate, txr_case_instantiate, with_resources_instantiate, path_test_instantiate, struct_instantiate, with_stream_instantiate, hash_instantiate, except_instantiate, type_instantiate, yield_instantiate, sock_instantiate, termios_instantiate, awk_instantiate, build_instantiate, trace_instantiate, getopts_instantiate, package_instantiate, getput_instantiate, tagbody_instantiate, pmac_instantiate, error_instantiate, keyparams_instantiate, ffi_instantiate, doloop_instantiate, stream_wrap_instantiate, asm_instantiate, compiler_instantiate, debugger_instantiate, op_instantiate, save_exe_instantiate, defset_instantiate, copy_file_instantiate): Use scat2 to glue two strings instead of format. * parser.c (find_matching_syms, hist_save, repl): Replace trivial uses of format with scat2 or scat3. * sysif.c (ensure_dir): Likewise. * txr.c (get_self_path, substitute_basename, sysroot, sysroot_init, parse_once_noerr, read_compiled_file_noerr, read_eval_stream_noerr): Likewise. * unwind.c (uw_unwind_to_exit_point): Likewise.
* quasistrings: reduce consing.Kaz Kylheku2020-05-304-11/+47
| | | | | | | | | | | | | | | | | | | Quasistrings compile to code that requires on the sys:fmt-join function to glue strings together. Rewriting that function to avoid converting its arguments from struct args * to a list. * eval.c (fmt_join): Static function removed. * lib.c (cat_str_measure, cat_str_append): more_p parameter changed to int type, which better matches the C style Boolean values it takes. (fmt_join): New external function. * lib.h: Declared. * args.h (args_more_nozap, args_get_nozap): New inline functions allowing multiple iterations over arguments without making a copy.
* signal: bugfix: sharing of alt stack.Kaz Kylheku2020-05-291-38/+36
| | | | | | | | | | | | | | | The alternative stack is shared by SIGSEGV and SIGBUS. Therefore, we cannot tear it down when disabling either signal; the other may be using it. * signal.c (stack_refcount): New static variable. (setup_alt_stack, teardown_alt_stack): Functions removed. (addref_alt_stack, release_alt_stack): New functions to manage stack with reference counting. (set_sig_handler): Rearrange the code to only call addref_alt_stack when transitioning from no-handler to handler for SIGSEGV and SIGBUS and to only call release_alt_stack when transitioning from handler to no-handler for these signals.
* search, rsearch: rewrite using seq_info and bugfix.Kaz Kylheku2020-05-253-118/+104
| | | | | | | | | | | | | | | * lib.c (seq_getpos, seq_setpos): New functions. * lib.h (seq_getpos, seq_setpos): Declared. (search_list, rsearch_list): Static functions removed. (search_common): New static function. (search, contains, rsearch): These functions are now trivial wrappers around search_common. A requirement problem is fixed in rsearch: when the key is empty, the length of sequence is returned rather than zero, because zero is obviously not the right most place where an empty key matches. * txr.1: Documentation updated.
* update: convert to seq_info.Kaz Kylheku2020-05-251-14/+11
| | | | | * lib.c (update): Function converted to seq_info classification instead of switching on type.
* rsearch: fix broken.Kaz Kylheku2020-05-251-4/+2
| | | | | | | | | | | The rsearch function is completely broken, returning incorrect values. * lib.c (search_list, rsearch_list): Update the position in the increment part of the loop. This fix only affects research, but the code is copy-and-paste, so it's good to keep them the same, and the position of the pos update is a code smell regardless.
* search/rsearch: wrong object in bad key diagnostic.Kaz Kylheku2020-05-251-2/+2
| | | | | * lib.c (search_list, rsearch_list): When the key has a bad type, don't report the seq object in its place.
* lib: combine cat_str and vscat implementations.Kaz Kylheku2020-05-241-105/+91
| | | | | | | | | | | | | | | | | | | | | | | The vscat function is white-box copy of cat_str, with just the iteration over the inputs done differently, and without the support for separators that are characters instead of strings (which was added to cat_str after vscat was forked. In this patch, the common logic underlying both functions is factored out into a small ad-hoc "struct cat_str" object which maintains the state and provides the operations to measure the pieces of the string, allocate the space, copy the pieces together and produce the resulting object. The motivation here isn't just to reduce duplication. I would like a more efficient function for catenating strings which takes a "struct args *", not requiring a list to be consed up. * lib.c (struct cat_str): New struct type. (cat_str_init, cat_str_measure, cat_str_alloc, cat_str_append, cat_str_get): New static functions. (cat_str, vscat): Considerably shorten by using the above functions.
* Fix few typos reported from Fossies.Kaz Kylheku2020-05-232-3/+3
| | | | | | | | | | | | | Fossies administrator Jens alerted me to some typos. * txr.1: Fix two instances of alphanumeric being hyphenated, and one case of invocable being rendered as invokable. * linenoise/linenoise.c (struct lino_state): Misspelled "buffer" in a comment. One other comment typos in this file is from the original code, so it stays: who needs yet another merge conflict? Not touching the original typo in example.c, either.
* Version 238.txr-238Kaz Kylheku2020-05-186-803/+839
| | | | | | | | | | * RELNOTES: Updated. * configure, txr.1: Bumped version and date. * share/txr/stdlib/ver.tl: Likewise. * txr.vim, tl.vim: Regenerated.
* New assert macro.Kaz Kylheku2020-05-184-0/+88
| | | | | | | | | | | | * eval.c (rt_assert_fail, me_assert): New static functions. (eval_init): assert macro and sys:rt-assert-fail function registered. * lib.c (func_n4ov): New function. * lib.h (func_n4ov): Declared. * txr.1: Documented.
* sort: prudently make it subject to compat valueKaz Kylheku2020-05-143-5/+27
| | | | | | | | | | | | * eval.c (eval_init): If opt_compat is 237 or less, make sort and shuffle destructive. * share/txr/stdlib/getopts.tl (opthelp): Revert previous change, restoring use of copy-list and use nsort instead of sort, so the function is not affected by the 237 compatibility being turned on. * txr.1: Add compatibility notes.
* lib: sort becomes non-destructive; nsort introduced.Kaz Kylheku2020-05-137-22/+87
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I'm fixing a historic mistake copied from ANSI Lisp, which trips up language newcomers and sometimes even experienced users. The function innocently named sort will now return newly allocated structure. The function previously called sort will be available as nsort (non-consing/allocating sort). The shuffle function also becomes pure, and is accompanied by nshuffle. * eval (me_op): Continue to use destructive sort in this legacy code that is only triggered in very old compat mode. (eval_init): Registered nsort and nshuffle. * lib.c (nsort, nshuffle): New functions introduced, closely based on sort and shuffle. (sort, shuffle): Rewritten to avoid destructive behavior: work by copying the input and calling destructive counterparts. (sort_group): Continue to use destructive sort, which is safe; the structure is locally allocated. The sort_group function has pure semantics. (grade): Likewise. * lib.h (nsort, nshuffle): Declared. * share/txr/stdlib/getopts.tl (opthelp): Replace an instance of the (sort (copy-list ...)) pattern with just (sort ...). * tags.tl (toplevel): Continue to use destructive sort to sort tags before writing the tag file; the lifetime of the tags list ends when the file is written. * tests/010/seq.txr: Switch some sort calls to nsort to keep test case working. * txr.1: Documented.
* lib: use seq-info for sort and shuffle.Kaz Kylheku2020-05-132-19/+45
| | | | | | | | * lib.c (sort, shuffle): Switch to seq_info. For consistency with sort, shuffle now handles hashes in the same peculiar way. * txr.1: Document hash behavior for sort and shuffle.
* Expose isatty function.Kaz Kylheku2020-05-112-0/+57
| | | | | | | * sysif.c (isatty_wrap): New function. (sysif_init): Register isatty intrinsic. * txr.1: Documented.
* doc: quote, umethod, hash-invert: bad syntaxKaz Kylheku2020-05-091-3/+3
| | | | | * txr.1: Remove manually added angle brackets on <form>. Fix inappropriate use of << and >>.
* configure: --help doesn't clober ./reconfigureKaz Kylheku2020-05-081-15/+16
| | | | | * configure: move the section of the script which produces ./reconfigure after the help processing.
* gc: fight spurious retention.Kaz Kylheku2020-05-061-4/+4
| | | | | | | | | | | | | | | | | I've noticed that the January 9, 2020 commit "gc: obtain stack top using alloca" triggers spurious retention when compiling with HAVE_VALGRIND. The finalization test case tests/012/fini.tl breaks because the expected finalizers are not called. Changing the (sys:gc) call to two calls to (sys:gc 1) makes it pass. The culprit seems to be the inlining of the complex function sweep into gc. It has local variables for which spaces has to be reserved, which are not used until after mark() is called; likely the values in those spaces are picked up by the stack scan. Let's make sure that functions called out of gc() are not inlined. * gc.c (mark, sweep, prepare_finals, call_finals): Mark NOTINLINE.
* funcall: fight spurious retention.Kaz Kylheku2020-05-051-4/+4
| | | | | * lib.c (funcall1, funcall2, funcall3, funcall4): Add forgotten argument zaps in the case that routes to generic_funcall.
* lib: convert counting and predicate quantifying to seq_info.Kaz Kylheku2020-05-051-65/+88
| | | | | | * lib.c (countqual, countql, countq, count_if, some_satisfy, all_satisfy, none_satisfy): Convert from list iteration to seq_info.
* compiler: rearrange handling of callsKaz Kylheku2020-05-041-33/+37
| | | | | | | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Open up the main caseq statement for handling symbols other than just special operators. Now we handle the compiler-only special operator sys:ift here, as well as the special casing for call and apply. Function calls are handled as the fallback case here now. (compiler call-fun-form): Remove the checking for ift, and for call, apply and usr:apply. Only regular case function calls are handled here now. (compiler comp-apply-call): New method dedicated for compiling calls to the call, apply or usr:apply functions, dispatched directly out of compiler compile.
* compile: don't expand.Kaz Kylheku2020-05-031-2/+2
| | | | | | | | The compile function doesn't need to expand because the input is a function that has already been expanded. * share/txr/stdlib/compiler.tl (compile): Pass the second argument to compile-toplevel to suppress expansion.
* symbol-function: bugfix: expand lambda expression.Kaz Kylheku2020-05-032-2/+3
| | | | | | | * eval.c (lookup_fun): A lambda expression must be expanded before being turned into a function. * txr.1: Documented.
* compiler: implement lambda lifting.Kaz Kylheku2020-05-031-1/+15
| | | | | | | | | | | | | | | | | This is what the recent load-time changes were grooming the compiler toward. When we compile a lambda, we can look at the function and variable refernces it is making. If the lambda makes no lexical function or variable references, we can lift that lambda into load time, so that it's instantiated once and then re-used out of a D register. Effectively, it becomes a top-level function. * share/txr/stdlib/compiler.tl (compiler comp-lambda-impl): New method, formed by renaming comp-lambda. (compiler comp-lambda): Turned not wrapper for comp-lambda impl which compiles the lambda, and checks for the conditions for hoisting it into load time, which is currently done by generating the sys:load-time-lit form around it and re-compiling.
* compiler: honor load-time in parts of loop.Kaz Kylheku2020-05-032-0/+15
| | | | | | | | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-for): If a for loop occurs in the top level, or inside a load-time, then we don't want to suppress the semantics of load-time for any parts of the loop that are repeatedly evaluated. The programmer may be doing that specifically to hoist those calculations out of the loop. We thus bind *load-time* to nil after compiling the initializing and test expressions. * txr.1: New paragraph in Notes for load-time, mentioning compiler treatment of loops and lambda. The language is deliberately general rather than being specifically about the for loop, because several loop constructs compile to the for loop, and that is also subject to future changes.
* compiler: top-level is in load-time.Kaz Kylheku2020-05-031-1/+2
| | | | | | * share/txr/stdlib/compiler.tl (compile-toplevel): Bind *load-time* to t, because of course initially we are in the top level, where load-time can be eliminated.
* compiler: check constantp in load-time.Kaz Kylheku2020-05-021-1/+1
| | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-load-time-lit): Don't hoist constant expressions into load-time, since they already get hoisted into a D register. Otherwise we just end up generating load-time code that moves from one D register to another.
* compiler: treat nested load-time forms.Kaz Kylheku2020-05-022-14/+65
| | | | | | | | | | | | | | | | | | | | | | | load-time forms nested in load-time forms have no special semantics; it's wasteful to separately hoist them into load time and store their value in their own D register. We must be careful: this is not true if a nested form occurs in a lambda. * share/txr/stdlib/compiler.tl (*load-time*): New special variable. (compiler comp-lambda): Bind *load-time* to nil around the compilation of the lambda, so load-time forms in the lambda are hoisted to load time, even if the lambda itself is wrapped in a load-time form. (compiler comp-load-time-lit): Bind *load-time* true around the compilation of the form. If *load-time* is already true, then skip the special load-time logic and just compile the enclosed form; the surrounding load-time compilation is taking care of the load-time hoisting. * txr.1: Document that load-time forms nested in load-time forms don't do anything, except in the lambda case.
* doc: new typos under User-Defined Streams.Kaz Kylheku2020-05-021-4/+4
| | | | | * txr.1: Fix typos and incorrect symbol under put-buf and fill-buf method.
* compiler: load-time: eliminate temp register.Kaz Kylheku2020-05-011-5/+3
| | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-load-time-lit): When compiling the load-time argument expression, indicate the allocated D register as the destination, rather than using a freshly allocated T register. Now we need an instruction to move into the D reg only if the fragment chose a different register.
* sockets: ipv6 address condensing rewrite.Kaz Kylheku2020-05-011-14/+12
| | | | | | | | | | | | | | | * share/txr/stdlib/socket.tl (sys:in6addr-condensed-text): Rewrite with regex based implementation that formats the number without condensing. This one has better semantics in that it finds the longest run of 0.0..0 to replace, rather than the leftmost. Ignoring this semantic difference, it also has better average performance on pseudo-random addresses, with similar performance on addresses with long condensable 0's. The original algorithm has a significantly poorer average case on random addresses, but better best case on condensable zeros like 1::1. The new algorithm could improve further with future work to make regexes faster.
* sockets: bug in formatting ipv6 address.Kaz Kylheku2020-05-011-11/+14
| | | | | | | | The str-in6addr and str-in6addr-net functions mishandle the zero address, rendering it as ":" instead of "::". * share/txr/stdlib/socket.tl (sys:in6addr-condensed-text): Test for the degenerate case and map it to "::" output.
* doc: mention zero-width bit-field at end of structure.Kaz Kylheku2020-04-271-1/+2
| | | | | * txr.1: A zero-width bit-field placed as the last member can have an effect on the structure; let's mention it.
* doc: fix wrong claim in Bitfield Allocation Rules.Kaz Kylheku2020-04-271-9/+6
| | | | | | | | * txr.1: Rewriting the last two sentences to fix the wrong claim of its last two sentences, which contradicts the correct statement in the the previous paragraph. The statements are only correct about big-endian, not about both types of machine.
* ffi: big-endian: unused parameter warnings.Kaz Kylheku2020-04-281-1/+55
| | | | | | | | | | | | | * ffi.c (ffi_i8_rput, ffi_i8_rget, ffi_u8_rput, ffi_u8_rget, ffi_i16_rput, ffi_i16_rget, ffi_u16_rput, ffi_u16_rget, ffi_i32_rput, ffi_i32_rget, ffi_u32_rput, ffi_u32_rget, ffi_char_rput, ffi_char_rget, ffi_uchar_rput, ffi_uchar_rget, ffi_bchar_rget, ffi_short_rput, ffi_short_rget, ffi_ushort_rput, ffi_ushort_rget, ffi_int_rput, ffi_int_rget, ffi_uint_rput, ffi_uint_rget, ffi_long_rput, ffi_long_rget, ffi_ulong_rput, ffi_ulong_rget, ffi_wchar_rput, ffi_wchar_rget, ffi_be_i16_rput): Add casts to suppress warnings about unused tft and self.
* Version 237.txr-237Kaz Kylheku2020-04-266-715/+771
| | | | | | | | | | * RELNOTES: Updated. * configure, txr.1: Bumped version and date. * share/txr/stdlib/ver.tl: Likewise. * txr.vim, tl.vim: Regenerated.
* Reduce footprint of :fd property.Kaz Kylheku2020-04-253-14/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Querying the :fd stream property is equivalent to calling the stream-fd function. Streams have a C virtual function get_fd, so implementing :fd in their getprop functions is redundant functionality. The stream-getprop function can test for :fd and call stream-fd, so the stream implementations don't have to deal with the :fd property. Also, there are still places in the code base that are using stream_getprop to get the file descriptor, instead of calling stream_fd. If we fix all this, then fd_k remains referenced only in a very small number of places. * socket.c (dgram_get_prop): Don't handle :fd any more. * stream.c (unimpl_get_fd): Static function removed. (fill_stream_ops): Default the get_fd function to null_get_fd instead of unimpl_get_fd, so it doesn't throw. Even a stdio stream don't throw; when the file is closed, it returns nil. (stdio_get_prop): Don't handle :fd any more. (stream_get_prop): Handle :fd here. If the stream has a get_fd function that isn't null_get_fd, then call it. Only if the stream doesn't have a get_fd function, fall back on its get_prop function. * sysif.c (mkdir_wrap, poll_wrap, simulate_setuid_setgid): Call stream_fd instead of stream_get_prop.