{"id":29480938,"url":"https://github.com/hymkor/sxencode-go","last_synced_at":"2025-07-14T23:55:10.496Z","repository":{"id":304509310,"uuid":"1018990592","full_name":"hymkor/sxencode-go","owner":"hymkor","description":"Go library that encodes arbitrary Go values into Lisp-style S-expressions","archived":false,"fork":false,"pushed_at":"2025-07-14T06:17:09.000Z","size":15,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-07-14T09:21:07.986Z","etag":null,"topics":["encoder","go","golang","lisp","s-expression"],"latest_commit_sha":null,"homepage":"","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":"2025-07-13T13:57:44.000Z","updated_at":"2025-07-14T06:17:12.000Z","dependencies_parsed_at":"2025-07-14T09:23:54.680Z","dependency_job_id":null,"html_url":"https://github.com/hymkor/sxencode-go","commit_stats":null,"previous_names":["hymkor/sxencode","hymkor/sxencode-go"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/hymkor/sxencode-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fsxencode-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fsxencode-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fsxencode-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fsxencode-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hymkor","download_url":"https://codeload.github.com/hymkor/sxencode-go/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hymkor%2Fsxencode-go/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265375149,"owners_count":23755182,"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":["encoder","go","golang","lisp","s-expression"],"created_at":"2025-07-14T23:55:08.351Z","updated_at":"2025-07-14T23:55:10.478Z","avatar_url":"https://github.com/hymkor.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"sxencode - Golang Encoder to S-Expression\r\n=========================================\r\n\r\n`sxencode` is a Go library that encodes arbitrary Go values into **Lisp-style S-expressions**.  \r\nIt is useful for interfacing with Lisp systems, structured debugging, or human-readable serialization.  \r\nThe output is readable by standard Lisp implementations including Common Lisp and ISLisp.\r\n\r\n\r\nExample\r\n-------\r\n\r\nThe following is a minimal Go program that encodes a Go struct and the encoder itself into S-expressions:\r\n\r\n```example.go\r\npackage main\r\n\r\nimport (\r\n    \"fmt\"\r\n    \"os\"\r\n\r\n    \"github.com/hymkor/sxencode-go\"\r\n)\r\n\r\nfunc main() {\r\n    type Foo struct {\r\n        Bar   string\r\n        Baz   float64\r\n        Qux   []int\r\n        Quux  map[string]int\r\n        Quuux string\r\n    }\r\n\r\n    value := \u0026Foo{\r\n        Bar:   \"hogehoge\",\r\n        Baz:   0.1,\r\n        Qux:   []int{1, 2, 3, 4},\r\n        Quux:  map[string]int{\"ahaha\": 1, \"ihihi\": 2, \"ufufu\": 3},\r\n        Quuux: \"a\\\"\\\\\\n\\tb\",\r\n    }\r\n\r\n    enc := sxencode.NewEncoder(os.Stdout)\r\n\r\n    enc.Encode(value)\r\n    fmt.Println()\r\n\r\n    enc.Encode(enc)\r\n    fmt.Println()\r\n}\r\n```\r\n\r\n\r\n## Output of `go run example.go`\r\n\r\nThe output of the above program is a pair of S-expressions representing the encoded data:\r\n\r\n```make example|\r\ngo run example.go\r\n((struct Foo)(Bar \"hogehoge\")(Baz 0.1)(Qux (1 2 3 4))(Quux ((\"ahaha\" 1)(\"ihihi\" 2)(\"ufufu\" 3)))(Quuux \"a\\\"\\\\\r\n    b\"))\r\n((struct Encoder)(ArrayHeader \"\")(ArrayIndex nil)(TypeNotFound \"\"))\r\n```\r\n\r\n### Output Format\r\n\r\n* A struct is encoded as a list beginning with `(struct \u003cTypeName\u003e)`, followed by pairs of field name and value:\r\n  Example: `((struct Foo)(Bar \"hogehoge\") ...)`.\r\n  The field names and type name are emitted as symbols, making them easy to extract with `(assoc)` in Lisp.\r\n\r\n* A map is encoded as a list of `(key value)` pairs.\r\n  If the keys are strings, note that in many Lisp dialects, `(assoc)` with a string key won't match unless `equal` is used.\r\n  For this reason, helper functions like `field` (shown later) may be necessary.\r\n\r\n* A slice or array is encoded as a plain list of elements: `(1 2 3 4)`.\r\n\r\nThese conventions make it easy to parse the output in various Lisp systems while retaining structural information.\r\n\r\n## Reading the output in SBCL\r\n\r\nThe following shows how the output can be parsed and validated using [SBCL (Steel Bank Common Lisp)][SBCL].\r\n\r\n[SBCL]: https://www.sbcl.org/ \r\n\r\n```make test-sbcl |\r\ngo run example.go | sbcl --load \"test-sbcl.lsp\"\r\nThis is SBCL 2.5.6, an implementation of ANSI Common Lisp.\r\nMore information about SBCL is available at \u003chttp://www.sbcl.org/\u003e.\r\n\r\nSBCL is free software, provided as is, with absolutely no warranty.\r\nIt is mostly in the public domain; some portions are provided under\r\nBSD-style licenses.  See the CREDITS and COPYING files in the\r\ndistribution for more information.\r\nPASS: (test (FIELD 'STRUCT DATA) FOO)\r\nPASS: (test (FIELD 'BAR DATA) \"hogehoge\")\r\nPASS: (test (FIELD 'BAZ DATA) 0.1)\r\nPASS: (test (FIELD 'QUX DATA) (1 2 3 4))\r\nPASS: (test (FIELD \"ahaha\" M) 1)\r\nPASS: (test (FIELD \"ihihi\" M) 2)\r\nPASS: (test (FIELD \"ufufu\" M) 3)\r\nPASS: (test (FIELD 'QUUUX DATA) \"a\\\"\\\\\r\n    b\")\r\nPASS: (test (FIELD 'STRUCT DATA) ENCODER)\r\nPASS: (test (FIELD 'ARRAYHEADER DATA) \"\")\r\nPASS: (test (FIELD 'ARRAYINDEX DATA) NIL)\r\nPASS: (test (FIELD 'TYPENOTFOUND DATA) \"\")\r\n* \r\n```\r\n\r\n### Lisp files\r\n\r\nThese are the supporting Lisp files used for the SBCL test:\r\n\r\n#### `test-sbcl.lsp`\r\n\r\n```lisp\r\n(defun standard-input () *standard-input*)\r\n(defun standard-output () t)\r\n(load \"test.lsp\")\r\n```\r\n\r\n#### `test.lsp`\r\n\r\n```lisp\r\n(defmacro test (source expect)\r\n  (let ((result (gensym)))\r\n    `(let ((,result ,source))\r\n       (if (equal ,result ,expect)\r\n           (format (standard-output) \"PASS: (test ~S ~S)~%\"\r\n                   (quote ,source)\r\n                   ,expect)\r\n           (format (standard-output) \"FAIL: (test ~S ~S)~%  but ~S~%\"\r\n                   (quote ,source)\r\n                   ,expect\r\n                   ,result)\r\n       ))))\r\n\r\n(defun field (key m)\r\n  (and\r\n    m\r\n    (consp m)\r\n    (if (equal (car (car m)) key)\r\n      (car (cdr (car m)))\r\n      (field key (cdr m)))))\r\n\r\n(let ((data (read (standard-input) nil nil)))\r\n  (test (field 'struct-name data) 'Foo)\r\n  (test (field 'name data) \"hogehoge\")\r\n  (test (field 'value data) 0.1)\r\n  (test (field 'array data) '(1 2 3 4))\r\n  (let ((m (field 'map data)))\r\n    (test (field \"ahaha\" m) 1)\r\n    (test (field \"ihihi\" m) 2)\r\n    (test (field \"ufufu\" m) 3)))\r\n\r\n(let ((data (read (standard-input) nil nil)))\r\n  (test (field 'struct-name data) 'Encoder)\r\n  (test (field 'arrayheader data) \"\")\r\n  (test (field 'arrayindex data) nil)\r\n  (test (field 'typenotfound data) \"\"))\r\n```\r\n\r\n\r\n## Reading the output in OKI ISLisp\r\n\r\nThe same logic can be used in [OKI ISLisp](https://openlab.jp/islisp/), by loading the wrapper file `test-oki.lsp`:\r\n\r\n```sh\r\ngo run example.go \u003e sample.log\r\necho \"(load \\\"test-oki.lsp\\\")\" | islisp\r\n```\r\n\r\nExecution result:\r\n\r\n```\r\n\u003e ISLisp  Version 0.80 (1999/02/25)\r\n\u003e\r\nISLisp\u003ePASS: (test (FIELD (QUOTE STRUCT-NAME) DATA) FOO)\r\nPASS: (test (FIELD (QUOTE NAME) DATA) \"hogehoge\")\r\nPASS: (test (FIELD (QUOTE VALUE) DATA) 0.1)\r\nPASS: (test (FIELD (QUOTE ARRAY) DATA) (1 2 3 4))\r\nPASS: (test (FIELD \"ahaha\" M) 1)\r\nPASS: (test (FIELD \"ihihi\" M) 2)\r\nPASS: (test (FIELD \"ufufu\" M) 3)\r\nPASS: (test (FIELD (QUOTE STRUCT-NAME) DATA) ENCODER)\r\nPASS: (test (FIELD (QUOTE ARRAYHEADER) DATA) \"\")\r\nPASS: (test (FIELD (QUOTE ARRAYINDEX) DATA) NIL)\r\nPASS: (test (FIELD (QUOTE TYPENOTFOUND) DATA) \"\")\r\nT\r\nISLisp\u003e\r\n```\r\n\r\n#### `test-oki.lsp`\r\n\r\n```lisp\r\n(with-open-input-file\r\n  (fd \"sample.log\")\r\n  (with-standard-input\r\n    fd\r\n    (load \"test.lsp\")))\r\n```\r\n\r\n\r\n## Also works with gmnlisp\r\n\r\nThe same test.lsp file can be run directly using [gmnlisp] — no modifications are needed, since [gmnlisp] is designed to be largely compatible with ISLisp and supports the same input/output conventions.\r\n\r\n[gmnlisp]: https://github.com/hymkor/gmnlisp\r\n\r\n```sh\r\ngo run example.go | gmnlisp test.lsp\r\n```\r\n\r\nResult:\r\n\r\n```\r\nPASS: (test (FIELD 'STRUCT-NAME DATA) FOO)\r\nPASS: (test (FIELD 'NAME DATA) \"hogehoge\")\r\nPASS: (test (FIELD 'VALUE DATA) 0.100000)\r\nPASS: (test (FIELD 'ARRAY DATA) (1 2 3 4))\r\nPASS: (test (FIELD \"ahaha\" M) 1)\r\nPASS: (test (FIELD \"ihihi\" M) 2)\r\nPASS: (test (FIELD \"ufufu\" M) 3)\r\nPASS: (test (FIELD 'STRUCT-NAME DATA) ENCODER)\r\nPASS: (test (FIELD 'ARRAYHEADER DATA) \"\")\r\nPASS: (test (FIELD 'ARRAYINDEX DATA) NIL)\r\nPASS: (test (FIELD 'TYPENOTFOUND DATA) \"\")\r\n```\r\n\r\n## Summary\r\n\r\n* `sxencode` converts Go values into Lisp-compatible S-expressions\r\n* Output is compatible with multiple Lisp systems: Common Lisp, ISLisp (OKI, gmnlisp)\r\n* Includes reusable test logic in `test.lsp`\r\n* Ideal for inter-language data exchange and human-readable serialization\r\n\r\nPull requests and feedback are welcome!\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhymkor%2Fsxencode-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhymkor%2Fsxencode-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhymkor%2Fsxencode-go/lists"}