{"id":40505601,"url":"https://github.com/cwi-swat/recaf","last_synced_at":"2026-01-20T19:33:43.098Z","repository":{"id":10247573,"uuid":"49957410","full_name":"cwi-swat/recaf","owner":"cwi-swat","description":"Recaffeinating Java ☕️ with custom semantics and extensions","archived":false,"fork":false,"pushed_at":"2022-04-05T09:22:19.000Z","size":52381,"stargazers_count":49,"open_issues_count":8,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-04-21T18:08:51.572Z","etag":null,"topics":["dialects","domain-specific-language","java","metaprogramming","modularity"],"latest_commit_sha":null,"homepage":"","language":"Java","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/cwi-swat.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}},"created_at":"2016-01-19T14:18:03.000Z","updated_at":"2024-01-13T23:54:47.000Z","dependencies_parsed_at":"2022-08-07T05:15:36.879Z","dependency_job_id":null,"html_url":"https://github.com/cwi-swat/recaf","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cwi-swat/recaf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwi-swat%2Frecaf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwi-swat%2Frecaf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwi-swat%2Frecaf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwi-swat%2Frecaf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cwi-swat","download_url":"https://codeload.github.com/cwi-swat/recaf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwi-swat%2Frecaf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28610654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T18:56:40.769Z","status":"ssl_error","status_checked_at":"2026-01-20T18:54:26.653Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["dialects","domain-specific-language","java","metaprogramming","modularity"],"created_at":"2026-01-20T19:33:42.267Z","updated_at":"2026-01-20T19:33:43.092Z","avatar_url":"https://github.com/cwi-swat.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cimg src=\"/resources/recaf.png\" width=\"300\"\u003e\n\n[![Build Status](https://travis-ci.org/cwi-swat/recaf.svg?branch=master)](https://travis-ci.org/cwi-swat/recaf) [![Join the chat at https://gitter.im/cwi-swat/recaf](https://badges.gitter.im/cwi-swat/recaf.svg)](https://gitter.im/cwi-swat/recaf?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n### What is Recaf?\n\n_Recaf_ is an open-source framework for authoring extensions (_dialects_) as libraries for Java. You can redefine every major syntactic element of the language, either add new ones or create your own flavor of Java that matches your needs. It can be used to give syntactic support to libraries, to generate and instrument code. Last but not least you can experiment with the design and implementation of Java extensions in plain Java.\n\n- Recaf: Java Dialects as Libraries ([pdf](https://biboudis.github.io/papers/recaf-gpce16.pdf)) will be presented at the _15th International Conference on Generative Programming: Concepts \u0026 Experience_ ([GPCE'16](http://conf.researchr.org/home/gpce-2016)) in Amsterdam.\n\n### Getting Started\n\n```shell\n\u003e git clone git@github.com:cwi-swat/recaf.git\n\u003e cd recaf\n\u003e ./testnogen # or testgen to regenerate all test files\n```\n\n### Hello World with a simple example!\n\nImagine we want to create our own try-with-resources statement for Java! Let's call it ```using```.\n```Java\nString method(String path)  {\n  using (BufferedReader br : new BufferedReader(new FileReader(path))){ \n    return br.readLine();\n  }\n}\n```\n\nThe code above is not valid Java, but it can, most certainly be through Recaf! Using two small additions, we enable the generic transformation of that snippet of code into something that we can override and define. In our case, our goal is to define what ```using``` does. So firstly, we decorate ```method``` with the ```recaf``` keyword. That enables the generic translation of our code. Secondly, we use a special field that we also decorate with the same keyword. By doing that we enable an extension for the scope of the whole compilation unit (the are other ways as well). Now every recaffeinated method uses the ```Using``` extension. As you may have guessed this object defines the behavior of our new keyword.\n\n```Java\nrecaf Using\u003cString\u003e alg = new Using\u003cString\u003e();\n\nrecaf String method(String path)  {\n  using (BufferedReader br : new BufferedReader(new FileReader(path))){ \n    return br.readLine();\n  }\n}\n```\n\nThe key point is that Recaf transforms code at compile time, applying a predefined set of rewrite rules (no need to hack around it or even to know anything about it). The user does not get involved with parsers, language workbenchs and compilers. The code is transformed into method calls of a certain interface. The runtime instance of that structure defines the whole operational behavior of the program.\n\nFor example, the statement ```return 1 + 1``` is transformed in the following nested method calls chain: ```alg.Return(alg.Plus(alg.Lit(1), alg.Lit(1)))```.  What happens in reality depends on the implemention of the runtime instance of ```alg```. With Recaf we are able to override not only expressions but also the control flow of the program and orchestrate it with libraries for a certain style of execution e.g., for asynchronous computing, reactive computing. \n\nWithout diving into the gory details of Recaf, the body of ```method``` above, is transformed into method invocations to the ```Using``` object above (named ```alg```). Note that this is valid Java now. \n\n```Java\nString method(String path) {\n  return alg.Method(\n    alg.Using(() -\u003e new BufferedReader(new FileReader(path)), (BufferedReader br) -\u003e {\n      return alg.Return(() -\u003e br.readLine());\n    }));\n}\t\n```\n\n## Language extension gymnastics with Recaf\nIn the following section we present some extensions of Java developed with _Recaf_. For demonstration purposes you can browse all extensions in the [directory with the recaf files](recaf-desugar/input) and examine the [generated java code](recaf-runtime/src/test-generated/generated).\n\n### Spicing up Java (controlling the flow)\n\nWe support three new syntactic constructs that manipulate the control flow of the program. We can add support for generators, async and async* operations by programming the basic denotations of each operation as described in the [Spicing up Dart with Side Effects](https://queue.acm.org/detail.cfm?id=2747873) article.\n\n_Generators_\n```Java\nrecaf Iterable\u003cInteger\u003e range(int s, int n) {\n  if (n \u003e 0) {\n    yield! s;\n    yieldFrom! range(s + 1, n - 1);\n  }\n}\n```\n\n_Async_\n```Java\nrecaf Future\u003cInteger\u003e task(String url) {\n  await String html = fetchAsync(url);\n  return html.length();\n}\n```\n\n_Async*_\n```Java\nrecaf \u003cX\u003e Observable\u003cX\u003e print(Observable\u003cX\u003e src) {\n  awaitFor (X x: src) {\n    System.out.println(x);\n    yield! x;\n  }\n}\n```\n\n#### Parsing Expression Grammars (PEGs)\n\nThe following example demonstrates language embedding and aspect-oriented language customization. We have defined a DSL for Parsing Expression Grammars (PEGs). The ```lit!``` construct parses an atomic string, and ignores the result. ```let``` is used to bind intermediate parsing results. For terminal symbols, the ```regexp``` construct can be used. The language overloads the standard sequencing and return constructs of Java to encode sequential composition and the result of a parsing process. The constructs ```choice```, ```opt```, ```star```, and ```plus``` correspond to the usual regular EBNF operators. The ```choice``` combinator accepts a list of alternatives. The following parser implements parsing for primary expressions.\n\n```Java\nrecaf Parser\u003cExp\u003e primary() {\n   choice {\n      alt \"value\":\n        regexp String n = \"[0-9]+\";\n        return new Int(n);\n      alt \"bracket\":\n        lit! \"(\"; let Exp e = addSub(); lit! \")\";\n        return e;\n    }   \n}\n```\n\n### Constraint solving as a language\n\nIn this example we demonstrate deep embedding of a simple constraint solving language. We have developed a Recaf embedding which translates a subset of Java expressions to the internal constraints of [Choco](http://choco-solver.org/) solver, which can then be solved. Note the use of ```recaff``` as we enable java expression overriding in this example.\n\n```Java\nrecaf Solve alg = new Solve();\nrecaff Iterable\u003cMap\u003cString,Integer\u003e\u003e example() {\n  var 0, 5, IntVar x;\n  var 0, 5, IntVar y;\n  solve! x + y \u003c 5;\n}\n```\n\n### Program your UI with a Java-Swul like embedding\nWe have implemented [SWUL](http://strategoxt.org/Stratego/Java-Swul) as an extension of the direct style implementation of Java, without virtualized expressions. For example part of the following demonstration UI can be generated by the snippet that follows:\n\n\u003cimg src=\"/resources/SWUL.png\" width=\"100\"\u003e\n\n```Java\nrecaf JPanel example1() {\n  panel { \n   label text! \"Welcome!\";\n   panel border {\n      center label text! \"Hello world!\";\n      south panel grid {\n          row 2:  \n            button {\n              text! \"cancel\";\n              action { System.out.println(\"Cancel\"); }\n            }\n            button text! \"ok\";\n        }\n   }\n  }\n}\n```\n\nWe enumerate all the small extensions we developed with Recaf. The code is in plain Java and each file corresponds to one extension.\n\n- Manipulating control flow\n  - [Async](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/cps/Async.java)\n  - [Come From](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/cps/ComeFrom.java)\n  - [Backtrack](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/cps/Backtrack.java)\n  - [Coroutines](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/cps/Coroutine.java)\n  - [Yield](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/cps/Iter.java) (Semi-coroutines)\n  - [Rx/Observable](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/cps/StreamExt.java)\n- Direct\n  - [Memoization](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/direct/Memo.java)\n  - [Security](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/direct/Security.java)\n  - [Constraints](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/constraint/Solve.java)\n  - [SWING userinterface language](https://github.com/cwi-swat/recaf/blob/master/recaf-runtime/src/main/java/recaf/demo/swul/SWUL.java)\n- Fully Generic \n  - [Times/Unless/Until](https://github.com/cwi-swat/recaf/tree/master/recaf-runtime/src/main/java/recaf/demo/generic)\n\n### Bugs and Feedback\n\nTo discuss bugs, improvements and post questions please use our [Github Issues](https://github.com/cwi-swat/recaf/issues). Also, join the chat at https://gitter.im/cwi-swat/recaf! \n\n### Team\n- Aggelos Biboudis [@biboudis](https://twitter.com/biboudis)\n- Pablo Inostroza [@metalinguist](https://twitter.com/metalinguist)\n- Tijs van der Storm [@tvdstorm](https://twitter.com/tvdstorm)\n\n### Powered by Rascal \nUnder the hood we use the [Rascal Metaprogramming Language](http://www.rascal-mpl.org/). It is included as a runtime dependency in the project. \n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwi-swat%2Frecaf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcwi-swat%2Frecaf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwi-swat%2Frecaf/lists"}