Re: [PATCH] Implement SRFI-105 curly infix expressions

2012-10-14 Thread Mark H Weaver
Hello all,

Here's an improved version of the SRFI-105 patch for Guile 2.0.  It
incorporates the recent name change 'nfx' --> '$nfx$', has an improved
test suite, and now correctly handles the case where 'curly-infix' is
enabled but the 'square-brackets' read option is disabled.

This patch assumes that the following patch set (per-port read options
and reader directives) has already been applied:

  http://lists.gnu.org/archive/html/guile-devel/2012-10/msg00056.html

Note that in the interests of backward compatibility, SRFI-105 syntax is
enabled by default, since '{' and '}' are currently considered "extended
alphabetic characters".  It must first be enabled in one of two ways:

* On a per-port basis, when the reader encounters the "#!curly-infix"
  reader directive, e.g. near the top of source files.

* Globally, by evaluating: (read-enable 'curly-infix)

Reviews solicited.

   Thanks,
 Mark


>From 4102fbbd852d2f36e13f0c7f10dbac2017552bff Mon Sep 17 00:00:00 2001
From: Mark H Weaver 
Date: Sun, 14 Oct 2012 04:09:01 -0400
Subject: [PATCH] Implement SRFI-105 curly infix expressions.

* libguile/private-options.h: Add SCM_CURLY_INFIX_P macro, and increment
  SCM_N_READ_OPTIONS.

* libguile/read.c (scm_read_opts): Add curly-infix reader option.
  (scm_t_read_opts): Add curly_infix_p field.
  (init_read_options): Initialize new curly_infix_p field.
  (CHAR_IS_DELIMITER): Add '{', '}', '[', and ']' as delimiters if
  curly_infix_p is set.

  (set_per_port_curly_infix_p): New internal static function.

  (scm_read_shebang): Handle '#!curly-infix' reader directive.

  (scm_read, scm_read_keyword, scm_read_vector, scm_read_bytevector):
  Pass new 'neoteric_p' argument to subroutines where needed.

  (scm_read_expression_1): New internal static function, which contains
  the code that was previously in 'scm_read_expression'.  Handle curly
  braces when curly_infix_p is set.  Pass new 'neoteric_p' argument to
  subroutines where needed.

  (scm_read_expression): Add 'neoteric_p' argument.  New function body
  to handle neoteric expressions where appropriate.

  (scm_read_sexp): Add 'neoteric_p' argument.  Handle curly infix
  expressions, converting them to normal s-expressions.

  (flush_ws, scm_read_commented_expression, scm_read_sharp,
  scm_read_quote, scm_read_syntax): Add 'neoteric_p' argument.
  Pass new 'neoteric_p' argument to subroutines where needed.

* doc/ref/srfi-modules.texi (SRFI-105): Add stub doc for SRFI-105.

* doc/ref/api-evaluation.texi (Scheme Read): Add documentation for the
  'curly-infix' read option and the '#!curly-infix' reader directive.

* doc/ref/api-options.texi (Runtime Options): Add 'curly-infix' to the
  list of read options.

* test-suite/Makefile.am: Add tests/srfi-105.test.

* test-suite/tests/srfi-105.test: New file.
---
 doc/ref/api-evaluation.texi|   10 +-
 doc/ref/api-options.texi   |1 +
 doc/ref/srfi-modules.texi  |   14 +++
 libguile/private-options.h |3 +-
 libguile/read.c|  231 +++-
 test-suite/Makefile.am |1 +
 test-suite/tests/srfi-105.test |   76 +
 7 files changed, 282 insertions(+), 54 deletions(-)
 create mode 100644 test-suite/tests/srfi-105.test

diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi
index 9eccb39..245d4e0 100644
--- a/doc/ref/api-evaluation.texi
+++ b/doc/ref/api-evaluation.texi
@@ -338,13 +338,15 @@ r6rs-hex-escapes  noUse R6RS variable-length character and string hex escape
 square-brackets   yes   Treat `[' and `]' as parentheses, for R6RS compatibility.
 hungry-eol-escapes no   In strings, consume leading whitespace after an
 escaped end-of-line.
