{"id":13783007,"url":"https://github.com/mk12/eva","last_synced_at":"2026-05-23T11:33:53.968Z","repository":{"id":147508631,"uuid":"45286922","full_name":"mk12/eva","owner":"mk12","description":"The preferred Scheme interpreter of Eva Lu Ator.","archived":false,"fork":false,"pushed_at":"2022-09-25T21:20:24.000Z","size":263,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-11T18:06:50.843Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/mk12.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2015-10-31T03:08:21.000Z","updated_at":"2021-11-14T01:53:53.000Z","dependencies_parsed_at":"2024-01-07T23:09:18.606Z","dependency_job_id":"ea8433bb-e62d-4788-80a4-76f44abbde25","html_url":"https://github.com/mk12/eva","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mk12/eva","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk12%2Feva","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk12%2Feva/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk12%2Feva/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk12%2Feva/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mk12","download_url":"https://codeload.github.com/mk12/eva/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mk12%2Feva/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28048014,"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-12-26T02:00:06.189Z","response_time":55,"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":[],"created_at":"2024-08-03T18:01:50.855Z","updated_at":"2025-12-26T07:03:04.283Z","avatar_url":"https://github.com/mk12.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# Eva\n\nEva is a Scheme interpreter written in C.\n\n## Build\n\nJust run `make`.\n\n## Usage\n\nThere are three ways to use the program `bin/eva`:\n\n- `eva`: Start a new REPL session.\n- `eva -e expression`: Evaluate expressions and print their results.\n- `eva file1 file2 ...`: Execute one or more Scheme files.\n\nIn addition, you can pass the `-n` or `--no-prelude` flag to disable automatic loading of the [prelude](src/prelude.scm).\n\n## Language\n\nAll Schemes are different. The Eva dialect is fairly minimal. It supports some cool things, like first-class macros, but it lacks other things I didn't feel like implementing, such as floating-point numbers and tail-call optimization.\n\n### Data types\n\nEva has 9 types:\n\n1. **Null**. There is only one null value, written `()`. Unlike in most Schemes, `()` does not need to be quoted.\n2. **Symbol**. Symbols are implemented as interned strings. The quoted expression `'foo` evaluates to the symbol `foo`. (Another round of evaluation would look up a variable called \"foo.\")\n3. **Number**. Numbers in Eva are signed integers. Their width is whatever Clang decides `long` is on your machine.\n4. **Boolean**. There are two boolean constants: `#t` and `#f`. Everything in Eva is truthy (considered true in a boolean context) except for `#f`. \n5. **Character**. These are just single-byte ASCII characters. They are written like `#\\A`, and then there are the special characters `#\\space`, `#\\newline`, `#\\return`, and `#\\tab`.\n6. **String**. A string of characters. Unlike symbols, these are not interned, and they are mutable. They are written with double quotes, like `\"Hello, World!\"`.\n7. **Pair**. You can't have Lisp without pairs. These are your standard cons cells. For example, `(cons 1 2)` evaluates to the pair `(1 . 2)`, and `(cons 1 (cons 2 ()))` evaluates to `(1 2)`.\n8. **Procedure**. Procedures are created by lambda abstractions. A procedure `f` can be called like `(f a b c)`.\n9. **Macro**. Macros are just procedures that follow different evaluation rules. They allow the syntax of Eva to be extended.\n\nThere is also a void type for the result of operations with side effects such as `define` and `set!`.\n\n### Evaluation\n\nWhen Eva sees `(f a b c)`, it evaluates as follows:\n\n1. Evaluate the operator, `f`.\n\t1. If it evaluated to a procedure:\n\t\t1. Evaluate the operands `a`, `b`, and `c`.\n\t\t2. Substitute them into the function body.\n\t\t3. Evaluate the resulting body.\n\t2. If it evaluated to a macro:\n\t\t1. Substitute the operands `a`, `b`, and `c` unevaluated into the macro body.\n\t\t2. Evaluate the resulting body to get the code.\n\t\t3. Evaluate the resulting code at the call site.\n\nThese rules make it possible for macros to be first-class values in Eva. Although this may seem like a strange feature, it actually results in a simpler implementation. There are no special cases: if you really want to, you can `(define d define)` to save 5 characters. You could then write `(d (define x y) (error \"Use d\"))`.\n\n### Macros\n\nIn Eva, any function `f` can be turned into a macro simply by writing `(macro f)`. For this new object, `macro?` will return `#t` and `procedure?` will return false.\n\nFor example, consider the following function which converts infix arithmetic to prefix form:\n\n```scheme\n(define (infix-\u003eprefix code)\n  (define operators\n    '(+ - * / = \u003c \u003e \u003c= \u003e=))\n  (if (not (pair? code))\n    code\n    (let ((c (map infix-\u003eprefix code)))\n      (if (and (= (length c) 3)\n               (memq (cadr c) operators))\n        (list (cadr c) (car c) (car (cddr c)))\n        c))))\n        \n(infix-\u003eprefix '(1 + ((4 * (5 - 1)) / 3)))\n;; =\u003e (+ 1 (/ (* 4 (- 5 1)) 3))\n```\n\nNow, let's turn it into a macro:\n\n```scheme\n(define with-infix (macro infix-\u003eprefix))\n\n(macro? with-infix)\n;; =\u003e #t\n\n(with-infix\n  (let ((x (1 + ((4 * (5 - 1)) / 3))))\n    (x + x)))\n;; =\u003e 12\n```\n\nAnother benefit of having first-class macros is that reducing a list with a macro like `and` or `or` works. First-class macros are very cool and powerful, but I'm sure they'd be a nightmare if anyone actually used them in a large project.\n\n## Input/output\n\nEva has seven IO procedures worth mentioning:\n\n1. `(load str)`: Loads an Eva file. If `str` is \"prelude,\" then it loads the prelude. Otherwise, it tries to open a file.\n2. `(error expr1 ...)`: Creates an error. This can be used anywhere. The arguments will be printed when the error is reported.\n3. `(read)`: Reads an expression using the same parser as for code.\n4. `(write expr)`: Writes an expression in a format that `read` would accept.\n5. `(display expr)`: Displays an expression to standard output without a trailing newline. Strings are displayed without double quotes or escaped characters.\n6. `(newline)`: Prints a newline to standard output.\n7. `(print expr)`: Like `display`, except it adds a trailing newline and it recursively enters lists to print each item individually.\n\n### R5RS conformity\n\nEva implements the following standard macros (also called special forms) from [R5RS][1]:\n\n```\ndefine set!\nlambda begin\nif cond and or\nlet let*\nquote quasiquote unquote unquote-splicing\n```\n\nThe quotation special forms can be used via the usual `'`, `` ` ``, and `,` syntax. Due to the way environments are implemented, there is no need for `letrec`. You can write mutually recursive definitions using `let` bindings.\n\nEva implements the following standard procedures from [R5RS][2]:\n\n```\neq? eqv? equal?\nnumber? integer?\n+ - * / quotient remainder modulo\n= \u003c \u003e \u003c= \u003e=\nzero? positive? negative? even? odd?\nmin max abs gcd lcm expt\nnumber-\u003estring string-\u003enumber\nboolean? not\npair? cons car cdr set-car! set-cdr!\ncaar cadr cdar cddr\nnull? list? list length append reverse\nlist-tail list-ref\nmemq memv member assq assv assoc\nsymbol? symbol-\u003estring string-\u003esymbol\nchar? char=? char\u003c? char\u003e? char\u003c=? char\u003e=?\nchar-alphabetic? char-numeric? char-whitespace?\nchar-lower-case? char-upper-case?\nchar-\u003einteger integer-\u003echar\nchar-upcase char-downcase\nstring? string make-string string-length string-ref string-set!\nstring=? string\u003c? string\u003e? string\u003c=? string\u003e=?\nsubstring string-append string-\u003elist list-\u003estring\nstring-copy string-fill!\nprocedure? eval apply map for-each force delay\nread write load\n```\n\n[1]: https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_6.html\n[2]: https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html/r5rs_8.html\n\n## Implementation\n\nEva is implemented in 15 parts:\n\n1. `main.c`: Implements the main function. Handles command-line arguments.\n2. `util.c`: Utilities for reading files, allocating memory, etc.\n3. `repl.c`: Implements the REPL and a routine for executing files.\n4. `parse.c`: Parser for the language.\n5. `expr.c`: Defines the Expression struct and related functions.\n6. `type.c`: Typechecking for applications of standard procedures and macros.\n7. `eval.c`: Implements the core of the interpreter (eval and apply).\n8. `proc.c`: Implementation functions for standard procedures.\n9. `macro.c`: Implementation functions for standard macros.\n10. `env.c`: Data structure for environment frames.\n11. `intern.c`: Table for interning strings.\n12. `list.c`: Helper functions for dealing with linked lists.\n13. `set.c`: Set data structure for detecting duplicates.\n14. `error.c`: Creating and printing error messages.\n15. `prelude.c`: Auto-generated from `prelude.scm`, the prelude.\n\n## License\n\n© 2016 Mitchell Kember\n\nEva is available under the MIT License; see [LICENSE](LICENSE.md) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmk12%2Feva","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmk12%2Feva","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmk12%2Feva/lists"}