Skip to content

Commit 6bb8bed

Browse files
committed
[doc] Move docs back to master branch (#360)
* add docs back to master branch * remove unnecessary files
1 parent 785fb26 commit 6bb8bed

31 files changed

+1453
-1
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ boot
4747
*.dump
4848
coverage
4949
*.g.js
50-
dist/
50+
5151
man/
5252
lib/ocaml
5353
bin/*

docs/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
dist/*.html

docs/Compiler-options.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
BuckleScript inherits the command line arguments of the [OCaml compiler](http://caml.inria.fr/pub/docs/manual-ocaml/comp.html). It also adds several flags:
2+
3+
* -js-module
4+
5+
Specify the JavaScript module system to use in the generated JavaScript code. Supported values are `commonjs`, `amdjs` and `goog:<namespace>`
6+
7+
When you want to use `goog` module system, you can do things like this:
8+
9+
```bash
10+
bsc -js-module goog xx.ml
11+
# no namespace
12+
13+
bsc -js-module goog:bloomberg.buckle.test xx.ml
14+
# namespace is bloomberg.buckle.test
15+
```
16+
17+
You would then need a bundler for different the different module systems: `webpack` supports `commonjs` and `amdjs` while `google closure compiler` supports all.
18+
19+
* -js-gen-tds
20+
21+
Trigger the generation of TypeScript `.d.ts` files.
22+
23+
## Hello world
24+
25+
Currently, `BuckleScript` shares the same command line options as `ocamlc`
26+
bytecode compiler.
27+
28+
Create a file called `hello.ml` as below
29+
30+
```sh
31+
echo 'print_endline "hello world"' > hello.ml
32+
```
33+
34+
```sh
35+
bsc -c hello.ml
36+
```
37+
38+
If everything goes well, you should have `hello.js`
39+
40+
```
41+
console.log('hello world')
42+
```

docs/Compiler-overview.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
## High Level compiler workflow
2+
3+
The high level architecture is illustrated as below:
4+
5+
```
6+
Source Language
7+
|
8+
| (Reuse OCaml Parser)
9+
v
10+
Surface Syntax Tree
11+
|
12+
| (built in Syntax tree transformation)
13+
v
14+
Surface Syntax Tree
15+
|
16+
| (Reuse OCaml Type checker)
17+
v
18+
Typedtree
19+
|
20+
| (Reuse OCaml pattern match compiler and erase types)
21+
v
22+
Lambda IR (OCaml compiler libs) ---+
23+
| ^ |
24+
| | Lambda Passes (lam_* files)
25+
| | Optimization/inlining/dead code elimination
26+
| \ |
27+
| \ --------------------------+
28+
|
29+
| Self tail call elimination
30+
| Constant folding + propagation
31+
V
32+
JS IR (J.ml) ---------------------+
33+
| ^ |
34+
| | JS Passes (js_* files)
35+
| | Optimization/inlining/dead code elimination
36+
| \ |
37+
| \ -------------------------+
38+
|
39+
| Smart printer includes scope analysis
40+
|
41+
V
42+
Javascript Code
43+
```
44+
45+
## Design Principles
46+
47+
The current design of BuckleScript follows several high level principles. While those principles might change in the future, there are enforced today and can explain certain technical limitations BuckleScript has.
48+
49+
**Lambda Representation**
50+
51+
As pictured in the diagram above BuckleScript is primarily based on the Lambda representation of the OCaml compiler. While this representation is quite rich, some information is lost from upstream representation. The patch to the OCaml compiler tries to enrich this representation in a non-intrusive way (see next section).
52+
53+
**Minimal Patch to the OCaml compiler**
54+
55+
BuckleScript requires patches to the OCaml compiler. One of the main reason is to enrich the Lambda representation so that the generated code is as nice as possible. A design goal is to keep those patches minimal and useful for the OCaml compiler in general so that they can later be integrated.
56+
57+
>A common question is to wonder why BuckleScript transpiles OCaml record value to JavaScript array while a more intuitive representation would be a JavaScript object. This technical decision is a direct consequence of the above 2 design principles: the Lambda layer assumes in a lot of places that a record value is an array and such modification would be too large of a change to OCaml compiler.
58+
59+
**Soundness**
60+
61+
BuckleScript preserves the soundness of the OCaml language. Assuming the FFI is correctly implemented, the type safety is preserved.
62+
63+
**Minimal new symbol creation**
64+
65+
In order to make the JavaScript generated code as close as possible to the original OCaml core we thrive to introduce as little new symbols as possible.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
Assume you have the required OCaml compiler installed, see [Installation](./Installation).
3+
4+
Create a temporary directory called `npm_test`
5+
6+
```sh
7+
cd npm_test
8+
echo "{}" > package.json
9+
npm install --save bs-platform
10+
echo 'let _ = Js.log "hello bucklescript!"' > hello.ml
11+
./node_modules/.bin/bsc -I ./node_modules/bs-platform/ -c hello.ml
12+
node hello.js
13+
```

docs/Curry-and-Uncurry-functions.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
JavaScript functions are all [uncurried](https://en.wikipedia.org/wiki/Currying), while OCaml functions are curried by default.
2+
3+
A naive approach would be to Curry every OCaml functions but this has a non trivial cost and makes the generated code harder to read. Therefore BuckleScript will try its best to uncurry its function in both definition and call site.
4+
5+
It is also possible to help BuckleScript perform the uncurrying by using using the runtime provided `Fn` module:
6+
7+
```OCaml
8+
let iter_f = Fn.mk1 my_function in
9+
List.iter iter_f l
10+
```
11+
12+

docs/Dev-mode-How-to.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
### Build the compiler
2+
3+
The development of BuckleScript compiler relies on 2 tools which are readily available in `opam` and work with our patch OCaml compiler:
4+
- [ocamlbuild](http://caml.inria.fr/pub/docs/manual-ocaml-400/manual032.html): Default build tool for OCaml project
5+
- [camlp4](https://github.com/ocaml/camlp4): Tool used to generate OCaml code for processing large AST. (j.ml file).
6+
7+
After having installed the above dependencies from opam you can run the following:
8+
9+
```sh
10+
cd jscomp/
11+
./build.sh
12+
```
13+
14+
### Build the runtime
15+
16+
```sh
17+
cd ./runtime; make all
18+
```
19+
### Build the stdlib
20+
21+
```sh
22+
cd ./stdlib; make all
23+
```

docs/Differences-from-js_of_ocaml.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
[js_of_ocaml](https://github.com/ocsigen/js_of_ocaml) is a popular compiler which compiles OCaml's bytecode into JavaScript. It is the inspiration for this project, and has already been under development for several years and is ready for production. In comparison, BuckleScript, while moving fast, is still a very young project. BuckleScript's motivation, like `js_of_ocaml`, is to unify the ubiquity of the JavaScript platform and the truly sophisticated type system of OCaml, however, there are some areas where we view things differently from `js_of_ocaml`. We describe below, some of these differences, and also refer readers to some of the original informal [discussions](https://github.com/ocsigen/js_of_ocaml/issues/338).
2+
3+
## Debuggable Output
4+
5+
One of the main BuckleScript goal is to generate debuggable JavaScript code. From the start we believed developers using BuckleScript for JavaScript development will look at the generated code an order of magnitude more than an OCaml developer will look at the assembly one. Part of our intent is to make it easier for a JavaScript developer to transition to the OCaml language. Furthermore looking at existing transpilers for JavaScript: [coffescript](http://coffeescript.org/), [babel](https://babeljs.io/) and [typescript](https://github.com/Microsoft/TypeScript), the most widely adopted ones are the one that favors code readability.
6+
The generated code by BuckleScript is pretty close to the JavaScript code one might write by hand, especially if you use mostly the language features which are shared between JavaScript and OCaml.
7+
8+
`js_of_ocaml` produces code with mangled names, which is typically not a concern, except when the code is used as a primary backend and must be extensively debugged and maintained. In these situations, `js_of_ocaml` proves harder to debug, because the original names in the code are lost.
9+
10+
## Runtime Representations && FFI
11+
12+
**Runtime Representation**
13+
14+
`js_of_ocaml` runtime representation is as close as possible to the runtime representation of native/byte compiler. This makes it particularly easy for an OCaml developer already familiar with that representation.
15+
16+
BuckleScript runtime representation is closer to JavaScript. This is particularly helpful for both the ability to debug OCaml values in JavaScript but also when writing the FFI.
17+
18+
Some example of differences are:
19+
- `string` : In BuckleScript the string is represented as a JavaScript string while in `js_of_ocaml` it's a much more involved data structure.
20+
- `array`: In BuckleScript the array has the same indexing as a JavaScript array while for `js_of_ocaml` the index starts at 1.
21+
- `tuple`: In BuckleScript the array has the same indexing as a JavaScript array while for `js_of_ocaml` the index starts at 1.
22+
23+
**FFI**
24+
25+
Regarding the FFI, BuckleScript favors using only [attributes](http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec245); one drawback that we plan to address on the future is that it lacks some expressiveness.
26+
27+
`js_of_ocaml` introduces a very sophisticated and expressive syntax extension, which works great most of the time, but can sometimes generate confusing compiler errors, and be difficult to integrate with existing IDEs and build systems.
28+
29+
**Runtime library**
30+
31+
BuckleScript runtime library is mostly implemented in OCaml while `js_of_ocaml` runtime is purely in JavaScript. The difference is actually significant since we believe it reflects how easy it is to write JavaScript code in OCaml using the BuckleScript model (FFI and Runtime representation).
32+
33+
## Separate Compilation
34+
35+
BuckleScript compiles one OCaml module into one Javascript module. This follows the modern JavaScript development and makes it easier to gradually use OCaml in an existing code base. This is particularly relevant for our use cases for which we plan to implement components in OCaml while the larger application is written in JavaScript. The JavaScript echo system also has plenty of tools and support for modules, making it easy and natural to integrate modules generated by BuckleScript. It also opens the door for supporting [hot module replacement](http://webpack.github.io/docs/hot-module-replacement.html) in future.
36+
The module compilation strategy allows more granular compilation and as consequence faster feedback loop during development.
37+
38+
`js_of_ocaml` compiles a whole OCaml program in JavaScript. This makes it easier when the main application is written in OCaml but less natural when integrating OCaml as a component in a larger JavaScript application.
39+
40+
## Integration with existing ecosystems
41+
42+
BuckleScript is aware of `npm` module paths and favor libraries development. In contrast with `js_of_ocaml`' focus on developing executable.
43+
BuckleScript does not provide a whole program compilation mode out of the box; it rather delegates this to existing linker/bundler (such as webpack or Google Closure compiler).
44+
45+
When integrating code generated by BuckleScript developers only need to look at the `.mli` files. BuckleScript respect those interfaces and will only export the functions from the `.mli file. No special code needs to be added to expose OCaml code to the JavaScript.
46+
47+
`js_of_ocaml` requires specific code to export functions OCaml code to the larger JavaScript application.
48+
49+
## Intrusiveness
50+
51+
The major advantage of `js_of_ocaml` is that it is non intrusive; you can reuse your existing project setup (build system) and simply convert the bytecode output to JavaScript output as a post-processing step.
52+
53+
With BuckleScript, however, users have to adapt their build system for existing OCaml code base. In BuckleScript, we traded intrusiveness for being able to extract more information from the code.
54+
55+
We think there's a need for both tools to exist simultaneously. If you have some OCaml code, and your primary motivation is that it should run inside a browser, then `js_of_ocaml` is a very good choice. However, if you target JavaScript (browser/Node.Js) as the primary backend for your application and care about the integration with the JavaScript environment then we believe BuckleScript can offer a better experience. We also think both projects can help and learn from each other.
56+
57+
## Performance
58+
59+
We have not conducted exhaustive benchmarks yet, however, our initial results show similar performance between `js_of_ocaml` and BuckleScript (using Google Closure simple optimization level).
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`bsc` has the ability to also emits `.d.ts` for better interaction with typescript. This is still experimental.

docs/Extensions-to-OCaml-Language.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
BuckleScript leverages the OCaml support for extension with dedicated builtin extensions. Those BuckleScript extensions facilitates the integration of native JavaScript code as well as improve the generated code.
2+
3+
> Note that all those extension will be correctly ignored by the native OCaml compiler.
4+
5+
1. extension `bs.raw`
6+
7+
It can be either `[%bs.raw{| this_is_arbitrary_js_expression |}]` or `[%%bs.raw{| this is arbitrary_js_statement |}`
8+
9+
Use cases:
10+
for example if you want to use a JavaScript string, you can write code like this
11+
12+
```OCaml
13+
let x : string = [%bs.raw{|"\x01\x02"|}]
14+
```
15+
16+
which will be compiled into
17+
18+
```js
19+
var x = "\x01\x02"
20+
```
21+
22+
```OCaml
23+
[%%bs.raw{|
24+
// Math.imul polyfill
25+
if (!Math.imul){
26+
Math.imul = function (..) {..}
27+
}
28+
|}]
29+
```
30+
In the expression level, i.e, `[%js.raw ...]` user can add a type annotation, the compiler would use such type annotation to deduce its arities. for example, the next three versions:
31+
32+
```ocaml
33+
let f = [%bs.raw ("Math.max" : float -> float -> float) ] 3.0
34+
let f : float -> float -> float = [%bs.raw "Math.max" ] 3.0
35+
let f = ([%bs.raw "Math.max"] : float -> float -> float ) 3.0
36+
```
37+
will be translated into
38+
39+
```js
40+
function f(prim){
41+
return Math.max(3.0,prim);
42+
}
43+
```
44+
Caveat:
45+
1. So far we don't do any sanity check in the quoted text (syntax check is a long-term goal)
46+
2. You should not refer symbols in OCaml code, it is not guaranteed that the order is correct.
47+
You should avoid introducing new symbols in the raw code, if needed, use the `$$` prefix (ie `$$your_func_name`)
48+
49+
2. extension `bs.debugger`
50+
51+
It can be `[%bs.debugger]`
52+
53+
use case
54+
55+
```ocaml
56+
let f x y =
57+
[%bs.debugger];
58+
x + y
59+
```
60+
61+
which will be compiled into
62+
63+
```js
64+
function f (x,y) {
65+
debugger; // JavaScript developer tools will set an breakpoint and stop here
66+
x + y;
67+
}
68+
```

docs/FAQ.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
* The compiler does not build
3+
4+
In production mode, the compiler is a single file in `jscomp/bin/compiler.ml`, if it is not compiling, make sure you have the right OCaml compiler version. Currently OCaml Compiler is a submodule of bucklescript. Make sure the exact commit hash matches (we only update the compiler occasionally).

docs/Help-continuous-integration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Help is appreciated!
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
BuckleScript runtime implementation is currently a mix of OCaml and JavaScript. (jscomp/runtime directory). The JavaScript code is defined in the `.ml` file using the `bs.raw` syntax extension.
2+
3+
The goal is to implement the runtime **purely in OCaml** and you can help contribute.
4+
5+
Each new PR should include appropriate testing.
6+
7+
Currently all tests are in `jscomp/test` directory and you should either add a new test file or modify an existing test which covers the part of the compiler you modified.
8+
9+
* Add the filename in `jscomp/test/test.mllib`
10+
11+
* Add a suite test
12+
13+
The specification is in `jscomp/test/mt.ml`
14+
15+
For example a simple tests would be like
16+
17+
```ocaml
18+
let suites : _ Mt.pair_suites = Mt.[
19+
"hey", (fun _ -> Eq(true, 3 > 2));
20+
"hi", (fun _ -> Neq(2,3);
21+
"hello", (fun _ -> Approx(3.0, 3.0));
22+
"throw", (fun _ -> ThrowAny(fun _ -> raise 3))
23+
]
24+
let () = Mt.from_pair_suites __FILE__ suites
25+
```
26+
27+
* Run the test
28+
29+
Suppose you have mocha installed, if not, try `npm install mocha`
30+
31+
```
32+
mocha -R list jscomp/test/your_test_file.js
33+
```
34+
35+
* See the coverage
36+
37+
```
38+
npm run cover
39+
```
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
BuckleScript compilation model is the same as the OCaml compiler.
2+
3+
If `b.ml` depends on `a.ml`, you have to compile `a.ml` **and** `a.mli` first.
4+
5+
> The technical reason is that BuckleScript will generate intermediate file with extension `.cmj` which are later used for cross module inlining and other information.
6+
7+
Find below a simple Makefile to get started:
8+
9+
```make
10+
OCAMLC=bsc
11+
# bsc is BuckleScript compiler
12+
OCAMLDEP=ocamldep
13+
# ocamldep executable is part of the OCaml compiler installation
14+
15+
SOURCE_LIST := src_a src_b
16+
SOURCE_MLI = $(addsuffic .mli, $(SOURCE_LIST))
17+
SOURCE_ML = $(addsuffic .ml, $(SOURCE_LIST))
18+
19+
TARGETS := $(addsuffix .cmj, $(SOURCE_LIST))
20+
21+
INCLUDES=
22+
23+
all: $(TARGETS)
24+
25+
.mli.cmi:
26+
$(OCAMLC) $(INCLUDES) $(COMPFLAGS) -c $<
27+
.ml.cmj:
28+
$(OCAMLC) $(INCLUDES) $(COMPFLAGS) -c $<
29+
30+
-include .depend
31+
32+
depend:
33+
$(OCAMLDEP) $(INCLUDES) $(SOURCE_ML) $(SOURCE_MLI) | sed -e 's/\.cmx/.cmj/g' > .depend
34+
```

0 commit comments

Comments
 (0)