An absolutely-not-solid Emacs implementation (WIP)
See the code#+title: Juicemacs - An absolutely-not-solid Emacs implementation [[https://justforfunnoreally.dev][https://img.shields.io/badge/justforfunnoreally-dev-9ff.svg]] [[https://openjdk.org/projects/jdk/25/][https://img.shields.io/badge/Java-25-orange.svg?logo=openjdk&ext=.svg]] [[https://emacsen.de/dev/tests/][https://emacsen.de/dev/tests.svg]] [[https://app.codecov.io/gh/gudzpoz/Juicemacs/][https://img.shields.io/codecov/c/github/gudzpoz/Juicemacs?label=coverage&ext=.svg]] [[https://emacsen.de/dev/bench/][https://img.shields.io/badge/benchmark-charts-blue?ext=.svg]] [[https://juice.zulipchat.com][https://img.shields.io/badge/chat-white?style=social&logo=zulip&ext=.svg]] Juicemacs is a work-in-progress Emacs implementation +just for the fun of it+ that over-ambitiously aims to explore the following: - Speculative JIT compilation - Transparent(-ish) concurrentization of ELisp code - Polyglot programming with Python, JavaScript, etc. - GNU Emacs 30 compatibility Java helps to make all these possible, for it runs on JVM, which happens to be a platform with several nice things: - A decent GC: HotSpot has a number of state-of-the-art GCs. - Green threads & OS threads: One without the hassle of function coloring. - An incredible JIT framework: [[https://www.graalvm.org/latest/graalvm-as-a-platform/language-implementation-framework/][Truffle]] lets you build an interpreter and a JIT compiler all at once. Of course using Java brings in its own problems, which this project will need to live with: - Sloooow startup (and with Truffle, it actually needs two warm-ups) - It bloats (and we can only hope Project Valhalla somehow tackles that) * Running Currently, Juicemacs has two functional interpreters (one for AST, one for bytecode) and enough built-in routines implemented to handle =pdump=. It usually stops when =top-level= tries to use unimplemented UI subroutines. To run it: 1. Make sure to have JDK 25 installed (preferably [[https://github.com/graalvm/graalvm-ce-builds/releases/][graalvm-ce]]). 2. Clone the repository, go to [[file:elisp/emacs/]] and build a GNU Emacs to have all the generated data/elisp files ready. 3. Run =sh -c "cd app && $(./gradlew -q :app:jvmCmd)"= (in the project root) for a REPL. #+begin_quote If you're on Windows or just can't run the command above, it basically just does the following: 1. Run the =:app:jvmCmd= Gradle task, which will produce a command with the correct JVM flags to make the JIT magic from Truffle work. 2. Run the produced command under the =app/= directory, because we currently hard-code the Emacs directory path to help with our tests. You can also use the =-L/--directory= option to specify a Lisp source directory. #+end_quote By the way, you may also try: - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --help"= - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --inspect=4242"= (for a [[https://www.graalvm.org/latest/tools/chrome-debugger/][Chrome DevTools protocol server]]) And specially, if you want to try out the experimental slowish pdump: - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --dump=pdump"= - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --dump-file ./emacs.pdmp"= We also support [[https://www.graalvm.org/latest/reference-manual/native-image/][Java native images]]: - =./gradlew :app:nativeCompile= (pdump is much faster with native images) ** ERT Testing Emacs comes with a unit-testing toolkit, Emacs Lisp Regression Testing (ERT), and has a bunch of ELisp tests in its source repository (=./test/src/=). Juicemacs currently can run some of these tests [[file:elisp/src/test/java/party/iroiro/juicemacs/elisp/ELispRegressionTest.java][with a bit of workaround]]: #+begin_src elisp ;; TODO: pp requires a bunch of sexp parsing functions (require 'pp) (defalias 'pp 'princ) ;; ert asserts about newlines produced by pp (defun cl--assertion-failed (&rest _) t) (require 'ert) (load "../test/src/data-tests") (ert-run-tests-batch) (null (ert-run-tests-batch)) ; don't print the huge info object #+end_src You're welcome to try the tests and report any failing cases! (I think many of them might simply throw an =UnsupportedOperationException= since they are yet to be implemented.) * Contributing Check out [[file:CONTRIBUTING.org]] for a walkthrough. Check out [[file:docs/TODO.org]] or search for =UnsupportedOperationException= or =TODO= in code for things that need more work. * Documentation - [[file:elisp/README.org]]: Documenting the structure of the ELisp interpreter - [[file:commons/piece-tree/README.org]]: Introduction to a [[https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation][piece tree]] - [[file:docs/Notes.org]]: Reading list and notes for implementing this Emacs clone - [[file:docs/Bytecode.org]]: Extracting (part of) the Emacs bytecode specs from Emacs - [[file:docs/NativeComp.org]]: Looking into Emacs =native-comp= and how we can reuse it for a more efficient bytecode interpreter - [[file:docs/TODO.org]]: TODO list & DONE list, tracking current/solved challenges ** Blog posts - [[https://kyo.iroiro.party/en/posts/emacs-lisp-interpreter-with-graalvm-truffle/][Writing a Lisp JIT Interpreter with GraalVM Truffle]] - [[https://kyo.iroiro.party/en/posts/why-rewriting-emacs-is-hard/][Why Rewriting Emacs Is Hard]] * Similar projects - https://github.com/remacs/remacs - https://github.com/CeleritasCelery/rune - https://github.com/federicotdn/pimacs - https://codeberg.org/ramin_hal9001/schemacs - [[https://www.cliki.net/cl-emacs][CL-Emacs]]: “Various people have proposed an emacs-like editor written in Common Lisp. This page collects together a few possibilities.” - Also the discontinued [[https://jemacs.sourceforge.net/][JEmacs - the Java/Scheme-based Emacs Text Editor]] (source @ [[https://gitlab.com/kashell/Kawa/-/tree/master/gnu/jemacs?ref_type=heads][GNU Kawa]]) * Disclaimers By calling this project Juicemacs, I do mean that: - It does not aim to become a solid implementation (yet). - It is not bug-free ([[https://www.fda.gov/food/current-good-manufacturing-practices-cgmps-food-and-dietary-supplements/food-defect-levels-handbook][~5 Drosophila eggs per 250 ml]]).
Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.
347 commits
Java
99.1%
An absolutely-not-solid Emacs implementation (WIP)
See the code#+title: Juicemacs - An absolutely-not-solid Emacs implementation [[https://justforfunnoreally.dev][https://img.shields.io/badge/justforfunnoreally-dev-9ff.svg]] [[https://openjdk.org/projects/jdk/25/][https://img.shields.io/badge/Java-25-orange.svg?logo=openjdk&ext=.svg]] [[https://emacsen.de/dev/tests/][https://emacsen.de/dev/tests.svg]] [[https://app.codecov.io/gh/gudzpoz/Juicemacs/][https://img.shields.io/codecov/c/github/gudzpoz/Juicemacs?label=coverage&ext=.svg]] [[https://emacsen.de/dev/bench/][https://img.shields.io/badge/benchmark-charts-blue?ext=.svg]] [[https://juice.zulipchat.com][https://img.shields.io/badge/chat-white?style=social&logo=zulip&ext=.svg]] Juicemacs is a work-in-progress Emacs implementation +just for the fun of it+ that over-ambitiously aims to explore the following: - Speculative JIT compilation - Transparent(-ish) concurrentization of ELisp code - Polyglot programming with Python, JavaScript, etc. - GNU Emacs 30 compatibility Java helps to make all these possible, for it runs on JVM, which happens to be a platform with several nice things: - A decent GC: HotSpot has a number of state-of-the-art GCs. - Green threads & OS threads: One without the hassle of function coloring. - An incredible JIT framework: [[https://www.graalvm.org/latest/graalvm-as-a-platform/language-implementation-framework/][Truffle]] lets you build an interpreter and a JIT compiler all at once. Of course using Java brings in its own problems, which this project will need to live with: - Sloooow startup (and with Truffle, it actually needs two warm-ups) - It bloats (and we can only hope Project Valhalla somehow tackles that) * Running Currently, Juicemacs has two functional interpreters (one for AST, one for bytecode) and enough built-in routines implemented to handle =pdump=. It usually stops when =top-level= tries to use unimplemented UI subroutines. To run it: 1. Make sure to have JDK 25 installed (preferably [[https://github.com/graalvm/graalvm-ce-builds/releases/][graalvm-ce]]). 2. Clone the repository, go to [[file:elisp/emacs/]] and build a GNU Emacs to have all the generated data/elisp files ready. 3. Run =sh -c "cd app && $(./gradlew -q :app:jvmCmd)"= (in the project root) for a REPL. #+begin_quote If you're on Windows or just can't run the command above, it basically just does the following: 1. Run the =:app:jvmCmd= Gradle task, which will produce a command with the correct JVM flags to make the JIT magic from Truffle work. 2. Run the produced command under the =app/= directory, because we currently hard-code the Emacs directory path to help with our tests. You can also use the =-L/--directory= option to specify a Lisp source directory. #+end_quote By the way, you may also try: - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --help"= - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --inspect=4242"= (for a [[https://www.graalvm.org/latest/tools/chrome-debugger/][Chrome DevTools protocol server]]) And specially, if you want to try out the experimental slowish pdump: - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --dump=pdump"= - =sh -c "cd app && $(./gradlew -q :app:jvmCmd) --dump-file ./emacs.pdmp"= We also support [[https://www.graalvm.org/latest/reference-manual/native-image/][Java native images]]: - =./gradlew :app:nativeCompile= (pdump is much faster with native images) ** ERT Testing Emacs comes with a unit-testing toolkit, Emacs Lisp Regression Testing (ERT), and has a bunch of ELisp tests in its source repository (=./test/src/=). Juicemacs currently can run some of these tests [[file:elisp/src/test/java/party/iroiro/juicemacs/elisp/ELispRegressionTest.java][with a bit of workaround]]: #+begin_src elisp ;; TODO: pp requires a bunch of sexp parsing functions (require 'pp) (defalias 'pp 'princ) ;; ert asserts about newlines produced by pp (defun cl--assertion-failed (&rest _) t) (require 'ert) (load "../test/src/data-tests") (ert-run-tests-batch) (null (ert-run-tests-batch)) ; don't print the huge info object #+end_src You're welcome to try the tests and report any failing cases! (I think many of them might simply throw an =UnsupportedOperationException= since they are yet to be implemented.) * Contributing Check out [[file:CONTRIBUTING.org]] for a walkthrough. Check out [[file:docs/TODO.org]] or search for =UnsupportedOperationException= or =TODO= in code for things that need more work. * Documentation - [[file:elisp/README.org]]: Documenting the structure of the ELisp interpreter - [[file:commons/piece-tree/README.org]]: Introduction to a [[https://code.visualstudio.com/blogs/2018/03/23/text-buffer-reimplementation][piece tree]] - [[file:docs/Notes.org]]: Reading list and notes for implementing this Emacs clone - [[file:docs/Bytecode.org]]: Extracting (part of) the Emacs bytecode specs from Emacs - [[file:docs/NativeComp.org]]: Looking into Emacs =native-comp= and how we can reuse it for a more efficient bytecode interpreter - [[file:docs/TODO.org]]: TODO list & DONE list, tracking current/solved challenges ** Blog posts - [[https://kyo.iroiro.party/en/posts/emacs-lisp-interpreter-with-graalvm-truffle/][Writing a Lisp JIT Interpreter with GraalVM Truffle]] - [[https://kyo.iroiro.party/en/posts/why-rewriting-emacs-is-hard/][Why Rewriting Emacs Is Hard]] * Similar projects - https://github.com/remacs/remacs - https://github.com/CeleritasCelery/rune - https://github.com/federicotdn/pimacs - https://codeberg.org/ramin_hal9001/schemacs - [[https://www.cliki.net/cl-emacs][CL-Emacs]]: “Various people have proposed an emacs-like editor written in Common Lisp. This page collects together a few possibilities.” - Also the discontinued [[https://jemacs.sourceforge.net/][JEmacs - the Java/Scheme-based Emacs Text Editor]] (source @ [[https://gitlab.com/kashell/Kawa/-/tree/master/gnu/jemacs?ref_type=heads][GNU Kawa]]) * Disclaimers By calling this project Juicemacs, I do mean that: - It does not aim to become a solid implementation (yet). - It is not bug-free ([[https://www.fda.gov/food/current-good-manufacturing-practices-cgmps-food-and-dietary-supplements/food-defect-levels-handbook][~5 Drosophila eggs per 250 ml]]).
Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.
347 commits
Java
99.1%