From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: taylanbayirli@gmail.com (Taylan Ulrich B.) Newsgroups: gmane.lisp.guile.devel Subject: Guile Emacs: Elisp nil/t and Guile #nil/#t Date: Thu, 01 Aug 2013 05:03:06 +0300 Message-ID: <87a9l2rwv9.fsf@taylan.uni.cx> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: ger.gmane.org 1375322602 26959 80.91.229.3 (1 Aug 2013 02:03:22 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 1 Aug 2013 02:03:22 +0000 (UTC) Cc: guile-devel@gnu.org To: bt@hcoop.org Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Thu Aug 01 04:03:25 2013 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1V4iEe-0000t5-Vi for guile-devel@m.gmane.org; Thu, 01 Aug 2013 04:03:25 +0200 Original-Received: from localhost ([::1]:56298 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V4iEe-0000S5-GY for guile-devel@m.gmane.org; Wed, 31 Jul 2013 22:03:24 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:37620) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V4iEW-0000R8-HU for guile-devel@gnu.org; Wed, 31 Jul 2013 22:03:21 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V4iER-0006ja-2J for guile-devel@gnu.org; Wed, 31 Jul 2013 22:03:16 -0400 Original-Received: from mail-ee0-x233.google.com ([2a00:1450:4013:c00::233]:40682) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V4iEQ-0006jA-OL for guile-devel@gnu.org; Wed, 31 Jul 2013 22:03:10 -0400 Original-Received: by mail-ee0-f51.google.com with SMTP id c1so680741eek.38 for ; Wed, 31 Jul 2013 19:03:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:mime-version:content-type; bh=prJ7XUOamnKujkqmIR7hFgWqlTx9sgOnrXbO4RYrTe0=; b=c64R7CIOpDJZ1RbgZ+Qbyu8zSl9Uj4L+ofcaOw4iXmA+N8C/kycL6cxgrfsCSa60yZ SRujXaQ4Yzces7ei+MCsGB4Fe7xGXpAESHFqNF1oPRABIUQoTUTK7jM+u3fWquVCGy0M 8QW8A80vg76kuJP7ORWbRNxdJEQEgs4hZ31OFCAodKUYiWNBQZ5RmX7hFWuFqxBBZqnP xrJ9QrNtrs9CJGriyFJVdYOE4MMbn0bqgnSn3Umn+9inkXf9WwogWwoljJDRWef57iUE b5Y4ty2ZPWlz3L3IqcjuisoCq5ZxeS0zQJkfzEGlEKzNCMIDhIkjI0zsQ2OClOj/DWco g+Ug== X-Received: by 10.14.179.131 with SMTP id h3mr9249107eem.102.1375322589810; Wed, 31 Jul 2013 19:03:09 -0700 (PDT) Original-Received: from taylan.uni.cx ([78.179.208.222]) by mx.google.com with ESMTPSA id p49sm764588eeu.2.2013.07.31.19.03.07 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Wed, 31 Jul 2013 19:03:09 -0700 (PDT) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:4013:c00::233 X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:16545 Archived-At: --=-=-= Content-Type: text/plain Hi, It occurred to me that nil and t are basically just symbols in Elisp, just with some magical properties. Like any symbol, they respond to symbolp, have a plist, value and symbol slot (although the value slot is immutable), etc. They're self-quoting, so 'nil and 't also just return nil and t. Nasty stuff. Given all that, the #nil and #t values of Guile are obviously not nearly interchangeable. Did anyone already have a solution in mind? If not, I have thought of and implemented a solution, which is dirty but seems to work well, except for perhaps incorporating overhead in Elisp code (but not Scheme). Explanation follows. * Qnil and Qt are simply SCM_ELISP_NIL and SCM_BOOL_T. * NILP is simply scm_is_lisp_false, naturally. * SYMBOLP handles Qnil and Qt specially: (SMOB_TYPEP (x, lisp_symbol_tag) || EQ (x, Qnil) || EQ (x, Qt)) This has some overhead. Maybe a more efficient solution exists. * XSYMBOL handles Qnil and Qt specially, returning SMOB pointers for Qnil_ and Qt_ instead (explanation will follow): ((struct Lisp_Symbol *) \ (EQ (a, Qnil) ? SMOB_PTR (Qnil_) \ : EQ (a, Qt) ? SMOB_PTR (Qt_) \ : (eassert (SMOB_TYPEP (a, lisp_symbol_tag)), \ SMOB_PTR (a)))) Again, overhead. * Last part is fancy: Qnil_ and Qt_ are basically the old Qnil and Qt, and are initialized with intern("nil") and intern("t"), however the implementation of intern has a twist: on subsequent calls with "nil" and "t" it actually returns Qnil and Qt instead of Qnil_ and Qt_, this works well because as per the previous points we assured that Qnil and Qt (SCM_ELISP_NIL and SCM_BOOL_T) are interchangeable with the symbols Qnil_ and Qt_ in the Elisp C API. This incorporates overhead in intern, when returning and already-interned symbol: it is first tested against Qnil_ and Qt_, before being returned. Note that `read' uses intern, too, so that's how we get Qnil and Qt when reading source code or other data. (Tell me if I missed a way in which one can accidentally access the underlying nil and t symbols instead of the "delegating" Qnil and Qt values, or something that could expose the non-symbol nature of the Qnil and Qt values, for they must appear to be symbols.) The result is that "everything works fine", except that I don't know how much I slowed down SYMBOLP, XSYMBOL, and intern: (The following examples use the Elisp macro `guile-ref' which works like Guile's @, and they pass Guile procedures to funcall; I implemented these locally.) (funcall (guile-ref (guile) null?) nil) => t (funcall (guile-ref (guile) not) nil) => t (eq (eval-scheme "#nil") nil) => t (eq (eval-scheme "#t") t) => t (symbolp nil) => t (symbolp t) => t (symbol-value nil) => nil (symbol-value t) => t (null (eval-scheme "#nil")) => t (null (eval-scheme "#f")) => t (null (eval-scheme "'()")) => t Patches follow. The first one is the one relevant to the topic. The second allows Scheme procedures in `funcall' (thus also `apply') and function-slots of symbols; the third implements guile-ref (@) and guile-private-ref (@@), and fixes eval-scheme to not print excessively (git insisted on putting the two changes in the same hunk, I gave up). I'm providing the latter two for completion's sake and in case you want to test this yoursel, since there's otherwise no way to pass Elisp data to Scheme procedures (eval-scheme takes a string). The problems they solve will probably be solved better in the future. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Reconcile-Elisp-nil-and-t-with-Guile-nil-and-t.patch Content-Description: Reconcile Elisp nil and t with Guile >From f926a808e98e9ace24d07ee9ca7c1137f4670a62 Mon Sep 17 00:00:00 2001 From: Taylan Ulrich B Date: Thu, 1 Aug 2013 03:45:09 +0300 Subject: [PATCH 1/3] Reconcile Elisp nil and t with Guile #nil and #t. --- src/data.c | 6 +++--- src/lisp.h | 16 +++++++++++----- src/lread.c | 47 +++++++++++++++++++++++++---------------------- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/data.c b/src/data.c index 347c3f9..6d7c95d 100644 --- a/src/data.c +++ b/src/data.c @@ -34,7 +34,7 @@ along with GNU Emacs. If not, see . */ #include "font.h" #include "keymap.h" -Lisp_Object Qnil, Qt, Qquote, Qlambda, Qunbound; +Lisp_Object Qnil, Qnil_, Qt, Qt_, Qquote, Qlambda, Qunbound; static Lisp_Object Qsubr; Lisp_Object Qerror_conditions, Qerror_message, Qtop_level; Lisp_Object Qerror, Quser_error, Qquit, Qargs_out_of_range; @@ -3081,8 +3081,8 @@ syms_of_data (void) PUT_ERROR (Qunderflow_error, Fcons (Qdomain_error, arith_tail), "Arithmetic underflow error"); - staticpro (&Qnil); - staticpro (&Qt); + staticpro (&Qnil_); + staticpro (&Qt_); staticpro (&Qunbound); /* Types that type-of returns. */ diff --git a/src/lisp.h b/src/lisp.h index 438affb..2afac48 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -209,19 +209,24 @@ enum enum_USE_LSB_TAG { USE_LSB_TAG = 1 }; #define lisp_h_INTEGERP(x) (SCM_I_INUMP (x)) #define lisp_h_MARKERP(x) (MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Marker) #define lisp_h_MISCP(x) (SMOB_TYPEP (x, lisp_misc_tag)) -#define lisp_h_NILP(x) EQ (x, Qnil) +#define lisp_h_NILP(x) (scm_is_lisp_false (x)) #define lisp_h_SET_SYMBOL_VAL(sym, v) \ (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value = (v)) #define lisp_h_SYMBOL_CONSTANT_P(sym) (XSYMBOL (sym)->constant) #define lisp_h_SYMBOL_VAL(sym) \ (eassert ((sym)->redirect == SYMBOL_PLAINVAL), (sym)->val.value) -#define lisp_h_SYMBOLP(x) (SMOB_TYPEP (x, lisp_symbol_tag)) +#define lisp_h_SYMBOLP(x) \ + (SMOB_TYPEP (x, lisp_symbol_tag) || EQ (x, Qnil) || EQ (x, Qt)) #define lisp_h_VECTORLIKEP(x) (SMOB_TYPEP (x, lisp_vectorlike_tag)) #define lisp_h_XCAR(c) (scm_car (c)) #define lisp_h_XCDR(c) (scm_cdr (c)) #define lisp_h_XHASH(a) (SCM_UNPACK (a)) -#define lisp_h_XSYMBOL(a) \ - (eassert (SYMBOLP (a)), (struct Lisp_Symbol *) SMOB_PTR (a)) +#define lisp_h_XSYMBOL(a) \ + ((struct Lisp_Symbol *) \ + (EQ (a, Qnil) ? SMOB_PTR (Qnil_) \ + : EQ (a, Qt) ? SMOB_PTR (Qt_) \ + : (eassert (SMOB_TYPEP (a, lisp_symbol_tag)), \ + SMOB_PTR (a)))) /* When compiling via gcc -O0, define the key operations as macros, as Emacs is too slow otherwise. To disable this optimization, compile @@ -529,7 +534,8 @@ extern int char_table_translate (Lisp_Object, int); /* Defined in data.c. */ extern Lisp_Object Qarrayp, Qbufferp, Qbuffer_or_string_p, Qchar_table_p; -extern Lisp_Object Qconsp, Qfloatp, Qintegerp, Qlambda, Qlistp, Qmarkerp, Qnil; +extern Lisp_Object Qconsp, Qfloatp, Qintegerp, Qlambda, Qlistp, Qmarkerp; +extern Lisp_Object Qnil, Qnil_, Qt, Qt_; extern Lisp_Object Qnumberp, Qstringp, Qsymbolp, Qvectorp; extern Lisp_Object Qvector_or_char_table_p, Qwholenump; extern Lisp_Object Ffboundp (Lisp_Object); diff --git a/src/lread.c b/src/lread.c index 859725d..06f6e14 100644 --- a/src/lread.c +++ b/src/lread.c @@ -3737,7 +3737,16 @@ it defaults to the value of `obarray'. */) SCHARS (string), SBYTES (string)); if (!INTEGERP (tem)) - return tem; + { + /* The symbols `nil' and `t' are only returned the first time + * they're created, to initialize Qnil_ and Qt_. On subsequent + * calls, we return Qnil and Qt instead. */ + if (EQ (tem, Qnil_)) + return Qnil; + if (EQ (tem, Qt_)) + return Qt; + return tem; + } if (!NILP (Vpurify_flag)) string = Fpurecopy (string); @@ -3955,31 +3964,25 @@ init_obarray (void) initial_obarray = Vobarray; staticpro (&initial_obarray); - Qunbound = Fmake_symbol (build_pure_c_string ("unbound")); - /* Set temporary dummy values to Qnil and Vpurify_flag to satisfy the - NILP (Vpurify_flag) check in intern_c_string. */ - Qnil = make_number (-1); Vpurify_flag = make_number (1); - Qnil = intern_c_string ("nil"); - - /* Fmake_symbol inits fields of new symbols with Qunbound and Qnil, - so those two need to be fixed manually. */ - SET_SYMBOL_VAL (XSYMBOL (Qunbound), Qunbound); - set_symbol_function (Qunbound, Qnil); - set_symbol_plist (Qunbound, Qnil); - SET_SYMBOL_VAL (XSYMBOL (Qnil), Qnil); - XSYMBOL (Qnil)->constant = 1; - XSYMBOL (Qnil)->declared_special = 1; - set_symbol_plist (Qnil, Qnil); - set_symbol_function (Qnil, Qnil); - - Qt = intern_c_string ("t"); - SET_SYMBOL_VAL (XSYMBOL (Qt), Qt); - XSYMBOL (Qnil)->declared_special = 1; - XSYMBOL (Qt)->constant = 1; + Qnil = SCM_ELISP_NIL; + Qt = SCM_BOOL_T; /* Qt is correct even if CANNOT_DUMP. loadup.el will set to nil at end. */ Vpurify_flag = Qt; + Qnil_ = intern_c_string ("nil"); + SET_SYMBOL_VAL (XSYMBOL (Qnil_), Qnil); + XSYMBOL (Qnil_)->constant = 1; + XSYMBOL (Qnil_)->declared_special = 1; + + Qt_ = intern_c_string ("t"); + SET_SYMBOL_VAL (XSYMBOL (Qt_), Qt); + XSYMBOL (Qt_)->constant = 1; + XSYMBOL (Qt_)->declared_special = 1; + + Qunbound = Fmake_symbol (build_pure_c_string ("unbound")); + SET_SYMBOL_VAL (XSYMBOL (Qunbound), Qunbound); + DEFSYM (Qvariable_documentation, "variable-documentation"); read_buffer = xmalloc_atomic (size); -- 1.8.1.2 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0002-Allow-Scheme-procedures-as-Elisp-functions.patch Content-Description: Allow Scheme procedures as Elisp functions >From 5b951edbb9710ccbd0178bfea5e0fee4ecbcc40f Mon Sep 17 00:00:00 2001 From: Taylan Ulrich B Date: Thu, 1 Aug 2013 04:02:40 +0300 Subject: [PATCH 2/3] Allow Scheme procedures as Elisp functions. * src/eval.c (eval_sub, Ffuncall, funcall_lambda): Allow Scheme procedures. --- src/eval.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/eval.c b/src/eval.c index 7911397..b2094e9 100644 --- a/src/eval.c +++ b/src/eval.c @@ -2349,7 +2349,7 @@ eval_sub (Lisp_Object form) } } } - else if (COMPILEDP (fun)) + else if (COMPILEDP (fun) || scm_is_true (scm_procedure_p (fun))) val = apply_lambda (fun, original_args); else { @@ -2984,7 +2984,7 @@ usage: (funcall FUNCTION &rest ARGUMENTS) */) } } } - else if (COMPILEDP (fun)) + else if (COMPILEDP (fun) || scm_is_true (scm_procedure_p (fun))) val = funcall_lambda (fun, numargs, args + 1); else { @@ -3110,6 +3110,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, } lexenv = Qnil; } + else if (scm_is_true (scm_procedure_p (fun))) + { + dynwind_end(); + return scm_call_n (fun, arg_vector, nargs); + } else emacs_abort (); -- 1.8.1.2 --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0003-src-fns.c-Add-guile-ref-and-guile-private-ref.patch Content-Description: Add guile-ref and guile-private ref, fix eval-scheme >From 103a2a2348a3abfd9a2f8f967ba146a856210d7e Mon Sep 17 00:00:00 2001 From: Taylan Ulrich B Date: Thu, 1 Aug 2013 04:08:14 +0300 Subject: [PATCH 3/3] src/fns.c: Add `guile-ref' and `guile-private-ref'. (Feval_scheme): Don't print, it's done automatically. --- src/fns.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/fns.c b/src/fns.c index cb89437..79a50ad 100644 --- a/src/fns.c +++ b/src/fns.c @@ -48,6 +48,8 @@ Lisp_Object Qcursor_in_echo_area; static Lisp_Object Qwidget_type; static Lisp_Object Qcodeset, Qdays, Qmonths, Qpaper; +static Lisp_Object Qguile_ref, Qguile_private_ref; + static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512; DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, @@ -4502,12 +4504,56 @@ DEFUN ("eval-scheme", Feval_scheme, Seval_scheme, 1, 1, doc: /* Evaluate a string containing a Scheme expression. */) (Lisp_Object string) { - Lisp_Object tem; - CHECK_STRING (string); + return scm_c_eval_string (SSDATA (string)); +} + +static SCM +elisp_symbol_or_string_to_scm (Lisp_Object obj) +{ + return scm_from_locale_symbol (SSDATA (SYMBOLP (obj) + ? (Fsymbol_name (obj)) + : obj)); +} + +static SCM +guile_ref (Lisp_Object args, int privatep) +{ + Lisp_Object module, binding; + + if (XINT (Flength (args)) != 2) + xsignal2 (Qwrong_number_of_arguments, + (privatep ? Qguile_private_ref : Qguile_ref), + Flength (args)); - tem = scm_c_eval_string (SSDATA (string)); - return (INTERACTIVE ? Fprin1 (tem, Qt) : tem); + module = Fcar (args); + binding = Fcar (Fcdr (args)); + + CHECK_LIST (module); + CHECK_SYMBOL (binding); + + for (Lisp_Object mod = module; !NILP (mod); mod = XCDR (mod)) + XSETCAR (mod, elisp_symbol_or_string_to_scm (XCAR (mod))); + + binding = elisp_symbol_or_string_to_scm (binding); + + return ((privatep ? scm_private_ref : scm_public_ref) + (module, binding)); +} + +DEFUN ("guile-ref", Fguile_ref, Sguile_ref, 2, UNEVALLED, 0, + doc: /* Reference a binding in a Guile module. */) + (Lisp_Object args) +{ + return guile_ref (args, 0); +} + +DEFUN ("guile-private-ref", Fguile_private_ref, Sguile_private_ref, + 2, UNEVALLED, 0, + doc: /* Reference a private binding in a Guile module. */) + (Lisp_Object args) +{ + return guile_ref (args, 1); } void @@ -4554,6 +4600,9 @@ syms_of_fns (void) DEFSYM (Qcursor_in_echo_area, "cursor-in-echo-area"); DEFSYM (Qwidget_type, "widget-type"); + DEFSYM (Qguile_ref, "guile-ref"); + DEFSYM (Qguile_private_ref, "guile-private-ref"); + staticpro (&string_char_byte_cache_string); string_char_byte_cache_string = Qnil; -- 1.8.1.2 --=-=-= Content-Type: text/plain Taylan --=-=-=--