{"id":33096119,"url":"https://kanaka.github.io/miniMAL/","last_synced_at":"2025-11-19T13:03:07.162Z","repository":{"id":26969245,"uuid":"30432649","full_name":"kanaka/miniMAL","owner":"kanaka","description":"A Delightfully Diminutive Lisp. Implemented in \u003c 1 KB of JavaScript with JSON source, macros, tail-calls, JS interop, error-handling, and more.","archived":false,"fork":false,"pushed_at":"2024-08-15T15:46:24.000Z","size":932,"stargazers_count":634,"open_issues_count":2,"forks_count":30,"subscribers_count":19,"default_branch":"gh-pages","last_synced_at":"2025-10-04T01:38:57.735Z","etag":null,"topics":["code-golf","interop","interpreter","javascript","lambda","lisp","macros","mal","python","small","tail-calls","tco","tiny"],"latest_commit_sha":null,"homepage":"http://kanaka.github.io/miniMAL","language":"JavaScript","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/kanaka.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}},"created_at":"2015-02-06T20:56:03.000Z","updated_at":"2025-09-27T04:46:04.000Z","dependencies_parsed_at":"2024-03-19T00:30:17.463Z","dependency_job_id":"1a57eaaf-8b01-4c93-8c82-0be6940cf698","html_url":"https://github.com/kanaka/miniMAL","commit_stats":{"total_commits":80,"total_committers":3,"mean_commits":"26.666666666666668","dds":0.03749999999999998,"last_synced_commit":"c64353fa9d2da4f279c0611586077fb1c3fe4039"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kanaka/miniMAL","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanaka%2FminiMAL","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanaka%2FminiMAL/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanaka%2FminiMAL/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanaka%2FminiMAL/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kanaka","download_url":"https://codeload.github.com/kanaka/miniMAL/tar.gz/refs/heads/gh-pages","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanaka%2FminiMAL/sbom","scorecard":{"id":549071,"data":{"date":"2025-08-11","repo":{"name":"github.com/kanaka/miniMAL","commit":"c64353fa9d2da4f279c0611586077fb1c3fe4039"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.5,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/20 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/push.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: python/env.pyc:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/push.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/kanaka/miniMAL/push.yml/gh-pages?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/push.yml:20","Warn: npmCommand not pinned by hash: .github/workflows/push.yml:21","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'gh-pages'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-434g-2637-qmqr","Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m","Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw","Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p","Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747","Warn: Project is vulnerable to: GHSA-vjh7-7g9h-fjfh","Warn: Project is vulnerable to: GHSA-h7cp-r72f-jxh6","Warn: Project is vulnerable to: GHSA-v62p-rq8g-8h59","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-20T10:17:58.875Z","repository_id":26969245,"created_at":"2025-08-20T10:17:58.875Z","updated_at":"2025-08-20T10:17:58.875Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":285249460,"owners_count":27139375,"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","status":"online","status_checked_at":"2025-11-19T02:00:05.673Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["code-golf","interop","interpreter","javascript","lambda","lisp","macros","mal","python","small","tail-calls","tco","tiny"],"created_at":"2025-11-14T20:00:24.455Z","updated_at":"2025-11-19T13:03:07.154Z","avatar_url":"https://github.com/kanaka.png","language":"JavaScript","readme":"## miniMAL\n\nA Delightfully Dimuntive Lisp.\n\nThe miniMAL core interpreter is implemented in less than 1024 bytes of\nJavaScript (uglify/regpack). There is also an implementation of\nminiMAL in python (1.1K as a pyz file) and ClojureScript (1.8K\nafter minification).\n\nThe design of miniMAL started with\n[mal](https://github.com/kanaka/mal) (a Clojure-insipred pedagogical\nLisp interpreter with implementations in over eighty languages).\nAnd in fact, in the miniMAL repository you can see the incremental\nsteps to build up the interpreter just like for each of the mal\nimplementations. However, the syntax and functionality of miniMAL is\nfairly different from mal so it is a standalone project.\n\nEven though miniMAL is tiny it is actually a very powerful Lisp with\nadvanced features including: higher-order functions, tail-call\noptimization, macros, JavaScript interop, and error-handling. miniMAL\nis powerful enough that it has been used to create a full\n[implementation of mal](https://github.com/kanaka/mal/tree/master/impls/miniMAL).\n\n### Usage\n\nYou can try out miniMAL with the [online REPL](http://kanaka.github.io/miniMAL/).\n\nInstall the miniMAL binary using npm:\n\n```bash\nsudo npm install -g minimal-lisp\n```\n\nThere are several different ways to use and/or integrate miniMAL:\n\n* **Start a REPL**: run the miniMAL REPL (read-eval-print-loop). Requires\n  Node.js.\n```bash\nminiMAL\n```\n\n* **Run a miniMAL program**: run a miniMAL program and then exit.\n  Requires Node.js.\n```bash\nminiMAL hello.json\n```\n\n* **As a shebang script**: add a shebang line to the top of your\n  miniMAL program and turn it into an executable script. Requires\n  Node.js.\n```bash\necho \"#!/usr/bin/env miniMAL\" \u003e hello2.json\ncat hello.json \u003e\u003e hello2.json\nchmod +x hello2.json\n./hello2.json\n```\n\nTo use miniMAL as a library in another project, first install the\nmodule locally using npm:\n\n```bash\nsudo npm install minimal-lisp\n```\n\n* **Node.js library**: you can use the miniMAL Node.js library to\n  evaluate miniMAL source code in a regular Node.js program.\n```javascript\nvar miniMAL = require('minimal-lisp'),\n    m = miniMAL(global);\nm.eval([\"+\", 2, 3]);\n```\n\n* **Web library**: you can use the miniMAL web library to evaluate\n  miniMAL code in your web application.\n```html\n\u003cscript src=\"node_modules/minimal-lisp/js/web/miniMAL-min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\nvar m = miniMAL();\nm.eval([\"+\", 2, 3]);\n\u003c/script\u003e\n```\n\n\n### Features and Examples\n\n* **JSON source**: the source code of miniMAL programs is just plain\n  JSON (JavaScript object notation).\n```json\n[\"+\", 2, 3]\n=\u003e5\n[\"if\", [\"=\", 5, 5], 7, 8]\n=\u003e7\n[\"+\", 2, [\"*\", 3, 4]]\n=\u003e14\n```\n\n* **\"Lisp-0\"**: Functions, symbols and strings\n  are all in the same namespace making miniMAL a \"Lisp-0\". In\n  contrast, Lisp-2 languages have functions and symbols (and strings)\n  that are in separate namespaces. In Lisp-1 languages functions and\n  symbols are in the same namespace (and strings are still separate).\n  Strings in miniMAL are just quoted symbols.\n```json\n[\"def\", \"a_symbol\", 3]\n=\u003e3\n\"a_symbol\"\n=\u003e3\n[\"*\", \"a_symbol\", 6]\n=\u003e18\n[\"`\", \"a quoted symbol is a string\"]\n=\u003e\"a quoted symbol is a string\"\n```\n\n* **Lambdas**: miniMAL has anonymous and named functions.\n```json\n[ [\"fn\", [\"a\"], [\"*\", \"a\", \"a\"]], 8]\n=\u003e64\n[\"def\", \"sqr\", [\"fn\", [\"a\"], [\"*\", \"a\", \"a\"]]]\n[\"sqr\", 7]\n=\u003e49\n```\n\n* **Variadic Functions**: miniMAL functions/lambdas can support\n  variable numbers of parameters using the Clojure style \"\u0026\"\n  delimeter.\n```json\n[\"def\", \"drop1\", [\"fn\", [\"a\", \"\u0026\", \"b\"], \"b\"]]\n[\"drop1\", 1, 2, 3]\n=\u003e[2,3]\n```\n\n* **Lexical scope and let blocks**: miniMAL has full lexical scoping\n  within let blocks and lambdas. In the following example, \"add5\" is\n  defined as a function that refers to a lexicallly scoped variable\n  \"x\". The \"x\" variable is available to the function because the\n  definition of the function happened within same lexical scope\n  (it is a function closure), but it is not accessible outside the\n  \"let\" block lexical scope.\n```json\n[\"def\", \"add5\", [\"let\", [\"x\", 5], [\"fn\", [\"a\"], [\"+\", \"x\", \"a\"]]]]\n[\"add5\", 7]\n=\u003e12\n\"x\"\n=\u003e__ERROR__\n```\n\n* **First class functions/lambdas**: functions/lambdas are first class\n  values in miniMAL. They can be bound to variables, passed into and\n  returned from functions just like normal values.\n```json\n[\"def\", \"addX\", [\"fn\", [\"X\"], [\"fn\", [\"a\"], [\"+\", \"X\", \"a\"]]]]\n[\"def\", \"add9\", [\"addX\", 9]]\n[\"add9\", 20]\n=\u003e29\n[\"map\", \"add9\", [\"`\", [2, 3, 4]]]\n=\u003e[11,12,13]\n```\n\n* **Automatic tail call optimization (TCO)**: when a function calls\n  itself (recursion) as the very last thing it does (tail call), this\n  is automatically optimized so that the call does not consume any\n  stack.  This allows recursion to be as efficient as iteration. In\n  this example, \"sum1\" is not tail optimized because an addition\n  happens after the recursive call to \"sum1\". \"sum2\" is tail optimized\n  by miniMAL because the recursive \"sum2\" call happens in tail\n  position.\n```json\n[\"def\", \"sum1\", [\"fn\", [\"n\"], [\"if\", [\"=\", \"n\", 0], 0, [\"+\", \"n\", [\"sum1\", [\"-\", \"n\", 1]]]]]]\n[\"sum1\", 10000]\n=\u003e__ERROR: stack overflow__\n[\"def\", \"sum2\", [\"fn\", [\"n\", \"a\"], [\"if\", [\"=\", \"n\", 0], \"a\", [\"sum2\", [\"-\", \"n\", 1], [\"+\", \"n\", \"a\"]]]]]\n[\"sum2\", 10000, 0]\n=\u003e500500\n```\n\n* **JavaScript Interop**: miniMAL uses native JavaScript types (e.g.\n  lists are implemented as arrays) and supports JavaScript interop\n  using the method call function (`\".\"`) and the property get/set\n  function (`\".-\"`).\n```json\n[\"def\", \"randInt\", [\"fn\", [\"max\"], [\"parseInt\", [\"*\", \"max\", [\".\", \"Math\", [\"`\", \"random\"]]]]]]\n[\"randInt\", 100]\n=\u003e16\n[\"def\", \"rand-hsl\", [\"fn\", [], [\"+\", [\"+\", [\"`\", \"hsl(\"], [\"randInt\", 360]], [\"`\", \", 50%, 70%)\"]]]]\n[\"def\", \"set-style\", [\"fn\", [\"o\", \"k\", \"v\"],  [\".-\",  [\".-\", \"o\", [\"`\", \"style\"]], \"k\", \"v\"]]]\n[\"def\", \"by-tag\", [\"fn\", [\"tag\"], [\".\", \"document\", [\"`\", \"getElementsByTagName\"], \"tag\"]]]\n[\"set-style\", [\".-\", [\"by-tag\", [\"`\", \"body\"]],0], [\"`\", \"backgroundColor\"], [\"rand-hsl\"]]\n=\u003e__background color set to random hsl value__\n```\n\n*The following features are omitted from JS1K version of the\nimplementation in order to make space for example code.*\n\n* **Exception Handling**: miniMAL supports try/catch/throw style\n  exception handling. The thrown exceptions can be any arbitrary type.\n```json\n[\"try\", \"abc\", [\"catch\", \"exc\", [\"list\", [\"`\", \"exc was:\"], \"exc\"]]]\n=\u003e[\"exc was:\",\"abc not found\"]\n[\"try\", [\"throw\", 123], [\"catch\", \"exc\", [\"list\", [\"`\", \"exc was:\"], \"exc\"]]]\n=\u003e[\"exc was:\",123]\n[\"try\", [\"throw\", 123], [\"catch\", \"exc\", [\"list\", [\"`\", \"exc was:\"], \"exc\"]]]\n=\u003e[\"exc was:\",123]\n```\n\n* **Macros**: miniMAL has the ability to define macros. Macros allow\n  a program to create new syntactic structures. When a normal\n  function call is handled, the arguments to the function are all\n  evaluated first before the function is called. A macro receives all\n  its arguments unevaluated and can manipulate the raw arguments.\n  Whatever value is returned from the macro (perhaps a re-written\n  function call) is evaluated again. In the following example, the\n  \"unless\" macro reverses the logic of the if statement. If \"unless\"\n  was a defined as a regular function both of the true and false\n  positions would all be evaluated before the \"unless\" function was\n  called.  However, defining \"unless\" as a macro allows either the\n  true or false position to be evaluated but not both .\n```json\n[\"def\", \"unless\", [\"~\", [\"fn\", [\"p\", \"a\", \"b\"], [\"list\", [\"`\", \"if\"], \"p\", \"b\", \"a\"]]]]\n[\"unless\", false, 7, 8]\n=\u003e7\n[\"unless\", true, 7, 8]\n=\u003e8\n```\n\n### Rationale\n\nI originally started implementing a tiny Lisp interpreter as a quick\nhack to submit to the [2015 JS1K\ncompetition](http://js1k.com/2015-hypetrain/)\n([demo 2209](http://js1k.com/2015-hypetrain/demo/2209)). However,\nI soon realized that I could fit far more functionality into 1024\nbytes of JavaScript than I expected and so miniMAL was born as\na \"full-fledged\" Lisp in its own right.\n\n### License\n\nminiMAL is licensed under the [MPL 2.0](http://www.mozilla.org/MPL/2.0/) (Mozilla Public License 2.0).\nSee LICENSE for more details.\n\n","funding_links":[],"categories":["Clojure-likes"],"sub_categories":["[miniMAL](https://github.com/kanaka/miniMAL)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/kanaka.github.io%2FminiMAL%2F","html_url":"https://awesome.ecosyste.ms/projects/kanaka.github.io%2FminiMAL%2F","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/kanaka.github.io%2FminiMAL%2F/lists"}