guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, master, updated. v2.1.0-374-ge0f68f7


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, master, updated. v2.1.0-374-ge0f68f7
Date: Sat, 28 Jul 2012 10:45:44 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=e0f68f785d3899c6b565c12d6540f20730fcd9cc

The branch, master has been updated
       via  e0f68f785d3899c6b565c12d6540f20730fcd9cc (commit)
       via  2842a17112418052975728e3dd75e03aa6540aed (commit)
       via  40c73b5992d6212ffb345e496a9a2a6984a26cac (commit)
       via  10a97755d4a1b2034f8a131215a92c0b29000969 (commit)
      from  4bfe73072b75259a97a9daa81ed5c9c01e8a4af5 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit e0f68f785d3899c6b565c12d6540f20730fcd9cc
Merge: 2842a17 10a9775
Author: Andy Wingo <address@hidden>
Date:   Sat Jul 28 12:44:36 2012 +0200

    1;3202;0cMerge remote-tracking branch 'origin/stable-2.0'

commit 2842a17112418052975728e3dd75e03aa6540aed
Author: Andy Wingo <address@hidden>
Date:   Sat Jul 28 12:43:46 2012 +0200

    improve documentation for structs
    
    * doc/ref/api-compound.texi (Structures): Update to describe
      <standard-vtable>, to remove documentation for make-vtable-vtable, to
      describe meta-vtables, and to add a long example.

commit 40c73b5992d6212ffb345e496a9a2a6984a26cac
Author: Andy Wingo <address@hidden>
Date:   Sat Jul 28 12:28:21 2012 +0200

    set struct names for <standard-vtable>, etc
    
    * libguile/struct.c (scm_init_struct): Set the struct names for
      <standard-vtable>, <applicable-struct-vtable>, and
      <applicable-struct-with-setter-vtable>.

-----------------------------------------------------------------------

Summary of changes:
 doc/ref/api-compound.texi     |  329 ++++++++++++++++++++++++++---------------
 libguile/numbers.c            |    3 +-
 libguile/struct.c             |   14 ++-
 test-suite/tests/numbers.test |    7 +-
 4 files changed, 224 insertions(+), 129 deletions(-)

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 779c76d..d020774 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -2370,11 +2370,12 @@ data abstractions, and for that purpose structures are 
useful.  Indeed,
 records in Guile are implemented with structures.
 
 @menu
-* Vtables::                     
-* Structure Basics::            
-* Vtable Contents::              
-* Vtable Vtables::              
-* Tail Arrays::              
+* Vtables::
+* Structure Basics::
+* Vtable Contents::
+* Meta-Vtables::
+* Vtable Example::
+* Tail Arrays::
 @end menu
 
 @node Vtables
@@ -2447,11 +2448,9 @@ structure.
 @example
 (make-vtable "prpw"
              (lambda (struct port)
-               (display "#<" port)
-               (display (struct-ref struct 0) port)
-               (display " and " port)
-               (display (struct-ref struct 1) port)
-               (display ">" port)))
+               (format port "#<~a and ~a>"
+                       (struct-ref struct 0)
+                       (struct-ref struct 1))))
 @end example
 @end deffn
 
@@ -2542,26 +2541,24 @@ Contents}, for more on vtables.
 @node Vtable Contents
 @subsubsection Vtable Contents
 
-A vtable is itself a structure, with particular fields that hold
-information about the structures to be created.  These include the
-fields of those structures, and the print function for them.  The
-variables below allow access to those fields.
+A vtable is itself a structure.  It has a specific set of fields
+describing various aspects of its @dfn{instances}: the structures
+created from a vtable.  Some of the fields are internal to Guile, some
+of them are part of the public interface, and there may be additional
+fields added on by the user.
 
