[Top][All Lists]

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

[epsilon-devel] Bootstrapping away from Guile: essentially complete

From: Luca Saiu
Subject: [epsilon-devel] Bootstrapping away from Guile: essentially complete
Date: Wed, 12 Feb 2014 19:12:43 +0100
User-agent: Gnus (Ma Gnus v0.8), GNU Emacs, x86_64-unknown-linux-gnu


Between December and January both amz3 and Basile reminded me about how
important it was to complete the bootstrap process and remove the
dependency from Guile.  Of course I agreed.  (Basile, I have a couple
personal emails from you in my backlog.  I apologize for not having
replied yet.)

I'm now happy to report major progress in the direction of having a
native non-Guile REPL.  My extensible s-expression reader now works, and
very few warts remain:

1) there's no escaping for strings, characters and symbols.  For
   example, the string "a\na" is recognized correctly as valid, but is
   read into a four-fixnum vector.  This isn't deep at all, and is
   probably the first problem I'll solve.
   By the way, I've improved Unicode support, and any Unicode code point
   is now accepted as a character;

2) the end-of-file condition is not managed correctly.  I would like to
   be able to check for EOF on a given input port, and then possibly
   read characters or strings from it; that is how the Scheme library
   works, but is different from libc: at the libc level you have to
   attempt a character read to know if we are at the end of the stream:
   feof only checks a flag that is set by the reading functions.  I've
   decided that I don't want to invest time in writing a complex
   library right now, so I'll only wrap some libc functions in a
   trivial way; I had built an imperfect emulation with my preferred
   semantics, but I'm now switching to a simpler libc-style interface.
   My epsilon1 code dealing with input still relies on the old
   semantics, and is currently broken in the EOF case.  Not a terribly
   big deal, for the time being;

3) of course the debugging features implemented in Guile such as
   meta:macroexpand are not available in the native REPL.  They can and
   will be reimplemented in epsilon1.

4) s-expressions now hold optional locus information as a third field;
   the reader builds s-expressions with correct reference to source
   rows and columns.  However such information is not used anywhere,
   and is already lost at macroexpansion time.  This is not a
   regression, since no such information was ever available in the
   Guile-based system.

So, the big news: when I was in some devroom at FOSDEM, at a distance of
about one meter from Ludovic Court├Ęs, which is ironic, I ran for the
first time a non-Guile epsilon REPL based on my own s-expression reader
and writer.  Let me seize the occasion to repeat once more how I *love*
Guile: I need to remove it as a dependency because epsilon is an
incompatible system with a different focus, but I'll continue to use
Guile in other projects and to like Ludovic, Andy and the other people
involved with it.

You will find my recent work on the "reader" branch; see
https://savannah.gnu.org/git/?group=epsilon .  In case I didn't already
write it here, epsilon switched from bzr to git at the end of 2013.

Here's how you can play with it.

First get a copy, and switch to the reader branch.  Configure and
buld as usual; let's say in the source directory, for simplicity.
--8<---------------cut here---------------start------------->8---
address@hidden ~/epsilon]$ ./configure && make && echo SUCCESS
--8<---------------cut here---------------end--------------->8---

Now, before bootstrapping, make sure you have enough stack space.  It's
important, at least on my test machines.
--8<---------------cut here---------------start------------->8---
address@hidden ~/epsilon]$ ulimit -s unlimited
--8<---------------cut here---------------end--------------->8---

Now, let's use the Guile-based system to compile everything, including
the native REPL.  Please omit the command-line option --no-auto-compile
if you use Guile 1.8 instead of Guile 2.
--8<---------------cut here---------------start------------->8---
address@hidden ~/epsilon]$ cd bootstrap/scheme/
address@hidden ~/epsilon/bootstrap/scheme]$ ../../bin/guile+whatever 
GNU Guile 2.0.9-deb+1-1
Copyright (C) 1995-2013 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (load "bootstrap.scm")
--8<---------------cut here---------------end--------------->8---
This will take some time.

Now load the reader as well.
--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (load "sexpression-parser.e")
--8<---------------cut here---------------end--------------->8---

At this point you can use unexec to dump the current system state,
including the REPL definitions, into some file:
--8<---------------cut here---------------start------------->8---
(e1:toplevel (e1:unexec "/tmp/image" (repl:repl)))
--8<---------------cut here---------------end--------------->8---

The system will print nothing, but you'll notice the new file /tmp/image
.  Now exit guile+whatever by calling (exit) or pressing C-d.

There are three different image interpreters in bin/:
--8<---------------cut here---------------start------------->8---
address@hidden ~/epsilon/bootstrap/scheme]$ 
address@hidden ~/epsilon/bootstrap/scheme]$ cd ../..
address@hidden ~/epsilon]$ ls -XFs bin/
total 1300
228 epsilon-c-test-untagged*           132 epsilon-image-interpreter-untagged*  
 52 epsilon-test-utility*
