![](/style/images/good.png)
![](/style/images/bad.png)
Parens - parens is a scripting layer for Golang that uses lisp syntax
source link: https://www.tuicool.com/articles/hit/ZVbQRfb
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Parens
Parens is a LISP-like scripting layer for Go
(or Golang
).
Installation
To embed parens in your application import github.com/spy16/parens
.
For stand-alone usage, install the parens binary using:
go get -u -v github.com/spy16/parens/cmd/parens
Then you can
- Run
REPL
by runningparens
command. - Run a lisp file using
parens <filename>
command. - Execute a LISP string using
parens -e "(+ 1 2)"
Usage
Take a look at cmd/parens/main.go
for a good example.
Check out examples/
for supported constructs.
Goals:
1. Simple
Should have absolute bare minimum functionality.
scope := reflection.NewScope(nil) exec := parens.New(scope) exec.Execute("10")
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.
stdlib.RegisterAll(scope)
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 parens.New(scope)
is the following interface:
// Scope is responsible for managing bindings. type Scope interface { Get(name string) (interface{}, error) Bind(name string, v interface{}) error Root() Scope }
So, if you wanted to do some dynamic resolution during Get(name)
(e.g. If you wanted to return method Print
of object stdout
when Get("stdout.Print")
is called), you can easily implement this interface and pass it to parens.New
.
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: exec.Execute("(println banner)") exec.Execute(`(printf "value of π is = %f" π)`)
4. Extensible Semantics
Special constructs like do
, cond
, if
etc. can be added using Macros.
// This is standard implementation of '(do expr*)' special-form from Clojure! func doMacro(scope *reflection.Scope, callName string, exps []parser.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", parser.MacroFunc(doMacro)) // finally use it! src := ` (do (println "Hello from parens") (label π 3.1412)) ` // value of 'val' after below statement should be 3.1412 val, _ := exec.Execute(src)
See stdlib/macros.go
for some built-in macros.
Parens is NOT :
- An implementaion of a particular LISP dialect (like scheme, common-lisp etc.)
- A new dialect of LISP
TODO
- Better way to map error returns from Go functios to LISP
-
Result<interface{}, error>
type of design in Rust ?
-
- Better
parser
package- Support for macro functions
- Support for vectors
[]
- Better error reporting
- Better
reflection
package- Support for variadic functions
- Support for methods
- Type promotion/conversion
-
intX
types toint64
andfloat64
-
floatX
types toint64
andfloat64
- any values to
interface{}
type -
intX
andfloatX
types toint8
,int16
,float32
and vice versa?
-
- Performance Benchmark (optimization ?)
-
Go
code generation?
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK