DEPRECATED: This repository is deprecated in favour much better slurp project and will be archived/removed soon.
Sabre is highly customizable, embeddable LISP engine for Go.
Check out Slang for a tiny LISP written using Sabre.
find-δ
, π
etc.)
and 🧠
, 🏃
etc. (yes, smileys too).\a
for a
)\newline
, \tab
etc.)\u00A5
for ¥
etc.)fn*
, def
, if
, do
, throw
, let*
sabre.Value
and optional sabre.Invokable
, sabre.Seq
interfaces for
adding custom data types. (See Evaluation)Please note that Sabre is NOT an implementation of a particular LISP dialect. It provides pieces that can be used to build a LISP dialect or can be used as a scripting layer.
What can you use it for?
Sabre requires Go 1.13 or higher.
Sabre has concept of Scope
which is responsible for maintaining bindings. You can bind
any Go value and access it using LISP code, which makes it possible to expose parts of your
API and make it scriptable or build your own LISP dialect. Also, See Extending
for more information on customizing the reader or eval.
package main
import "github.com/spy16/sabre"
func main() {
scope := sabre.NewScope(nil)
_ = scope.BindGo("inc", func(v int) int { return v+1 })
result, _ := sabre.ReadEvalStr(scope, "(inc 10)")
fmt.Printf("Result: %v\n", result) // should print "Result: 11"
}
Sabre comes with a tiny repl
package that is very flexible and easy to setup
to expose your LISP through a read-eval-print-loop.
package main
import (
"context"
"github.com/spy16/sabre"
"github.com/spy16/sabre/repl"
)
func main() {
scope := sabre.NewScope(nil)
scope.BindGo("inc", func(v int) int { return v+1 })
repl.New(scope,
repl.WithBanner("Welcome to my own LISP!"),
repl.WithPrompts("=>", "|"),
// many more options available
).Loop(context.Background())
}
Sabre has a small reference LISP dialect named Slang (short for Sabre Lang) for which a standalone binary is available. Check out Slang for instructions on installing Slang.
Sabre reader is inspired by Clojure reader and uses a read table. Reader supports following forms:
int64
Go representation and can be specified using decimal, binary
hexadecimal or radix notations. (e.g., 123, -123, 0b101011, 0xAF, 2r10100, 8r126 etc.)float64
Go representation and can be specified using
decimal notation or scientific notation. (e.g.: 3.1412, -1.234, 1e-5, 2e3, 1.5e3 etc.)rune
or uint8
Go representation and can be written in 3 ways:
\a
, \λ
, \β
etc.\newline
, \tab
etc.\u1267
true
or false
are converted to Bool
type.nil
is represented as a zero-allocation empty struct in Go.:
and evaluate to themselves.(1 2 3)
, (1 [])
).
Evaluating a list leads to an invocation.[]
, [1 2 3]
)#{1 2 3}
){:name "Bob" :age 10}
)Reader can be extended to add new syntactical features by adding reader macros
to the read table. Reader Macros are implementations of sabre.ReaderMacro
function type. Except numbers and symbols, everything else supported by the reader
is implemented using reader macros.
Keyword
, String
, Int
, Float
, Character
, Bool
, nil
, MultiFn
,
Fn
, Type
and Any
evaluate to themselves.Symbol
is resolved as follows:
.
, symbol is directly used to lookup in current Scope
to find the value..
), symbol is split using .
as
delimiter and first field is resolved as per previous rule and rest of the
fields are recursively resolved as members. (For example, foo.Bar.Baz
: foo
is resolved from scope, Bar
should be member of value of foo
. And Baz
should be member of value resolved for foo.Bar
)HashMap
, Vector
& Set
simply yields new hashmap, vector and set
whose values are evaluated values contained in the original hashmaap, vector and set.Module
evaluates all the forms in the module and returns the result
of last evaluation. Any error stops the evaluation process.List
is returned as is.List
is an invocation and evaluated using following rules:
SpecialForm
Go type),
it is invoked and return value is cached in the list. This return value
is used for evaluating the list.(do retval)
form.Invokable
value, Invoke()
is called. Functions
are implemented using MultiFn
which implements Invokable
. Vector
also implements
Invokable
and provides index access.