Skip to content

Commit 45c9396

Browse files
authored
Merge pull request #1068 from live-codes/ocaml
add Ocaml (JS) language support
2 parents 06ff57f + 23411cd commit 45c9396

97 files changed

Lines changed: 886 additions & 7 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
1313
[![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes)
1414
[![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes)
1515
[![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes)
16-
[![LiveCodes: languages](https://img.shields.io/badge/languages-123-blue)](https://livecodes.io/docs/languages/)
16+
[![LiveCodes: languages](https://img.shields.io/badge/languages-124-blue)](https://livecodes.io/docs/languages/)
1717
[![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/)
1818
[![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt)
1919
[![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt)

‎docs/docs/languages/ocaml-js.mdx‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# OCaml (JS)
2+
3+
[OCaml](https://ocaml.org/) is an industrial-strength programming language supporting functional, imperative and object-oriented styles.
4+
5+
LiveCodes runs the OCaml compiler itself, built with [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml), so compilation happens in the browser and nothing is sent to a server. The compiler emits a JavaScript program, which the result page then runs.
6+
7+
:::info Note
8+
9+
LiveCodes also has an `ocaml` language, which runs the [ReScript](https://rescript-lang.org/) compiler. It is deprecated in favour of this one. Read documentation [here](./ocaml.mdx).
10+
11+
:::
12+
13+
## Demo
14+
15+
import LiveCodes from '../../src/components/LiveCodes.tsx';
16+
17+
export const params = {
18+
'ocaml-js': 'let () =\n print_endline "Hello, World!"\n',
19+
console: 'full',
20+
};
21+
22+
<LiveCodes params={params}></LiveCodes>
23+
24+
## Usage
25+
26+
LiveCodes runs OCaml in the browser, including the standard library.
27+
28+
Because the compiled program *is* JavaScript by the time it runs, it can interact with the page. JavaScript interoperability and DOM access come from [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml)'s `Js` and `Dom_html` with `open Js_of_ocaml` (see the [example below](#example-usage)).
29+
30+
## Modules and Libraries
31+
32+
The standard library is always available. Beyond it, these are linked on demand — the archive is fetched the first time a program names one of its modules, so a program that uses none of them downloads none of them.
33+
34+
- **js_of_ocaml** — `Js`, `Dom_html`, and the rest of the browser APIs
35+
- **Str**, **Unix**, **Graphics** — from the OCaml distribution
36+
- **Lwt**, **js_of_ocaml-lwt** — promises and concurrency
37+
- **Re** — regular expressions
38+
- **jsonm**, **xmlm**, **uutf** — JSON, XML and Unicode text
39+
- **fmt**, **logs** — formatting and logging
40+
- **base64** — base64 encoding
41+
- **Zarith** — `Z` and `Q`, arbitrary-precision integers and rationals
42+
43+
Everything here runs in the browser, so a library has to be pure OCaml, or have a JavaScript replacement for its C stubs — Zarith's are provided by `zarith_stubs_js`. Anything needing real threads, processes or a filesystem will not work, whatever is linked.
44+
45+
This is the set built with the compiler. Other opam packages are not available.
46+
47+
## Language Info
48+
49+
### Name
50+
51+
`ocaml-js`
52+
53+
### Extensions
54+
55+
`js.ocaml`, `js.ml`
56+
57+
### Editor
58+
59+
`script`
60+
61+
## Compiler
62+
63+
The OCaml compiler — the same `compiler-libs` frontend that compiles ordinary OCaml — compiled to JavaScript with [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml). It is published as [@live-codes/ocaml](https://www.npmjs.com/package/@live-codes/ocaml).
64+
65+
### Version
66+
67+
`@live-codes/ocaml`: v0.2.0
68+
69+
## Code Formatting
70+
71+
Not supported.
72+
73+
## Limitations
74+
75+
There is no ppx support, since a ppx would have to run at compile time and compilation happens at run time here. So `##`, `##.` and `[%js]` are not available; use `Js.Unsafe` and the rest of the bindings instead.
76+
77+
## Example Usage
78+
79+
This example counts button clicks in the DOM, using `Dom_html`:
80+
81+
<LiveCodes template="ocaml-js" height="80vh"></LiveCodes>
82+
83+
## Starter Template
84+
85+
https://livecodes.io/?template=ocaml-js
86+
87+
## Links
88+
89+
- [OCaml website](https://ocaml.org/)
90+
- [OCaml documentation](https://ocaml.org/docs/)
91+
- [@live-codes/ocaml on npm](https://www.npmjs.com/package/@live-codes/ocaml)
92+
- [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml)
93+
- [OCaml with the ReScript compiler](./ocaml.mdx) in LiveCodes

‎docs/docs/languages/ocaml.mdx‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
LiveCodes compiles OCaml code to JavaScript using the [ReScript compiler](https://rescript-lang.org/). OCaml in LiveCodes supports JSX via a ReasonReact-compatible syntax.
66

7+
:::info Deprecation Note
8+
9+
This language is deprecated in favour of [OCaml (JS)](./ocaml-js.mdx).
10+
11+
To continue using this language use the language name `rescript-ocaml`.
12+
13+
:::
14+
715
## Usage
816

917
### Demo
@@ -66,6 +74,10 @@ OCaml React does not support React 19. Use an import map (in [custom settings](.
6674

6775
`ocaml`
6876

77+
### Aliases
78+
79+
`rescript-ocaml`
80+
6981
### Extensions
7082

7183
`.ml`, `.mli`

‎docs/src/components/LanguageSliders.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export default function Sliders() {
7777
{ name: 'elm', title: 'Elm' },
7878
{ name: 'rescript', title: 'ReScript' },
7979
{ name: 'reason', title: 'Reason' },
80+
{ name: 'ocaml-js', title: 'OCaml (JS)' },
8081
{ name: 'ocaml', title: 'OCaml' },
8182
{ name: 'nim', title: 'Nim' },
8283
{ name: 'nim-wasm', title: 'Nim (Wasm)' },

‎docs/src/components/TemplateList.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const templates = [
3737
{ name: 'rescript', title: 'ReScript Starter', thumbnail: 'rescript.png' },
3838
{ name: 'reason', title: 'Reason Starter', thumbnail: 'reason.svg' },
3939
{ name: 'ocaml', title: 'Ocaml Starter', thumbnail: 'ocaml.svg' },
40+
{ name: 'ocaml-js', title: 'OCaml (JS) Starter', thumbnail: 'ocaml.svg' },
4041
{ name: 'nim', title: 'Nim Starter', thumbnail: 'nim.svg' },
4142
{ name: 'nim-wasm', title: 'Nim (Wasm) Starter', thumbnail: 'nim.svg' },
4243
{ name: 'janet-wasm', title: 'Janet (Wasm) Starter', thumbnail: 'janet.png' },

‎e2e/specs/compilers.spec.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,30 @@ export class App {
14941494
};`);
14951495
});
14961496

1497+
test('OCaml (JS)', async ({ page, getTestUrl }) => {
1498+
await page.goto(getTestUrl());
1499+
1500+
const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
1501+
1502+
await app.click(':nth-match([title="Change Language"], 3)');
1503+
await (await app.$('[data-lang="ocaml-js"]'))?.click();
1504+
await waitForEditorFocus(app);
1505+
await page.keyboard.insertText(
1506+
[
1507+
'let () =',
1508+
' let squares = List.init 5 (fun i -> i * i) in',
1509+
' Printf.printf "sum=%d\\n" (List.fold_left (+) 0 squares)',
1510+
].join('\n'),
1511+
);
1512+
1513+
await waitForResultUpdate();
1514+
const resultText = await getResult().innerHTML('body > script');
1515+
1516+
// The real OCaml compiler, compiled to JavaScript, emitted a bundle the page runs.
1517+
expect(resultText).toContain('// Generated by js_of_ocaml');
1518+
expect(resultText).toContain('sum=');
1519+
});
1520+
14971521
test('LiveScript', async ({ page, getTestUrl, editor }) => {
14981522
test.skip(editor === 'codejar', 'please fix');
14991523

‎functions/vendors/templates.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const starterTemplates = {
3737
"rescript": "ReScript Starter",
3838
"reason": "Reason Starter",
3939
"ocaml": "Ocaml Starter",
40+
"ocaml-js": "OCaml (JS) Starter",
4041
"nim": "Nim Starter",
4142
"nim-wasm": "Nim (Wasm) Starter",
4243
"crystal-wasm": "Crystal Starter",

‎scripts/build.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ const esmBuild = () =>
203203
'languages/postgresql/lang-postgresql-compiler-esm.ts',
204204
'languages/duckdb/lang-duckdb-compiler-esm.ts',
205205
'languages/r/lang-r-script-esm.ts',
206+
'languages/ocaml-js/lang-ocaml-js-compiler-esm.ts',
206207
'languages/rescript/lang-rescript-compiler-esm.ts',
207208
'i18n/i18n.ts',
208209
]

‎server/php/inc/starter-templates.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"rescript": "ReScript Starter",
3838
"reason": "Reason Starter",
3939
"ocaml": "Ocaml Starter",
40+
"ocaml-js": "OCaml (JS) Starter",
4041
"nim": "Nim Starter",
4142
"nim-wasm": "Nim (Wasm) Starter",
4243
"crystal-wasm": "Crystal Starter",

‎src/livecodes/UI/command-menu-actions.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ export const getCommandMenuActions = ({
293293
'rescript',
294294
'reason',
295295
'ocaml',
296+
'ocaml-js',
296297
'nim',
297298
'nim-wasm',
298299
'janet-wasm',

0 commit comments

Comments
 (0)