Skip to content

hymkor/gmnlisp

Repository files navigation

GoDoc

Gmnlisp

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.

Example image

Install executable

Download the binary package from Releases and extract the executable.

for scoop-installer

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

Examples

1. Execute Lisp code in string with parameters

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 of map[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))

2. Execute Lisp-code and give call-back function written in Go

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 itself
  • C: 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 of gmnlisp.Function{F:FUNCNAME}

Support Types

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()

Support functions

Gmnlisp's functions are subset of ISLisp.

1 Scope, Conventions and Compliance

2 Classes

3 Scope and Extent

3.1 The lexical Principle

3.2 Scope of Identifiers

3.3 Some Specific Scope Rules

3.4 Extent

  • 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

4 Forms and Evaluation

4.1 Forms

4.2 Function Application Forms

4.3 Special Forms

  • 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

4.4 Defining Forms

  • defclass
  • defconstant
  • defdynamic
  • defgeneric
  • defglobal
  • defmacro
  • defmethod
  • defun

4.5 Macro Forms

4.6 The Evaluation Model

4.7 Functions

  • functionp
  • function
  • lambda
  • labels
  • flet
  • apply
  • funcall

4.8 Defining Operators

  • defconstant
  • defglobal
  • defdynamic
  • defun

5 Predicates

5.1 Boolean Values

  • t
  • nil

5.2 Class Predicates

  • 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

5.3 Equality

  • eq
  • eql
  • equal
  • Non-standard functions
    • equalp

5.4 Logical Connectives

  • not
  • and
  • or

6 Control Structure

6.1 Constants

  • (quote)
  • 'OBJ

6.2 Variables

  • setq
  • setf
  • let
  • let*

6.3 Dynamic Variables

  • dynamic
  • dynamic-let

6.4 Conditional Expressions

  • if
  • cond
  • case
  • case-using
  • Non-standard functions
    • when
    • unless

6.5 Sequencing Forms

  • progn
  • Non-standard functions
    • prog1
    • prog2

6.6 Iteration

  • while
  • for
  • Non-standard functions
    • dolist
    • dotimes

6.7 Non-Local Exits

6.7.1 Establishing and Invoking Non-Local Exits
  • block
  • return-from
  • catch
  • throw
  • tagbody
  • go
  • Non-standard functions
    • return
6.7.2 Assuring Data Consistency during Non-Local Exists
  • unwind-protect

7 Objects

7.1 Defining Classes

  • defclass
  • generic-function-p

7.2 Generic Functions

7.2.1 Defining Generic Functions
  • defgeneric
7.2.2 Defining Methods for Generic Functions
  • defmethod

7.3 Calling Generic Functions

7.3.4 Calling More General Methods
  • call-next-method
  • next-method-p

7.4 Object Creation and Initialization

  • create
  • initialize-object

7.5 Class Enquiry

  • class-of
  • instancep
  • subclassp
  • class

8 Macros

  • defmacro
  • 'form
  • `form
  • ,@form

9 Declarations and Coercions

  • the
  • assure
  • convert
    • (convert OBJ <float>)
    • (convert OBJ <integer>)
    • (convert OBJ <list>)
    • (convert OBJ <string>)
    • (convert OBJ <symbol>)

10 Symbol classes

  • symbolp

10.2 Symbol Properties

  • property
  • set-property , setf
  • remove-property

10.3 Unnamed Symbols

  • gensym

11 Number class

11.1 Number class

  • 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

11.2 Float class

  • *pi*
  • *most-positive-float*
  • *most-negative-float*
  • floatp
  • float
  • floor
  • ceiling
  • truncate
  • round

11.3 Integer class

  • integerp
  • div
  • mod
  • gcd
  • lcm
  • isqrt
  • Non-standard functions
    • rem
    • most-postive-fixnum
    • most-negative-fixnum

12 Character class

  • characterp
  • char=
  • char/=
  • char<
  • char>
  • char<=
  • char>=

13 List class

13.1 Cons

  • consp
  • cons OBJ
  • car
  • cdr
  • set-car, (setf (car CONS) OBJ)
  • set-cdr, (setf (cdr CONS) OBJ)

13.2 Null class

  • null

13.3 List operations

  • listp
  • create-list
  • list
  • reverse
  • nreverse
  • append
  • member
  • mapcar
  • mapc
  • maplist
  • mapl
  • mapcan
  • mapcon
  • assoc
  • Non-standard functions
    • last

14 Arrays

14.1 Array Classes

14.2 General Arrays

14.3 Array Operations

  • 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(((.. ..))) ...

15 Vector

  • basic-vector-p
  • general-vector-p
  • create-vector
  • vector

16 String class

  • stringp
  • create-string
  • string=
  • string/=
  • string<
  • string>
  • string>=
  • string<=
  • char-index
  • string-index
  • string-append

17 Sequence Functions

  • length
  • elt
  • set-elt, (setf (elt SEQ Z) OBJ)
  • subseq
  • map-into

18 Stream class

  • 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

18.1 Streams to files

  • open-input-file
  • open-output-file
  • open-io-file
  • with-open-input-file
  • with-open-output-file
  • with-open-io-file
  • close
  • finish-output

18.2 Other streams

  • create-string-input-stream
  • create-string-output-stream
  • get-output-stream-string

19 Input and Output

19.1 Argument conventions for input functions

  • read
  • read-char
  • preview-char
  • read-line
  • stream-ready-p
  • format
  • format-char
  • format-float
  • format-fresh-line
  • format-integer
  • format-object
  • format-tab

19.2 Charactoer I/O

19.3 Binary I/O

  • read-byte
  • write-byte

20 Files

  • probe-file
  • file-position
  • set-file-position
  • file-length

21 Condition System

21.1 Condition

21.2 Signaling and handling condtions

21.2.1 Operations relating to condition signaling
  • error
  • cerror
  • signal-condition
21.2.2 Operations relating to condition handling
  • ignore-error
  • report-condition
  • condition-continuable
  • with-handler

21.3 Data associated with condition classes

21.3.1 Arithmetic errors
  • arithmetic-error-operands
21.3.2 Domain errors
  • domain-error-object
  • domain-error-expected-class
21.3.3 Parse errors
  • parse-error-string
  • parse-error-expected-class
21.3.4 Simple errors
  • simple-error-format-string
  • simple-error-format-arguments
21.3.5 Stream errors
  • stream-error-stream
  • undefined-entity-name
  • undefined-entity-namespace

21.4 Error identification

  • arity-error
    :
  • undefined-function

22 Miscellaneous

  • identify
  • get-universal-time
  • get-internal-real-time
  • get-internal-run-time
  • internal-time-units-per-second

Regular Expression

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))

Hash-table

(let ((h1 (make-hash-table)))
  (setf (gethash 'width h1) 600)
  (gethash 'width h1)
  (hash-table-count h1)
  (remhash 'width h1)
  (clrhash h1)
  )

Quit

  • (exit)
  • (quit)
  • (abort)

References