{"id":13800710,"url":"https://github.com/turbopape/scheje","last_synced_at":"2025-04-10T04:58:43.336Z","repository":{"id":62434599,"uuid":"47837601","full_name":"turbopape/scheje","owner":"turbopape","description":"A little scheme implementation on top of Clojure","archived":false,"fork":false,"pushed_at":"2016-10-04T09:33:02.000Z","size":1537,"stargazers_count":140,"open_issues_count":6,"forks_count":11,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-03-14T10:45:54.777Z","etag":null,"topics":["clojure","compiler","evaluator","lisp","macros","programming-language","scheme"],"latest_commit_sha":null,"homepage":"http://turbopape.github.io/scheje","language":"Clojure","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/turbopape.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-11T16:27:29.000Z","updated_at":"2023-09-05T06:22:45.000Z","dependencies_parsed_at":"2022-11-01T21:01:50.050Z","dependency_job_id":null,"html_url":"https://github.com/turbopape/scheje","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fscheje","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fscheje/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fscheje/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbopape%2Fscheje/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/turbopape","download_url":"https://codeload.github.com/turbopape/scheje/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248161265,"owners_count":21057554,"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":["clojure","compiler","evaluator","lisp","macros","programming-language","scheme"],"created_at":"2024-08-04T00:01:15.339Z","updated_at":"2025-04-10T04:58:43.318Z","avatar_url":"https://github.com/turbopape.png","language":"Clojure","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# scheje - A little Scheme on Top of Clojure\n[![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT)\n[![Build Status](https://travis-ci.org/turbopape/scheje.svg?branch=master)](https://travis-ci.org/turbopape/scheje)\n[![Clojars Project](https://img.shields.io/clojars/v/scheje.svg)](https://clojars.org/scheje)\n[![Gratipay Team](https://img.shields.io/gratipay/team/scheje.svg)](https://gratipay.com/scheje/)\n[![Slack Team](https://img.shields.io/badge/chat-%23%20team-yellowgreen.svg)](https://scheje.slack.com)\n\n\u003cimg src=\"./scheje-logo.jpg\"\n alt=\"Scheje Logo\" title=\"The Scheje Logo\" align=\"center\" /\u003e\n\n\u003e\"If you give someone Fortran, he has Fortran. If you give someone Lisp, he has any language he pleases.\"\n - Guy L. Steele\n\nUsing the magnificent eval/apply dance (as in page 13 of the\nLisp 1.5 Manual), *scheje* is a tiny scheme implementation on Top of\nClojure.\n\n\n*Scheje* properly implements *define-syntax*, ellipsis is properly\nexpanded into relevant symbols, which can be respectively used in the\ngenerated *syntax-rules* templates. In fact, even *let* is implemented in\nterms of *define-syntax*.\n\nThe two defining forms, *define* and *define-syntax* generate new\nenvironments as per the bindings they introduce. Helper functions that\ninterpret these along with other evaluations will be discussed later.\n\n## Usage\nYou can play with scheje on-line with the [Web REPL](http://turbopape.github.io/scheje/).\n\nThe main interpretation function is *form-eval* in the *interpreter*\nnamespace.\n\nYou give it a form and an environment, and you get your evaluation:\n```clojure\n(form-eval '(+ x y) '{x 1 y 2})\n;;=\u003e 3\n```\n\nThe function *eval-prog*, evaluates a whole program. This function is\nbootstrapped with a starting\nenvironment, called the library (see [library.cljc](https://github.com/turbopape/scheje/blob/master/src/scheje/library.cljc) for the contents of the library). When launched, eval-prog evaluates all the forms, only showing the value of the last one.\n\nHere are some examples:\n\n```clojure\n(eval-prog  '((define-syntax let\n                (syntax-rules ()\n                              ((let ((var expr) ...) body ...)\n                               ((lambda (var ...) body ...) expr ...))))\n              (let ((x 1)(y 2)) (+ x y))))\n;;=\u003e3\n```\nThis example shows what we did to introduce the let form, though it is\nalready implemented in the root environment used by scheje, so you\ndon't have to define it every time you use *eval-prog*\n\nAnalogous to *let*, here's how one can declare *and* using a recursive\n*define-syntax*:\n```clojure\n(eval-prog '((define-syntax and\n               (syntax-rules ()\n                             ((and x) x)\n                             ((and) true)\n                             ((and x y ...) (if x (and y ...) false))))\n             (and true true true  true true false)))\n;;=\u003e false\n```\nSame here, this is already defined in *root-env* so you don't have to\ndefine it every time you use *eval-prog*. *or* is defined in the same\nway:\n```clojure\n(eval-prog '((define-syntax or\n               (syntax-rules ()\n                             ((or x) x)\n                             ((or) true)\n                             ((or x y ...) (if x true (or y ...)))))\n             (or false false false true false)))\n;;=\u003e true\n```\n\nLast but not least, here is the must-have *append* function, necessary for\nevery decent scheme implementation!\n```clojure\n(eval-prog '((define append\n               (lambda (l1 l2)\n                  (cond\n                    ((null? l1) l2)\n                    (else (cons (car l1) (append (cdr l1) l2))))))\n             (append '(1 2 3) '(4 5 6))))\n;;=\u003e '(1 2 3 4 5 6)\n```\n\n\nAlso, *quote*, *quasiquote*, *unquote* and *unquote-splicing* are\nsupported:\n\n```clojure\n(form-eval '(quasiquote\n             (1\n              (+ 1 (unquote-splicing (cdr '(1 2 3))))\n              (unquote  (+ 1 a))))\n           { 'a 5})\n;;=\u003e (1 (+ 1 2 3) 6)\n```\nAlso, named let, let*, and many more are available. Please refer to\nthe test files for the interpreter namespace to see possible uses.\n\n## Lexical Scoping in *let* Macros\n\nTo prevent symbol capture when using the *let* macro, when expanded,\neach *let* introduced expression's symbols are stored in its own\nscope. This avoids name clash:\n\nIn the following example, a is defined at the root-env, but \"inner\" a\nis returned from the *let* macro:\n```clojure\n(eval-prog '((define a \"outer\")\n             (let ((x (and false false))\n                   (a \"inner\"))\n               (if x \"_\" a))))\n;;=\u003e \"inner\"\n```\n\nIf we access a symbol outside the macro, we get its root binding:\n\n```clojure\n(eval-prog '((define a \"outer\")\n             (let ((x (and false false))\n                   (a \"inner\"))\n               (if x \"_\" a))\n             a))\n;;=\u003e \"outer\"\n```\n## Hygienic Macros\n\nInspired by\n[KFFD](http://web.cs.ucdavis.edu/~devanbu/teaching/260/kohlbecker.pdf)\nAlgorithm. Now Scheje appends a timestamp with respect to the\niteration in which every form is being expanded, thus preventing it from\ninadvertently capturing symbols across different expansion stages.\nIf some symbols have timestamps that cannot be evaluated, Scheje tries to\nevaluate their \"root\" form, i.e, checks if their name, stripped out of the timestamps, isn't\nbound in the execution environment. This 'sort of' forces capture of such symbols,\nas to see if they were intended to be passed as globals, for instance.\n\nFor instance, these two examples work properly:\n```clojure\n(eval-prog '(\n             (define-syntax or2\n               (syntax-rules ()\n                             ((or2 e1 e2) (let ((t e1)) (if t t e2) ))))\n             (let ((t true)) (or2 false t ))))\n;;=\u003e true\n```\nand\n\n```clojure\n(eval-prog '(\n             (let ((if (lambda(x y z) \"oops\")))\n              (let ((g false))\n                    (if g g false)))))\n;;=\u003e false\n```\n\n### ClojureScript Support\nScheje is written using reader conditionals. The interpreter namespace\ncan be used in a clojurescript project right away, in the browser, \nor in node.js if you want to use the file loading facilities.\n\n### A little REPL\nNow a **REPL** namespace is shipped, exposing a little REPL permitting\nto evaluating expressions and loading files.\n\nIf you want to run it in Clojure/JVM, just clone the repo and launch\n```shell\nlein run\n```\nYou can also build a ClojureScript/Node.js REPL and enjoy the ultra fast startup compared to JVM's version. Simply\nproceed like so:\n```shell\n#install npm dependencies\nnpm install readline-sync\n# then build the node app\nlein cljsbuild once\n# and enjoy scheje.js :)\nnode target/repl_out/scheje_repl.js\n```\n## Features\nPlease refer to the [Changelog](https://github.com/turbopape/scheje/blob/master/CHANGELOG.md) and the [interpreter_test.clj test file](https://github.com/turbopape/scheje/blob/master/test/scheje/interpreter_test.clj) to get a comprehensive list of the features and usage of *scheje*.\n\n## Contributors\nThanks to these wonderful people who helped the development of Scheje:\n- [balajirrao](https://github.com/balajirrao)\n\nAnd to these awesome proof-readers:\n- [jaredestroud](https://github.com/jaredestroud)\n- [yurimalheiros](https://github.com/yurimalheiros)\n- [chasingSublimity](https://github.com/chasingSublimity)\n- [rom1504](https://github.com/rom1504)\n\nSpecial thanks for the awesome logo go to:\n- [morachimo](https://github.com/morachimo)\n\n## TODOS - Wanna Contribute?\nYou can see how you can help by seeing the [open issues](https://github.com/turbopape/scheje/issues)\n\nPlease note that this project is released with a [Contributor Code of\nConduct.](./CODE_OF_CONDUCT.md) By participating in this project you agree to abide by its\nterms.\n\n## Credits\nScheje's Node.js REPL uses [readLineSync](https://github.com/anseki/readline-sync) from @anseki, which is licensed under the MIT License. \n## License\nCopyright © 2016 Rafik Naccache and Contributors.\nDistributed under the terms of the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturbopape%2Fscheje","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fturbopape%2Fscheje","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturbopape%2Fscheje/lists"}