package module
Version: v1.0.0 Latest Latest

This package is not in the latest version of its module.

Go to latest
Published: Dec 13, 2019 License: MIT Imports: 12 Imported by: 2



GoDoc Go Report Card FOSSA Status

Parens is a LISP-like scripting layer for Go (or Golang).


  • Highly Customizable reader/parser through a read table (Inspired by Clojure)
  • Built-in data types: string, number, character, keyword, symbol, list, vector
  • Multiple number formats supported: decimal, octal, hexadecimal, radix and scientific notations.
  • Full unicode support. Symbols can include unicode characters (Example: find-δ, π etc.)
  • Character Literals with support for:
    1. simple literals (e.g., \a for a)
    2. special literals (e.g., \newline, \tab etc.)
    3. unicode literals (e.g., \u00A5 for ¥ etc.)
  • A simple stdlib which acts as reference for extending and provides some simple useful functions and macros.


To embed Parens in your application import

For stand-alone usage, install the Parens binary using:

go get -u -v

Then you can

  1. Run REPL by running parens command.
  2. Run a lisp file using parens <filename> command.
  3. Execute a LISP string using parens -e "(+ 1 2)"


Take a look at cmd/parens/main.go for a good example.

Check out examples/ for supported constructs.


1. Simple

Should have absolute bare minimum functionality.

scope := parens.NewScope(nil)

Above snippet gives you an interpreter that understands literals, (eval expr) and (load <file>).

2. Flexible

Should be possible to control what is available. Standard functions should be registered not built-in.


Adding this one line into the previous snippet allows you to include some minimal set of standard functions like +, -, *, / etc. and macros like let, cond, do etc.

The type of scope argument in any parens function is the following interface:

