{"id":13683719,"url":"https://github.com/shellyln/liyad","last_synced_at":"2025-04-13T06:08:14.216Z","repository":{"id":32638690,"uuid":"138583510","full_name":"shellyln/liyad","owner":"shellyln","description":"Liyad (Lisp yet another DSL interpreter) is very small Lisp interpreter written in JavaScript.","archived":false,"fork":false,"pushed_at":"2023-03-15T02:46:17.000Z","size":1903,"stargazers_count":31,"open_issues_count":5,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-01T15:37:37.242Z","etag":null,"topics":["dsl","dsl-interpreter","javascript","jsx","lisp","lisp-in-javascript","lisp-interpreter","lsx","s-expression","typescript"],"latest_commit_sha":null,"homepage":"https://shellyln.github.io/liyad/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shellyln.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-06-25T11:05:47.000Z","updated_at":"2024-08-27T06:11:40.000Z","dependencies_parsed_at":"2024-01-14T17:18:44.737Z","dependency_job_id":"dd340bb0-dc28-49f1-92f7-e242243a178f","html_url":"https://github.com/shellyln/liyad","commit_stats":{"total_commits":319,"total_committers":1,"mean_commits":319.0,"dds":0.0,"last_synced_commit":"d5fbc89ce1d998047b711ad5145aabfb79e04ae0"},"previous_names":[],"tags_count":68,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellyln%2Fliyad","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellyln%2Fliyad/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellyln%2Fliyad/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shellyln%2Fliyad/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shellyln","download_url":"https://codeload.github.com/shellyln/liyad/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219846951,"owners_count":16556418,"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":["dsl","dsl-interpreter","javascript","jsx","lisp","lisp-in-javascript","lisp-interpreter","lsx","s-expression","typescript"],"created_at":"2024-08-02T13:02:26.081Z","updated_at":"2024-10-14T18:40:44.403Z","avatar_url":"https://github.com/shellyln.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Liyad\n## Let's make your yet another DSL with Lisp S-expression!\n\n[![Liyad](https://shellyln.github.io/assets/image/liyad-logo.svg)](https://shellyln.github.io/liyad/)\n\nLiyad (Lisp yet another DSL interpreter, or LIYAD is yum and delicious) is\nvery small Lisp interpreter written in JavaScript.  \nYou can easily start making your new DSL using Lisp and S-expression.\n\n\n[![npm](https://img.shields.io/npm/v/liyad.svg)](https://www.npmjs.com/package/liyad)\n[![GitHub release](https://img.shields.io/github/release/shellyln/liyad.svg)](https://github.com/shellyln/liyad/releases)\n[![.github/workflows/test.yml](https://github.com/shellyln/liyad/workflows/.github/workflows/test.yml/badge.svg)](https://github.com/shellyln/liyad/actions)\n[![GitHub forks](https://img.shields.io/github/forks/shellyln/liyad.svg?style=social\u0026label=Fork)](https://github.com/shellyln/liyad/fork)\n[![GitHub stars](https://img.shields.io/github/stars/shellyln/liyad.svg?style=social\u0026label=Star)](https://github.com/shellyln/liyad)\n\n\n\n## Install\n\nfrom NPM:\n```bash\n$ npm install liyad --save\n```\n\nor download UMD from [release](https://github.com/shellyln/liyad/releases) page.\n\n\n\u003e NOTICE:  \n\u003e Use with `webpack \u003e= 5`\n\u003e\n\u003e If you get the error:\n\u003e\n\u003e ```\n\u003e Module not found: Error: Can't resolve '(importing/path/to/filename)'\n\u003e in '(path/to/node_modules/path/to/dirname)'\n\u003e Did you mean '(filename).js'?`\n\u003e ```\n\u003e\n\u003e Add following setting to your `webpack.config.js`.\n\u003e\n\u003e ```js\n\u003e {\n\u003e     test: /\\.m?js/,\n\u003e     resolve: {\n\u003e         fullySpecified: false,\n\u003e     },\n\u003e },\n\u003e ```\n\u003e\n\u003e On `webpack \u003e= 5`, the extension in the request is mandatory for it to be fully specified\n\u003e if the origin is a '*.mjs' file or a '*.js' file where the package.json contains '\"type\": \"module\"'.\n\n\n## Install CLI\n\nSee [liyad-cli](https://github.com/shellyln/liyad-cli) .\n\n```bash\n$ npm install -g liyad-cli\n$ liyad\n```\n\n## Playground\n\n[https://shellyln.github.io/liyad/playground.html](https://shellyln.github.io/liyad/playground.html)\n\n----\n\n\n## Features\n\n* APIs to customize all operators and macros\n* Builtin S-expression parser\n* Builtin minimal Lisp interpreter\n* Reference implementation of LSX (alternative JSX notation using Lisp)\n\n----\n\n## Real world examples\n\n* [Ménneu](https://www.npmjs.com/package/menneu)  \n    Component-based extensible document processor\n* [mdne - Markdown Neo Edit](https://www.npmjs.com/package/mdne)  \n    A simple markdown and code editor powered by Markdown-it, Ace and Carlo.\n* [Tynder](https://github.com/shellyln/tynder)  \n    TypeScript friendly Data validator for JavaScript.\n\n----\n\n\n## What is LSX\n\nLSX is an alternative JSX notation using Lisp.\n\n### LSX and Liyad advantages:\n* No transpiler needed\n  + Liyad uses ES6 template literal syntax.   \n    You don't pass the entire code to transpile and evaluate it.  \n    Save your coding times.\n\n* Secure execution for untrusted contents\n  + No host environment's symbols are accessible from evaluated user contents by default.  \n    Malicious codes can not make a serious attack.\n\n* Simple and powerful\n  + What you can do with JSX can be done with LSX.  \n    Plus, LSX itself is a complete data description format\n    and is a complete programming language,  \n    so you can write more concise and powerful.\n\n\nThe LSX runtime directly calls `React.createElement`\n(or a [JSX Factory](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx/) function such as\n[RedAgate](https://github.com/shellyln/red-agate/tree/master/packages/red-agate#configurations-for-building-application),\n[Vue.js](https://vuejs.org/v2/guide/render-function.html#JSX), etc.) as a Lisp function,  \nConvert a Lisp list to a renderer component object tree.\n\nIn order to resolve the renderer component, you must register the object's constructor with the LSX runtime in advance.\n\nAll unresolved lisp function symbols are dispatched to `React.createElement('some_unresolved_name', ...)`.  \nYou can declare HTML/XML standard tags.\n\nAs with JSX, LSX must always return a single component.  \nUsing `Template` Lisp function instead of JSX `Fragment` tag will produce the same result.\n\n\n### Example:\n\n```ts\nlsx`\n(Template\n    (select (@ (style (display \"inline-block\")\n                      (width \"300px\") )\n               (className \"foo bar baz\")\n               (onChange ${(e) =\u003e this.handleExampleSelected(e.target.value)}) )\n        ($=for ${exampleCodes}\n            ($=if (== (% $index 2) 1)\n                (option (@ (value $index)) ($concat \"odd: \" ($get $data \"name\"))) )\n            ($=if (== (% $index 2) 0)\n                (option (@ (value $index)) ($concat \"even: \" ($get $data \"name\"))) ))))`;\n```\n\n### See also:\n[Playground](https://shellyln.github.io/liyad/playground.html)'s\n[source code](https://github.com/shellyln/liyad/blob/master/src.dist/assets/script/playground.js)\nis written in LSX.\n\n----\n\n\n## Usage\n\n### Output S-expression into JSON:\n```ts\nimport { S } from 'liyad';\n\nconsole.log(\n    JSON.stringify(S`\n        ($list\n            1 2 3 \"a\" \"b\" \"C\"\n            ($list 4 5 6) ${\"X\"} ${[\"Y\", \"Z\"]} )`\n\n        // You can also parse by calling w/o template literal syntax as following:\n        // S(' ... ')\n    )\n);\n```\n\nOutput:\n```json\n[{\"symbol\":\"$list\"},1,2,3,\"a\",\"b\",\"C\",[{\"symbol\":\"$list\"},4,5,6],{\"value\":\"X\"},{\"value\":[\"Y\",\"Z\"]}]\n```\n\n\n\n### Run minimal Lisp interpreter:\n```ts\nimport { lisp } from 'liyad';\n\nconsole.log(\n    JSON.stringify(lisp`\n        ($defun fac (n)\n            ($if (== n 0)\n                1\n                (* n ($self (- n 1))) ))\n        ($list\n            1 2 (fac 3) \"a\" \"b\" \"c\"\n            ($list 4 5 (fac 6) ${\"X\"} ${[\"Y\", \"Z\"]}) )`\n\n        // You can also evaluate by calling w/o template literal syntax as following:\n        // lisp(' ... ')\n    )\n);\n```\n\nOutput:\n```json\n[1,2,6,\"a\",\"b\",\"c\",[4,5,720,\"X\",[\"Y\",\"Z\"]]]\n```\n\n\n\n### Render web page with LSX:\n```ts\nimport * as React    from 'react';\nimport * as ReactDOM from 'react-dom';\nimport { LSX }       from 'liyad';\n\nvar lsx = null;\n\nconst exampleCodes = [{\n    name: \"Example1: factorial\",\n    code: ` ... `\n}, {\n    name: \"Example2: Hello, World!\",\n    code: ` ... `,\n}];\n\nclass ExampleLoader extends React.Component {\n    constructor(props, context) {\n        super(props, context);\n        this.state = {};\n    }\n\n    handleExampleSelected(i) {\n        this.props.loadExample(i);\n    }\n\n    render() {\n        return (lsx`\n        (Template\n            (select (@ (style (display \"inline-block\")\n                              (width \"300px\") )\n                       (onChange ${(e) =\u003e this.handleExampleSelected(e.target.value)}) )\n                ($=for ${exampleCodes}\n                    (option (@ (value $index)) ($get $data \"name\")) )))`);\n    }\n}\n\nclass App extends React.Component {\n    constructor(props, context) {\n        super(props, context);\n        this.state = {};\n    }\n\n    loadExample(i) {\n        console.log(exampleCodes[i].code);\n    }\n\n    render() {\n        return (lsx`\n        (Template\n            (div (@ (style (margin \"4px\")))\n                (ExampleLoader  (@ (loadExample ${(i) =\u003e this.loadExample(i)}))) ))`);\n    }\n}\n\nvar lsx = LSX({\n    jsx: React.createElement,\n    jsxFlagment: React.Fragment,\n    components: {\n        ExampleLoader,\n        App,\n    },\n});\n\nReactDOM.render(lsx`(App)`, document.getElementById('app'));\n```\n\n\n### Build your new DSL:\n```ts\nimport { SxFuncInfo,\n         SxMacroInfo,\n         SxSymbolInfo,\n         SExpression,\n         SxParserConfig,\n         defaultConfig,\n         installCore,\n         installArithmetic,\n         installSequence } from 'liyad';\n\nconst myOperators: SxFuncInfo[] = [{\n    name: '$__defun',\n    fn: (state: SxParserState, name: string) =\u003e (...args: any[]) =\u003e {\n        // S expression: ($__defun 'name '(sym1 ... symN) 'expr ... 'expr)\n        //  -\u003e S expr  : fn\n        const car: SxSymbol = $$first(...args);\n        if (args.length \u003c 3) {\n            throw new Error(`[SX] $__defun: Invalid argument length: expected: ${3} / args: ${args.length}.`);\n        }\n        const fn = $__lambda(state, name)(...args.slice(1));\n        state.funcMap.set(car.symbol, {\n            name: car.symbol,\n            fn: (st, nm) =\u003e fn\n        });\n        return fn;\n    },\n}];\n\nconst myMacros: SxMacroInfo[] = [{\n    name: '$defun',\n    fn: (state: SxParserState, name: string) =\u003e (list) =\u003e {\n        // S expression: ($defun name (sym1 ... symN) expr ... expr)\n        //  -\u003e S expr  : ($__defun 'name '(sym1 ... symN) 'expr ... 'expr)\n        return [{symbol: '$__defun'},\n            ...(list.slice(1).map(x =\u003e quote(state, x))),\n        ];\n    },\n}];\n\nconst mySymbols: SxSymbolInfo[] = [\n    {name: '#t', fn: (state: SxParserState, name: string) =\u003e true}\n];\n\nexport const MyDSL = (() =\u003e {\n    let config: SxParserConfig = Object.assign({}, defaultConfig);\n\n    config = installCore(config);\n    config = installArithmetic(config);\n    config = installSequence(config);\n\n    config.stripComments = true;\n\n    config.funcs = (config.funcs || []).concat(myOperators);\n    config.macros = (config.macros || []).concat(myMacros);\n    config.symbols = (config.symbols || []).concat(mySymbols);\n\n    return SExpression(config);\n})();\n\n\nconsole.log(\n    JSON.stringify(MyDSL`( ... )`)\n);\n```\n\n\n----\n\n\n## Extended syntax\n\n\n----\n\n### Comments\n\n```lisp\n# This is a line comment\n\n(# ; \u003c-- This is a object literal, not a line comment\n)\n\n; This is a line comment\n\n#|\nThis is a block comment\n |#\n```\n\n----\n\n### Here document:\n\n#### `lisp` preset interpreter:\n\n```lisp\n\"\"\"\nHello, Liyad!\n\"\"\"\n```\n\nis equivalent to:\n```lisp\n($concat\n\"\nHello, Liyad!\n\"\n)\n```\n\n#### `LSX` preset interpreter:\n\n```lisp\n\"\"\"\nHello, Liyad!\n\"\"\"\n```\n\nis equivalent to:\n```lisp\n(Template\n\"\nHello, Liyad!\n\"\n)\n```\n\n\u003e `Template` on the `LSX` preset interpreter, it is mapped to the function passed by `LsxConfig.JsxFragment`.  \n\u003e See also: [Fragments (React)](https://reactjs.org/docs/fragments.html), [Template (RedAgate)](https://github.com/shellyln/red-agate/tree/master/packages/red-agate#standard-tag-libs).\n\n----\n\n\n### Here document with variable substitution:\n\n```lisp\n\"\"\"\nHello, %%%($get name)!\n\"\"\"\n```\n\nis equivalent to:\n```lisp\n(Template\n\"\nHello, \" ($get name) \"!\n\"\n)\n```\n\n\n----\n\n\n### Here document with custom function:\n\n```lisp\n\"\"\"div\nHello, %%%($get name)!\n\"\"\"\n```\n\nis equivalent to:\n```lisp\n(div\n\"\nHello, \" ($get name) \"!\n\"\n)\n```\n\n\n### Here document with custom function and LSX props:\n\n```lisp\n\"\"\"div@{(id \"123\") (class \"foo bar baz\")}\nHello, %%%($get name)!\n\"\"\"\n```\n\nis equivalent to:\n```lisp\n(div (@ (id \"123\") (class \"foo bar baz\"))\n\"\nHello, \" ($get name) \"!\n\"\n)\n```\n\n\n----\n\n\n### Spread operator\n\n```lisp\n($list 1 2 ...($concat (3 4) (5 6)) 7 8)\n```\n\nis equivalent to:\n```lisp\n($list 1 2 ($spread ($concat (3 4) (5 6))) 7 8)\n```\n\nand is to be:\n```json\n[1,2,3,4,5,6,7,8]\n```\n\n`$spread` is NOT a macro. The list passed as a parameter is spliced ​​after evaluation.\n\n\n----\n\n### Splice macro\n\n```lisp\n($list 1 2 3 4 ($splice (5 6 7 8)) 9 10)\n```\n\nis equivalent to:\n```lisp\n($list 1 2 3 4 5 6 7 8 9 10)\n```\n\n```lisp\n(($splice ($call x add)) 5 7)\n```\n\nis equivalent to:\n```lisp\n($call x add 5 7)\n```\n\n----\n\n### Shorthands\n\n#### $set\n\n```lisp\n(::foo:bar:baz= 7)\n```\n\nis equivalent to:\n```lisp\n($set (\"foo\" \"bar\" \"baz\") 7)\n```\n\n#### $get\n\n```lisp\n($list ::foo:bar:baz)\n```\n\nis equivalent to:\n```lisp\n($list ($get \"foo\" \"bar\" \"baz\"))\n```\n\n#### $call\n\n```lisp\n(::foo:bar@baz 3 5 7)\n```\n\nis equivalent to:\n```lisp\n($call ($get \"foo\" \"bar\") baz 3 5 7)\n```\n\n----\n\n\n### Rest parameter\n\n```lisp\n($defun f (x ...y)\n    ($list x y) )\n\n($list\n    (f 1)\n    (f 1 2)\n    (f 1 2 3)\n    (f 1 2 3 4)\n    (f 1 2 3 4 5) )\n```\n\nis to be:\n```json\n[\n    [1,[]],\n    [1,[2]],\n    [1,[2,3]],\n    [1,[2,3,4]],\n    [1,[2,3,4,5]]\n]\n```\n\n----\n\n### Verbatim string literal\n\nVerbatim string literal\n```lisp\n($last @\"c:\\documents\\files\\u0066.txt\")\n```\n\nis to be:\n```json\n\"c:\\\\documents\\\\files\\\\u0066.txt\"\n```\n\nNormal string literal\n```lisp\n($last \"c:\\documents\\files\\u0066.txt\")\n```\n\nis to be:\n```json\n\"c:documents\\filesf.txt\"\n```\n\n----\n\n### Object literal\n\n```lisp\n(# (foo \"a\")\n   (bar 10)\n   (baz) )\n```\n\nis to be:\n```json\n{\n    \"foo\": \"a\",\n    \"bar\": 10,\n    \"baz\": true\n}\n```\n\n----\n\n### nil, null, undefined\n```lisp\n($list nil null undefined)\n```\n\nis to be:\n```js\n[[], null, undefined]\n```\n\nSee [this](https://github.com/shellyln/liyad/blob/master/src/s-exp/operators/core/core.symbol.ts).\n\n----\n\n### Refer the function\n\n```lisp\n($defun fn(x) (+ x 1))\n($let x (\u003c- fn))\n(x 3) ;; 4\n```\n\u003e Liyad is `Lisp-2` language.\n\n----\n\n### Lambda and closure\n\nLambda\n```lisp\n($let fn (-\u003e (x y z) (+ x y z)))\n\n(fn 1 2 3) ;; 6\n```\n\u003e `$lambda` is synonym of `-\u003e`.\n\nClosure\n```lisp\n($let fn ($local ((a 1)(b 2)(c 3))\n    (|-\u003e (x y z) use (a b c)\n        ($set a (+ a x))\n        ($set b (+ b y))\n        ($set c (+ c z))\n        (+ a b c) )))\n\n(fn 1 2 3) ;; 12\n(fn 1 2 3) ;; 18\n```\n\u003e `$closure` is synonym of `|-\u003e`.\n\nis equivalent to:\n```lisp\n($let fn ($local ((a 1)(b 2)(c 3))\n    ($capture (a b c) (-\u003e (x y z)\n        ($set a (+ a x))\n        ($set b (+ b y))\n        ($set c (+ c z))\n        (+ a b c) ))))\n\n(fn 1 2 3) ;; 12\n(fn 1 2 3) ;; 18\n```\n\u003e `$capture` can also be used with `$defun`.\n\n----\n\n### Recursive call\n\n```lisp\n($defun tarai(x y z)\n    ($if (\u003c= x y)\n        y\n        ($self ($self (- x 1) y z)\n               ($self (- y 1) z x)\n               ($self (- z 1) x y) )))\n```\n\u003e `$self` refers to the function currently defined by `$defun` or `-\u003e`.\n\n----\n\n### Macro\n\n```lisp\n($defmacro FOR (!i \u003c[\u003e \u003cFROM\u003e s \u003cTO\u003e e \u003c]\u003e ...body)\n    `($last\n        ($local ((,i ,s))\n            ($while (\u003c= ,i ,e)\n                ,@body\n                ($set ,i (+ ,i 1)) ))))\n\n($let c1   0)\n($let c2 100)\n(FOR p [ FROM (+ 1) TO (+ 6 -3) ]\n    ($set c1 (+ c1 p))\n    ($set c2 (+ c2 p)) )\n```\n\n#### Parameter type checking\n\n|formal parameter  |constraint|\n|------------------|----------|\n|`!`_token_        |parameter should be symbol\n|`\u003c`_token_`\u003e`     |parameter should be symbol named `token`\n|_token_`:number`  |parameter should be number\n|_token_`:string`  |parameter should be string\n|_token_`:function`|parameter should be function\n|_token_`:list`    |parameter should be list\n|_token_`:symbol`  |parameter should be symbol\n\n\u003e Don't put spaces between `!` `\u003c` `\u003e` `:type` and _token_.\n\n\u003e Type checking checks formal parameter types before evaluation.\n\n\u003e Macro can be overloaded with the same macro name but different numbers of formal parameters.\n\n----\n\n### This object\n\n```lisp\n($let fn (-\u003e () $this))\n($let xx (# (a 3)\n            (b 5)\n            (f fn) ))\n($json-stringify (::xx@f)) ;; {\"a\":3,\"b\":5}\n```\n\n----\n\n### Compiling functions and lambdas (experimental)\n\n|interpreting|compiling| |\n|------------|---------|-|\n|$defun      |$$defun  |define the function\n|$lambda     |$$lambda |define the lambda\n|-\u003e          |=\u003e       |define the lambda\n|$closure    |$$closure|define the closure\n|\\|-\u003e        |\\|=\u003e     |define the closure\n\n----\n\n\n## APIs\n\n### `SExpression` / `SExpressionAsync`\n\nCreate a new DSL.\n\n```ts\ninterface SxParserConfig {\n    raiseOnUnresolvedSymbol: boolean;\n    enableEvaluate: boolean;\n    enableHereDoc: boolean;\n    enableSpread: boolean;\n    enableSplice: boolean;\n    enableShorthands: boolean;\n    enableVerbatimStringLiteral: boolean;\n    enableTailCallOptimization: boolean;\n    enableRegExpMatchOperator: true,     // IMPORTANT: Turn off to prevent ReDoS when executing untrusted code\n    enableCompilationOperators: boolean; // IMPORTANT: Turn off to prevent DoS when executing untrusted code\n    stripComments: boolean;\n    wrapExternalValue: boolean;\n    reservedNames: SxReservedNames;\n    returnMultipleRoot: boolean;\n    maxEvalCount: number;                // IMPORTANT: Set positive value to prevent DoS when executing untrusted code\n\n    jsx?: (comp: any, props: any, ...children: any[]) =\u003e any;\n    JsxFragment?: any;\n\n    funcs: SxFuncInfo[];\n    macros: SxMacroInfo[];\n    symbols: SxSymbolInfo[];\n\n    funcSymbolResolverFallback?: SxFunc;\n    valueSymbolResolverFallback?: SxSymbolResolver;\n}\n\nfunction SExpression(config: SxParserConfig): (strings: TemplateStringsArray | string, ...values?: any[]) =\u003e SxToken\n```\n\n* returns : Template literal function.\n* `config` : Parser config.\n\n----\n\n\n### `S`\n\nParse a S-expression.\n\n```ts\nfunction S(strings: TemplateStringsArray | string, ...values?: any[]): SxToken\n```\n\n* returns : S-expression parsing result as JSON object.\n* `strings` : Template strings.\n* `values` : values.\n\n----\n\n\n### `lisp`\n\nEvaluate a Lisp code.\n\n```ts\nfunction lisp(strings: TemplateStringsArray | string, ...values?: any[]): SxToken\n```\n\n* returns : Evalueting result value of Lisp code.  \n    * If input Lisp code has multiple top level parenthesis,  \n      result value is last one.\n* `strings` : Template strings.\n* `values` : values.\n\n----\n\n\n### `lisp_async`\n\nEvaluate a Lisp code.  \n(asynchronous features are enabled.)\n\n```ts\nfunction lisp_async(strings: TemplateStringsArray | string, ...values?: any[]): Promise\u003cSxToken\u003e\n```\n\n* returns : Promise that evalueting result value of Lisp code.  \n    * If input Lisp code has multiple top level parenthesis,  \n      result value is last one.\n* `strings` : Template strings.\n* `values` : values.\n\n----\n\n\n### `LM`\nEvaluate a Lisp code (returns multiple value).\n\n```ts\nfunction LM(strings: TemplateStringsArray | string, ...values?: any[]): SxToken\n```\n\n* returns : Evalueting result value of lisp code.  \n    * If input Lisp code has multiple top level parenthesis,  \n      result value is array.\n* `strings` : Template strings.\n* `values` : values.\n\n----\n\n\n### `LM_async`\nEvaluate a Lisp code (returns multiple value).  \n(asynchronous features are enabled.)\n\n```ts\nfunction LM_async(strings: TemplateStringsArray | string, ...values?: any[]): Promise\u003cSxToken\u003e\n```\n\n* returns : Promise that evalueting result value of lisp code.  \n    * If input Lisp code has multiple top level parenthesis,  \n      result value is array.\n* `strings` : Template strings.\n* `values` : values.\n\n----\n\n\n### `LSX`\nEvaluate a Lisp code as LSX.\n\n```ts\ninterface LsxConfig {\n    jsx: (comp: any, props: any, ...children: any[]) =\u003e any;\n    jsxFlagment: any;\n    components: object;\n}\n\nfunction LSX\u003cR = SxToken\u003e(lsxConf: LsxConfig): (strings: TemplateStringsArray, ...values: any[]) =\u003e R\n```\n\n* returns : Template literal function.\n* `lsxConf` : LSX config.\n\n----\n\n\n### `LSX_async`\nEvaluate a Lisp code as LSX.  \n(asynchronous features are enabled.)\n\n```ts\ninterface LsxConfig {\n    jsx: (comp: any, props: any, ...children: any[]) =\u003e any;\n    jsxFlagment: any;\n    components: object;\n}\n\nfunction LSX_async\u003cR = SxToken\u003e(lsxConf: LsxConfig): (strings: TemplateStringsArray, ...values: any[]) =\u003e Promise\u003cR\u003e\n```\n\n* returns : Template literal function.\n* `lsxConf` : LSX config.\n\n\n### (`lisp` | `lisp_async` | `LM` | `LM_async` : SExpressionTemplateFn) methods\n\n#### evaluateAST\n\n```ts\nevaluateAST(ast: SxToken[]): SxToken;\n```\n\n* returns : evaluation result value.\n* `ast` : AST to evaluate. it should be enclosed in `[]`.\n    ```ts\n    lisp.evaluateAST([[{symbol: '+'}, 1, 2 ,3]]);  // 6\n    ```\n\n#### repl\n\n```ts\nrepl(): SExpressionTemplateFn;\n```\n\n* returns : Template literal function that will keep variables and states for each evaluation.\n\n#### setGlobals\n\n```ts\nsetGlobals(globals: object): SExpressionTemplateFn;\n```\n\n* returns : myself (template literal function).\n* `globals` : Global variables to preset.\n\n#### appendGlobals\n\n```ts\nappendGlobals(globals: object): SExpressionTemplateFn;\n```\n\n* returns : myself (template literal function).\n* `globals` : Global variables to preset.\n\n#### setStartup\n\n```ts\nsetStartup(strings: TemplateStringsArray | string, ...values: any[]): SExpressionTemplateFn;\n```\n\n* returns : myself (template literal function).\n* `strings` : Startup code that evaluate before each evaluation of user code.\n\n#### setStartupAST\n\n```ts\nsetStartupAST(ast: SxToken[]): SExpressionTemplateFn;\n```\n\n* returns : myself (template literal function).\n* `ast` : Startup code AST that evaluate before each evaluation of user code.\n\n#### appendStartup\n\n```ts\nappendStartup(strings: TemplateStringsArray | string, ...values: any[]): SExpressionTemplateFn;\n```\n\n* returns : myself (template literal function).\n* `strings` : Startup code that evaluate before each evaluation of user code.\n\n#### appendStartupAST\n\n```ts\nappendStartupAST(ast: SxToken[]): SExpressionTemplateFn;\n```\n\n* returns : myself (template literal function).\n* `ast` : Startup code AST that evaluate before each evaluation of user code.\n\n#### install\n\n```ts\ninstall(installer: (config: SxParserConfig) =\u003e SxParserConfig): SExpressionTemplateFn;\n```\n\n* returns : myself (template literal function).\n* `installer` : Installer function that register the operators, macros, constants to the `config` object.\n\n\n### `runScriptTags`\nRun script tags.\n\n```ts\nfunction runScriptTags(\n    lisp: SExpressionTemplateFn | SExpressionAsyncTemplateFn,\n    globals?: object,\n    contentType = 'text/lisp')\n```\n\n* returns : Evaluation result.\n* `lisp` : Evaluater function.\n* `globals` : Global variables.\n* `contentType` : Content type attribute of script tags.\n\nUsage:\n```html\n\u003c!DOCTYPE html\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"utf-8\"\u003e\n    \u003cscript type=\"text/lisp\"\u003e\n        ($local ((body (::document@querySelector \"body\")))\n            ($set (body innerText) \"Hello, Lisp! \") )\n        ($local (c) ($capture (c)\n            ($$defun tarai(x y z)\n                ($set c (+ c 1))\n                ($if (\u003c= x y)\n                    y\n                    ($self ($self (- x 1) y z)\n                        ($self (- y 1) z x)\n                        ($self (- z 1) x y))))\n            ($list ($datetime-to-iso-string ($now)) (tarai 13 6 0) c) ))\n    \u003c/script\u003e\n    \u003cscript src=\"liyad.min.js\"\u003e\u003c/script\u003e\n    \u003cscript\u003e\n        // Since the above lisp code refers to the body element,\n        // you need to enclose the lisp evaluation with addEventListener.\n        document.addEventListener('DOMContentLoaded', function(event) {\n            const result = JSON.stringify(\n                liyad.runScriptTags(liyad.lisp, {window, document}));\n            const body = document.querySelector('body');\n            setTimeout(() =\u003e body.innerText = body.innerText + result, 30);\n        });\n    \u003c/script\u003e\n\u003c/head\u003e\n\u003cbody\u003e\u003c/body\u003e\n```\n\n----\n\n\n## Tree shaking (webpack)\n\nYou can benefit from tree shaking by importing ES module separated files.\n\n| Import path                                     | Description    |\n|-------------------------------------------------|----------------|\n| `liyad/modules`                                 | Entire library |\n| `liyad/modules/s-exp/types`                     | Type definitions |\n| `liyad/modules/s-exp/interpreter`               | Interpreter DIY APIs `SExpression`, `SExpressionAsync` |\n| `liyad/modules/s-exp/interpreter/presets/s-exp` | Preset s-expression parser `S` |\n| `liyad/modules/s-exp/interpreter/presets/lisp`  | Preset interpreters `lisp`, `lisp_async`, `LM`, `LM_async` |\n| `liyad/modules/s-exp/interpreter/presets/lsx`   | Preset interpreters `LSX`, `LSX_async` |\n| `liyad/modules/s-exp/operators/core`            | Core operators |\n| `liyad/modules/s-exp/operators/arithmetic`      | Arithmetic operators |\n| `liyad/modules/s-exp/operators/sequence`        | Sequence operators |\n| `liyad/modules/s-exp/operators/concurrent`      | Concurrent operators |\n| `liyad/modules/s-exp/operators/jsx`             | JSX (LSX) operators |\n\n\u003e NOTICE: `liyad/modules/*` are not babelized. These are output as `ES2015` by tsc.\n\n----\n\n\n## Operators\n\nSee\n[core](https://github.com/shellyln/liyad/blob/master/src/s-exp/operators/core/index.ts),\n[arithmetic](https://github.com/shellyln/liyad/blob/master/src/s-exp/operators/arithmetic/index.ts),\n[sequence](https://github.com/shellyln/liyad/blob/master/src/s-exp/operators/sequence/index.ts),\n[concurrent](https://github.com/shellyln/liyad/blob/master/src/s-exp/operators/concurrent/index.ts),\n[JSX (LSX)](https://github.com/shellyln/liyad/blob/master/src/s-exp/operators/jsx/index.ts) operators.\n\n\n----\n\n\n## License\n[ISC](https://github.com/shellyln/liyad/blob/master/LICENSE.md)  \nCopyright (c) 2018, 2019 Shellyl_N and Authors.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshellyln%2Fliyad","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshellyln%2Fliyad","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshellyln%2Fliyad/lists"}