{"id":18587573,"url":"https://github.com/inanyan/ilispy","last_synced_at":"2025-11-01T23:30:31.398Z","repository":{"id":119195156,"uuid":"543737625","full_name":"InAnYan/ilispy","owner":"InAnYan","description":"Ilispy - Lisp dialect and interpreter.","archived":false,"fork":false,"pushed_at":"2023-10-31T16:09:57.000Z","size":140,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-26T18:28:02.469Z","etag":null,"topics":["c","interpreter","lisp"],"latest_commit_sha":null,"homepage":"","language":"C","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/InAnYan.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}},"created_at":"2022-09-30T18:30:55.000Z","updated_at":"2022-10-02T17:05:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"3f29a213-0e35-4a57-b54a-213ae89197bf","html_url":"https://github.com/InAnYan/ilispy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InAnYan%2Filispy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InAnYan%2Filispy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InAnYan%2Filispy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/InAnYan%2Filispy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/InAnYan","download_url":"https://codeload.github.com/InAnYan/ilispy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239340504,"owners_count":19622704,"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":["c","interpreter","lisp"],"created_at":"2024-11-07T00:39:38.489Z","updated_at":"2025-11-01T23:30:31.331Z","avatar_url":"https://github.com/InAnYan.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ilispy\nTHERE IS A NEW PROJECT: [LispCpp](https://github.com/InAnYan/LispCpp).\n\nIlispy - Lisp dialect and interpreter.  \nIt was written, while reading a book \"Build Your Own Lisp\" by Daniel Holden [https://www.buildyourownlisp.com/].  \nThis Lisp dialect is similar to the original and to the one in book.  \nIlispy has quoted expressions and macros. It doesn't have Q-exprs.  \nThe program is not tested fully, quality is not guaranteed.  \n\n# Usage\n\t./ilispy [filename]\nWhile no `filename` is provided, the program will start in interpreter mode, where you can type expressions from command line.  \nIf there is a `filename` the program will interpret this file.  \n  \n# Build\nTo build this program, create directories `bin` and `obj` and type `make` in the root directory of the project.  \nIMPORTANT: edit the Makefile and fill `DEFINES` according to your system (`LISPY_COMPILE_LINUX`, `LISPY_COMPILE_OSX` or `LISPY_COMPILE_OTHER`).  \n\n# Values\nThere are 9 types of value:\n\n* __Number__ - signed integer. `13`, `42`, etc.\n* __Boolean__ - contains true or false. `true` or `false`.\n* __Symbol__ - like a Lisp symbol. `node-type`, `number?`, it's like identifier in other languages, but it can contain a lot of different characters.\n* __List__ - list of Ilispy values. `'(1 2 3)` or `(first second third)`.\n* __String__ - sequence of characters.\n* __Lambda__ - unnamed function.\n* __Macro__ - unnamed macro.\n* __Builtin__ - function, that written in C, but executes in Lispy.\n* __Error__ - error string.\n\nThe last 4 cannot be typed directly, they are results of builtin functions. Also, there is `Quoted type`, it contains value, which evaluation is delayed (details in [Evaluation] section).\n\nIlispy value type and its equivalent in C\n| Ilispy value type  | Type in C                                                             |\n|--------------------|-----------------------------------------------------------------------|\n| Ilispy value       | `lval`                                                                |\n| Ilispy environment | `lenv`                                                                |\n| Number             | `long`                                                                |\n| Boolean            | `bool`                                                                |\n| Symbol             | `char*`                                                               |\n| List               | ``` struct { unsigned count; struct lval** cells; } ```               |\n| String             | `char*`                                                               |\n| Lambda             | ``` struct { lenv* env; lval* formals; lval* body; }  ```             |\n| Builtin            | `lval* (*lbuiltin_func)(lenv* e, lval* a)`                            |\n| Macro              | ``` struct { lval* formals; lval* body; } ```                         |\n\n# Evaluation\nIlispy program - is a List. A List, that under evaluation, is named `S-expr`. By default, the first member of S-expr is a function and the rest are arguments of function (like code mode in Lisp). For example:\n\n    (+ 1 2 3)\n\nIt returns sum of 1, 2 and 3. This method of writing expressions is similar to Polish notation.  \nBecause List can store any Ilispy value, the Lists can be nested:  \n\n\t(+ 10 (- 5 9))\n\nIt's similar to Lisp, Scheme, Common Lisp, etc.  \nBefore a function call all S-expr elements are evaluated. This is problematic in a lot of cases. For instance:  \n\n\t(head (4 5 6))\n\nI have List of 3 elements, I want to take the first element of the List. Because all elements are evaluated, the interpreter will try to call `4` with arguments `5` and `6`. To prevent this, Ilispy uses Quoted type:  \n\n\t(head '(4 5 6))\n\nQuoted type is simply a wrapper on Ilispy value. It's purpose is \"to delay\" evaluation (it's really a \"delay\", it isn't a switchig to data mode). This means, that evaluation of a Quoted type return wrapped value, it doesn't try to evaluate wrapped value. Look at the example (`-\u003e` means evaluation pass):  \n\n\t(+ 1 2 3) -\u003e 6\n\t'(+ 1 2 3) -\u003e (+ 1 2 3)\n\t(head (+ 2 3)) -\u003e (head 6) -\u003e error\n\t(head '(+ 2 3)) -\u003e +\n\nAgain, it's similar to Lisp. But in Ilispy you can type, probably, funny things:  \n\n\t'1 -\u003e 1\n\t''(1 2 3) -\u003e '(1 2 3) -\u003e (1 2 3)\n\nQuotes can be nested and be placed on any type.  \nYes, that's not a `Q-expr`, and maybe `Q-expr` is a better concept because it doesn't have those strange cases.    \n\nThe rules of evalutaion of Ilispy value:\n\n1. If it is a Symbol, then retrieve value from current environment by symbol.  \n2. If it is a List, then evaluate List as S-expr.  \n3. If it is a Quoted type, then return wrapped object.  \n3. Otherwise, just return the value.  \n\nThe rules of evaluation of S-expr:\n\n1. Evaluate first element of the List.  \n2. If the result is a macro, then expand macro and evaluate the expanded expression.\n3. Otherwise, evaluate the rest of the List\n4. If there is an error in any evaluation, then return only this value.  \n5. If there is only one element in S-expr, then return it. (Because of this, there is no functions without arguments).  \n6. Take the first element:\n\t* If it's a Builtin, then call it with the rest of list as arguments.  \n\t* If it's a Lambda, then call it with the rest of list as arguments.  \n\t* Otherwise, return an error.  \n\n# Macros\nI don't know how macros work in Lisp.  \nMacros in Ilispy are very simple: macros contain formal and actual arguments, like a lambda. A macro tries to find symbol in its body, which equals to formal, and replaces it with actual. Look at the example:  \n\n\t(defmacro head! (lst) (head 'lst))\n\t(head! (1 2 3)) -\u003e (head '(1 2 3))\n\nAll it have done is replaced all occurences of `lst` in macro body with `(1 2 3)`.  \nThe existence of macros gives ability to a lot of things. One of the usage is:  \n\n\t(defmacro defun (name params body) (def 'name (\\ 'params 'body)))\n\t(defun inc (n) (+ n 1))\n\nWithout macros, we have to do this:  \n\n\t(def 'inc (\\ '(n) '(+ n 1)))\n\t\n# End\nThe rest of the language is similar to Lisp and Lispy. Look at the files in examples directory.\n\n# TODO\n1. Separate value and object types. Represent lists, lambdas and macros as pointers in `lvalue` struct.\n2. Static type check. Probably, it needs an intermediate representation between `mpc_node_t` and `lvalue`.\n3. Instead of using macros and quotes create some special forms of syntax. `lambda`, `quote`, `define`, etc. should be evaluated in special way.\n4. Delete `Quoted type` and use special form - `quote`.\n5. Represent `List` as `cons` cells.\n6. Syntax check.\n7. Closures.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finanyan%2Filispy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finanyan%2Filispy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finanyan%2Filispy/lists"}