[PATCH] Add unboxed floating point comparison instructions.
This patch adds 5 new VM instructions (br-if-f64-<, br-if-f64-<=, br-if-f64-=, br-if-f64->, br-if-f64->=) and a compiler optimization to perform unboxed floating point number comparisons where possible. Take this contrived example code: (lambda () (let ((foo (f64vector 1 2 3))) (< (f64vector-ref foo 0) (f64vector-ref foo 1 Here is the disassembly without the optimization: 0(assert-nargs-ee/locals 1 6);; 7 slots (0 args) at (unknown file):131:3 1(make-short-immediate 6 1028) ;; #t 2(toplevel-box 5 104 88 102 #t) ;; `f64vector' 7(box-ref 3 5) 8(make-short-immediate 2 6) ;; 1 9(make-short-immediate 1 10) ;; 2 10(make-short-immediate 0 14) ;; 3 11(handle-interrupts) at (unknown file):132:37 12(call 3 4) 14(receive 1 3 7) 16(load-u64 4 0 0) at (unknown file):133:31 19(bv-f64-ref 4 5 4) 20(f64->scm 4 4) 21(load-u64 3 0 8) at (unknown file):134:31 24(bv-f64-ref 5 5 3) 25(f64->scm 5 5) 26(br-if-< 4 5 #f 4) ;; -> L1 at (unknown file):133:28 29(make-short-immediate 6 4) ;; #f L1: 30(handle-interrupts) 31(mov 5 6) 32(return-values 2) ;; 1 value And here is the disassembly with the optimization: 0(assert-nargs-ee/locals 1 6);; 7 slots (0 args) at (unknown file):1:3 1(make-short-immediate 6 1028) ;; #t 2(toplevel-box 5 102 86 100 #t) ;; `f64vector' 7(box-ref 3 5) 8(make-short-immediate 2 6) ;; 1 9(make-short-immediate 1 10) ;; 2 10(make-short-immediate 0 14) ;; 3 11(handle-interrupts) at (unknown file):2:37 12(call 3 4) 14(receive 1 3 7) 16(load-u64 4 0 0) at (unknown file):3:31 19(bv-f64-ref 4 5 4) 20(load-u64 3 0 8) at (unknown file):4:31 23(bv-f64-ref 5 5 3) 24(br-if-f64-< 4 5 #f 4) ;; -> #f at (unknown file):3:28 27(make-short-immediate 6 4) ;; #f 28(handle-interrupts) 29(mov 5 6) 30(return-values 2) ;; 1 value Much better! The f64->scm instructions have been eliminated. This greatly improves performance for things like realtime simulations that do lots of floating point vector and matrix arithmetic. Many thanks to Andy for already implementing this optimization for u64s which I shamelessly copied from and for the additional guidance on IRC. >From 5f97216c1d19e9302903235da6e89b164d10ba30 Mon Sep 17 00:00:00 2001 From: David Thompson <dthomps...@worcester.edu> Date: Mon, 12 Dec 2016 22:46:08 -0500 Subject: [PATCH] Add unboxed floating point comparison instructions. * libguile/vm-engine.c (BR_F64_ARITHMETIC): New preprocessor macro. (br_if_f64_ee, br_if_f64_lt, br_if_f64_le, br_if_f64_gt, br_if_f64_ge): New VM instructions. * module/language/cps/compile-bytecode.scm (compile-function): Emit f64 comparison instructions. * module/language/cps/effects-analysis.scm: Define effects for f64 primcalls. * module/language/cps/primitives.scm (*branching-primcall-arities*): Add arities for f64 primcalls. * module/language/cps/specialize-numbers.scm (specialize-f64-comparison): New procedure. (specialize-operations): Specialize f64 comparisons. * module/language/cps/type-fold.scm: Define branch folder aliases for f64 primcalls. * module/language/cps/types.scm: Define type checkers and comparison inferrers for f64 primcalls. (/f64, define-f64-comparison-inferrer): New syntax. (infer-f64-comparison-ranges): New procedure. * module/system/vm/assembler.scm (emit-br-if-f64-=, emit-br-if-f64-<) (emit-br-if-f64-<=, emit-br-if-f64->, emit-br-if-f64->=): Export. * module/system/vm/disassembler.scm (code-annotation): Add annotations for f64 comparison instructions. --- libguile/vm-engine.c | 68 +++--- module/language/cps/compile-bytecode.scm | 7 ++- module/language/cps/effects-analysis.scm | 5 +++ module/language/cps/primitives.scm | 7 ++- module/language/cps/specialize-numbers.scm | 49 +++-- module/language/cps/type-fold.scm | 5 +++ module/language/cps/types.scm | 30 + module/system/vm/assembler.scm | 5 +++ module/system/vm/disassembler.scm | 2 + 9 files changed, 157 insertions(+), 21 deletions(-) diff --git a/libguile/vm-engine.c b/libguile/vm-engine.c index 4406845..6a7ba51 100644 --- a/libguile/vm-engine.c +++
Attempting to unbox struct fields
Hello wingo and list, A couple days ago on #guile, I started a conversation about optimizing some record types I use for linear algebra to take advantage of unboxed arithmetic in the upcoming Guile 2.2. Andy informed me of a temporary hack I could try, but then said that The Right Thing is for Guile to unbox struct fields. So, I thought since Andy wrote such a nice post on his blog about about Guile compiler tasks [0] that maybe I would give it a try! I have gone about as far as I can on my own (not far), and seek the guiding light of the Guile maintainers to help unblock me. The task is as follows, quoting from the above mentioned blog post: Guile's "structs", on which records are implemented, support unboxed values, but these values are untyped, not really integrated with the record layer, and always boxed in the VM. Your task would be to design a language facility that allows us to declare records with typed fields, and to store unboxed values in those fields, and to cause access to their values to emit boxing/unboxing instructions around them. The optimizer will get rid of those boxing/unboxing instructions if it can. Good luck! I took an exploratory romp around the codebase and here's what I've learned: - Guile indeed supports unboxed fields in the struct implementation. Currently it only supports unboxed unsigned integers, but there's some preprocessor magic that can be removed to enable unboxed signed integers and doubles: switch (field_type) { case 'u': data[p] = SCM_NUM2ULONG (3, val); break; #if 0 case 'i': data[p] = SCM_NUM2LONG (3, val); break; case 'd': *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3); break; #endif ... - It's easy enough to create a vtable with unboxed fields: (define vtable (make-vtable "uwuw")) (define s (make-struct vtable 123 456)) (struct-ref s 0) ;; => 123 - struct-ref/immediate and struct-set!/immediate are the VM operations for reading from/writing to structs - Roughly speaking, in the case of unboxed unsigned integers, one would want to insert a scm->u64 instruction before setting the value of an unboxed field, and one would want to insert a u64->scm instructor after getting the value of an unboxed field. - In TreeIL, struct refs and sets are primcalls, and when compiling to CPS they receive some special treatment to unbox the index component of the respective operations. This might be the procedure that will insert the boxing/unboxing instructions for the struct fields, but I'm not sure. Now that I've learned a little bit, I have a bunch of questions that I cannot yet answer: - Is it possible to know the layout of a vtable at compile time? - If so, where is that information stored? - If not, does this mean that TreeIL needs to be changed to be able to store typed struct field data in order to generate the correct CPS? - Can the TreeIL format even be reasonably changed since its a public interface that people target when writing their own language implementations? Basically, how could I possibly get my hands on the vtable information at compile time? Help would be very much appreciated! Thanks, -- David Thompson GPG Key: 0FF1D807 [0] http://wingolog.org/archives/2016/02/04/guile-compiler-tasks
Re: [PATCH] ice-9: Add JSON module.
Noticed a couple of small issues after I sent the initial patch that I've fixed in my local git branch: David Thompson da...@gnu.org writes: +(define-module (ice-9 json) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:export (read-json write-json)) No need to import SRFI-1. +(define (read-zeroes port) + Read a sequence of zeroes from PORT. + (let loop ((result '())) +(match (peek-char port) + ((? eof-object?) + result) + (#\0 + (read-char port) + (loop (cons 0 result))) + (else result Never used. Removed. -- David Thompson GPG Key: 0FF1D807
[PATCH] ice-9: Add JSON module.
Hello Guilers, JSON is an commonly encountered format when writing web applications, much like XML, and I think it would be a good idea if the core Guile distribution had an SXML equivalent for JSON. This patch introduces such an interface in the (ice-9 json) module. With (ice-9 json), this expression: (@ (name . Eva Luator) (age . 24) (schemer . #t) (hobbies hacking cycling surfing)) serializes to this JSON (except not pretty-printed): { name: Eva Luator, age: 24, schemer: true, hobbies: [ hacking, cycling, surfing ] } Thanks to Mark Weaver and Chris Webber for helping come to a consensus on a good syntax for JSON objects. From 2d4d8607aedaede98f413a84f135d8798d506233 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 15 Aug 2015 14:09:23 -0400 Subject: [PATCH] ice-9: Add JSON module. * module/ice-9/json.scm: New file. * module/Makefile.am (ICE_9_SOURCES): Add it. * test-suite/tests/json.test: New file. * test-suite/Makefile.am (SCM_TESTS): Add it. * doc/ref/guile.texi (Guile Modules): Add JSON section. * doc/ref/json.texi: New file. * doc/ref/Makefile.am (guile_TEXINFOS): Add it. --- doc/ref/Makefile.am| 3 +- doc/ref/guile.texi | 2 + doc/ref/json.texi | 62 +++ module/Makefile.am | 3 +- module/ice-9/json.scm | 395 + test-suite/Makefile.am | 1 + test-suite/tests/json.test | 149 + 7 files changed, 613 insertions(+), 2 deletions(-) create mode 100644 doc/ref/json.texi create mode 100644 module/ice-9/json.scm create mode 100644 test-suite/tests/json.test diff --git a/doc/ref/Makefile.am b/doc/ref/Makefile.am index 31c26a7..5dfc019 100644 --- a/doc/ref/Makefile.am +++ b/doc/ref/Makefile.am @@ -95,7 +95,8 @@ guile_TEXINFOS = preface.texi \ goops.texi \ goops-tutorial.texi \ guile-invoke.texi \ - effective-version.texi + effective-version.texi \ + json.texi ETAGS_ARGS = $(info_TEXINFOS) $(guile_TEXINFOS) diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index db815eb..468d3a5 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -375,6 +375,7 @@ available through both Scheme and C interfaces. * Statprof::An easy-to-use statistical profiler. * SXML::Parsing, transforming, and serializing XML. * Texinfo Processing:: Munging documents written in Texinfo. +* JSON::Parsing and serializing JSON. @end menu @include slib.texi @@ -397,6 +398,7 @@ available through both Scheme and C interfaces. @include statprof.texi @include sxml.texi @include texinfo.texi +@include json.texi @include goops.texi diff --git a/doc/ref/json.texi b/doc/ref/json.texi new file mode 100644 index 000..43dba4d --- /dev/null +++ b/doc/ref/json.texi @@ -0,0 +1,62 @@ +@c -*-texinfo-*- +@c This is part of the GNU Guile Reference Manual. +@c Copyright (C) 2015 Free Software Foundation, Inc. +@c See the file guile.texi for copying conditions. +@c + +@node JSON +@section JSON + +@cindex json +@cindex (ice-9 json) + +The @code{(ice-9 json)} module provides procedures for parsing and +serializing JSON, the JavaScript Object Notation data interchange +format. For example, the JSON document: + +@example +@verbatim +{ + name: Eva Luator, + age: 24, + schemer: true, + hobbies: [ +hacking, +cycling, +surfing + ] +} +@end verbatim +@end example + +may be represented with the following s-expression: + +@example +@verbatim +(@ (name . Eva Luator) + (age . 24) + (schemer . #t) + (hobbies hacking cycling surfing)) +@end verbatim +@end example + +Strings, real numbers, @code{#t}, @code{#f}, @code{#nil}, lists, and +association lists may be serialized as JSON. Association lists +serialize to objects, and regular lists serialize to arrays. To +distinguish regular lists from association lists, the @code{@@} symbol +is used to ``tag'' the association list as a JSON object, as in the +above example. The keys of association lists may be either strings or +symbols. + +@deffn {Scheme Procedure} read-json port + +Parse JSON-encoded text from @var{port} and return its s-expression +representation. + +@end deffn + +@deffn {Scheme Procedure} write-json exp port + +Write the expression @var{exp} as JSON-encoded text to @var{port}. + +@end deffn diff --git a/module/Makefile.am b/module/Makefile.am index 7e96de7..6380953 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -256,7 +256,8 @@ ICE_9_SOURCES = \ ice-9/list.scm \ ice-9/serialize.scm \ ice-9/local-eval.scm \ - ice-9/unicode.scm + ice-9/unicode.scm \ + ice-9/json.scm srfi/srfi-64.go: srfi/srfi-64.scm srfi/srfi-64/testing.scm diff --git a/module/ice-9/json.scm b/module/ice-9/json.scm new file mode 100644 index 000..3850ee4 --- /dev/null +++ b/module/ice-9/json.scm @@ -0,0 +1,395
[PATCH] web: http: Accept blank Content-Type headers.
Hello, I encountered a bug in the HTTP header parsing bug when trying to download a file via Guix. The response had a Content-Type header, but with no value, like so: Content-Type: From reading the W3C spec[0], an unknown Content-Type header can be treated as if it were an application/octet-stream type. I'm unsure if that means even Content-Type values that have invalid syntax should be accepted or not, so I didn't try to handle them. I'm not even sure if we should be translating the empty string to application/octet-stream. I know that it shouldn't throw an excpetion, but maybe it should just return the empty list and the user can decide how to interpret it? Anyway, here's a patch to get the ball rolling. From c9994a7b94ab2c43adfea2980da99515e6292e16 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Thu, 23 Jul 2015 22:07:53 -0400 Subject: [PATCH] web: http: Accept blank Content-Type headers. * module/web/http.scm (parse-media-type): Return 'application/octet-stream' when given the empty string. * test-suite/tests/web-http.test (entity headers): Add test. --- module/web/http.scm| 10 +++--- test-suite/tests/web-http.test | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/module/web/http.scm b/module/web/http.scm index f8aa8db..6f0f6fd 100644 --- a/module/web/http.scm +++ b/module/web/http.scm @@ -271,9 +271,13 @@ as an ordered alist. (and idx (= idx (string-rindex str #\/)) (not (string-index str separators-without-slash) (define (parse-media-type str) - (if (validate-media-type str) - (string-symbol str) - (bad-header-component 'media-type str))) + (cond + ((string-null? str) +'application/octet-stream) + ((validate-media-type str) +(string-symbol str)) + (else +(bad-header-component 'media-type str (define* (skip-whitespace str #:optional (start 0) (end (string-length str))) (let lp ((i start)) diff --git a/test-suite/tests/web-http.test b/test-suite/tests/web-http.test index c59674f..0675dbc 100644 --- a/test-suite/tests/web-http.test +++ b/test-suite/tests/web-http.test @@ -267,6 +267,7 @@ (pass-if-parse content-range bytes */30 '(bytes * 30)) (pass-if-parse content-type foo/bar '(foo/bar)) (pass-if-parse content-type foo/bar; baz=qux '(foo/bar (baz . qux))) + (pass-if-parse content-type '(application/octet-stream)) (pass-if-parse expires Tue, 15 Nov 1994 08:12:31 GMT (string-date Tue, 15 Nov 1994 08:12:31 + ~a, ~d ~b ~Y ~H:~M:~S ~z)) -- 2.4.3 -- David Thompson GPG Key: 0FF1D807
[PATCH] socket: Add AF_NETLINK support.
Hello Guile hackers, This is my first attempt at providing support for AF_NETLINK sockets in Guile, based on a preliminary patch that Ludovic sent me. Netlink sockets are supported only on Linux. The ultimate goal of this work is to be able to create virtual ethernet devices from Scheme code. There are no tests yet and I'm not sure if I went overboard by defining all of the numerous netlink families and multicast group constants. Feedback requested! :) This patch is for stable-2.0. Thanks, From 3fed7633ee4556907408c55ae29c12641ad6d80c Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sun, 3 May 2015 09:35:49 -0400 Subject: [PATCH] socket: Add AF_NETLINK support. * libguile/socket.c (scm_fill_sockaddr, _scm_from_sockaddr, scm_to_sockaddr): Add AF_NETLINK cases. (AF_NETLINK, PF_NETLINK, NETLINK_ROUTE, NETLINK_USERSOCK, NETLINK_FIREWALL, NETLINK_SOCK_DIAG, NETLINK_NFLOG, NETLINK_XFRM, NETLINK_SELINUX, NETLINK_ISCSI, NETLINK_AUDIT, NETLINK_FIB_LOOKUP, NETLINK_CONNECTOR, NETLINK_NETFILTER, NETLINK_IP6_FW, NETLINK_DNRTMSG, NETLINK_UEVENT, NETLINK_GENERIC, NETLINK_SCSITRANSPORT, NETLINK_ECRYPTFS, NETLINK_RDMA, NETLINK_CRYPTO, RTNLGRP_NONE, RTNGRP_LINK, RTNGRP_NOTIFY, RTNGRP_NEIGH, RTNGRP_TC, RTNGRP_IPV4_IFADDR, RTNGRP_IPV4_MROUTE, RTNGRP_IPV4_ROUTE, RTNGRP_IPV4_RULE, RTNGRP_IPV6_IFADDR, RTNGRP_IPV6_MROUTE, RTNGRP_IPV6_ROUTE, RTNGRP_IPV6_IFINFO, RTNGRP_DECnet_IFADDR, RTNGRP_DECnet_ROUTE, RTNGRP_DECnet_RULE, RTNGRP_IPV6_PREFIX, RTNGRP_IPV6_RULE, RTNGRP_ND_USEROPT, RTNGRP_PHONET_IFADDR, RTNGRP_PHONET_ROUTE, RTNGRP_DCB, RTNGRP_IPV4_NETCONF, RTNGRP_IPV6_NETCONF, RTNGRP_MDB): New Scheme variables. * module/ice-9/networking.scm (sockaddr:pid, sockaddr:groups): New procedures. * doc/ref/posix.texi (make-socket-address, connect, bind): Document AF_NETLINK usage. (sockaddr:pid, sockaddr:groups): Document new procedures. (socket): Document PF_NETLINK family constant. --- doc/ref/posix.texi | 17 libguile/socket.c | 203 module/ice-9/networking.scm | 2 + 3 files changed, 222 insertions(+) diff --git a/doc/ref/posix.texi b/doc/ref/posix.texi index ad5460c..33fe185 100644 --- a/doc/ref/posix.texi +++ b/doc/ref/posix.texi @@ -2950,6 +2950,7 @@ created with, @deffn {Scheme Procedure} make-socket-address AF_INET ipv4addr port @deffnx {Scheme Procedure} make-socket-address AF_INET6 ipv6addr port [flowinfo [scopeid]] @deffnx {Scheme Procedure} make-socket-address AF_UNIX path +@deffnx {Scheme Procedure} make-socket-address AF_NETLINK pid groups @deffnx {C Function} scm_make_socket_address (family, address, arglist) Return a new socket address object. The first argument is the address family, one of the @code{AF} constants, then the arguments vary @@ -2964,6 +2965,9 @@ arguments may be given (both integers, default 0). For @code{AF_UNIX} the argument is a filename (a string). +For @code{AF_NETLINK}, the arguments are a process ID and a multicast +groups bitmask. This socket type is only available on Linux. + The C function @code{scm_make_socket_address} takes the @var{family} and @var{address} arguments directly, then @var{arglist} is a list of further arguments, being the port for IPv4, port and optional flowinfo @@ -3004,6 +3008,16 @@ For an @code{AF_INET6} socket address object @var{sa}, return the scope ID value. @end deffn +@deffn {Scheme Procedure} sockaddr:pid sa +For an @code{AF_NETLINK} socket address object @var{sa}, return the +process ID number. +@end deffn + +@deffn {Scheme Procedure} sockaddr:groups sa +For an @code{AF_NETLINK} socket address object @var{sa}, return the +multicast groups bitmask. +@end deffn + @tpindex @code{struct sockaddr} @tpindex @code{sockaddr} The functions below convert to and from the C @code{struct sockaddr} @@ -3075,6 +3089,7 @@ the system, @defvar PF_UNIX @defvarx PF_INET @defvarx PF_INET6 +@defvarx PF_NETLINK @end defvar The possible values for @var{style} are as follows, again where @@ -3213,6 +3228,7 @@ The return value is unspecified. @deffnx {Scheme Procedure} connect sock AF_INET ipv4addr port @deffnx {Scheme Procedure} connect sock AF_INET6 ipv6addr port [flowinfo [scopeid]] @deffnx {Scheme Procedure} connect sock AF_UNIX path +@deffnx {Scheme Procedure} connect sock AF_NETLINK pid groups @deffnx {C Function} scm_connect (sock, fam, address, args) Initiate a connection on socket port @var{sock} to a given address. The destination is either a socket address object, or arguments the @@ -3229,6 +3245,7 @@ same as @code{make-socket-address} would take to make such an object @deffnx {Scheme Procedure} bind sock AF_INET ipv4addr port @deffnx {Scheme Procedure} bind sock AF_INET6 ipv6addr port [flowinfo [scopeid]] @deffnx {Scheme Procedure} bind sock AF_UNIX path +@deffnx {Scheme Procedure} bind sock AF_NETLINK pid groups @deffnx {C Function} scm_bind (sock, fam, address, args) Bind socket port @var{sock
Handling HTTP Upgrade requests
I've been tinkering with adding WebSockets[0] support to Guile's HTTP arsenal. The first blocking issue I've come across is that an HTTP server must be able to detect the Upgrade header[1] and change protocols. In my case, once a client thread accepts a WebSocket connection, it should speak the WebSocket protocol, not HTTP. Here's an example of a backtrace that you'd see after a successful WebSocket handshake, when the client tries to actually make use of the socket: In ice-9/boot-9.scm: 171:12 3 (with-throw-handler #t #procedure 1720560 at web/... #) In web/server/http.scm: 126:17 2 (#procedure 1720560 at web/server/http.scm:125:15 ()) In web/request.scm: 204:31 1 (read-request #closed: file 0 ()) In ice-9/boot-9.scm: 106:20 0 (#procedure 10ce380 at ice-9/boot-9.scm:97:6 (thr... ...) ERROR: Bad request: Bad Request-Line: \x81\x86B\x93�Q Does anyone have an idea about how to approach this problem? Thanks in advance! [0] http://www.websocket.org/ [1] http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
Re: WebSockets
Digging up this old thread. :) Neil Jerram n...@ossau.homelinux.net writes: I'm interested in adding support for WebSockets (http://tools.ietf.org/html/rfc6455) to Guile's web modules. Is anyone else interested in - or possibly already working on - that? Did you ever decide to work on this? I'm also interested in getting WebSockets support into Guile. -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
MIME type guessing module
Hello Guile hackers, Recently I've taken to writing simple web servers in Guile. Each time I write one I wish that core Guile came with a procedure to guess the mime type of a file. Such a procedure would be very useful when serving arbitrary static files from disk. However, I can't figure out the best way to implement it. Here are 3 possible ways of guessing a MIME type: 1) Use a lookup table that maps file extensions to MIME types. This is the simplest method as it would only test file extensions. Python does this, see: https://docs.python.org/2/library/mimetypes.html 2) Use pipes to read the output of the 'file' utility. The guessing will be more accurate because 'file' inspects a file's contents to make better guesses. 3) Use the FFI to call libmagic. Same benefits as above, but better because we can use the FFI instead of subprocesses and pipes. 2 and 3 both have the disadvantage of requiring an additional dependency, which seems hard to justify for such a minor feature. I wrote a simple static file server (inspired by Python's SimpleHTTPServer) that I would like to contribute once this blocker is resolved. Thoughts? Would this be useful at all? Thanks, -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
Re: inotify ffi
Eli Zaretskii e...@gnu.org writes: Why not use the glib file monitoring instead? It is much more portable, and has an inotify back-end AFAIK. If you're only after inotify, glib seems like a heavy dependency. -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
Re: inotify ffi
Eli Zaretskii e...@gnu.org writes: But inotify is practically a single-OS solution. How does it make sense for Guile to support file notifications only on one platform? That effectively limits packages that use Guile as an extension language to that single platform. From what I could see, this is a third-party library, not one intended for Guile core. If such support were to be added to Guile core, I would agree that it should be cross-platform. I'm interested in file notifications for a project of mine, but I'm not sure I would want to introduce glib as a dependency if I'm only using that one feature. -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
[ANN] guile-toxcore
Hello guilers, A couple months ago I started a project to create Guile bindings for Tox, the free software Skype replacement. So far, I have wrapped the core, group chat, and file transfer functions. Audio/video functions still need to be wrapped. Tox is still under heavy development with no official stable release, so work is also needed to keep this library in sync with the libtoxcore project. One of my goals with this project is to write a bot that users can add as a friend and use to test text/audio/video chat. Currently, I have a working text chat echo bot. I was going to wait to announce this until it was more complete, but I've been busy with other projects. Help is welcomed. :) The source code is hosted on Gitorious: https://gitorious.org/guile-toxcore/guile-toxcore -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
Re: [ANN] guile-toxcore
David Thompson dthomps...@worcester.edu writes: One of my goals with this project is to write a bot that users can add as a friend and use to test text/audio/video chat. Currently, I have a working text chat echo bot. Here's the config for the example client (examples/client.scm) that provides the echo bot functionality: (use-modules (tox util)) (define tox-bootstrap-nodes '(((ip . 192.254.75.98) (id . 951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F) (port . 33445) (ipv6? . #t)) ((ip . 144.76.60.215) (id . 04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F) (port . 33445) (ipv6? . #t)) ((ip . 23.226.230.47) (id . A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074) (port . 33445) (ipv6? . #t)) ((ip . 37.187.20.216) (id . 4FD54CFD426A338399767E56FD0F44F5E35FA8C38C8E87C8DC3FEAC0160F8E17) (port . 33445) (ipv6? . #t)) ((ip . 54.199.139.199) (id . 7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029) (port . 33445) (ipv6? . #f)) ((ip . 37.59.102.176) (id . B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B) (port . 33445) (ipv6? . #t)) ((ip . 192.210.149.121) (id . F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67) (port . 33445) (ipv6? . #f)) ((ip . 37.187.46.132) (id . 5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331) (port . 33445) (ipv6? . #t (define (tox-friend-names tox) (map (lambda (friend-number) (tox-friend-name tox friend-number)) (tox-friend-list tox))) (set-tox-name tox Tox Test Bot) (set-tox-status-message tox Hanging around) (add-hook! tox-friend-request-hook (lambda (tox public-key message) (format #t Friend request:\nClient ID: ~a\nMessage: ~a\n\n (bytevector-hex-string public-key) message) (tox-add-friend-no-request tox public-key))) (add-hook! tox-message-hook (lambda (tox friend message) (let ((name (tox-friend-name tox friend)) (response (format #f I received the message: \~a\ message))) (format #t ~a says: ~a\n name message) (tox-send-message tox friend response -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
Re: [FEATURE Request] Built-in server should support a thunk as body
Hi Nala, Nala Ginrut nalagin...@gmail.com writes: I'm trying to handle static file with our sendfile, but I realized it's impossible to call it in the handler of run-server. Although sanitize-response supports procedure as body, it never let me use sendfile at any chance, because the final writing operation should be delayed to server-impl-write. If I do it in advanced (in sanitize-response), the body will appear before the http header, which is wrong way. My suggestion is to support thunk as body, the thunk included body writing operation, and sanitize-response will pass it to the next step without any cooking. When server-impl-write detected it's a thunk, it'll call it directly to write the body rather than calling write-response-body. Of course, in this way, users have to pass Content-Length manually in build-response. Consider the size of file will be confirmed when calling sendfile, it's easy to do that. In short, my approach is some kind of lazy evaluation for body handling. I can format a patch if it's agreed. Comments? I'm currently writing a web application using Guile's built-in HTTP server. To serve static files, I build a response like: (values `((content-type . (text/css))) (call-with-input-file file-name get-bytevector-all)) Since the response body can be a string, bytevector, or lambda, I tried using sendfile: (values `((content-type . (text/css))) (lambda (output) (call-with-input-file file-name (lambda (input) (sendfile output input file-size) However, it didn't work because 'output' is a string port, but sendfile requires file ports. Does your proposal give us access to a file port that we can write to? I'm still learning to use Guile's HTTP modules and serving static files was something that confused me for awhile. -- David Thompson Web Developer - Free Software Foundation - http://fsf.org GPG Key: 0FF1D807 Support the FSF: https://fsf.org/donate
Re: Welcome Mark as new co-maintainer
Ludovic Courtès l...@gnu.org writes: Hello Guilers, I’m happy to announce that Mark H. Weaver has now been officially appointed as Guile co-maintainer by the GNU Project overseers, along with Andy and myself. Mark has been doing excellent work on Guile for several years, tirelessly looking for improvements, fearlessly treading into scary places like psyntax and I/O ports, so I’m glad to have him officially on board now. Welcome, Mark! :-) Ludo’. Awesome news! Mark has helped me understand Guile concepts and improve myself as a programmer on numerous occasions since I first joined #guile about 2 years ago. I wouldn't be the avid Guiler that I am today without him. Congrats, Mark! - Dave
Re: [PATCH] Test for weak pairs in hash-for-each
David Thompson dthomps...@worcester.edu writes: Hello, Updated patch attached that fixes a small style issue. - Dave From 1bbf073905bc12f80b0a32fc6311163a0b0ab849 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 8 Mar 2014 17:15:52 -0500 Subject: [PATCH] Test for deleted weak pairs in hash-for-each. * libguile/hashtab.c (hash-for-each): Test for deleted weak pairs. * test-suite/tests/hash.test: Add test case. --- libguile/hashtab.c | 4 +++- test-suite/tests/hash.test | 12 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libguile/hashtab.c b/libguile/hashtab.c index 9107ce5..44db051 100644 --- a/libguile/hashtab.c +++ b/libguile/hashtab.c @@ -1464,7 +1464,9 @@ scm_internal_hash_for_each_handle (scm_t_hash_handle_fn fn, void *closure, handle = SCM_CAR (ls); if (!scm_is_pair (handle)) SCM_WRONG_TYPE_ARG (SCM_ARG3, buckets); - fn (closure, handle); + if (!SCM_HASHTABLE_WEAK_P (table) + || !SCM_WEAK_PAIR_DELETED_P (handle)) +fn (closure, handle); ls = SCM_CDR (ls); } } diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test index 64d10bb..4c21d71 100644 --- a/test-suite/tests/hash.test +++ b/test-suite/tests/hash.test @@ -347,3 +347,15 @@ (pass-if (equal? 2 (hash-count (lambda (k v) (string? v)) table) + +;;; +;;; weak key hash table +;;; + +(with-test-prefix weak key hash table + (pass-if hash-for-each after gc +(let ((table (make-weak-key-hash-table))) + (hashq-set! table (list 'foo) 'bar) + (gc) + ;; Iterate over deleted weak ref without crashing. + (unspecified? (hash-for-each (lambda (key value) key) table) -- 1.8.5.3
[PATCH] Test for weak pairs in hash-for-each
Hello all, This patch fixes a segfault that occurs when iterating over a weak hash table with deleted weak pairs. WDYT? - Dave From 531c773dae023f15e0719d76a4352064e3681a7b Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 8 Mar 2014 17:15:52 -0500 Subject: [PATCH] Test for deleted weak pairs in hash-for-each. * libguile/hashtab.c (hash-for-each): Test for deleted weak pairs. * test-suite/tests/hash.test: Add test case. --- libguile/hashtab.c | 4 +++- test-suite/tests/hash.test | 12 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libguile/hashtab.c b/libguile/hashtab.c index 9107ce5..c5277c1 100644 --- a/libguile/hashtab.c +++ b/libguile/hashtab.c @@ -1464,7 +1464,9 @@ scm_internal_hash_for_each_handle (scm_t_hash_handle_fn fn, void *closure, handle = SCM_CAR (ls); if (!scm_is_pair (handle)) SCM_WRONG_TYPE_ARG (SCM_ARG3, buckets); - fn (closure, handle); + if (!SCM_HASHTABLE_WEAK_P (table) || + !SCM_WEAK_PAIR_DELETED_P (handle)) +fn (closure, handle); ls = SCM_CDR (ls); } } diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test index 64d10bb..4c21d71 100644 --- a/test-suite/tests/hash.test +++ b/test-suite/tests/hash.test @@ -347,3 +347,15 @@ (pass-if (equal? 2 (hash-count (lambda (k v) (string? v)) table) + +;;; +;;; weak key hash table +;;; + +(with-test-prefix weak key hash table + (pass-if hash-for-each after gc +(let ((table (make-weak-key-hash-table))) + (hashq-set! table (list 'foo) 'bar) + (gc) + ;; Iterate over deleted weak ref without crashing. + (unspecified? (hash-for-each (lambda (key value) key) table) -- 1.8.5.3
Re: Fwd: PATCH - Add cooperative REPL server module
Mark H Weaver m...@netris.org writes: Hi David, Your latest patch looks great to me. I have only one request: please update the docstrings of 'spawn-coop-repl-server' and 'poll-coop-repl-server' to match their current descriptions in the manual, except without texinfo markup, as usual. Done. Updated patch attached. Other than that, I think the patch is ready to push, although of course MVars have to go in first. Now it's my turn to write docs, and tests :) Yay! Thanks. Thanks again! Mark - Dave From 9ec93726bf96c38ff1a6b704269578f1a1081962 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sun, 19 Jan 2014 13:16:02 -0500 Subject: [PATCH] Add cooperative REPL server module. * module/system/repl/coop-server.scm: New module. * module/system/repl/repl.scm (start-repl): Extract body to start-repl*. (start-repl*): New procedure. (run-repl): Extract body to run-repl*. (run-repl*): New procedure. * module/system/repl/server.scm (run-server): Extract body to run-server*. (run-server*): New procedure. * doc/ref/api-evaluation.texi: Add docs. * module/Makefile.am: Add system/repl/coop-server.scm to SYSTEM_SOURCES. --- doc/ref/api-evaluation.texi| 45 +++ module/Makefile.am | 3 +- module/system/repl/coop-server.scm | 160 + module/system/repl/repl.scm| 11 ++- module/system/repl/server.scm | 5 +- 5 files changed, 220 insertions(+), 4 deletions(-) create mode 100644 module/system/repl/coop-server.scm diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi index 7d67d9a..27585e6 100644 --- a/doc/ref/api-evaluation.texi +++ b/doc/ref/api-evaluation.texi @@ -23,6 +23,7 @@ loading, evaluating, and compiling Scheme code at run time. * Local Evaluation::Evaluation in a local lexical environment. * Local Inclusion:: Compile-time inclusion of one file in another. * REPL Servers::Serving a REPL over a socket. +* Cooperative REPL Servers::REPL server for single-threaded applications. @end menu @@ -1281,6 +1282,50 @@ with no arguments. Closes the connection on all running server sockets. @end deffn +@node Cooperative REPL Servers +@subsection Cooperative REPL Servers + +@cindex Cooperative REPL server + +The procedures in this section are provided by +@lisp +(use-modules (system repl coop-server)) +@end lisp + +Whereas ordinary REPL servers run in their own threads (@pxref{REPL +Servers}), sometimes it is more convenient to provide REPLs that run at +specified times within an existing thread, for example in programs +utilizing an event loop or in single-threaded programs. This allows for +safe access and mutation of a program's data structures from the REPL, +without concern for thread synchronization. + +Although the REPLs are run in the thread that calls +@code{spawn-coop-repl-server} and @code{poll-coop-repl-server}, +dedicated threads are spawned so that the calling thread is not blocked. +The spawned threads read input for the REPLs and to listen for new +connections. + +Cooperative REPL servers must be polled periodically to evaluate any +pending expressions by calling @code{poll-coop-repl-server} with the +object returned from @code{spawn-coop-repl-server}. The thread that +calls @code{poll-coop-repl-server} will be blocked for as long as the +expression takes to be evaluated or if the debugger is entered. + +@deffn {Scheme Procedure} spawn-coop-repl-server [server-socket] +Create and return a new cooperative REPL server object, and spawn a new +thread to listen for connections on @var{server-socket}. Proper +functioning of the REPL server requires that +@code{poll-coop-repl-server} be called periodically on the returned +server object. +@end deffn + +@deffn {Scheme Procedure} poll-coop-repl-server coop-server +Poll the cooperative REPL server @var{coop-server} and apply a pending +operation if there is one, such as evaluating an expression typed at the +REPL prompt. This procedure must be called from the same thread that +called @code{spawn-coop-repl-server}. +@end deffn + @c Local Variables: @c TeX-master: guile.texi @c End: diff --git a/module/Makefile.am b/module/Makefile.am index 8a7befd..b7960dc 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -360,7 +360,8 @@ SYSTEM_SOURCES =\ system/repl/common.scm \ system/repl/command.scm \ system/repl/repl.scm\ - system/repl/server.scm + system/repl/server.scm \ + system/repl/coop-server.scm LIB_SOURCES = \ statprof.scm \ diff --git a/module/system/repl/coop-server.scm b/module/system/repl/coop-server.scm new file mode 100644 index 000..41759c9 --- /dev/null +++ b/module/system/repl/coop-server.scm @@ -0,0 +1,160 @@ +;;; Cooperative REPL server + +;; Copyright (C) 2014 Free Software Foundation, Inc. + +;; This library is free software; you can redistribute it and/or +;; modify it under
Re: Fwd: PATCH - Add cooperative REPL server module
) at threads.c:1019 #24 0x76cf8b83 in GC_inner_start_routine () from /usr/lib/x86_64-linux-gnu/libgc.so.1 #25 0x76cf3e72 in GC_call_with_stack_base () from /usr/lib/x86_64-linux-gnu/libgc.so.1 #26 0x772fae0e in start_thread (arg=0x74ea2700) at pthread_create.c:311 #27 0x770300fd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113 Please see below for comments. Thanks for the further review. Updated patch attached. My technical writing skills aren't what they should be, so an extra thanks for helping with the documentation. - Dave From 952e2b3f199031896996b33bc058e42586cbc69e Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sun, 19 Jan 2014 13:16:02 -0500 Subject: [PATCH] Add cooperative REPL server module. * module/system/repl/coop-server.scm: New module. * module/system/repl/repl.scm (start-repl): Extract body to start-repl*. (start-repl*): New procedure. (run-repl): Extract body to run-repl*. (run-repl*): New procedure. * module/system/repl/server.scm (run-server): Extract body to run-server*. (run-server*): New procedure. * doc/ref/api-evaluation.texi: Add docs. * module/Makefile.am: Add system/repl/coop-server.scm to SYSTEM_SOURCES. --- doc/ref/api-evaluation.texi| 45 +++ module/Makefile.am | 3 +- module/system/repl/coop-server.scm | 156 + module/system/repl/repl.scm| 11 ++- module/system/repl/server.scm | 5 +- 5 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 module/system/repl/coop-server.scm diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi index 7d67d9a..27585e6 100644 --- a/doc/ref/api-evaluation.texi +++ b/doc/ref/api-evaluation.texi @@ -23,6 +23,7 @@ loading, evaluating, and compiling Scheme code at run time. * Local Evaluation::Evaluation in a local lexical environment. * Local Inclusion:: Compile-time inclusion of one file in another. * REPL Servers::Serving a REPL over a socket. +* Cooperative REPL Servers::REPL server for single-threaded applications. @end menu @@ -1281,6 +1282,50 @@ with no arguments. Closes the connection on all running server sockets. @end deffn +@node Cooperative REPL Servers +@subsection Cooperative REPL Servers + +@cindex Cooperative REPL server + +The procedures in this section are provided by +@lisp +(use-modules (system repl coop-server)) +@end lisp + +Whereas ordinary REPL servers run in their own threads (@pxref{REPL +Servers}), sometimes it is more convenient to provide REPLs that run at +specified times within an existing thread, for example in programs +utilizing an event loop or in single-threaded programs. This allows for +safe access and mutation of a program's data structures from the REPL, +without concern for thread synchronization. + +Although the REPLs are run in the thread that calls +@code{spawn-coop-repl-server} and @code{poll-coop-repl-server}, +dedicated threads are spawned so that the calling thread is not blocked. +The spawned threads read input for the REPLs and to listen for new +connections. + +Cooperative REPL servers must be polled periodically to evaluate any +pending expressions by calling @code{poll-coop-repl-server} with the +object returned from @code{spawn-coop-repl-server}. The thread that +calls @code{poll-coop-repl-server} will be blocked for as long as the +expression takes to be evaluated or if the debugger is entered. + +@deffn {Scheme Procedure} spawn-coop-repl-server [server-socket] +Create and return a new cooperative REPL server object, and spawn a new +thread to listen for connections on @var{server-socket}. Proper +functioning of the REPL server requires that +@code{poll-coop-repl-server} be called periodically on the returned +server object. +@end deffn + +@deffn {Scheme Procedure} poll-coop-repl-server coop-server +Poll the cooperative REPL server @var{coop-server} and apply a pending +operation if there is one, such as evaluating an expression typed at the +REPL prompt. This procedure must be called from the same thread that +called @code{spawn-coop-repl-server}. +@end deffn + @c Local Variables: @c TeX-master: guile.texi @c End: diff --git a/module/Makefile.am b/module/Makefile.am index 8a7befd..b7960dc 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -360,7 +360,8 @@ SYSTEM_SOURCES =\ system/repl/common.scm \ system/repl/command.scm \ system/repl/repl.scm\ - system/repl/server.scm + system/repl/server.scm \ + system/repl/coop-server.scm LIB_SOURCES = \ statprof.scm \ diff --git a/module/system/repl/coop-server.scm b/module/system/repl/coop-server.scm new file mode 100644 index 000..4c8dc77 --- /dev/null +++ b/module/system/repl/coop-server.scm @@ -0,0 +1,156 @@ +;;; Cooperative REPL server + +;; Copyright (C) 2014 Free Software Foundation, Inc. + +;; This library is free software
PATCH - Add cooperative REPL server module
Hey all, Attached is a patch to add a cooperative REPL server to Guile. This new type of REPL server allows programs that run an event loop (like a game or a simulation) to make use of a REPL server that doesn't present a common pitfall of multithreaded programs: Crashing when 2 threads write to the same resource at the same time. The cooperative REPL ensures that evaluation only happens within the context of a single thread, and the user can control when evaluation is allowed to happen. By cooperative, I mean that the client REPL's are run as coroutines using prompts. All of the REPL's run within the same thread, the thread that calls (spawn-coop-server) and later (poll-coop-server). Reading user input is passed off to another thread and the REPL prompt is aborted. To actually evaluate code, the user must call (poll-coop-server) periodically. Only one REPL can evaluate code at a time. Things seem to be working well. I did basic tests by connecting to the server via telnet and later (when I was confident that I wouldn't crash Emacs) via Geiser. This patch is built on top of Mark Weaver's patch to add the (ice-9 mvars) module. What do you think? - Dave Thompson From 6c23c19610c1ab884d0a8ba2f3d1a94d72022303 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sun, 19 Jan 2014 13:16:02 -0500 Subject: [PATCH] Add cooperative REPL server module. * module/system/repl/coop-server.scm: New module. * module/system/repl/repl.scm (start-repl): Extract body to start-repl*. (start-repl*): New procedure. * module/system/repl/server.scm (run-server): Extract body to run-server*. (run-server*): New procedure. * doc/ref/api-evaluation.texi: Add docs. --- doc/ref/api-evaluation.texi| 46 +++-- module/system/repl/coop-server.scm | 133 + module/system/repl/repl.scm| 9 ++- module/system/repl/server.scm | 3 + 4 files changed, 183 insertions(+), 8 deletions(-) create mode 100644 module/system/repl/coop-server.scm diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi index 63b1d60..2fa3e62 100644 --- a/doc/ref/api-evaluation.texi +++ b/doc/ref/api-evaluation.texi @@ -1234,11 +1234,6 @@ to evaluate an installed file from source, instead of relying on the @cindex REPL server -The procedures in this section are provided by -@lisp -(use-modules (system repl server)) -@end lisp - When an application is written in Guile, it is often convenient to allow the user to be able to interact with it by evaluating Scheme expressions in a REPL. @@ -1248,6 +1243,11 @@ which permits interaction over a local or TCP connection. Guile itself uses them internally to implement the @option{--listen} switch, @ref{Command-line Options}. +To use the REPL server, include the following module: +@lisp +(use-modules (system repl server)) +@end lisp + @deffn {Scheme Procedure} make-tcp-server-socket [#:host=#f] @ [#:addr] [#:port=37146] Return a stream socket bound to a given address @var{addr} and port @@ -1275,6 +1275,42 @@ with no arguments. Closes the connection on all running server sockets. @end deffn +For some programs, the regular REPL server may be inadequate. For +example, the main thread of a realtime simulation runs a loop that +processes user input and integrates the simulation. Using the regular +REPL server, the main thread and a REPL client thread could attempt to +write to the same resource at the same time, causing the program to +crash. Additionally, some programs rely on thread-specific context, so +evaluating code in another thread does not have the desired effect. The +cooperative REPL server solves this problem by running all of the client +REPLs within the same thread. In order to prevent blocking, the +responsibility of reading user input is passed to another thread. To +integrate this server within a loop, the loop must poll the server +periodically to evaluate any pending expressions. + +The interface is essentially the same as the regular REPL server module, +but with slightly different procedure names. + +To use the cooperative REPL server, include the following module: +@lisp +(use-modules (system repl coop-server)) +@end lisp + +@deffn {Scheme Procedure} run-coop-server [server-socket] +@deffnx {Scheme Procedure} spawn-coop-server [server-socket] +Create and run a cooperative REPL server, making it available over the +given @var{server-socket}. If @var{server-socket} is not provided, it +defaults to the socket created by calling @code{make-tcp-server-socket} +with no arguments. + +@code{run-coop-server} runs the server in the current thread, whereas +@code{spawn-coop-server} runs the server in a new thread. +@end deffn + +@deffn {Scheme Procedure} poll-coop-server +Poll the server and evaluate a pending expression if there is one. +@end deffn + @c Local Variables: @c TeX-master: guile.texi @c End: diff --git a/module/system/repl/coop
Re: [PATCH] Add procedures to convert alists into hash tables
On 11/18/2013 03:32 PM, Ludovic Courtès wrote: David Thompson dthomps...@worcester.edu skribis: From 03f604cc3dfffb816cfe66a355e36ede337749f1 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 19 Oct 2013 22:43:37 -0400 Subject: [PATCH] Add procedures to convert alists into hash tables. * module/ice-9/hash-table.scm: New module. * test-suite/tests/hash.test (alist conversion): Add tests. * doc/ref/api-compound.texi (Hash Table Reference): Add docs. Agreed with Mark’s comment, but otherwise looks good to me. +(define-syntax-rule (define-alist-converter name hash-set-proc) + (define (name alist) [...] +(define (alist-hashx-table hash assoc alist) + Convert @var{alist} into a hash table with custom @var{hash} and +@var{assoc} procedures. Currently Texinfo markup in docstrings is left uninterpreted so it can/should be avoided (it may change in the future, but the future’s not now ;-)). Thanks! Ludo’. Fixed texi docs and docstrings. - Dave From 37571c1a11d53cee176bf93ddd539f0dd91f3669 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 19 Oct 2013 22:43:37 -0400 Subject: [PATCH] Add procedures to convert alists into hash tables. * module/ice-9/hash-table.scm: New module. * test-suite/tests/hash.test (alist conversion): Add tests. * doc/ref/api-compound.texi (Hash Table Reference): Add docs. --- doc/ref/api-compound.texi | 21 + module/Makefile.am | 1 + module/ice-9/hash-table.scm | 45 + test-suite/tests/hash.test | 38 +- 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 module/ice-9/hash-table.scm diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi index 94e0145..0b14c48 100644 --- a/doc/ref/api-compound.texi +++ b/doc/ref/api-compound.texi @@ -3829,6 +3829,27 @@ then it can use @var{size} to avoid rehashing when initial entries are added. @end deffn +@deffn {Scheme Procedure} alist-hash-table alist +@deffnx {Scheme Procedure} alist-hashq-table alist +@deffnx {Scheme Procedure} alist-hashv-table alist +@deffnx {Scheme Procedure} alist-hashx-table hash assoc alist +Convert @var{alist} into a hash table. When keys are repeated in +@var{alist}, the leftmost association takes precedence. + +@example +(use-modules (ice-9 hash-table)) +(alist-hash-table '((foo . 1) (bar . 2))) +@end example + +When converting to an extended hash table, custom @var{hash} and +@var{assoc} procedures must be provided. + +@example +(alist-hashx-table hash assoc '((foo . 1) (bar . 2))) +@end example + +@end deffn + @deffn {Scheme Procedure} hash-table? obj @deffnx {C Function} scm_hash_table_p (obj) Return @code{#t} if @var{obj} is a abstract hash table object. diff --git a/module/Makefile.am b/module/Makefile.am index e8dcd4a..8a7befd 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -207,6 +207,7 @@ ICE_9_SOURCES = \ ice-9/format.scm \ ice-9/futures.scm \ ice-9/getopt-long.scm \ + ice-9/hash-table.scm \ ice-9/hcons.scm \ ice-9/i18n.scm \ ice-9/iconv.scm \ diff --git a/module/ice-9/hash-table.scm b/module/ice-9/hash-table.scm new file mode 100644 index 000..ca9d2fd --- /dev/null +++ b/module/ice-9/hash-table.scm @@ -0,0 +1,45 @@ + hash-table.scm --- Additional hash table procedures + Copyright (C) 2013 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +(define-module (ice-9 hash-table) + #:export (alist-hash-table +alist-hashq-table +alist-hashv-table +alist-hashx-table)) + +(define-syntax-rule (define-alist-converter name hash-set-proc) + (define (name alist) +Convert ALIST into a hash table. +(let ((table (make-hash-table))) + (for-each (lambda (pair) + (hash-set-proc table (car pair) (cdr pair))) +(reverse alist)) + table))) + +(define-alist-converter alist-hash-table hash-set!) +(define-alist-converter alist-hashq-table hashq-set!) +(define-alist-converter alist-hashv-table hashv-set!) + +(define (alist-hashx-table hash assoc alist) + Convert ALIST into a hash table with custom HASH
Re: [PATCH] Add procedures to convert alists into hash tables
On 11/06/2013 07:54 AM, Ludovic Courtès wrote: Mark H Weaver m...@netris.org skribis: Thompson, David dthomps...@worcester.edu writes: On Tue, Oct 29, 2013 at 8:38 AM, Ludovic Courtès l...@gnu.org wrote: I think it would make sense to implement them in Scheme, say in ice-9/hash-table.scm, which could be either a separate module or a file included from boot-9.scm. WDYT? Does anyone else feel that this is a better approach? FWIW, I think Ludovic is right. There's no compelling reason to write these procedures in C, and it would be good to reduce the amount of C code for several reasons. However, unlike ttn, I think it would be good to have these procedures in core Guile. Agreed. David: would you be willing to do that? Apologies for my late comment, and for the extra work involved. Your contributions are appreciated! Thanks, Ludo’. Finally got around to updating this patch. I opted for adding a standalone module named (ice-9 hash-table) rather than including it from boot-9. How did I do? - Dave From 30b122a2638689e919f8b6722905ed5fa51e2138 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 19 Oct 2013 22:43:37 -0400 Subject: [PATCH] Add procedures to convert alists into hash tables. * module/ice-9/hash-table.scm: New module. * test-suite/tests/hash.test (alist conversion): Add tests. * doc/ref/api-compound.texi (Hash Table Reference): Add docs. --- doc/ref/api-compound.texi | 21 + module/ice-9/hash-table.scm | 45 + test-suite/tests/hash.test | 38 +- 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 module/ice-9/hash-table.scm diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi index 94e0145..9e5e649 100644 --- a/doc/ref/api-compound.texi +++ b/doc/ref/api-compound.texi @@ -3829,6 +3829,27 @@ then it can use @var{size} to avoid rehashing when initial entries are added. @end deffn +@deffn {Scheme Procedure} alist-hash-table alist +@deffnx {Scheme Procedure} alist-hashq-table alist +@deffnx {Scheme Procedure} alist-hashv-table alist +@deffnx {Scheme Procedure} alist-hashx-table hash assoc alist +Convert @var{alist} into a hash table. When keys are repeated in +@var{alist}, the leftmost association takes precedence. + +@example +(use-modules (ice-9 hash-table)) +(alist-hash-table '((foo . 1) (bar . 2))) +@end example + +When converting to an extended hash table, custom @var{hash} and +@var{assoc} procedures must be provided. + +@example +(alist-hash-table hash assoc '((foo . 1) (bar . 2))) +@end example + +@end deffn + @deffn {Scheme Procedure} hash-table? obj @deffnx {C Function} scm_hash_table_p (obj) Return @code{#t} if @var{obj} is a abstract hash table object. diff --git a/module/ice-9/hash-table.scm b/module/ice-9/hash-table.scm new file mode 100644 index 000..6b0fa04 --- /dev/null +++ b/module/ice-9/hash-table.scm @@ -0,0 +1,45 @@ + hash-table.scm --- Additional hash table procedures + Copyright (C) 2013 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +(define-module (ice-9 hash-table) + #:export (alist-hash-table +alist-hashq-table +alist-hashv-table +alist-hashx-table)) + +(define-syntax-rule (define-alist-converter name hash-set-proc) + (define (name alist) +Convert @var{alist} into a hash table. +(let ((table (make-hash-table))) + (for-each (lambda (pair) + (hash-set-proc table (car pair) (cdr pair))) +(reverse alist)) + table))) + +(define-alist-converter alist-hash-table hash-set!) +(define-alist-converter alist-hashq-table hashq-set!) +(define-alist-converter alist-hashv-table hashv-set!) + +(define (alist-hashx-table hash assoc alist) + Convert @var{alist} into a hash table with custom @var{hash} and +@var{assoc} procedures. + (let ((table (make-hash-table))) +(for-each (lambda (pair) +(hashx-set! hash assoc table (car pair) (cdr pair))) + (reverse alist)) +table)) diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test index 3bd4004..ad247f5 100644 --- a/test-suite/tests
Re: [PATCH] Add procedures to convert alists into hash tables
On 11/17/2013 08:50 PM, David Thompson wrote: Finally got around to updating this patch. I opted for adding a standalone module named (ice-9 hash-table) rather than including it from boot-9. How did I do? - Dave Forgot to add the new module file to Makefile.am. Updated patch attached. - Dave From 03f604cc3dfffb816cfe66a355e36ede337749f1 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 19 Oct 2013 22:43:37 -0400 Subject: [PATCH] Add procedures to convert alists into hash tables. * module/ice-9/hash-table.scm: New module. * test-suite/tests/hash.test (alist conversion): Add tests. * doc/ref/api-compound.texi (Hash Table Reference): Add docs. --- doc/ref/api-compound.texi | 21 + module/Makefile.am | 1 + module/ice-9/hash-table.scm | 45 + test-suite/tests/hash.test | 38 +- 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 module/ice-9/hash-table.scm diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi index 94e0145..9e5e649 100644 --- a/doc/ref/api-compound.texi +++ b/doc/ref/api-compound.texi @@ -3829,6 +3829,27 @@ then it can use @var{size} to avoid rehashing when initial entries are added. @end deffn +@deffn {Scheme Procedure} alist-hash-table alist +@deffnx {Scheme Procedure} alist-hashq-table alist +@deffnx {Scheme Procedure} alist-hashv-table alist +@deffnx {Scheme Procedure} alist-hashx-table hash assoc alist +Convert @var{alist} into a hash table. When keys are repeated in +@var{alist}, the leftmost association takes precedence. + +@example +(use-modules (ice-9 hash-table)) +(alist-hash-table '((foo . 1) (bar . 2))) +@end example + +When converting to an extended hash table, custom @var{hash} and +@var{assoc} procedures must be provided. + +@example +(alist-hash-table hash assoc '((foo . 1) (bar . 2))) +@end example + +@end deffn + @deffn {Scheme Procedure} hash-table? obj @deffnx {C Function} scm_hash_table_p (obj) Return @code{#t} if @var{obj} is a abstract hash table object. diff --git a/module/Makefile.am b/module/Makefile.am index e8dcd4a..8a7befd 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -207,6 +207,7 @@ ICE_9_SOURCES = \ ice-9/format.scm \ ice-9/futures.scm \ ice-9/getopt-long.scm \ + ice-9/hash-table.scm \ ice-9/hcons.scm \ ice-9/i18n.scm \ ice-9/iconv.scm \ diff --git a/module/ice-9/hash-table.scm b/module/ice-9/hash-table.scm new file mode 100644 index 000..6b0fa04 --- /dev/null +++ b/module/ice-9/hash-table.scm @@ -0,0 +1,45 @@ + hash-table.scm --- Additional hash table procedures + Copyright (C) 2013 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +(define-module (ice-9 hash-table) + #:export (alist-hash-table +alist-hashq-table +alist-hashv-table +alist-hashx-table)) + +(define-syntax-rule (define-alist-converter name hash-set-proc) + (define (name alist) +Convert @var{alist} into a hash table. +(let ((table (make-hash-table))) + (for-each (lambda (pair) + (hash-set-proc table (car pair) (cdr pair))) +(reverse alist)) + table))) + +(define-alist-converter alist-hash-table hash-set!) +(define-alist-converter alist-hashq-table hashq-set!) +(define-alist-converter alist-hashv-table hashv-set!) + +(define (alist-hashx-table hash assoc alist) + Convert @var{alist} into a hash table with custom @var{hash} and +@var{assoc} procedures. + (let ((table (make-hash-table))) +(for-each (lambda (pair) +(hashx-set! hash assoc table (car pair) (cdr pair))) + (reverse alist)) +table)) diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test index 3bd4004..ad247f5 100644 --- a/test-suite/tests/hash.test +++ b/test-suite/tests/hash.test @@ -18,7 +18,8 @@ (define-module (test-suite test-numbers) #:use-module (test-suite lib) - #:use-module (ice-9 documentation)) + #:use-module (ice-9 documentation) + #:use-module (ice-9 hash-table)) ;;; ;;; hash @@ -81,6 +82,41 @@ (write (make-hash-table 100))) ;;; +;;; alist
[PATCH] Add procedures to convert alists into hash tables
Hello all, When looking through the different hash table implementations available (Guile, SRFI-69, and RNRS) I found a useful SRFI-69 procedure that had no equivalent in Guile's native hash table API: alist-hash-table. This patch is an attempt to add that. It works for all four types of hash tables: equal?, eq?, eqv? and custom. - Dave From e303098404321cbe2b978d526ee2737137a5d5b1 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 19 Oct 2013 22:43:37 -0400 Subject: [PATCH] Add procedures to convert alists into hash tables. * libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table, scm_alist_to_hashv_table, scm_alist_to_hashx_table): Add the equivalent of SRFI-69's alist-hash-table procedure for the native hash table implementation. * test-suite/tests/hash.test (alist-hash-table): Add tests. * doc/ref/api-compound.texi (alist-hash-table): Add docs. --- doc/ref/api-compound.texi | 18 ++ libguile/hashtab.c | 61 ++ libguile/hashtab.h | 6 + test-suite/tests/hash.test | 27 4 files changed, 112 insertions(+) diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi index 94e0145..9794e28 100644 --- a/doc/ref/api-compound.texi +++ b/doc/ref/api-compound.texi @@ -3829,6 +3829,24 @@ then it can use @var{size} to avoid rehashing when initial entries are added. @end deffn +@deffn {Scheme Procedure} alist-hash-table alist [size] +@deffnx {Scheme Procedure} alist-hashq-table alist [size] +@deffnx {Scheme Procedure} alist-hashv-table alist [size] +@deffnx {Scheme Procedure} alist-hashx-table hash assoc alist [size] +@deffnx {C Function} scm_alist_to_hash_table (alist, size) +@deffnx {C Function} scm_alist_to_hashq_table (alist, size) +@deffnx {C Function} scm_alist_to_hashv_table (alist, size) +@deffnx {C Function} scm_alist_to_hashx_table (alist, size) +Convert @var{alist} into a hash table with minimum number of buckets +@var{n}. When keys are repeated in @var{alist}, the leftmost association +takes precedence. + +@example +(alist-hash-table '((foo . 1) (bar . 2))) +@end example + +@end deffn + @deffn {Scheme Procedure} hash-table? obj @deffnx {C Function} scm_hash_table_p (obj) Return @code{#t} if @var{obj} is a abstract hash table object. diff --git a/libguile/hashtab.c b/libguile/hashtab.c index 88cb199..c215269 100644 --- a/libguile/hashtab.c +++ b/libguile/hashtab.c @@ -423,6 +423,67 @@ SCM_DEFINE (scm_make_hash_table, make-hash-table, 0, 1, 0, } #undef FUNC_NAME +#define SCM_ALIST_TO_HASH_TABLE(alist, n, hash_set_fn) \ + SCM hash_table; \ + SCM_VALIDATE_LIST (1, alist); \ + hash_table = scm_make_hash_table (n); \ + while (!scm_is_null (alist)) { \ +SCM pair = SCM_CAR (alist); \ +hash_set_fn (hash_table, scm_car (pair), scm_cdr (pair)); \ +alist = SCM_CDR (alist); \ + } \ + return hash_table; + +SCM_DEFINE (scm_alist_to_hash_table, alist-hash-table, 1, 1, 0, + (SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hash_table +{ + SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hash_set_x); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_alist_to_hashq_table, alist-hashq-table, 1, 1, 0, + (SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hashq_table +{ + SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashq_set_x); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_alist_to_hashv_table, alist-hashv-table, 1, 1, 0, + (SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hashv_table +{ + SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashv_set_x); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_alist_to_hashx_table, alist-hashx-table, 3, 1, 0, + (SCM hash, SCM assoc, SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hashx_table +{ + SCM hash_table; + SCM_VALIDATE_LIST (3, alist); + hash_table = scm_make_hash_table (n); + + while (!scm_is_null (alist)) { +SCM pair = SCM_CAR (alist); +scm_hashx_set_x (hash, assoc, hash_table, scm_car (pair), scm_cdr (pair)); +alist = SCM_CDR (alist); + } + + return hash_table; +} +#undef FUNC_NAME + /* The before-gc C hook only runs if GC_set_start_callback is available, so if not, fall back on a finalizer-based implementation. */ static int diff --git a/libguile/hashtab.h b/libguile/hashtab.h index dcebcb8..da4f28c 100644 --- a/libguile/hashtab.h +++ b/libguile/hashtab.h @@ -101,6 +101,12 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k); SCM_API SCM scm_make_weak_value_hash_table (SCM k); SCM_API SCM scm_make_doubly_weak_hash_table (SCM k); +SCM_API SCM
Re: [PATCH] Add procedures to convert alists into hash tables
On 10/20/2013 10:14 AM, David Thompson wrote: Hello all, When looking through the different hash table implementations available (Guile, SRFI-69, and RNRS) I found a useful SRFI-69 procedure that had no equivalent in Guile's native hash table API: alist-hash-table. This patch is an attempt to add that. It works for all four types of hash tables: equal?, eq?, eqv? and custom. - Dave Found an inconsistency in the docs. Updated patch attached. - Dave From 46b7905727ad2efed2dc1d1aca4d4ad00d8f48c5 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sat, 19 Oct 2013 22:43:37 -0400 Subject: [PATCH] Add procedures to convert alists into hash tables. * libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table, scm_alist_to_hashv_table, scm_alist_to_hashx_table): Add the equivalent of SRFI-69's alist-hash-table procedure for the native hash table implementation. * test-suite/tests/hash.test (alist-hash-table): Add tests. * doc/ref/api-compound.texi (alist-hash-table): Add docs. --- doc/ref/api-compound.texi | 18 ++ libguile/hashtab.c | 61 ++ libguile/hashtab.h | 6 + test-suite/tests/hash.test | 27 4 files changed, 112 insertions(+) diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi index 94e0145..06115be 100644 --- a/doc/ref/api-compound.texi +++ b/doc/ref/api-compound.texi @@ -3829,6 +3829,24 @@ then it can use @var{size} to avoid rehashing when initial entries are added. @end deffn +@deffn {Scheme Procedure} alist-hash-table alist [size] +@deffnx {Scheme Procedure} alist-hashq-table alist [size] +@deffnx {Scheme Procedure} alist-hashv-table alist [size] +@deffnx {Scheme Procedure} alist-hashx-table hash assoc alist [size] +@deffnx {C Function} scm_alist_to_hash_table (alist, size) +@deffnx {C Function} scm_alist_to_hashq_table (alist, size) +@deffnx {C Function} scm_alist_to_hashv_table (alist, size) +@deffnx {C Function} scm_alist_to_hashx_table (hash, assoc, alist, size) +Convert @var{alist} into a hash table with minimum number of buckets +@var{size}. When keys are repeated in @var{alist}, the leftmost +association takes precedence. + +@example +(alist-hash-table '((foo . 1) (bar . 2))) +@end example + +@end deffn + @deffn {Scheme Procedure} hash-table? obj @deffnx {C Function} scm_hash_table_p (obj) Return @code{#t} if @var{obj} is a abstract hash table object. diff --git a/libguile/hashtab.c b/libguile/hashtab.c index 88cb199..c215269 100644 --- a/libguile/hashtab.c +++ b/libguile/hashtab.c @@ -423,6 +423,67 @@ SCM_DEFINE (scm_make_hash_table, make-hash-table, 0, 1, 0, } #undef FUNC_NAME +#define SCM_ALIST_TO_HASH_TABLE(alist, n, hash_set_fn) \ + SCM hash_table; \ + SCM_VALIDATE_LIST (1, alist); \ + hash_table = scm_make_hash_table (n); \ + while (!scm_is_null (alist)) { \ +SCM pair = SCM_CAR (alist); \ +hash_set_fn (hash_table, scm_car (pair), scm_cdr (pair)); \ +alist = SCM_CDR (alist); \ + } \ + return hash_table; + +SCM_DEFINE (scm_alist_to_hash_table, alist-hash-table, 1, 1, 0, + (SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hash_table +{ + SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hash_set_x); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_alist_to_hashq_table, alist-hashq-table, 1, 1, 0, + (SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hashq_table +{ + SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashq_set_x); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_alist_to_hashv_table, alist-hashv-table, 1, 1, 0, + (SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hashv_table +{ + SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashv_set_x); +} +#undef FUNC_NAME + +SCM_DEFINE (scm_alist_to_hashx_table, alist-hashx-table, 3, 1, 0, + (SCM hash, SCM assoc, SCM alist, SCM n), +Convert @var{alist} into a hash table with minimum number of +buckets @var{n}.) +#define FUNC_NAME s_scm_alist_to_hashx_table +{ + SCM hash_table; + SCM_VALIDATE_LIST (3, alist); + hash_table = scm_make_hash_table (n); + + while (!scm_is_null (alist)) { +SCM pair = SCM_CAR (alist); +scm_hashx_set_x (hash, assoc, hash_table, scm_car (pair), scm_cdr (pair)); +alist = SCM_CDR (alist); + } + + return hash_table; +} +#undef FUNC_NAME + /* The before-gc C hook only runs if GC_set_start_callback is available, so if not, fall back on a finalizer-based implementation. */ static int diff --git a/libguile/hashtab.h b/libguile/hashtab.h index dcebcb8..da4f28c 100644 --- a/libguile/hashtab.h +++ b/libguile/hashtab.h @@ -101,6 +101,12 @@ SCM_API SCM scm_make_weak_key_hash_table
Re: A more generic REPL server
On 10/06/2013 06:08 AM, Chaos Eternal wrote: Is this thing a threadless repl server? if so, i suggest that the code be separated and can be easily integrated into other project. the guile-scsh badly needs such a feature. It's not exactly threadless. There is one server thread that waits for clients, and for each client there is one thread that waits for user input. The difference is that the client REPL is executed in the main thread, sans reading user input. I use my own coroutine and scheduler modules to do it in guile-2d. I call it the cooperative REPL. I agree that it would be nice to extract this into something that more people could use. The modules in question are (2d coroutine), (2d agenda), and (2d repl coop-repl). https://github.com/davexunit/guile-2d/blob/master/2d/coroutine.scm https://github.com/davexunit/guile-2d/blob/master/2d/agenda.scm https://github.com/davexunit/guile-2d/blob/repl-v2/2d/repl/coop-repl.scm Thoughts?
A more generic REPL server
Hello all, As some of you know, I am writing my own custom REPL that fits nicely with my game framework, guile-2d. I just finished hacking (system repl server) to suit my needs and things seem to be working well. Looking upon the diff, I see that I only changed the serve-client procedure. Thus, I think it would be a good idea to build some abstraction that allows custom REPLs to be run, not just start-repl in (system repl repl). Here is the original serve-client method: (define (serve-client client addr) (with-continuation-barrier (lambda () (with-input-from-port client (lambda () (with-output-to-port client (lambda () (with-error-to-port client (lambda () (with-fluids ((*repl-stack* '())) (start-repl)) (close-socket! client)) And here is my version: (define (serve-client client addr) (agenda-schedule (colambda () (with-input-from-port client (lambda () (with-output-to-port client (lambda () (with-error-to-port client (lambda () (with-fluids ((*repl-stack* '())) (start-repl (close-socket! client In this snippet, start-repl comes from a guile-2d module, not (system repl repl). There's an abstraction lurking here, but I'm not quite sure what it is. I've removed the continuation barrier, changed the start-repl procedure, and wrapped everything in a form that creates a coroutine. I tried simply adding an additional argument to spawn-server that specifies the procedure used to serve the client. However, close-socket! is private, and I don't think it would be a good idea to expose it. Can anyone think of a good way to generalize this? Thanks, - Dave
Re: [PATCH] Add read-wrapper REPL option
On 09/29/2013 06:10 PM, David Thompson wrote: Guile-2D needs a REPL that runs within its event loop without blocking when reading user input. Mark Weaver has helped me add a new REPL option, read-wrapper, that can be used by Guile-2D to push the read operation into another thread while the main thread's event loop continues to run as normal. This avoids the problem of thread safety with the normal REPL server. I think that this could be useful for other programs that run in an event loop. Perhaps Emacsy? - Dave Thompson Here is an updated patch. I've updated prompting-meta-read to preserve the REPL stack when the reader thunk is called, in the case of the thunk being called outside of the current thread. From b7cae3fb33d2cc059c4016709e4d0630eee1610d Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sun, 29 Sep 2013 18:01:31 -0400 Subject: [PATCH] Add read-wrapper REPL option. * module/system/repl/common.scm (repl-default-options): Add read-wrapper REPL option. * module/system/repl/repl.scm (prompting-meta-read): Use read-wrapper REPL option. --- module/system/repl/common.scm | 4 module/system/repl/repl.scm | 35 ++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/module/system/repl/common.scm b/module/system/repl/common.scm index 5da7c48..030d5de 100644 --- a/module/system/repl/common.scm +++ b/module/system/repl/common.scm @@ -125,6 +125,10 @@ See http://www.gnu.org/licenses/lgpl.html, for more details.) ((not print) #f) ((procedure? print) print) (else (error Invalid print procedure print) + (read-wrapper + ,(lambda (thunk) + (thunk)) + #f) (value-history ,(value-history-enabled?) ,(lambda (x) diff --git a/module/system/repl/repl.scm b/module/system/repl/repl.scm index 1649556..97adf72 100644 --- a/module/system/repl/repl.scm +++ b/module/system/repl/repl.scm @@ -107,20 +107,29 @@ ;; to be able to re-use the existing readline machinery. ;; ;; Catches read errors, returning *unspecified* in that case. +;; +;; The reader thunk is passed into the read-wrapper procedure. The state +;; of the stack is maintained, in case of the thunk being called outside +;; of the current thread. (define (prompting-meta-read repl) - (catch #t -(lambda () - (repl-reader (lambda () (repl-prompt repl)) - (meta-reader (repl-language repl) (current-module -(lambda (key . args) - (case key -((quit) - (apply throw key args)) -(else - (format (current-output-port) While reading expression:\n) - (print-exception (current-output-port) #f key args) - (flush-all-input) - *unspecified*) + (let ((read-wrapper (repl-option-ref repl 'read-wrapper)) +(stack (fluid-ref *repl-stack*))) +(read-wrapper + (lambda () + (with-fluids ((*repl-stack* stack)) + (catch #t + (lambda () + (repl-reader (lambda () (repl-prompt repl)) + (meta-reader (repl-language repl) (current-module + (lambda (key . args) + (case key + ((quit) +(apply throw key args)) + (else +(format (current-output-port) While reading expression:\n) +(print-exception (current-output-port) #f key args) +(flush-all-input) +*unspecified*) -- 1.8.4.rc3
[PATCH] Add read-wrapper REPL option
Guile-2D needs a REPL that runs within its event loop without blocking when reading user input. Mark Weaver has helped me add a new REPL option, read-wrapper, that can be used by Guile-2D to push the read operation into another thread while the main thread's event loop continues to run as normal. This avoids the problem of thread safety with the normal REPL server. I think that this could be useful for other programs that run in an event loop. Perhaps Emacsy? - Dave Thompson From 57e11747ee43d42e09b5c80e545f12728c75fbf5 Mon Sep 17 00:00:00 2001 From: David Thompson dthomps...@worcester.edu Date: Sun, 29 Sep 2013 18:01:31 -0400 Subject: [PATCH] Add read-wrapper REPL option. * module/system/repl/common.scm (repl-default-options): Add read-wrapper REPL option. * module/system/repl/repl.scm (prompting-meta-read): Use read-wrapper REPL option. --- module/system/repl/common.scm | 4 module/system/repl/repl.scm | 29 - 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/module/system/repl/common.scm b/module/system/repl/common.scm index 5da7c48..030d5de 100644 --- a/module/system/repl/common.scm +++ b/module/system/repl/common.scm @@ -125,6 +125,10 @@ See http://www.gnu.org/licenses/lgpl.html, for more details.) ((not print) #f) ((procedure? print) print) (else (error Invalid print procedure print) + (read-wrapper + ,(lambda (thunk) + (thunk)) + #f) (value-history ,(value-history-enabled?) ,(lambda (x) diff --git a/module/system/repl/repl.scm b/module/system/repl/repl.scm index 1649556..23c624a 100644 --- a/module/system/repl/repl.scm +++ b/module/system/repl/repl.scm @@ -108,19 +108,22 @@ ;; ;; Catches read errors, returning *unspecified* in that case. (define (prompting-meta-read repl) - (catch #t -(lambda () - (repl-reader (lambda () (repl-prompt repl)) - (meta-reader (repl-language repl) (current-module -(lambda (key . args) - (case key -((quit) - (apply throw key args)) -(else - (format (current-output-port) While reading expression:\n) - (print-exception (current-output-port) #f key args) - (flush-all-input) - *unspecified*) + (let ((read-wrapper (repl-option-ref repl 'read-wrapper))) +(read-wrapper + (lambda () + (catch #t + (lambda () + (repl-reader (lambda () (repl-prompt repl)) +(meta-reader (repl-language repl) (current-module + (lambda (key . args) + (case key + ((quit) + (apply throw key args)) + (else + (format (current-output-port) While reading expression:\n) + (print-exception (current-output-port) #f key args) + (flush-all-input) + *unspecified* -- 1.8.4.rc3