188 epsilon-image-interpreter-smob*    352 epsilon-svm*                         
196 guile+whatever*
140 epsilon-image-interpreter-tagged*   12 epsilon-svm-config*
--8<---------------cut here---------------end--------------->8---
epsilon-image-interpreter-smob implements epsilon objects (fixnums and
buffers) as Guile SMOB objects, exactly like guile+whatever does.  Of
course epsilon-image-interpreter-smob is also linked to the Guile
runtime, and is not any faster than guile+whatever.

epsilon-image-interpreter-tagged and epsilon-image-interpreter-untagged
are what you think they are: they contain a fast and lean implementation
of native epsilon objects, and are not linked to Guile.
epsilon-image-interpreter-tagged represents boxedness tags (one bit per
word to distinguish what is boxed, plus a buffer header word holding its
length); epsilon-image-interpreter-untagged doesn't do this: it's faster
than epsilon-image-interpreter-tagged, but unsafe.  All three image
interpreters can run the image we made by unexecing. (Of course
epsilon-image-interpreter-untagged won't be able to unexec again from
it, because unexecing relies on boxedness tags; however *execing*

And finally here's our non-Guile REPL.  I was very happy when I had it
working for the first time in Bruxelles.
--8<---------------cut here---------------start------------->8---
address@hidden ~/epsilon]$ bin/epsilon-image-interpreter-tagged /tmp/image
> (e1:define x 42)
[You wrote: (#<symbol> #<symbol> 42)]
Defining the non-procedure x...
> x
[You wrote: #<symbol>]
--8<---------------cut here---------------end--------------->8---
The 42 printed by the system is green: of course the tagged image
interpreter can see what is a pointer and what isn't.

The bracketed part is just for debugging.  Notice that my printer
doesn't know how to write symbols yet.  That's quite trivial if you
ignore escaping, but I was lazy.

Of course the ("E") part of the REPL also calls epsilon1 macroexpansion
and transformation: you can use the advanced parts of the language, if
you can ignore or work around the temporary reader and writer warts.
--8<---------------cut here---------------start------------->8---
> (e1:define-macro (silly-square x) `(fixnum:* ,x ,x))
[You wrote: (#<symbol> (#<symbol> #<symbol>) (#<symbol> (#<symbol> (#<symbol> 
#<symbol>) (#<symbol> #<symbol>))))]
Defining the macro silly-square...
> (silly-square 10)
[You wrote: (#<symbol> 10)]
--8<---------------cut here---------------end--------------->8---

As I've already written, input with escaping is not read correctly yet:
--8<---------------cut here---------------start------------->8---
> "a\na"
[You wrote: #<string>]
0x1831888[4 97 92 110 97]
--8<---------------cut here---------------end--------------->8---
Four characters: 97 is #\a, 92 is #\\, and 110 is #\n.  There's no

Cool.  Now exit with C-d, ignoring the error message which is related to
the strange EOF situation.

Let's try it again with the untagged runtime.
--8<---------------cut here---------------start------------->8---
address@hidden ~/epsilon]$ bin/epsilon-image-interpreter-untagged /tmp/image
> (e1:define (fibo n) (e1:if (fixnum:< n 2) n (fixnum:+ (fibo (fixnum:- n 2)) 
> (fibo (fixnum:1- n)))))
[You wrote: (#<symbol> (#<symbol> #<symbol>) (#<symbol> (#<symbol> #<symbol> 2) 
#<symbol> (#<symbol> (#<symbol> (#<symbol> #<symbol> 2)) (#<symbol> (#<symbol> 
Defining the procedure fibo...
> (fibo 30)
[You wrote: (#<symbol> 30)]
--8<---------------cut here---------------end--------------->8---
The last call will take a short while; you can compare performance with
the two other implementations --- notice that all three use the same
epsilon0 interpreter written in C, with epsilon data implemented by
different functions/macros.

Also notice that epsilon-image-interpreter-untagged doesn't print
numbers in green, and that unexecing from it fails.  Failure is not
handled gracefully at all, as you have already noticed if you mistyped
anything in the native REPL: I'll implement exceptions in epsilon1 after
the first release, following the advanced stack-handling idea suggested
by Basile.  After that I'll be able to write a garbage collector in
epsilon1, dropping one more dependency.

Hoping you'll have fun with this,

Luca Saiu
Home page:   http://ageinghacker.net
GNU epsilon: http://www.gnu.org/software/epsilon
Marionnet:   http://marionnet.org

reply via email to

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