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```