Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 44 additions & 103 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
# OCamlScript

## Introduction
OCamlScript is a Javascript backend for [the OCaml language](https://ocaml.org/)
which aims to provide a better language for the Javascript platform.
OCamlScript is a JavaScript backend for [the OCaml compiler](https://ocaml.org/). Users of OCamlScript can write type-safe, high performance OCaml code, and deploy the generated JavaScript in any platform with a JavaScript execution engine.

One OCaml module is mapped to one JS module, and no name mangling happens
so that:
Each OCaml module is mapped to a corresponding JavaScript module, and names are preserved so that:

1. The stacktrace is preserved, the generated code is debuggable with or without sourcemap.
2. You can call `List.length` (List is a module in OCaml standard library)
in a plain Javascript file.

2. Modules generated by OCamlScript can be used directly from other JavaScript code. For example, you can call the `List.length` function from the OCaml standard library `List` module from JavaScript.

### A simple example

Expand All @@ -23,7 +19,7 @@ let sum n =
!v
```

Generated code is as below:
OCamlScript generates code similar to this:

``` js
function sum(n) {
Expand All @@ -35,45 +31,41 @@ function sum(n) {
}
```

As you can see, there is no name mangling in the generated code, so suppose the
module is called `M`, you can call `M.sub` in vanilla Javascript

You can learn more by playing the online [in-browser compiler](http://zhanghongbo.me/js-demo).
As you can see, there is no name mangling in the generated code, so if this module is called `M`,
`M.sum()` is directly callable from other JavaScript code.

You can learn more by exploring the online [in-browser compiler](http://zhanghongbo.me/js-demo).


## Disclaimer

This project is currently released to exchange ideas outside
Bloomberg and collect some early feedback from OCaml and Javascript community,
it is in an *very early* stage and not production ready
for your own projects *yet*.
This project has been released to exchange ideas and collect feedback from the OCaml and JavaScript communities.
It is in an *very early* stage and not production ready for your own projects *yet*.


## Build

Note that you have to clone this project with `--recursive` option, we can only distribute
the patch of OCaml due to License restrictions.

Note that you have to clone this project with `--recursive` option, as the core OCaml compiler is brought into your clone as a Git `submodule`.

### Linux and Mac OS
### Linux and Mac OSX


1. Apply the patch to OCaml compiler and build

Please ignore the warnings generated by git apply

```
```sh
cd ocaml
git apply ../js.diff
./configure -prefix `pwd`
make world.opt
make install
```

2. Build OCamlScript Compiler

Assume that you have ocamlopt.opt in the PATH
```
Assume that you have `ocamlopt.opt` in the `PATH`
```sh
cd ../jscomp
ocamlopt.opt -I +compiler-libs -I bin -c bin/compiler.mli bin/compiler.ml
ocamlopt.opt -g -linkall -o bin/ocamlscript -I +compiler-libs ocamlcommon.cmxa ocamlbytecomp.cmxa bin/compiler.cmx main.cmx
Expand All @@ -94,39 +86,41 @@ the patch of OCaml due to License restrictions.
cd ../stdlib
make all
```

5. Test

We first create a file called `hello.ml`:
Create a file called `hello.ml`:

```sh
mkdir tmp # create tmp directory inside the stdlib
cd tmp
echo 'print_endline "hello world";;' >hello.ml
```
Then we compiled it with `ocamlscript`

Then compile it with `ocamlscript`
```sh
OCAML_RAW_JS=1 ocamlscript -I . -I ../ -c hello.ml
```

It should generate a file called `hello.js`, then we runt the `js` file
It should generate a file called `hello.js`, which can be executed with any JavaScript engine. In this example, we use Node.js

```sh
node hello.js
```

If everything goes well, you will see `hello world` on your screen.

## Windows support

We plan to provide a Windows Installer in the near future.
We plan to provide a Windows nstaller in the near future.

# Licensing

The [OCaml](./ocaml) directory is a submodule from OCaml's official repo(4.02.3), all its rights
are reserved by [INRIA](http://www.inria.fr/) (see its QPL LICENSE for more details).
The [OCaml](./ocaml) directory is the official OCaml compiler (version 4.02.3). Refer to its copyright and license notices for information about its licensing.

Our compiler relies on a patch [(js.diff)](./js.diff) to the OCaml compiler.
The `ocamlscript` backend relies on a patch [(js.diff)](./js.diff) to the OCaml compiler.

This project reused and adapted part of [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml)'s:
This project reused and adapted parts of [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml):
* Some small printing utilties in [pretty printer](./jscomp/js_dump.ml).
* Part of the [Javascript runtime](./jscomp/runtime) support

Expand All @@ -145,66 +139,34 @@ JS backend.
[stdlib](jscomp/stdlib) is copied from ocaml's [stdlib](ocaml/stdlib) to have it compiled with
the new JS compiler.

Since our work is derivative work, we choose the GPL V2 license to
make it compatible with
[js_of_ocaml](http://ocsigen.org/js_of_ocaml/).
Since our work is derivative work of [js_of_ocaml](http://ocsigen.org/js_of_ocaml/), the license of the OCamlScript components is GPLv2, the same as js_of_ocaml.

Note that QPL license is not compatible with GPL V2, so we distribute
our changes to the compiler as a patch instead.

## Design goal
## Design goals

1. Readability
1. No name mangling
2. Support Javascript modules systems
3. Integrate with existing javascript ecosystem, for example,
1. No name mangling.
2. Support JavaScript module system.
3. Integrate with existing JavaScript ecosystem, for example,
[npm](https://www.npmjs.com/), [webpack](https://github.com/webpack).
4. Straight-forward FFI, generate tds file to target [Typescript](http://www.typescriptlang.org/) for better tooling
4. Straight-forward FFI, generate tds file to target [Typescript](http://www.typescriptlang.org/) for better tooling.

2. Separate and *extremely fast* compilation.

3. Better performance than hand-written Javascript:
thanks to a sound type system in OCaml so that we
can play more optimizations and pipe it to Google Closure Compiler
for production mode.
Thanks to the solid type system in OCaml it is possible to optimize the generated JavaScript code.

4. Smaller code than hand written JS code, aggressive dead code elimination.
4. Smaller code than hand written JavaScript, aggressive dead code elimination.

5. Support NodeJs, web browser and various Javascript target platform.
5. Support Node.js, web browsers, and various Javascript target platforms.

6. Compatible with OCaml semantics modulo c-bindings and Obj, Marshal module
6. Compatible with OCaml semantics modulo c-bindings and Obj, Marshal modules.

## More examples

### NodeJS support

Below it is an idea how it would integrate with the existing JS
eco-system:

```js

var $$Array = require('./array'); // OCaml Array module
var List = require ('./list'); // OCaml List module

List.iter(function(x){console.log('hi, nodejs '+x)},
$$Array.to_list ($$Array.init(5,function(x){return x})))
```

You get the output:

```sh
hi, nodejs 0
hi, nodejs 1
hi, nodejs 2
hi, nodejs 3
hi, nodejs 4
```

### A naive benchmark with Facebook immutable

### A naive benchmark comparing to the Immutable map from Facebook

Below is a *contrived* example to demonstrate our motivation,
it tries to insert 1000,000 keys to an immutable map and query it
it tries to insert 1,000,000 keys into an immutable map, then query it.

```Ocaml
module IntMap = Map.Make(struct
Expand All @@ -226,8 +188,7 @@ let () = test()

```

This is an equivalent JS version by using Facebook's
[immutable](http://facebook.github.io/immutable-js/) library
The code generated by OCamlScript is a drop-in replacement for the Facebook [immutable](http://facebook.github.io/immutable-js/) library.


``` js
Expand All @@ -249,20 +210,16 @@ test ()
```

Runtime performance:
- OCaml Immutable Map: 1186ms
- OCamlScript Immutable Map: 1186ms
- Facebook Immutable Map: 3415ms

Code Size:
- OCaml (Prod mode): 899 Bytes
- OCamlScript (Prod mode): 899 Bytes
- Facebook Immutable : 55.3K Bytes


## Status


It covers the most of OCaml language, given that it is a quite young
project (5 men-months until Jan 2016), there are still plenty of work
to be done.
While most of the OCaml language is covered, because this project is still young there is plenmty of work left to be done.

Some known issues are listed as below:

Expand All @@ -271,9 +228,9 @@ Some known issues are listed as below:
Recursive modules, have not looked into it yet.

Better Currying support. Currently, we have an inference engine for
function curring and we do cross module inference, however, there
function currying and we do cross module inference, however, there
are some more challenging cases, for example, high order functions,
it can be resolved by either aggressive inlining or fall back to a
it can be resolved by either aggressive inlining or falling back to a
slow path using `Function.prototype.length`. We prepared the
runtime support in [module curry](jscomp/runtime/curry.ml), will support it in the near
future.
Expand All @@ -286,29 +243,13 @@ Some known issues are listed as below:
IO support, we have very limited support for
`Pervasives.print_endline` and `Pervasives.prerr_endline`, it's
non-trivial to preserve the same semantics of IO between OCaml and
NodeJS, one solution is to functorize all IO operations. Functors
Node.js, one solution is to functorize all IO operations. Functors
are then inlined so there will no be performance cost or code size
penalty.

Bigarray, Unix, Num, Int64

## License

The OCaml to JS compiler libraries are distributed under the GPL (version 2.0);
see the LICENSE file at the top of the source tree for more information.


The contents of some files in this distribution was derived from external
sources with different licenses. The original copyright and license
notice was preserved in the affected files.

## Question, Comments and Feedback

If you have questions, comments, suggestions for improvement or any other inquiries
regarding this project, feel free to open an issue in the issue tracker.