+curly-infix   noSupport SRFI-105 curly infix expressions.
 @end smalllisp
 
 Note that Guile also includes a preliminary mechanism for overriding
-read options on a per-port basis.  Currently, the only read option that
-is overridden in this way is the @code{case-insensitive} option, which
-is set or unset when the reader encounters the special directives
-@code{#!fold-case} or @code{#!no-fold-case}.  There is currently no
+read options on a per-port basis.  The only read options that can
+currently be overridden in this way are the @code{case-insensitive} and
+@code{curly-infix} options, which are set (or unset) when the reader
+encounters the special directives @code{#!fold-case},
+@code{#!no-fold-case}, or @code{#!curly-infix}.  There is currently no
 other way to access or set these per-port read options.
 
 The boolean options may be toggled with @code{read-enable} and
diff --git a/doc/ref/api-options.texi b/doc/ref/api-options.texi
index f635978..1734318 100644
--- a/doc/ref/api-options.texi
+++ b/doc/ref/api-options.texi
@@ -390,6 +390,7 @@ r6rs-hex-escapes  noUse R6RS variable-length character and string hex escape
 square-brackets   yes   Treat `[' and `]' as parentheses, for R6RS compatibility.
 hungry-eol-escapes no   In strin

Re: More RTL Tests

2012-10-14 Thread Stefan Israelsson Tampe
On Sun, Oct 14, 2012 at 9:59 PM, Noah Lavine wrote:

> Hello,
>
> I have been working on understanding RTL, and I wrote the following
> tests. They're mostly to illustrate for myself how calling works in
> RTL, but they also serve to test it. Any objections if I commit them
> as part of rtl.test?
>
> (with-test-prefix "call"
>   (assert-equal 42
> (let ((call ;; (lambda (x) (x))
>(assemble-program
> '((begin-program call)
>   (assert-nargs-ee/locals 1 0)
>   (call 1 0 ())
>   (return 1) ;; MVRA from call
>   (return 1) ;; RA from call
>   (call (lambda () 42
>
>   (assert-equal 6
> (let ((call-with-3 ;; (lambda (x) (x 3))
>(assemble-program
> '((begin-program call-with-3)
>   (assert-nargs-ee/locals 1 1)
>   (load-constant 1 3)
>   (call 2 0 (1))
>   (return 2) ;; MVRA from call
>   (return 2) ;; RA from call
>   (call-with-3 (lambda (x) (* x 2))
>
> (with-test-prefix "tail-call"
>   (assert-equal 3
> (let ((call ;; (lambda (x) (x))
>(assemble-program
> '((begin-program call)
>   (assert-nargs-ee/locals 1 0)
>   (tail-call 0 0)
>   (call (lambda () 3
>
>   (assert-equal 6
> (let ((call-with-3 ;; (lambda (x) (x 3))
>(assemble-program
> '((begin-program call-with-3)
>   (assert-nargs-ee/locals 1 1)
>   (mov 1 0) ;; R1 <- R0
>   (load-constant 0 3) ;; R0 <- 3
>   (tail-call 1 1)
>   (call-with-3 (lambda (x) (* x 2))
>
>
This look good to me

My next goal is to learn to reference top-level variables. Could
> anyone tell me how that works, to make it easier?
>

The general way, use a symbol in loc a and a module in loc b and then issue
(resolve c b a)
(box-ref c c)

To put the symbol into c. The simplest way to check this is to pass b and a
as arguments
to the funciton, you may set the toplevel by using box-set!

For reference inside functions you may use
(toplevel-ref dst var_label mod_label sym_label)

This is a bit complicated and I havenot found that all the infrastructure
is in place to handle this
but basically one should need to prepare the code like this if I'm not
missing anything

(program f)
(toplevel-ref 1 var mod sym)
...
(label var)
(store-slot SCM_BOOL_F)
(label mod)
(store-slot module)
(label sym)
(stire-slot 'symbol)


where the stire-slot mechanism is not yet supported but should mean that
aligned to SCM it stores
the needed references.

This is what I guess it all means, correct me if i'm wrong!

/Stefan


More RTL Tests

2012-10-14 Thread Noah Lavine
Hello,

I have been working on understanding RTL, and I wrote the following
tests. They're mostly to illustrate for myself how calling works in
RTL, but they also serve to test it. Any objections if I commit them
as part of rtl.test?

(with-test-prefix "call"
  (assert-equal 42
(let ((call ;; (lambda (x) (x))
   (assemble-program
'((begin-program call)
  (assert-nargs-ee/locals 1 0)
  (call 1 0 ())
  (return 1) ;; MVRA from call
  (return 1) ;; RA from call
  (call (lambda () 42

  (assert-equal 6
(let ((call-with-3 ;; (lambda (x) (x 3))
   (assemble-program
'((begin-program call-with-3)
  (assert-nargs-ee/locals 1 1)
  (load-constant 1 3)
  (call 2 0 (1))
  (return 2) ;; MVRA from call
  (return 2) ;; RA from call
  (call-with-3 (lambda (x) (* x 2))

(with-test-prefix "tail-call"
  (assert-equal 3
(let ((call ;; (lambda (x) (x))
   (assemble-program
'((begin-program call)
  (assert-nargs-ee/locals 1 0)
  (tail-call 0 0)
  (call (lambda () 3

  (assert-equal 6
(let ((call-with-3 ;; (lambda (x) (x 3))
   (assemble-program
'((begin-program call-with-3)
  (assert-nargs-ee/locals 1 1)
  (mov 1 0) ;; R1 <- R0
  (load-constant 0 3) ;; R0 <- 3
  (tail-call 1 1)
  (call-with-3 (lambda (x) (* x 2))

My next goal is to learn to reference top-level variables. Could
anyone tell me how that works, to make it easier?

Thanks,
Noah



compile-rtl

2012-10-14 Thread Stefan Israelsson Tampe
Hi,

I'm right now trying to port compile-glil to compile-rtl and I would say
that what's hindering me is
what design choices to take?

1.
The main problem is that we do not have a stack pointer the same way as
before. Of cause we still need
to store temporary values and we will simply have to use predefined local
register indices, that's not hard to implement though.
The problem is that we will have memory not cleared that's not going to be
GC:ed until the
frame is changed. This will cause some potential memory leaks. To let it be
as it is designed right now, will mean that it is
very difficult looking at the scheme code to see what will be protected
from gc or not. And I fear that we will need to handle
this in some smart way. The solutions are either, keep a stack pointer in a
register and updated it for each push and pop
as before. Or do what we do after let forms, clear the variable slots  -
expensive! What I think is
that we need to have the equivalent of a stack pointer in order to properly
handle gc'ing. We could still have a register approach
and gain quite some speed bump (2x) from using direct addressing in stead
of using the middle layer of the stack for everything.

My vote is introduce a register sp again!

2.
Now when we are tail-calling in rtl, we just fill the argument slots with
the new function arguments directly and then tail-call by filling in
number of arguments and function. This is very smart and just some simple
features added would mean that a lot of translation
from one memory location to the other is skipped. I really like how the rtl
code handle this but there is an expense. It complicates life a little
when we overwrite arguments that are used in the calculation of other
arguments. I'm working on how to handle this but I just wanted to point
out how nice this design choice is.

3.
call's, here currently we send a list of register positions to the call
function and the call function itself will copy those to the argument
fields. This is the opposite
of the tail-call, in a case like (f 1 3) you will create two temporary
variables and copy them later on to the argument position. Here I would
like to change the
semantic so that we fill in the arguments directly just like in the
tail-call. Also, I would like to use the end of the stack region to compute
the function frame. Well even if we use the end of the full frame we will
save one move per argument which is nice.

4.
Return values.
We talked about this before and there is some concerns how to make this
fast. I would like to skip the complication by simply put the return values
in the
argument positions to the function. Also the number of arguments is
mediated to the reciever. I would like to skip the mv-return slot and add a
rmove function
like,

(call pos proc)
(rmove pos (i ...))

And it is rmove's responsibility to move the arguments to it's return
positions, also it's possible for functions calling functions
to just clear the function slot and keep the values for later use by simply
increasing the stack to contain the return value(s).
this means that we can keep the copying to the minimal (which is one of the
big costs). Also keeping it this way lead to quite some smooth
handling of code that evaluates a function on the return values, one just
need to fill in the function and return ip and evaluate. cool.
The downside is for native code where we may transfer things back in
computer registers. But the overhead of function call's are of such dignity
that
the copying of one value is not of importance even for natively compiled
functions, The upfront cost of handling functions is pretty high. Note that
the improvement's that I suggest have two properties, 1. they are
composable, 2. they scale well in the number of arguments and return values.
My feeling is that speed bumps due to function overhead can be adressed by
a) Inlining
b) A well designed interface of user defined instructions
c) Develop separate function call mechanisms that a compiler can deduce and
use.

WDYT
/Stefan


[PATCH] Implement SRFI-105 curly infix expressions.

2012-10-14 Thread Mark H Weaver
Hello all,

Here's a patch to implement curly infix expressions in Guile's core
reader, based on the current draft of SRFI-105.  It depends upon the
per-port reader options patches that I posted here a few minutes ago.

With this patch, although curly-infix expressions are not enabled by
default, they will be automatically enabled on a per-port basis when
'read' encounters the "#!curly-infix" reader directive.  They can also
be enabled globally by enabling the 'curly-infix' reader option.

David: if you would be willing to produce a set of SRFI-105 expressions
(along with their s-expression equivalents) to add to our test suite,
that would be very helpful.

It's probably not appropriate to commit this patch before SRFI-105 has
been finalized, but in the meantime here's a (hopefully) complete patch
set for your enjoyment.

Comments and suggestions solicited,

  Mark


>From 57a4ae1eb7f58103574525c7e727ff08d44f18ec Mon Sep 17 00:00:00 2001
From: Mark H Weaver 
Date: Sun, 14 Oct 2012 04:09:01 -0400
Subject: [PATCH] Implement SRFI-105 curly infix expressions.

* libguile/private-options.h: Add SCM_CURLY_INFIX_P macro, and increment
  SCM_N_READ_OPTIONS.

* libguile/read.c (scm_read_opts): Add curly-infix reader option.
  (scm_t_read_opts): Add curly_infix_p field.
  (init_read_options): Initialize new curly_infix_p field.
  (CHAR_IS_DELIMITER): Add '{' and '}' as delimiters if curly_infix_p
  is set.

  (set_per_port_curly_infix_p): New internal static function.

  (scm_read_shebang): Handle '#!curly-infix' reader directive.

  (scm_read, scm_read_keyword, scm_read_vector, scm_read_bytevector):
  Pass new 'neoteric_p' argument to subroutines where needed.

  (scm_read_expression_1): New internal static function, which contains
  the code that was previously in 'scm_read_expression'.  Handle curly
  braces when curly_infix_p is set.  Pass new 'neoteric_p' argument to
  subroutines where needed.

  (scm_read_expression): Add 'neoteric_p' argument.  New function body
  to handle neoteric expressions where appropriate.

  (scm_read_sexp): Add 'neoteric_p' argument.  Handle curly infix
  expressions, converting them to normal s-expressions.

  (flush_ws, scm_read_commented_expression, scm_read_sharp,
  scm_read_quote, scm_read_syntax): Add 'neoteric_p' argument.
  Pass new 'neoteric_p' argument to subroutines where needed.

* doc/ref/srfi-modules.texi (SRFI-105): Add stub doc for SRFI-105.

* doc/ref/api-evaluation.texi (Scheme Read): Add documentation for the
  'curly-infix' read option and the '#!curly-infix' reader directive.

* doc/ref/api-options.texi (Runtime Options): Add 'curly-infix' to the
  list of read options.

* test-suite/Makefile.am: Add tests/srfi-105.test.

* test-suite/tests/srfi-105.test: New file.
---
 doc/ref/api-evaluation.texi|   10 +-
 doc/ref/api-options.texi   |1 +
 doc/ref/srfi-modules.texi  |   14 +++
 libguile/private-options.h |3 +-
 libguile/read.c|  212 
 test-suite/Makefile.am |1 +
 test-suite/tests/srfi-105.test |   67 +
 7 files changed, 260 insertions(+), 48 deletions(-)
 create mode 100644 test-suite/tests/srfi-105.test

diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi
index 9eccb39..245d4e0 100644
--- a/doc/ref/api-evaluation.texi
+++ b/doc/ref/api-evaluation.texi
@@ -338,13 +338,15 @@ r6rs-hex-escapes  noUse R6RS variable-length character and string hex escape
 square-brackets   yes   Treat `[' and `]' as parentheses, for R6RS compatibility.
 hungry-eol-escapes no   In strings, consume leading whitespace after an
 escaped end-of-line.
+curly-infix   noSupport SRFI-105 curly infix expressions.
 @end smalllisp
 
 Note that Guile also includes a preliminary mechanism for overriding
-read options on a per-port basis.  Currently, the only read option that
-is overridden in this way is the @code{case-insensitive} option, which
-is set or unset when the reader encounters the special directives
-@code{#!fold-case} or @code{#!no-fold-case}.  There is currently no
+read options on a per-port basis.  The only read options that can
+currently be overridden in this way are the @code{case-insensitive} and
+@code{curly-infix} options, which are set (or unset) when the reader
+encounters the special directives @code{#!fold-case},
+@code{#!no-fold-case}, or @code{#!curly-infix}.  There is currently no
 other way to access or set these per-port read options.
 
 The boolean options may be toggled with @code{read-enable} and
diff --git a/doc/ref/api-options.texi b/doc/ref/api-options.texi
index f635978..1734318 100644
--- a/doc/ref/api-options.texi
+++ b/doc/ref/api-options.texi
@@ -390,6 +390,7 @@ r6rs-hex-escapes  noUse R6RS variable-length character and string hex escape
 square-brackets   yes   Treat `[' and `]' as parentheses, for R6RS compatibility.
 hungry-eol-escapes no   In strings, consume leading whitespace after an
 

[PATCH] Implement per-port reader options and #!fold-case

2012-10-14 Thread Mark H Weaver
Hello all,

Here's a patch set to implement per-port reader options in 2.0.  It also
implements the "#!fold-case" and "#!no-fold-case" reader directives from
the R7RS draft.

The first two patches are cleanups for minor problems I noticed while
working on the last patch, which is the interesting one.

Comments and suggestions solicited.

 Mark

>From 005465769504c4173f3469d7d3958bb0945d1e3b Mon Sep 17 00:00:00 2001
From: Mark H Weaver 
Date: Sat, 13 Oct 2012 20:28:27 -0400
Subject: [PATCH 1/3] Improve formatting of options help given long option
 names

* module/ice-9/boot-9.scm (define-option-interface): When printing
  options help, e.g. for (read-options 'help), expand the width of the
  first column by another tab stop, to accommodate option names of up to
  23 characters.
---
 module/ice-9/boot-9.scm |7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index cf8252a..d679f6e 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -2850,8 +2850,11 @@ module '(ice-9 q) '(make-q q-length))}."
 (lambda (option)
   (apply (lambda (name value documentation)
(display name)
-   (if (< (string-length (symbol->string name)) 8)
-   (display #\tab))
+   (let ((len (string-length (symbol->string name
+ (when (< len 16)
+   (display #\tab)
+   (when (< len 8)
+ (display #\tab
(display #\tab)
(display value)
(display #\tab)
-- 
1.7.10.4

>From f7c40bfde4e27c6ae1cc0bc346aff07907b54f1d Mon Sep 17 00:00:00 2001
From: Mark H Weaver 
Date: Sat, 13 Oct 2012 20:41:45 -0400
Subject: [PATCH 2/3] Remove prototype for scm_read_token, which does not
 exist.

* libguile/read.h: Remove prototype for scm_read_token.
---
 libguile/read.h |1 -
 1 file changed, 1 deletion(-)

diff --git a/libguile/read.h b/libguile/read.h
index 4bd08fa..3c47afd 100644
--- a/libguile/read.h
+++ b/libguile/read.h
@@ -54,7 +54,6 @@ SCM_API SCM scm_sym_dot;
 
 SCM_API SCM scm_read_options (SCM setting);
 SCM_API SCM scm_read (SCM port);
-SCM_API size_t scm_read_token (int ic, SCM * tok_buf, SCM port, int weird);
 SCM_API SCM scm_read_hash_extend (SCM chr, SCM proc);
 SCM_INTERNAL char *scm_i_scan_for_encoding (SCM port);
 SCM_API SCM scm_file_encoding (SCM port);
-- 
1.7.10.4

>From a771be5c83a97ea728ba34e19114c966164e4dc2 Mon Sep 17 00:00:00 2001
From: Mark H Weaver 
Date: Sat, 13 Oct 2012 23:02:05 -0400
Subject: [PATCH 3/3] Implement per-port reader options, #!fold-case and
 #!no-fold-case.

* libguile/ports.c (scm_new_port_table_entry): Change initial values
  in 'scm_i_port_weak_hash' from SCM_BOOL_F to SCM_EOL, for use as
  an alist, where per-port reader options can be stored.

* libguile/read.c (scm_t_read_opts): New internal C struct type.

  (set_per_port_read_option, set_per_port_case_insensitive_p,
  init_read_options): New internal static functions.

  (CHAR_IS_R5RS_DELIMITER, CHAR_IS_DELIMITER): Move the '[' and ']'
  delimiters from CHAR_IS_R5RS_DELIMITER to CHAR_IS_DELIMITER.  Consult
  'opts' (assumed to be a local variable) to determine whether square
  brackets are delimiters.

  (scm_read): Call 'init_read_options' to initialize a local struct of
  type 'scm_t_read_opts'.  A pointer to this struct is passed down to
  all reader helper functions that need it.

  (flush_ws, maybe_annotate_source, read_complete_token, read_token,
  scm_read_array, scm_read_bytevector, scm_read_character,
  scm_read_commented_expression, scm_read_expression,
  scm_read_guile_bit_vector, scm_read_keyword,
  scm_read_mixed_case_symbol, scm_read_nil, scm_read_number,
  scm_read_number_and_radix, scm_read_quote, scm_read_sexp,
  scm_read_sharp, scm_read_sharp_extension, scm_read_shebang,
  scm_read_srfi4_vector, scm_read_string, scm_read_syntax,
  scm_read_vector): Add 'opts' as an additional parameter, and use it to
  look up read options.  Previously the global read options were
  consulted directly.

* doc/ref/api-evaluation.texi (Case Sensitivity, Scheme Read): Mention
  the existence of per-port reader options, and the reader directives
  #!fold-case and #!no-fold-case.

* test-suite/tests/reader.test ("per-port-read-options"): Add tests.
---
 doc/ref/api-evaluation.texi  |   23 ++-
 libguile/ports.c |5 +-
 libguile/read.c  |  422 +-
 test-suite/tests/reader.test |   13 ++
 4 files changed, 323 insertions(+), 140 deletions(-)

diff --git a/doc/ref/api-evaluation.texi b/doc/ref/api-evaluation.texi
index 6112832..9eccb39 100644
--- a/doc/ref/api-evaluation.texi
+++ b/doc/ref/api-evaluation.texi
@@ -254,6 +254,8 @@ Encoding of Source Files}.
 
 @node Case Sen