address@hidden {Scheme Procedure} struct-vtable? obj
address@hidden {C Function} scm_struct_vtable_p (obj)
-Return @code{#t} if @var{obj} is a vtable structure.
-
-Note that because vtables are simply structures with a particular
-layout, @code{struct-vtable?} can potentially return true on an
-application structure which merely happens to look like a vtable.
address@hidden deffn
+Every vtable has a field for the layout of their instances, a field for
+the procedure used to print its instances, and a field for the name of
+the vtable itself.  Access to the layout and printer is exposed directly
+via field indexes.  Access to the vtable name is exposed via accessor
+procedures.
 
 @defvr {Scheme Variable} vtable-index-layout
 @defvrx {C Macro} scm_vtable_index_layout
 The field number of the layout specification in a vtable.  The layout
 specification is a symbol like @code{pwpw} formed from the fields
 string passed to @code{make-vtable}, or created by
address@hidden (@pxref{Vtable Vtables}).
address@hidden (@pxref{Meta-Vtables}).
 
 @example
 (define v (make-vtable "pwpw" 0))
@@ -2572,12 +2569,6 @@ This field is read-only, since the layout of structures 
using a vtable
 cannot be changed.
 @end defvr
 
address@hidden {Scheme Variable} vtable-index-vtable
address@hidden {C Macro} scm_vtable_index_vtable
-A self-reference to the vtable, ie.@: a type @code{s} field.  This is
-used by C code within Guile and has no use at the Scheme level.
address@hidden defvr
-
 @defvr {Scheme Variable} vtable-index-printer
 @defvrx {C Macro} scm_vtable_index_printer
 The field number of the printer function.  This field contains @code{#f}
@@ -2612,125 +2603,217 @@ from @var{vtable}.
 @end deffn
 
 
address@hidden Vtable Vtables
address@hidden Vtable Vtables
-
-As noted above, a vtable is a structure and that structure is itself
-described by a vtable.  Such a ``vtable of a vtable'' can be created
-with @code{make-vtable-vtable} below.  This can be used to build sets
-of related vtables, possibly with extra application fields.
address@hidden Meta-Vtables
address@hidden Meta-Vtables
 
-This second level of vtable can be a little confusing.  The ball
-example below is a typical use, adding a ``class data'' field to the
-vtables, from which instance structures are created.  The current
-implementation of Guile's own records (@pxref{Records}) does something
-similar, a record type descriptor is a vtable with room to hold the
-field names of the records to be created from it.
+As a structure, a vtable also has a vtable, which is also a structure.
+Structures, their vtables, the vtables of the vtables, and so on form a
+tree of structures.  Making a new structure adds a leaf to the tree, and
+if that structure is a vtable, it may be used to create other leaves.
 
address@hidden {Scheme Procedure} make-vtable-vtable user-fields tail-size 
[print]
address@hidden {C Function} scm_make_vtable_vtable (user_fields, tail_size, 
print_and_init_list)
-Create a ``vtable-vtable'' which can be used to create vtables.  This
-vtable-vtable is also a vtable, and is self-describing, meaning its
-vtable is itself.  The following is a simple usage.
+If you traverse up the tree of vtables, via calling
address@hidden, eventually you reach a root which is the vtable of
+itself:
 
 @example
-(define vt-vt (make-vtable-vtable "" 0))
-(define vt    (make-struct vt-vt 0
-                           (make-struct-layout "pwpw"))
-(define s     (make-struct vt 0 123 456))
-
-(struct-ref s 0) @result{} 123
+scheme@@(guile-user)> (current-module)
+$1 = #<directory (guile-user) 221b090>
+scheme@@(guile-user)> (struct-vtable $1)
+$2 = #<record-type module>
+scheme@@(guile-user)> (struct-vtable $2)
+$3 = #<<standard-vtable> 12c30a0>
+scheme@@(guile-user)> (struct-vtable $3)
+$4 = #<<standard-vtable> 12c3fa0>
+scheme@@(guile-user)> (struct-vtable $4)
+$5 = #<<standard-vtable> 12c3fa0>
+scheme@@(guile-user)> <standard-vtable>
+$6 = #<<standard-vtable> 12c3fa0>
 @end example
 
address@hidden is used to create a vtable from the vtable-vtable.
-The first initializer is a layout object (field
address@hidden), usually obtained from
address@hidden (below).  An optional second initializer is
-a printer function (field @code{vtable-index-printer}), used as
-described under @code{make-vtable} (@pxref{Vtables}).
+In this example, we can say that @code{$1} is an instance of @code{$2},
address@hidden is an instance of @code{$3}, @code{$3} is an instance of
address@hidden, and @code{$4}, strangely enough, is an instance of itself.
+The value bound to @code{$4} in this console session also bound to
address@hidden<standard-vtable>} in the default environment.
 
address@hidden 1
address@hidden is a layout string giving extra fields to have in
-the vtables.  A vtable starts with some base fields as per @ref{Vtable
-Contents}, and @var{user-fields} is appended.  The @var{user-fields}
-start at field number @code{vtable-offset-user} (below), and exist in
-both the vtable-vtable and in the vtables created from it.  Such
-fields provide space for ``class data''.  For example,
address@hidden {Scheme Variable} <standard-vtable>
+A meta-vtable, useful for making new vtables.
address@hidden defvr
 
address@hidden
-(define vt-of-vt (make-vtable-vtable "pw" 0))
-(define vt       (make-struct vt-of-vt 0))
-(struct-set! vt vtable-offset-user "my class data")
address@hidden example
+All of these values are structures.  All but @code{$1} are vtables.  As
address@hidden is an instance of @code{$3}, and @code{$3} is a vtable, we can
+say that @code{$3} is a @dfn{meta-vtable}: a vtable that can create
+vtables.
 
address@hidden is the size of the tail array in the vtable-vtable
-itself, if @var{user-fields} specifies a tail array.  This should be 0
-if nothing extra is required or the format has no tail array.  The
-tail array field such as @samp{pW} holds the tail array size, as
-usual, and is followed by the extra space.
+With this definition, we can specify more precisely what a vtable is: a
+vtable is a structure made from a meta-vtable.  Making a structure from
+a meta-vtable runs some special checks to ensure that the first field of
+the structure is a valid layout.  Additionally, if these checks see that
+the layout of the child vtable contains all the required fields of a
+vtable, in the correct order, then the child vtable will also be a
+meta-table, inheriting a magical bit from the parent.
+
address@hidden {Scheme Procedure} struct-vtable? obj
address@hidden {C Function} scm_struct_vtable_p (obj)
+Return @code{#t} if @var{obj} is a vtable structure: an instance of a
+meta-vtable.
address@hidden deffn
+
address@hidden<standard-vtable>} is a root of the vtable tree.  (Normally there
+is only one root in a given Guile process, but due to some legacy
+interfaces there may be more than one.)
+
+The set of required fields of a vtable is the set of fields in the
address@hidden<standard-vtable>}, and is bound to @code{standard-vtable-fields}
+in the default environment.  It is possible to create a meta-vtable that
+with additional fields in its layout, which can be used to create
+vtables with additional data:
 
 @example
-(define vt-vt (make-vtable-vtable "pW" 20))
-(define my-vt-tail-start (1+ vtable-offset-user))
-(struct-set! vt-vt (+ 3 my-vt-tail-start) "data in tail")
+scheme@@(guile-user)> (struct-ref $3 vtable-index-layout)
+$6 = pruhsruhpwphuhuhprprpw
+scheme@@(guile-user)> (struct-ref $4 vtable-index-layout)
+$7 = pruhsruhpwphuhuh
+scheme@@(guile-user)> standard-vtable-fields 
+$8 = "pruhsruhpwphuhuh"
+scheme@@(guile-user)> (struct-ref $2 vtable-offset-user)
+$9 = module
 @end example
 
-The optional @var{print} argument is used by @code{display} and
address@hidden (etc) to print the vtable-vtable and any vtables created
-from it.  It's called as @code{(@var{print} vtable port)} and should
-look at @var{vtable} and write to @var{port}.  The default is the
-usual structure print function, which just gives machine addresses.
address@hidden deffn
+In this continuation of our earlier example, @code{$2} is a vtable that
+has extra fields, because its vtable, @code{$3}, was made from a
+meta-vtable with an extended layout.  @code{vtable-offset-user} is a
+convenient definition that indicates the number of fields in
address@hidden
+
address@hidden {Scheme Variable} standard-vtable-fields
+A string containing the orderedq set of fields that a vtable must have.
address@hidden defvr
+
address@hidden {Scheme Variable} vtable-offset-user
+The first index in a vtable that is available for a user.
address@hidden defvr
 
 @deffn {Scheme Procedure} make-struct-layout fields
 @deffnx {C Function} scm_make_struct_layout (fields)
 Return a structure layout symbol, from a @var{fields} string.
 @var{fields} is as described under @code{make-vtable}
 (@pxref{Vtables}).  An invalid @var{fields} string is an error.
address@hidden deffn
+
+With these definitions, one can define @code{make-vtable} in this way:
 
 @example
-(make-struct-layout "prpW") @result{} prpW
-(make-struct-layout "blah") @result{} ERROR
+(define* (make-vtable fields #:optional printer)
+  (make-struct/no-tail <standard-vtable>
+    (make-struct-layout fields)
+    printer))
 @end example
address@hidden deffn
 
address@hidden {Scheme Variable} vtable-offset-user
address@hidden {C Macro} scm_vtable_offset_user
-The first field in a vtable which is available for application use.
-Such fields only exist when specified by @var{user-fields} in
address@hidden above.
address@hidden defvr
 
address@hidden 1
-Here's an extended vtable-vtable example, creating classes of
-``balls''.  Each class has a ``colour'', which is fixed.  Instances of
-those classes are created, and such each such ball has an ``owner'',
-which can be changed.
address@hidden Vtable Example
address@hidden Vtable Example
 
address@hidden
-(define ball-root (make-vtable-vtable "pr" 0))
-
-(define (make-ball-type ball-color)
-  (make-struct ball-root 0
-              (make-struct-layout "pw")
-               (lambda (ball port)
-                 (format port "#<a ~A ball owned by ~A>"
-                         (color ball)
-                         (owner ball)))
-               ball-color))
-(define (color ball)
-  (struct-ref (struct-vtable ball) vtable-offset-user))
-(define (owner ball)
-  (struct-ref ball 0))
-
-(define red (make-ball-type 'red))
-(define green (make-ball-type 'green))
-
-(define (make-ball type owner) (make-struct type 0 owner))
-
-(define ball (make-ball green 'Nisse))
-ball @result{} #<a green ball owned by Nisse>
address@hidden lisp
+Let us bring these points together with an example.  Consider a simple
+object system with single inheritance.  Objects will be normal
+structures, and classes will be vtables with three extra class fields:
+the name of the class, the parent class, and the list of fields.
+
+So, first we need a meta-vtable that allocates instances with these
+extra class fields.
+
address@hidden
+(define <class>
+  (make-vtable
+   (string-append standard-vtable-fields "pwpwpw")
+   (lambda (x port)
+     (format port "<<class> ~a>" (class-name x)))))
+
+(define (class? x)
+  (and (struct? x)
+       (eq? (struct-vtable x) <class>)))
address@hidden example
+
+To make a structure with a specific meta-vtable, we will use
address@hidden/no-tail}, passing it the computed instance layout and
+printer, as with @code{make-vtable}, and additionally the extra three
+class fields.
+
address@hidden
+(define (make-class name parent fields)
+  (let* ((fields (compute-fields parent fields))
+         (layout (compute-layout fields)))
+    (make-struct/no-tail <class>
+      layout 
+      (lambda (x port)
+        (print-instance x port))
+      name
+      parent
+      fields)))
address@hidden example
+
+Instances will store their associated data in slots in the structure: as
+many slots as there are fields.  The @code{compute-layout} procedure
+below can compute a layout, and @code{field-index} returns the slot
+corresponding to a field.
+
address@hidden
+(define-syntax-rule (define-accessor name n)
+  (define (name obj)
+    (struct-ref obj n)))
+
+;; Accessors for classes
+(define-accessor class-name (+ vtable-offset-user 0))
+(define-accessor class-parent (+ vtable-offset-user 1))
+(define-accessor class-fields (+ vtable-offset-user 2))
+
+(define (compute-fields parent fields)
+  (if parent
+      (append (class-fields parent) fields)
+      fields))
+
+(define (compute-layout fields)
+  (make-struct-layout
+   (string-concatenate (make-list (length fields) "pw"))))
+
+(define (field-index class field)
+  (list-index (class-fields class) field))
+
+(define (print-instance x port)
+  (format port "<~a" (class-name (struct-vtable x)))
+  (for-each (lambda (field idx)
+              (format port " ~a: ~a" field (struct-ref x idx)))
+            (class-fields (struct-vtable x))
+            (iota (length (class-fields (struct-vtable x)))))
+  (format port ">"))
address@hidden example
+
+So, at this point we can actually make a few classes:
+
address@hidden
+(define-syntax-rule (define-class name parent field ...)
+  (define name (make-class 'name parent '(field ...))))
+
+(define-class <surface> #f
+  width height)
+
+(define-class <window> <surface>
+  x y)
address@hidden example
+
+And finally, make an instance:
+
address@hidden
+(make-struct/no-tail <window> 400 300 10 20)
address@hidden <<window> width: 400 height: 300 x: 10 y: 20>
address@hidden example
+
+And that's that.  Note that there are many possible optimizations and
+feature enhancements that can be made to this object system, and the
+included GOOPS system does make most of them.  For more simple use
+cases, the records facility is usually sufficient.  But sometimes you
+need to make new kinds of data abstractions, and for that purpose,
+structs are here.
 
 @node Tail Arrays
 @subsubsection Tail Arrays
diff --git a/libguile/numbers.c b/libguile/numbers.c
index 7bbdc56..63a6501 100644
--- a/libguile/numbers.c
+++ b/libguile/numbers.c
@@ -8906,7 +8906,8 @@ SCM_PRIMITIVE_GENERIC (scm_angle, "angle", 1, 0, 0,
     }
   else if (SCM_REALP (z))
     {
-      if (SCM_REAL_VALUE (z) >= 0)
+      double x = SCM_REAL_VALUE (z);
+      if (x > 0.0 || double_is_non_negative_zero (x))
         return flo0;
       else
         return scm_from_double (atan2 (0.0, -1.0));
diff --git a/libguile/struct.c b/libguile/struct.c
index fe6b042..1a30fef 100644
--- a/libguile/struct.c
+++ b/libguile/struct.c
@@ -945,6 +945,8 @@ scm_print_struct (SCM exp, SCM port, scm_print_state 
*pstate)
 void
 scm_init_struct ()
 {
+  SCM name;
+
   /* The first word of a struct is equal to `SCM_STRUCT_DATA (vtable) +
      scm_tc3_struct', and `SCM_STRUCT_DATA (vtable)' is 2 words after VTABLE by
      default.  */
@@ -961,21 +963,27 @@ scm_init_struct ()
   required_applicable_with_setter_fields = scm_from_locale_string 
(SCM_APPLICABLE_WITH_SETTER_BASE_LAYOUT);
 
   scm_standard_vtable_vtable = scm_i_make_vtable_vtable (scm_nullstr);
-  scm_c_define ("<standard-vtable>", scm_standard_vtable_vtable);
+  name = scm_from_utf8_symbol ("<standard-vtable>");
+  scm_set_struct_vtable_name_x (scm_standard_vtable_vtable, name);
+  scm_define (name, scm_standard_vtable_vtable);
 
   scm_applicable_struct_vtable_vtable =
     scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
                      scm_list_1 (scm_make_struct_layout 
(required_vtable_fields)));
+  name = scm_from_utf8_symbol ("<applicable-struct-vtable>");
   SCM_SET_VTABLE_FLAGS (scm_applicable_struct_vtable_vtable,
                         SCM_VTABLE_FLAG_APPLICABLE_VTABLE);
-  scm_c_define ("<applicable-struct-vtable>", 
scm_applicable_struct_vtable_vtable);
+  scm_set_struct_vtable_name_x (scm_applicable_struct_vtable_vtable, name);
+  scm_define (name, scm_applicable_struct_vtable_vtable);
 
   scm_applicable_struct_with_setter_vtable_vtable =
     scm_make_struct (scm_standard_vtable_vtable, SCM_INUM0,
                      scm_list_1 (scm_make_struct_layout 
(required_vtable_fields)));
+  name = scm_from_utf8_symbol ("<applicable-struct-with-setter-vtable>");
+  scm_set_struct_vtable_name_x 
(scm_applicable_struct_with_setter_vtable_vtable, name);
   SCM_SET_VTABLE_FLAGS (scm_applicable_struct_with_setter_vtable_vtable,
                         SCM_VTABLE_FLAG_APPLICABLE_VTABLE | 
SCM_VTABLE_FLAG_SETTER_VTABLE);
-  scm_c_define ("<applicable-struct-with-setter-vtable>", 
scm_applicable_struct_with_setter_vtable_vtable);
+  scm_define (name, scm_applicable_struct_with_setter_vtable_vtable);
 
   scm_c_define ("vtable-index-layout", scm_from_int (scm_vtable_index_layout));
   scm_c_define ("vtable-index-printer",
diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test
index b1f3d8b..a6697c9 100644
--- a/test-suite/tests/numbers.test
+++ b/test-suite/tests/numbers.test
@@ -4241,7 +4241,7 @@
 (with-test-prefix "angle"
   (define pi 3.14159265358979323846)
   (define (almost= x y)
-    (> 0.01 (magnitude (- x y))))
+    (> 0.000001 (magnitude (- x y))))
   
   (pass-if (documented? angle))
 
@@ -4252,7 +4252,10 @@
   (pass-if "bignum -ve" (almost= pi (angle (1- fixnum-min))))
 
   (pass-if "flonum +ve" (=        0 (angle 1.5)))
-  (pass-if "flonum -ve" (almost= pi (angle -1.5))))
+  (pass-if "flonum -ve" (almost= pi (angle -1.5)))
+
+  (pass-if "signed zero +ve" (=        0 (angle 0.0)))
+  (pass-if "signed zero -ve" (almost= pi (angle -0.0))))
 
 ;;;
 ;;; inexact->exact


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]