{"id":18053759,"url":"https://github.com/hymkor/gmnlisp","last_synced_at":"2025-07-09T07:07:43.010Z","repository":{"id":36074962,"uuid":"40374691","full_name":"hymkor/gmnlisp","owner":"hymkor","description":"The interpreter of ISLisp written in Go","archived":false,"fork":false,"pushed_at":"2025-06-13T07:34:14.000Z","size":1182,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-13T07:43:01.983Z","etag":null,"topics":["go","golang","islisp","lisp","lisp-interpreter"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/hymkor/gmnlisp","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hymkor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-08-07T18:22:42.000Z","updated_at":"2025-06-13T07:34:18.000Z","dependencies_parsed_at":"2024-06-28T17:47:41.035Z","dependency_job_id":"01986073-7ea9-47ac-9a60-da45b5de6ce3","html_url":"https://github.com/hymkor/gmnlisp","commit_stats":null,"previous_names":["zetamatta/gommon"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/hymkor/gmnlisp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fgmnlisp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fgmnlisp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fgmnlisp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fgmnlisp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hymkor","download_url":"https://codeload.github.com/hymkor/gmnlisp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fgmnlisp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260447652,"owners_count":23010543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","islisp","lisp","lisp-interpreter"],"created_at":"2024-10-31T00:07:55.048Z","updated_at":"2025-07-09T07:07:42.989Z","avatar_url":"https://github.com/hymkor.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"Gmnlisp\n=======\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/hymkor/gmnlisp.svg)](https://pkg.go.dev/github.com/hymkor/gmnlisp)\n[![Go Test](https://github.com/hymkor/gmnlisp/actions/workflows/go.yml/badge.svg)](https://github.com/hymkor/gmnlisp/actions/workflows/go.yml)\n\nGmnlisp is the interpreter of [ISLisp] written in Go.\nIt is developed to embbed to the applications for customizing.\n\n![Example image](factorial.png)\n\nUsage and Integration Guide\n----------------------------\n\n```examples/example.go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"os\"\n\n    \"github.com/hymkor/gmnlisp\"\n)\n\nfunc sum(ctx context.Context, w *gmnlisp.World, args []gmnlisp.Node) (gmnlisp.Node, error) {\n    a, err := gmnlisp.ExpectClass[gmnlisp.Integer](ctx, w, args[0])\n    if err != nil {\n        return nil, err\n    }\n    b, err := gmnlisp.ExpectClass[gmnlisp.Integer](ctx, w, args[1])\n    if err != nil {\n        return nil, err\n    }\n    return a + b, nil\n}\n\nfunc main() {\n    lisp := gmnlisp.New()\n\n    lisp = lisp.Let(gmnlisp.Variables{\n        gmnlisp.NewSymbol(\"a\"): gmnlisp.Integer(1),\n        gmnlisp.NewSymbol(\"b\"): gmnlisp.Integer(2),\n    })\n\n    lisp = lisp.Flet(\n        gmnlisp.Functions{\n            gmnlisp.NewSymbol(\"sum\"): \u0026gmnlisp.Function{C: 2, F: sum},\n        })\n\n    value, err := lisp.Interpret(context.TODO(), \"(sum a b)\")\n    if err != nil {\n        fmt.Fprintln(os.Stderr, err.Error())\n        return\n    }\n    fmt.Println(value.String())\n}\n```\n\n```\n$ go run examples/example.go\n3\n```\n\n- `gmnlisp.New` returns a new Lisp interpreter instance (`*gmnlisp.World`).\n- `gmnlisp.NewSymbol` constructs a symbol. Calling `gmnlisp.NewSymbol(\"a\")` always returns the same value, no matter how many times it's called.\n- `gmnlisp.Variables` is a symbol map type. It is an alias for `map[gmnlisp.Symbol]gmnlisp.Node`.  \n  `Node` is the interface that all Lisp objects must implement.\n- `.Let` creates a new world instance with the given variable bindings (namespace).\n\n```lisp\nlisp.Let(gmnlisp.Variables{\n    gmnlisp.NewSymbol(\"a\"): gmnlisp.Integer(1),\n    gmnlisp.NewSymbol(\"b\"): gmnlisp.Integer(2),\n}).Interpret(context.Background(), \"(c)\")\n\n```\n\nis equivalent to the Lisp code: `(let ((a 1) (b 2)) (c))`\n\n### Type assertions\n\n`a, err := gmnlisp.ExpectClass[gmnlisp.Integer](ctx, w, x)`  \nis similar to:  \n`a, ok := x.(gmnlisp.Integer)`  \n\nHowever, `ExpectClass` invokes the user-defined error handler if `x` is not of type `Integer`.\n\n### User-defined functions\n\nYou can register user-defined functions to the interpreter using `.Flet()`:\n\n```go\nlisp = lisp.Flet(\n    gmnlisp.Functions{\n        gmnlisp.NewSymbol(\"sum\"): \u0026gmnlisp.Function{C: 2, F: sum},\n    })\n```\n\nThe function definitions are passed as a `gmnlisp.Functions` map, where the keys are symbols and the values are Lisp function objects. There are several ways to define the function values:\n\n* `gmnlisp.Function1(f)`\n  For a function `f` with the signature:\n  `func(context.Context, *gmnlisp.World, gmnlisp.Node) (gmnlisp.Node, error)`\n  Accepts **one evaluated argument**.\n\n* `gmnlisp.Function2(f)`\n  For a function `f` with the signature:\n  `func(context.Context, *gmnlisp.World, gmnlisp.Node, gmnlisp.Node) (gmnlisp.Node, error)`\n  Accepts **two evaluated arguments**.\n\n* `\u0026gmnlisp.Function{ C: n, Min: min, Max: max, F: f }`\n  For a function `f` with the signature:\n  `func(context.Context, *gmnlisp.World, []gmnlisp.Node) (gmnlisp.Node, error)`\n  Accepts **multiple evaluated arguments**.\n\n  * If `C` is non-zero, the function strictly expects `C` arguments.\n  * If `Min` and `Max` are specified instead, the function accepts a range of arguments.\n  * If all are left as zero values, argument count is not validated.\n\n  **Note**: A zero value (0) means \"unspecified\"; negative values are not used.\n\n* `gmnlisp.SpecialF(f)`\n  For defining **special forms** (macros, control structures, etc.), where arguments are passed **unevaluated**:\n  `func(context.Context, *gmnlisp.World, gmnlisp.Node) (gmnlisp.Node, error)`\n  All arguments are passed as a Lisp list (e.g., `(list a b c)` becomes `\u0026gmnlisp.Cons{Car: ..., Cdr: ...}`).\n\n  Inside this function, you can evaluate an argument manually with:\n\n  ```go\n  result, err := w.Eval(ctx, x)\n  ```\n\nSee the example in the \"Usage and Integration Guide\" section above for how to define and register a user function.\n\n### Supported Types\n\nLisp values correspond to the following Go types or constructors when embedding gmnlisp in Go applications:\n\n| Lisp         | Go                                      |\n---------------|-----------------------------------------|\n| `t`          | `gmnlisp.True`                          |\n| `nil`        | `gmnlisp.Null`                          |\n| `1`          | `gmnlisp.Integer(1)`                    |\n| `2.3`        | `gmnlisp.Float(2.3)`                    |\n| `\"string\"`   | `gmnlisp.String(\"string\")`              |\n| `Symbol`     | `gmnlisp.NewSymbol(\"Symbol\")`           |\n| `(cons 1 2)` | `\u0026gmnlisp.Cons{ Car:gmnlisp.Integer(1), Cdr:gmnlisp.Integer(2) }` |\n| `#\\A`        | `gmnlisp.Rune('A')`                     |\n\nUnlike other types shown above, `gmnlisp.NewSymbol(...)` is a function call, not a type conversion.\nIt returns a value of type `Symbol` (defined as `type Symbol int`), which is distinct from `int`.\nThe function guarantees that the same string always maps to the same symbol value.\n\n`gmnlisp.Node` is the root interface.\nAll values that appear in Lisp code must implement this interface.\n\n```go\ntype Node interface {\n    Equals(Node, EqlMode) bool\n    String() string\n    ClassOf() Class\n}\n\ntype Class interface {\n    Node\n    Name() Symbol\n    InstanceP(Node) bool\n    Create() Node\n    InheritP(Class) bool\n}\n\ntype EqlMode int\n\nconst (\n    STRICT EqlMode = iota // corresponds to (eql a b)\n    EQUAL                 // corresponds to (equal a b)\n    EQUALP                // corresponds to (equalp a b) \n)\n```\n\nISLisp Compatibility\n--------------------\n\nGmnlisp implements a subset of functions defined in the [ISLisp] standard.\n\nThe full compatibility checklist has been moved to a separate file due to its length:  \n👉 [ISLisp Compatibility Checklist](./is_lisp_compat.md)\n\n(Items without checkboxes are not standard functions.)\n\nProjects Using gmnlisp\n-----------------------\n\nThe following open-source applications embed gmnlisp to provide ISLisp-based customization and scripting:\n\n- [**lispect**](https://github.com/hymkor/lispect):  \n  A text-terminal automation tool similar to `expect(1)`, powered by a subset of ISLisp.\n\n- [**smake**](https://github.com/hymkor/smake):  \n  A build automation tool where Makefiles are written in S-expressions.\n\nReferences\n----------\n\n### Documents (English)\n\n+ [ISLISP - Wikipedia](https://en.wikipedia.org/wiki/ISLISP)\n+ [ISLisp Home Page][ISLisp]\n+ [www.islisp.info: Home](http://www.islisp.info/)\n+ [Programming Language ISLISP Working Draft 23.0](https://nenbutsu.github.io/ISLispHyperDraft/islisp-v23.html)\n\n### Documents (Japanese)\n\n+ [JISX3012:1998 プログラム言語ＩＳＬＩＳＰ](https://kikakurui.com/x3/X3012-1998-01.html)\n+ [M.Hiroi's Home Page / お気楽 ISLisp プログラミング超入門](http://www.nct9.ne.jp/m_hiroi/clisp/islisp.html)\n\n### Gmnlisp and other implementations of [ISLisp]\n\n| Implementation      | Language      |  Windows  | Linux     | Execution Model      |\n|---------------------|---------------|-----------|-----------|----------------------|\n| [OK!ISLisp][oki]    | C             | Supported | Supported | Interpreter/Bytecode compiler |\n| [iris]              | Go/JavaScript | Supported | Supported | Interpreter          |\n| [Easy-ISLisp][eisl] | C             |           | Supported | Interpreter/Native Compiler |\n| **gmnlisp**         | Go            | Supported | Supported | Interpreter          |\n\n[ISLisp]: http://islisp.org/\n[oki]: http://islisp.org/OKIISLisp.html\n[iris]: https://github.com/islisp-dev/iris\n[eisl]: https://github.com/sasagawa888/eisl\n\nAuthor\n------\n\n[hymkor (HAYAMA Kaoru)](https://github.com/hymkor)\n\nLicense\n-------\n\n[MIT Licence](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhymkor%2Fgmnlisp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhymkor%2Fgmnlisp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhymkor%2Fgmnlisp/lists"}