jevstrudel.git / packages / hs2js / README.md
README.mdpreviewREADME.mdsource127 lines · 3.3 KB · raw
1# hs2js
2
3Experimental haskell in javascript interpreter. Many haskell features are not implemented.
4This projects mainly exists to be able to write and interpret [Tidal Cycles](https://tidalcycles.org/) code in the browser,
5as part of [Strudel](https://codeberg.org/uzu/strudel). This project could only exist thanks to [tree-sitter-haskell](https://github.com/tree-sitter/tree-sitter-haskell).
6
7## Installation
8
9### Via Script Tag
10
11You can load the library directly from a script tag via unpkg:
12
13```html
14<script src="https://unpkg.com/hs2js@0.0.3"></script>
15<button id="hello">hello</button>
16<script>
17  hs2js.setBase('https://unpkg.com/hs2js@0.0.3/dist/');
18  hs2js.loadParser().then(()=>{
19    document.getElementById('hello').addEventListener('click', () => {
20      hs2js.evaluate('alert "hello from haskell!"');
21    });
22  })
23</script>
24```
25
26### Via npm
27
28You need to add `postinstall` to your `package.json` script to copy the parser to your `public` folder:
29
30```json
31{
32  "scripts": {
33    "postinstall": "cp node_modules/hs2js/dist/tree-sitter.wasm public && cp node_modules/hs2js/dist/tree-sitter-haskell.wasm public"
34  }
35}
36```
37
38Depending on your setup, replace `public` with the folder that will serve your assets to `/`. Then install the package:
39
40```sh
41npm i hs2js
42```
43
44and use it:
45
46```js
47import * as hs2js from 'hs2js';
48hs2js.loadParser();
49document.getElementById('hello').addEventListener('click', () => {
50  hs2js.evaluate('alert "hello from haskell!"');
51});
52```
53
54## API
55
56These are all functions exported by the package:
57
58### evaluate
59
60Evaluates a piece of haskell code
61
62- `code`: [valid](https://github.com/tree-sitter/tree-sitter-haskell?tab=readme-ov-file#supported-language-extensions) haskell code
63- `scope`: global scope, defaults to globalThis. Allows you to pass an object of your own functions / variables from JS to Haskell.
64- `ops`: mapping for custom infix operator
65
66Example:
67
68```js
69// simple
70hs2js.evaluate(`2 + 2`) // = 4
71// passing variables via scope:
72hs2js.evaluate(`a + b`, { a: 1, b: 2 }) // = 3
73// custom operator
74hs2js.evaluate(`2 |* 3`, {}, { '|*': (l, r) => l * r }) // = 6
75```
76
77### parse
78
79[Parses](https://github.com/tree-sitter/tree-sitter-haskell) a piece of haskell code, returning its AST representation.
80
81Example:
82
83```js
84const ast = hs2js.parse(`2 + 2`)
85console.log(ast.toString())
86// (haskell declarations: (declarations (top_splice (apply function: (variable) argument: (literal (integer))))))
87```
88
89### run
90
91Evaluates `rootNode` of haskell AST (used by evaluate internally).
92
93- `rootNode`: haskell AST root node, as returned by `parse`
94- `scope`: see evaluate
95- `ops`: see evaluate
96
97Example:
98
99```js
100const ast = hs2js.parse(`2 + 3`);
101const res = hs2js.run(ast.rootNode);
102console.log(res); // = 5
103```
104
105### loadParser
106
107Loads and caches the parser by fetching `tree-sitter.wasm` and `tree-sitter-haskell.wasm`.
108Make sure to call and await this function before calling `parse` or `evaluate`.
109
110```js
111hs2js.loadParser().then(() => hs2js.evaluate('alert "ready"'))
112```
113
114### setBase
115
116Sets the base path where the WASM files are expected by `loadParser`. Defaults to `/`.
117Expects `tree-sitter.wasm` and `tree-sitter-haskell.wasm` to be present.
118Can either be a relative path or a URL.
119
120```js
121hs2js.setBase('https://unpkg.com/hs2js@0.0.4/dist/');
122hs2js.loadParser(); 
123/* loads 
124- https://unpkg.com/hs2js@0.0.4/dist/tree-sitter.wasm
125- https://unpkg.com/hs2js@0.0.4/dist/tree-sitter-haskell.wasm
126*/
127```