synrc/shen
{ "createdAt": "2013-07-20T00:48:24Z", "defaultBranch": "master", "description": "🐉 SHEN: Erlang JavaScript Compiler", "fullName": "synrc/shen", "homepage": "", "language": "Erlang", "name": "shen", "pushedAt": "2025-07-31T14:19:29Z", "stargazersCount": 235, "topics": [], "updatedAt": "2025-08-27T16:36:04Z", "url": "https://github.com/synrc/shen"}SHEN: Erlang JavaScript Compiler
Section titled “SHEN: Erlang JavaScript Compiler”Simple
Libraries
Section titled “Libraries”We support following stack by Erlang JavaScript compiler:
- matches.js — Erlang-like matching syntax
- tailrec.js — optimize tail calls
- beacon.js — FRP event streaming
The only real practical fast solution is to translate Erlang AST into JavaScript using JavaScript helpers like matches.js and tailrec.js.
- Compilation to JavaScript, node.js, Browser, Client-Side FRP
- Macros, String Templates, Embedding Mode, Server-Side, N2O
Compilation to Pure JavaScript
Section titled “Compilation to Pure JavaScript”In case of Client-Logic, Off-line clients, Client-side FRP Event System use can export you functions in module with -js attribute. All function will be stored to the same filename with js extension.
fac.erl:
-module(fac). -compile({parse_transform, shen}). -compile(export_all).
-js([start/0,fac/1]).
start() -> N = fac(5), console:log("factorial ~p", [J, N]).
fac(0) -> 1; fac(N) -> N * fac(N-1).Compile with Erlang:
$ erlc shen.erl$ erlc -pa . fac.erlAnd you will get fac.js:
var pattern = require("matches").pattern; var start = pattern({ '': function() { j = 5; n = fac(j); return console.log('factorial ~p',[j,[n,[]]]); }}); var fac = pattern({ '0': function(x1) { return 1; }, 'n': function(n) { return n * fac(n - 1); }}); start();Now you can check:
$ node fac.jsfactorial ~p [ 5, [ 120, [] ] ]JavaScript Macros
Section titled “JavaScript Macros”Let say we want to generate JavaScript in our Erlang code which is very useful for Server-Logic Event System, so you can write programs in Erlang and expand them into JavaScript using -jsmacro attribute. Specified functions will be expanded to JavaScript during compilation.
-module(fac). -compile({parse_transform, shen}). -compile(export_all).
-jsmacro([macro/3]).
macro(A,B,C) -> ws:send('Bert':encodebuf( [{source,'Bert':binary(A)}, {x,C}, {pickle,'Bert':binary(B)}, {linked,C}])).
main() -> A = "1", B = "2", Script = macro(A,B,"3"), io:format("JS Macro: ~s",[Script]).Lets try it:
7> fac:main().JS Macro: ws.send(Bert.encodebuf({source:Bert.binary(1),x:3,pickle:Bert.binary(2),linked:3}));okRoadmap
Section titled “Roadmap”- multiple clauses for lambdas
- list comprehensions
- more JavaScript/OTP mappings
- if statement :-)
Credits
Section titled “Credits”* Maxim Sokhatsky* Andrew ZadorozhnyOM A HUM