Skip to content
uehaj edited this page Sep 13, 2010 · 44 revisions

Welcome to the LispBuilder wiki!

what is this

LispBuilder is lisp interpreter and parser implemented as Groovy’s Builder. LispBuilder accepts Lisp like expression, and can be evaluated on groovy.

sample1

def bx = new LispBuilder()

assert bx.build{progn
                ${defun; fib; ${n}
                  ${IF; ${or; ${equal; n; $1}; ${equal; n; $2}}
                    $1
                    ${add; ${fib; ${add; n; $(-1)}}
                      ${fib; ${add; n; $(-2)}}}}}

                ${fib; $10}

}.eval() == 55

sample2

def env = new Env()

env.eval{progn
         ${defun; improve; ${y; x}
           ${average; y; ${div; x; y}}}

         ${defun; good_enoughp; ${y; x}
           ${le; ${abs; ${sub; ${mul; y; y}; x}}; $(0.000001)}}

         ${defun; sqrt_iter; ${y; x}
           ${IF; ${good_enoughp; y; x}
             y
             ${sqrt_iter; ${improve; y; x}
               x}}}

         ${defun; sqrt; ${x}
           ${sqrt_iter; $(1.0); x}}}

assert env.eval{sqrt; $(3.0)} == 1.73205081

Lisp DSL Syntax

The lisp code needs to obey the following rules as Groovy DSL.

  • Use dollar sign ‘$’ and curly bracket ‘{}’ instead of round brackets.
Usual Lisp LispBuilder
(a) ${a}
  • Elements in list are delimited by semicolons (‘;’).
Usual Lisp LispBuilder
(a b c) ${a;b;c}
  • The semicolons before newline can be omitted.
Usual Lisp LispBuilder
(a
 b
 c)
${a
 b
 c}
  • Dollar sign is applied to the string atom.
Usual Lisp LispBuilder
ABC $“ABC
  • Dollar sign is applied also to the nonnegative integer atom.
Usual Lisp LispBuilder
123 $123
  • Other numeric constants are bundled with dollar sign and round brackets.
Usual Lisp LispBuilder
-3 $(-3)
1.25 $(1.25)
  • Use capital letters for the reserved words of Groovy.
Usual Lisp LispBuilder
if IF
true TRUE
false FALSE
  • Use add,sub,mul,div instead of +,-,*,/.
Usual Lisp LispBuilder
(+ a b) ${add; a; b}
(- a b) ${sub; a; b}
(* a b) ${mul; a; b}
(/ a b) ${div; a; b}
  • The symbol that has same name of Groovy/Java class name collides. For example, ‘fib’ cannot be used as a symbol with groovy code ‘fib.groovy’. Because symbol ‘fib’ is treated as the class name.

Making the display color of ‘$’ and ‘;’ to faint by syntax highlight setting may help readability :)

Semantics

The semantics of this Lisp is comparatively traditional with dynamic scope, but the following points are different.

  • FALSE and nil is different.
  • No special quote (’) notation (use (quote ..)).
  • No #’ notation.
  • No macros.
  • No implicit progn in body of lambda.
  • Case sensitive.

Built-in functions and predefined functions

List of built-in functions and predefined functions is shown as follows(see Functions.groovy in detail).

Built-in functions eq IF quote TRUE FALSE nil car cdr cons setq and or progn equal lt le gt ge add sub mul div defun call print println
Predefineds function not neq nullp append

Other features

  • Arbitrary Groovy and Java code can be called from lisp (see sample/swing.groovy).
  • Lazy evaluation like that in functional language. If Groovy closure is in list element, the evaluated value is the result of closure, and the closure is replaced to the value when that is called first time. See fibonacci.groovy. You can implement infinite length list.
def zip(a,b) { new Cons(a.car+b.car, {zip(a.cdr, b.cdr)}); }
fibs = new Cons(0, new Cons(1, {zip(fibs, fibs.cdr)}))
assert fibs[34] == 5702887
  • LispBuilder2 & 3. those are other implementations of lisp parser.(see sample/fibonacci2.groovy, sample/fibonacci3.groovy)

LispBuilder2 sample

assert bx.build{$($(progn,
                     $(defun, fib, $(n),
                       $(IF, $(or, $(equal, n, 1), $(equal, n, 2)),
                         1,
                         $(add, $(fib, $(add, n, -1)),
                           $(fib, $(add, n, -2))))),
                     $(fib, 10)))
}.eval() == 55

LispBuilder3 sample

assert bx.build{[[progn,
                  [defun, fib, [n],
                   [IF, [or, [equal, n, 1], [equal, n, 2]],
                    1,
                    [add, [fib, [add, n, -1]],
                     [fib, [add, n, -2]]]]],
                  [fib, 10]]]
}.eval() == 55