The Gmnlisp is a small Lisp implementation in Go. The functions are the subset of ISLisp's. It is developed to embbed to the applications for customizing.
Download the binary package from Releases and extract the executable.
scoop install https://raw.githubusercontent.com/hymkor/gmnlisp/master/gmnlisp.json
or
scoop bucket add hymkor https://github.com/hymkor/scoop-bucket
scoop install gmnlisp
package main
import (
"context"
"fmt"
"os"
"github.com/hymkor/gmnlisp"
)
func main() {
lisp := gmnlisp.New()
lisp = lisp.Let(gmnlisp.Variables{
gmnlisp.NewSymbol("a"): gmnlisp.Integer(1),
gmnlisp.NewSymbol("b"): gmnlisp.Integer(2),
})
value, err := lisp.Interpret(context.TODO(), "(+ a b)")
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
return
}
value.PrintTo(os.Stdout, gmnlisp.PRINT)
fmt.Println()
}
$ go run examples/example1.go
3
gmnlisp.New
returns the new Lisp interpretor instance (*gmnlisp.World
).gmnlisp.NewSymbol
is the symbol constructor.gmnlisp.NewSymbol("a")
always returns the same value no matter how many times you call it.gmnlisp.Variables
is the symbol-map type. It is the alias ofmap[gmnlisp.Symbol]gmnlisp.Node
.Node
is the interface-type that all objects in the Lisp have to implement..Let
makes a new instance including the given namespace.
lisp.Let(gmnlisp.Variables{
gmnlisp.NewSymbol("a"): gmnlisp.Integer(1),
gmnlisp.NewSymbol("b"): gmnlisp.Integer(2),
}).Interpret(context.Background(),"(c)")
is same as (let ((a 1) (b 1)) (c))
package main
import (
"context"
"fmt"
"os"
"github.com/hymkor/gmnlisp"
)
func sum(ctx context.Context, w *gmnlisp.World, args []gmnlisp.Node) (gmnlisp.Node, error) {
a, ok := args[0].(gmnlisp.Integer)
if !ok {
return nil, fmt.Errorf("expect integer: %#v", args[0])
}
b, ok := args[1].(gmnlisp.Integer)
if !ok {
return nil, fmt.Errorf("expect integer: %#v", args[1])
}
return gmnlisp.Integer(a + b), nil
}
func main() {
lisp := gmnlisp.New()
lisp = lisp.Let(
gmnlisp.Variables{
gmnlisp.NewSymbol("sum"): &gmnlisp.Function{C: 2, F: sum},
})
result, err := lisp.Interpret(context.Background(), `(sum 1 2)`)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
return
}
fmt.Printf("(sum 1 2)=%v\n", result)
}
$ go run examples/example2.go
(sum 1 2)=3
The user defined normal functions have to get the three parameters.
- The 1st: context.Context that is given to the method .Interpret()
- The 2nd: *gmnlisp.World on which the instance runs.
- The 3rd: []gmnlisp.Node the parameters given by caller. They are already evaluated.
gmnlisp.Function
wraps the normal function as Lisp object.
F
: the function itselfC
: when the number of the parameter is not same as this, the error will be raised. If it does not have to be checked, omit it.
To get unevaluted parameters, the function's definition should be as below.
func FUNCNAME(c context.Context,w *World,args Node)(Node,error){...}
- The parameters are given as a list not an array.
- Use
gmnlisp.SpecialF(FUNCNAME)
instead ofgmnlisp.Function{F:FUNCNAME}
Type(Lisp) | Type(Go) |
---|---|
t | gmnlisp._TrueType |
nil | gmnlisp._NullType |
<integer> | gmnlisp.Integer == int64 |
<float> | gmnlisp.Float == float64 |
<string> | gmnlisp.String == string |
<symbol> | gmnlisp.Symbol == int |
<cons> | *gmnlisp.Cons == struct{ Car,Cdr: gmnlisp.Node } |
<character> | gmnlisp.Rune == rune |
(keyword) | gmnlisp.Keyword |
(array) | *gmnlisp.Array |
(hashtable) | gmnlisp._Hash == map[gmnlisp.Node]gmnlisp.Node |
gmnlisp.Node
is the root interface.
All objects used in Lisp code have to satisfy it.
gmnlisp.Symbol
is the unique number associated to string.
- string to gmnlisp.Symbol
sbl := gmnlisp.NewSymbol("foo")
- Symbol to string
sbl.String()
Gmnlisp's functions are subset of ISLisp.
- block
- dynamic-let
- flet
- for
- labels
- let
- let*
- tagbody
- with-error-output
- with-open-input-file
- with-open-io-file
- with-open-output-file
- with-standard-input
- with-standard-output
- and
- assure
- block
- case
- case-using
- catch
- class
- cond
- convert
- dynamic
- dynamic-let
- flet
- for
- function
- &rest
- #'FUNCTION
- go
- if
- ignore-errors
- labels
- lambda
- let
- let*
- or
- progn
- quote
- return-from
- setf
- setq
- tagbody
- the
- throw
- unwind-protect
- while
- with-error-output
- with-handler
- with-open-input-file
- with-open-io-file
- with-open-output-file
- with-standard-input
- with-standard-output
- defclass
- defconstant
- defdynamic
- defgeneric
- defglobal
- defmacro
- defmethod
- defun
- functionp
- function
- lambda
- labels
- flet
- apply
- funcall
- defconstant
- defglobal
- defdynamic
- defun
- t
- nil
- basic-array-p
- basic-array*-p
- basic-vector-p
- characterp
- consp
- floatp
- functionp
- general-array*-p
- general-vector-p
- generic-function-p
- integerp
- listp
- null
- numberp
- streamp
- stringp
- symbolp
- Non-standard functions
- atom OBJ
- evenp OBJ
- minusp OBJ
- oddp OBJ
- plusp OBJ
- zerop OBJ
- eq
- eql
- equal
- Non-standard functions
- equalp
- not
- and
- or
- (quote)
- 'OBJ
- setq
- setf
- let
- let*
- dynamic
- dynamic-let
- if
- cond
- case
- case-using
- Non-standard functions
- when
- unless
- progn
- Non-standard functions
- prog1
- prog2
- while
- for
- Non-standard functions
- dolist
- dotimes
- block
- return-from
- catch
- throw
- tagbody
- go
- Non-standard functions
- return
- unwind-protect
- defclass
- generic-function-p
- defgeneric
- defmethod
- call-next-method
- next-method-p
- create
- initialize-object
- class-of
- instancep
- subclassp
- class
- defmacro
- 'form
- `form
- ,@form
- the
- assure
- convert
- (convert OBJ <float>)
- (convert OBJ <integer>)
- (convert OBJ <list>)
- (convert OBJ <string>)
- (convert OBJ <symbol>)
- symbolp
- property
- set-property , setf
- remove-property
- gensym
- numberp
- parse-number
- =
- /=
- >=
- <=
- >
- <
- +
- *
- -
- reciproca1
- quotient
- max
- min
- abs
- exp
- log
- expt
- sqrt
- sin
- cos
- tan
- atan
- atan2
- sinh
- cosh
- tanh
- atanh
- Non-standard functions
- 1+
- 1-
- incf
- decf
- *pi*
- *most-positive-float*
- *most-negative-float*
- floatp
- float
- floor
- ceiling
- truncate
- round
- integerp
- div
- mod
- gcd
- lcm
- isqrt
- Non-standard functions
- rem
- most-postive-fixnum
- most-negative-fixnum
- characterp
- char=
- char/=
- char<
- char>
- char<=
- char>=
- consp
- cons OBJ
- car
- cdr
- set-car, (setf (car CONS) OBJ)
- set-cdr, (setf (cdr CONS) OBJ)
- null
- listp
- create-list
- list
- reverse
- nreverse
- append
- member
- mapcar
- mapc
- maplist
- mapl
- mapcan
- mapcon
- assoc
- Non-standard functions
- last
- basic-array-p
- basic-array*-p
- general-array*-p
- create-array
- aref
- garef
- set-aref , (setf (aref BASIC-ARRAY Z*) OBJ)
- set-garef , (setf (garef BASIC-ARRAY Z*) OBJ)
- array-dimensions
- #(...) , #2a((...) (...)) , #3a(((.. ..))) ...
- basic-vector-p
- general-vector-p
- create-vector
- vector
- stringp
- create-string
- string=
- string/=
- string<
- string>
- string>=
- string<=
- char-index
- string-index
- string-append
- length
- elt
- set-elt, (setf (elt SEQ Z) OBJ)
- subseq
- map-into
- streamp
- open-stream-p
- input-stream-p
- output-stream-p
- standard-input
- standard-output
- error-output
- with-standard-input
- with-standard-output
- with-error-output
- open-input-file
- open-output-file
- open-io-file
- with-open-input-file
- with-open-output-file
- with-open-io-file
- close
- finish-output
- create-string-input-stream
- create-string-output-stream
- get-output-stream-string
- read
- read-char
- preview-char
- read-line
- stream-ready-p
- format
- format-char
- format-float
- format-fresh-line
- format-integer
- format-object
- format-tab
- read-byte
- write-byte
- probe-file
- file-position
- set-file-position
- file-length
- error
- cerror
- signal-condition
- ignore-error
- report-condition
- condition-continuable
- with-handler
- arithmetic-error-operands
- domain-error-object
- domain-error-expected-class
- parse-error-string
- parse-error-expected-class
- simple-error-format-string
- simple-error-format-arguments
- stream-error-stream
- undefined-entity-name
- undefined-entity-namespace
- arity-error
: - undefined-function
- identify
- get-universal-time
- get-internal-real-time
- get-internal-run-time
- internal-time-units-per-second
import (
_ "github.com/hymkor/gmnlisp/regexp"
)
is required.
- (=~ REGEXP STRING)
compatible with "regexp".Regexp.FindAllStringSubmatch
(let ((m (=~ "a(x*)b" "-axxb-ab-")))
(format t "ALL=~s~%" m)
(format t "0,0=~s~%" (elt m 0 0))
(format t "0,1=~s~%" (elt m 0 1))
(format t "1,0=~s~%" (elt m 1 0))
(format t "1,1=~s~%" (elt m 1 1))
)
ALL=(("axxb" "xx") ("ab" ""))
0,0="axxb"
0,1="xx"
1,0="ab"
1,1=""
- (=~i REGEXP STRING)
compatible with "regexp".Regexp.FindAllStringSubmatchIndex
(let ((m (=~i "a(x*)b" "-axxb-ab-")))
(format t "INDEXES=~s~%" m)
)
INDEXES=((1 5 2 4) (6 8 7 7))
(let ((h1 (make-hash-table)))
(setf (gethash 'width h1) 600)
(gethash 'width h1)
(hash-table-count h1)
(remhash 'width h1)
(clrhash h1)
)
- (exit)
- (quit)
- (abort)