// Scope is responsible for managing bindings.
type Scope interface {
    Get(name string) (interface{}, error)
    Bind(name string, v interface{}, doc ...string) error
    Root() Scope
3. Interoperable

Should be able to expose Go values inside LISP and vice versa without custom signatures.

// any Go value can be exposed to interpreter as shown here:
scope.Bind("π", 3.1412)
scope.Bind("banner", "Hello from Parens!")

// functions can be bound directly.
// variadic functions are supported too.
scope.Bind("println", fmt.Println)
scope.Bind("printf", fmt.Printf)
scope.Bind("sin", math.Sin)

// once bound you can use them just as easily:
parens.ExecuteStr("(println banner)", scope)
parens.ExecuteStr(`(printf "value of π is = %f" π)`, scope)
4. Extensible Semantics

Special constructs like do, cond, if etc. can be added using Macros.

// This is simple implementation of '(do expr*)' special-form from Clojure!
func doMacro(scope parens.Scope, exps []parens.Expr) (interface{}, error) {
    var val interface{}
    var err error
    for _, exp := range exps {
        val, err = exp.Eval(scope)
        if err != nil {
            return nil, err

    return val, nil

// register the macro func in the scope.
scope.Bind("do", parens.MacroFunc(doMacro))

// finally use it!
src := `
    (println "Hello from parens")
    (label π 3.1412))
// value of 'val' after below statement should be 3.1412
val, _ := parens.ExecuteStr(src, scope)

See stdlib/macros.go for some built-in macros.

Parens is NOT

  1. An implementaion of a particular LISP dialect (like scheme, common-lisp etc.)
  2. A new dialect of LISP


  • Better error reporting
  • Optimization
  • Go code generation?


FOSSA Status




This section is empty.


View Source
var (
	// ErrNameNotFound is returned when a lookup is performed with a
	// non-bound name.
	ErrNameNotFound = errors.New("name not bound to a value")

	// ErrNotCallable is returned when a Call is attempted on a non-
	// callable value.
	ErrNotCallable = errors.New("value is not callable")

	// ErrConversionImpossible is returned when the Value type cannot be
	// converted to the expected type.
	ErrConversionImpossible = errors.New("cannot be converted")

	// ErrInvalidNumberOfArgs is returned when a function call is attempted
	// with invalid number of arguments.
	ErrInvalidNumberOfArgs = errors.New("invalid number of arguments")
View Source
var (
	// ErrSkip can be returned by reader macro to indicate a no-op.
	ErrSkip = errors.New("skip expr")


func Execute added in v0.0.7

func Execute(rd io.Reader, env Scope) (interface{}, error)

Execute reads until EOF or an error from the RuneScanner and executes the read s-expressions in the given scope.

func ExecuteExpr added in v0.0.7

func ExecuteExpr(expr Expr, env Scope) (interface{}, error)

ExecuteExpr executes the expr in the given scope.

func ExecuteStr added in v0.0.7

func ExecuteStr(src string, env Scope) (interface{}, error)

ExecuteStr is a convenience wrapper for Execute.


type Character added in v1.0.0

type Character rune

Character represents a character literal. For example, \a, \b, \1, \∂ etc are valid character literals. In addition, special literals like \newline, \space etc are supported.

func (Character) Eval added in v1.0.0

func (char Character) Eval(scope Scope) (interface{}, error)

Eval returns the character value.

func (Character) String added in v1.0.0

func (char Character) String() string

type Expr added in v0.0.7

type Expr interface {
	Eval(env Scope) (interface{}, error)

Expr represents an expression.

func Parse added in v0.0.7

func Parse(r io.Reader) (Expr, error)

Parse parses till the EOF and returns all s-exprs as a single ModuleExpr. This should be used to build an entire module from a file or string etc.

func ParseStr added in v0.0.7

func ParseStr(src string) (Expr, error)

ParseStr is a convenience wrapper for Parse.

type Float64 added in v1.0.0

type Float64 float64

Float64 represents double precision floating point numbers represented using float or scientific number formats.

func (Float64) Eval added in v1.0.0

func (f64 Float64) Eval(scope Scope) (interface{}, error)

Eval returns the underlying double-precision float value.

func (Float64) String added in v1.0.0

func (f64 Float64) String() string

type Int64 added in v1.0.0

type Int64 int64

Int64 represents integer values represented using decimal, octal, radix and hexadecimal formats.

func (Int64) Eval added in v1.0.0

func (i64 Int64) Eval(scope Scope) (interface{}, error)

Eval returns the underlying integer value.

func (Int64) String added in v1.0.0

func (i64 Int64) String() string

type Keyword added in v1.0.0

type Keyword string

Keyword represents a keyword literal.

func (Keyword) Eval added in v1.0.0

func (kw Keyword) Eval(scope Scope) (interface{}, error)

Eval returns the keyword value.

func (Keyword) String added in v1.0.0

func (kw Keyword) String() string

type List added in v1.0.0

type List []Expr

List represents an list of forms. Evaluating a list leads to a function invocation.

func (List) Eval added in v1.0.0

func (lf List) Eval(scope Scope) (interface{}, error)

Eval executes the list as a function invocation.

func (List) String added in v1.0.0

func (lf List) String() string

type MacroFunc added in v0.0.7

type MacroFunc func(scope Scope, exprs []Expr) (interface{}, error)

MacroFunc represents the signature of the Go macro functions. Functions bound in the scope as MacroFunc will receive un-evaluated list of s-exps and the current scope.

type Module added in v1.0.0

type Module []Expr

Module represents a group of forms. Evaluating a module form returns the result of evaluating the last form in the list.

func (Module) Eval added in v1.0.0

func (m Module) Eval(scope Scope) (interface{}, error)

Eval evaluates all the forms and returns the result of the last evaluation.

func (Module) String added in v1.0.0

func (m Module) String() string

type Reader added in v1.0.0

type Reader struct {

	Hook ReaderMacro
	// contains filtered or unexported fields

Reader provides functions to parse characters from a stream into symbolic expressions or forms.

func New

func New(rs io.Reader) *Reader

New returns a lisp reader instance which can read forms from r. Reader behavior can be customized by using SetMacro to override or remove from the default read table. File name will be inferred from the reader value and type information.

func (*Reader) All added in v1.0.0

func (rd *Reader) All() (Module, error)

All consumes characters from stream until EOF and returns a list of all the forms parsed. Any no-op forms (e.g., comment) returned will not be included in the result.

func (*Reader) IsTerminal added in v1.0.0

func (rd *Reader) IsTerminal(r rune) bool

IsTerminal returns true if the rune should terminate a form. ReaderMacro trigger runes defined in the read table and all space characters including "," are considered terminal.

func (*Reader) One added in v1.0.0

func (rd *Reader) One() (Expr, error)

One consumes characters from underlying stream until a complete form is parsed and returns the form while ignoring the no-op forms like comments. Except EOF, all errors will be wrapped with ReaderError type along with the positional information obtained using Info().

func (*Reader) SetMacro added in v1.0.0

func (rd *Reader) SetMacro(init rune, macro ReaderMacro)

SetMacro sets the given reader macro as the handler for init rune in the read table. Overwrites if a macro is already present. If the macro value given is nil, entry for the init rune will be removed from the read table.

type ReaderError added in v1.0.0

type ReaderError struct {
	Cause  error
	File   string
	Line   int
	Column int

ReaderError wraps the parsing error with file and positional information.

func (ReaderError) Error added in v1.0.0

func (err ReaderError) Error() string

type ReaderMacro added in v1.0.0

type ReaderMacro func(rd *Reader, init rune) (Expr, error)

ReaderMacro implementations can be plugged into the Reader to extend, override or customize behavior of the reader.

type Scope

type Scope interface {
	Get(name string) (interface{}, error)
	Bind(name string, v interface{}, doc ...string) error
	Root() Scope

Scope is responsible for managing bindings.

func NewScope

func NewScope(parent Scope) Scope

NewScope initializes a new scope with given parent scope. parent can be nil.

type Stream added in v1.0.0

type Stream struct {
	File string
	// contains filtered or unexported fields

Stream provides functions to read from a rune reader and also maintains the stream information such as filename and position in stream.

func (Stream) Info added in v1.0.0

func (stream Stream) Info() (file string, line, col int)

Info returns information about the stream including file name and the position of the reader.

func (*Stream) NextRune added in v1.0.0

func (stream *Stream) NextRune() (rune, error)

NextRune returns next rune from the stream and advances the stream.

func (*Stream) SkipSpaces added in v1.0.0

func (stream *Stream) SkipSpaces() error

SkipSpaces consumes and discards runes from stream repeatedly until a character that is not a whitespace is identified. Along with standard unicode white-space characters "," is also considered a white-space and discarded.

func (*Stream) Unread added in v1.0.0

func (stream *Stream) Unread(runes ...rune)

Unread can be used to return runes consumed from the stream back to the stream. Un-reading more runes than read is guaranteed to work but might cause inconsistency in stream positional information.

type String added in v1.0.0

type String string

String represents double-quoted string literals. String Form represents the true string value obtained from the reader. Escape sequences are not applicable at this level.

func (String) Eval added in v1.0.0

func (se String) Eval(scope Scope) (interface{}, error)

Eval returns the unquoted string value.

func (String) String added in v1.0.0

func (se String) String() string

type Symbol added in v1.0.0

type Symbol string

Symbol represents a name given to a value in memory.

func (Symbol) Eval added in v1.0.0

func (sym Symbol) Eval(scope Scope) (interface{}, error)

Eval returns the value bound for the symbol in the scope.

func (Symbol) String added in v1.0.0

func (sym Symbol) String() string

type Vector added in v1.0.0

type Vector []Expr

Vector represents a list of values. Unlike List type, evaluation of vector does not lead to function invoke.

func (Vector) Eval added in v1.0.0

func (vf Vector) Eval(scope Scope) (interface{}, error)

Eval evaluates each item in the vector and returns the result list.

func (Vector) String added in v1.0.0

func (vf Vector) String() string


Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL