Git Product home page Git Product logo

bucklescript's Introduction

NPM

Build Status Coverage Status

Introduction

BuckleScript is a JavaScript backend for the OCaml compiler.

You can try BuckleScript in the browser, edit the code on the left panel, and see the generated JS on the right panel instantly.

Users of BuckleScript can write type-safe, high performance OCaml code, and deploy the generated JavaScript in any platform with a JavaScript execution engine.

Each OCaml module is mapped to a corresponding JavaScript module, and names are preserved so that:

  1. The stack trace is preserved, so the generated code is debuggable with or without a source map.
  2. Modules generated by BuckleScript 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

let sum n =
    let v  = ref 0 in
    for i = 0 to n do
       v := !v + i
    done;
    !v

BuckleScript generates code similar to this:

function sum(n) {
  var v = 0;
  for(var i = 0; i<= n; ++i){
    v += i;
  }
  return v;
}

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.

Disclaimer

This project has been released to exchange ideas and collect feedback from the OCaml and JavaScript communities.

It is in an beta stage, and we encourage you to try it and share your feedback.

Documentation

See http://bloomberg.github.io/bucklescript. If you want to contribute documentation, the source is here.

More examples

See https://github.com/bloomberg/bucklescript-addons

Build

Linux and Mac OSX

Build from package manager

#. npm install

npm install  bs-platform

It will install OCaml compiler, BuckleScript compiler and Standard library in three module systems (CommonJS, AMDJS, and Google Module).

Build from source

  1. Clone the bucklescript repo
git clone https://github.com/bloomberg/bucklescript.git --recursive

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

  1. Build the patched OCaml Compiler
cd ./ocaml
git checkout master
./configure -prefix `pwd`
make world.opt
make install

The patched compiler is installed locally into your $(pwd)/bin directory; check if ocamlc.opt and ocamlopt.opt are there, and then temporarily add them into your $(PATH) (eg - PATH=$(pwd)/bin:$PATH).

  1. Build BuckleScript Compiler

Assume that you have ocamlopt.opt(the one which we just built) in the PATH

cd ./jscomp
npm_package_name=bs-platform make world

Now that you have a binary called bsc in the jscomp/bin directory, put it in your PATH.

Note that by default, bsc will generate commonjs modules. You can override this behavior to generate JS files for all three module systems by setting a variable:

BS_RELEASE_BUILD=1 npm_package_name=bs-platform make world
  1. Test

Outside of the bucklescript directory, create a separate directory with a file called hello.ml:

mkdir tmp
cd tmp
echo 'print_endline "hello world";;' >hello.ml

Then compile it with bsc.

bsc -I ../bucklescript/jscomp/runtime -I ../bucklescript/jscomp/stdlib -c hello.ml

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

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.

Licensing

The OCaml directory is the official OCaml compiler (version 4.02.3). Refer to its copyright and license notices for information about its licensing.

This project reused and adapted parts of js_of_ocaml:

It adapted two modules Lam_pass_exits and Lam_pass_lets_dce from OCaml's Simplif module, the main reasons are those optimizations are not optimal for JavaScript backend.

Js_main is adapted from driver/main. It is not actually used, since we currently make this JS backend a plugin instead, but it shows that it is easy to assemble a whole compler using OCaml compiler libraries and based upon that, we can add more compilation flags for a JS backend.

stdlib is copied from ocaml's stdlib to have it compiled with the new JS compiler.

test copies and adapts some modules from ocaml's testsuite.

Since our work is derivative work of js_of_ocaml, the license of the BuckleScript components is GPLv2, the same as js_of_ocaml.

Design goals

  1. Readability

  2. No name mangling.

  3. Support JavaScript module system.

  4. Integrate with existing JavaScript ecosystem, for example, npm, webpack.

  5. Straight-forward FFI, generate tds file to target Typescript for better tooling.

  6. Separate and extremely fast compilation.

  7. Better performance than hand-written Javascript: Thanks to the solid type system in OCaml it is possible to optimize the generated JavaScript code.

  8. Smaller code than hand written JavaScript, aggressive dead code elimination.

  9. Support Node.js, web browsers, and various JavaScript target platforms.

  10. Compatible with OCaml semantics modulo C-bindings and Obj, Marshal modules.

More examples

A naive benchmark comparing to the Immutable map from Facebook

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

module IntMap = Map.Make(struct
  type t = int
  let compare (x : int) y = compare x y
  end)

let test () =
  let m = ref IntMap.empty in
  let count = 1000000 in
  for i = 0 to count do
    m := IntMap.add i i !m
  done;
  for i = 0 to count  do
    ignore (IntMap.find i !m)
  done

let () = test()

The code generated by BuckleScript is a drop-in replacement for the Facebook immutable library.

'use strict';
var Immutable = require('immutable');
var Map = Immutable.Map;
var m = new Map();
var test = function() {
    var count = 1000000;
    for(var i = 0; i < count; ++i) {
        m = m.set(i, i);
    }
    for(var j = 0; j < count; ++j) {
        m.get(j);
    }
}

test();

Runtime performance:

  • BuckleScript Immutable Map: 1186ms
  • Facebook Immutable Map: 3415ms

Code Size:

  • BuckleScript (Prod mode): 899 Bytes
  • Facebook Immutable: 55.3K Bytes

Status

While most of the OCaml language is covered, because this project is still young, there is plenty of work left to be done.

Some known issues are listed as below:

  1. Standard libraries distributed with OCaml:

    For 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 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, Str(regex)

    For Print to behave correctly, you have to add a newline after your output to guarantee it will be flushed. Otherwise, it may be buffered.

  2. String is immutable. The user is expected to compile with the flag -safe-string for all modules:

    Note that this flag should be applied to all your modules.

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.

bucklescript's People

Contributors

bobzhang avatar kpfleming avatar mransan avatar agentcooper avatar chenglou avatar dguo avatar copy avatar iblech avatar jimt avatar mneumann avatar threepointone avatar wweic avatar chenxiaoqino avatar code-ghalib avatar hhugo avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.