Giter Club home page Giter Club logo

rescript-compiler's Introduction

Fast, Simple, Fully Typed JavaScript from the Future.

Current npm package version. Current Github Actions workflow status. ReScript is released under the LGPL license. Follow @rescriptlang

ReScript is a robustly typed language that compiles to efficient and human-readable JavaScript. It comes with a lightning fast compiler toolchain that scales to any codebase size.

  • Fast and Simple. ReScript cares about a consistent and fast feedback loop for any codebase size. Refactor code, pull complex changes, or switch to feature branches as you please. No sluggish CI builds, stale caches, wrong type hints, or memory hungry language servers that slow you down.
  • A Robust Type System. Every ReScript app is fully typed and provides reliable type information for any given value in your program. We prioritize simpler types over complex types for the sake of clarity and easy debugability. No any, no magic types, no surprise undefined.
  • Seamless Integration. Use any library from JavaScript, export ReScript libraries to JavaScript, automatically generate TypeScript types. It's like you've never left the good parts of JavaScript at all.
  • Tooling that just works out of the box. A builtin pretty printer, memory friendly VSCode & Vim plugins, a stable type system and compiler that doesn't require lots of extra configuration. ReScript brings all the tools you need to build reliable JavaScript, Node and ReactJS applications.
  • Easy to adopt — without any lock-in. ReScript was made with gradual adoption in mind. If you ever want to go back to plain JavaScript, just remove all source files and keep its clean JavaScript output. Tell your coworkers that your project will keep functioning with or without ReScript!

ReScript is used by many companies to ship and maintain mission-critical products and is maintained by the ReScript community.

Contents

🎉 Getting Started

Follow the Installation Guide to set up a new ReScript project or integrate ReScript into your existing JavaScript project.

For more information on building React apps with ReScript, see the rescript-react documentation.

For React Native apps, see the rescript-react-native website.

📖 Documentation

The full documentation for the ReScript language can be found on our website.

The source for the ReScript documentation and website is hosted in a separate repo.

🚀 Upgrading

See the Upgrading Guide for instructions on upgrading to newer ReScript versions.

👏 How to Contribute

Read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to ReScript.

The ReScript community has adopted a Code of Conduct that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated.

You can learn more about our vision for ReScript in the Roadmap.

For discussions on ongoing development, see the Development section of the ReScript forum.

📄 License

ReScript is licensed under LGPL version 3, with relaxed rules about creating and distributing combined work. See the LICENSE file for details.

The ReScript parser (subdirectory jscomp/syntax) is licensed under the MIT License.

The ninja subdirectory contains the vendored ninja build system. Refer to its copyright and license notices for information about its licensing.

🏅 Acknowledgments

ReScript was originally created by Hongbo Zhang in 2015.

See CREDITS.md for further acknowledgements and project history.

rescript-compiler's People

Contributors

arnarthor avatar bobzhang avatar bsansouci avatar chenglou avatar cknitt avatar cometkim avatar coobaha avatar cristianoc avatar dzakh avatar evmar avatar fhammerschmidt avatar glennsl avatar jchavarri avatar jdeisenberg avatar joshaber avatar mransan avatar mununki avatar nico avatar nicolasdespres avatar pcc avatar riannucci avatar rickyvetter avatar ryyppy avatar sgraham avatar syntheticpp avatar tfarina avatar tsnobip avatar ulrikstrid avatar zploskey avatar zth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rescript-compiler's Issues

Currying not optimized away any more

The following trivial example:

type point = {
  x: string;
  y: string;
}
let pmap fn p = { x = fn p.x; y = fn p.y }

produces

function pmap(fn, p) {
  return [
          /* record */0,
          Caml_curry.app1(fn, p[1]),
          Caml_curry.app1(fn, p[2])
        ];
}

It used to (and still does in the demo) produce

function pmap(fn, p) {
  return [
          /* record */0,
          fn(p[1]),
          fn(p[2])
        ];
}

Note that it also doesn't seem to get inlined:

let () = print_endline (pmap (fun x -> x) { x = "a"; y = "b" }).x
console.log(pmap(function (x) {
            return x;
          }, [
            /* record */0,
            "a",
            "b"
          ])[1]);

how to encode global exception id

there are serveral built in exceptions

var Out_of_memory = [248, "Out_of_memory", 0];                                                                                                                                                                      
var Sys_error = [248, "Sys_error", -1];                                                                                                                                                                             var Failure = [248, "Failure", -2];                                                                                                                                                                                 
var Invalid_argument = [248, "Invalid_argument", -3];                                                                                                                                                               var End_of_file = [248, "End_of_file",-4];                                                                                                                                                                          
var Division_by_zero = [248, "Division_by_zero", -5];                                                                                                                                                               
var Not_found = [248, "Not_found", -6];                                                                                                                                                                             
var Match_failure = [248, "Match_failure", -7];                                                                                                                                                                     
var Stack_overflow = [248, "Stack_overflow",-8];                                                                                                                                                                    
var Sys_blocked_io = [248, "Sys_blocked_io", -9];                                                                                                                                                                   
var Assert_failure = [248, "Assert_failure", -10];                                                                                                                                                                  
var Undefined_recursive_module = [248, "Undefined_recursive_module", -11];     

These are specially handled by the type checker, do they really need encode it that way, how about

var Out_of_memory =  "Out_of_memory";                                                                                                                                                                      
var Sys_error = "Sys_error";                                                                                                                                                                             var Failure =  "Failure";                                                                                                                                                                                 
var Invalid_argument = "Invalid_argument";                                                                                                                                                               var End_of_file =  "End_of_file";                                                                                                                                                                          
var Division_by_zero = "Division_by_zero";                                                                                                                                                               
var Not_found = "Not_found";                                                                                                                                                                             
var Match_failure =  "Match_failure";                                                                                                                                                                     
var Stack_overflow = "Stack_overflow";                                                                                                                                                                    
var Sys_blocked_io =  "Sys_blocked_io";                                                                                                                                                                   
var Assert_failure =  "Assert_failure";                                                                                                                                                                  
var Undefined_recursive_module = "Undefined_recursive_module";     

Float array indexing

In current master the following code:

type p = { x: float }
let p = { x = 3. }
let map fn p = { x = fn p.x }

Generates:

function map(fn, p) {
  return /* array */[fn(p[1])];
}

var p = /* float array */[3];

Note that the index in map is 1. The issue doesn't appear in the browser demo (maybe it's fixed already?).

add a algebra simplification rules for range pattern match compiler

for example:

let rec fib = function
  | 1 | 2 | 5 | 33 -> 1
  | n -> fib (n - 1 )  + fib (n - 2)
function fib(n) {
  var exit = 0;
  var switcher = n - 1;
  if (switcher > 4 || switcher < 0) {
    if (switcher !== 32) {
      exit = 1;
    }
    else {
      return 1;
    }
  }
  else if (switcher === 3 || switcher === 2) {
    exit = 1;
  }
  else {
    return 1;
  }
  if (exit === 1) {
    return fib(n - 1) + fib(n - 2);
  }

}

this should be simplified

enhance complex if compilation

cases like

if (p0){
  if(p1){
    branch_code0
  }else{
    branch_code1
  }
}else{
  branch_code1
}
if(p0 && p1){
  branch_code0
} else {
   branch_code1
}

test cases:

let rec fib = function
  | 1 | 23 -> 11111123
  | n -> fib (n - 1 )  + fib (n - 2)

same arguments tailcall bug

there is an edge case, when none of the arguments are changed, our optimization will take it as an expression and generate a return statment

let v = ref 0
let acc = ref 0

let rec loop n : int = 
   if !v > n then !acc else begin incr v ; loop n end

A quick fix is to use continue to mark it as a statement, so our engine will not return it, in the future we should have a way to explitly mark Js_output.t terminating...

Rethink about the runtime encoding of ocaml values in javascript

Goal:

  1. Less work to patch the compiler
  2. OCaml Array is JS Array

Some documentation about the current encoding is [https://github.com/bloomberg/ocamlscript/blob/master/docs%2Fffi.md] here, there is a problem with this encoding is that Pfield i is no longer the same as Parrayref, while the internal OCaml compiler think it is the same, for example stdlib/camlinternalOO.ml, bytecomp/translobj.ml, bytecomp/translclass.ml there might be some other files I am missing. (Recent changes in the trunk of stdlib/camlinternalOO requires us to sync up the change)

So I am thinking of that Obj.tag is not used in too much in the compiler itself(except the GC, which is not relevant in js backend)

So I am proposing that blocks with tag zero is encoded as array, blocks with tag non zero (mostly normal variants) will be encoded as array plus an extra property via Object.defineProperty so that they are polymorphic. and Pfield, Parrayref will behave the same.

for example

type u = 
| B of int * int
|A of int * int * int 

A (1,2,3) will be encoded as Object.defineProperty([1,2,3], {'t', {'value', 1}}
B(1,2) will be encoded as [1,2]

FFI: Property access

It would be useful if we had external declarations to generate property access (obj.foo, obj.foo = bar) and also dynamic property access (obj[foo]).

What is the probability of not requiring a compiler patch?

I'm curious, what are the odds of not requiring a compiler patch? I believe that compiler-libs lets you compose your own compiler pipeline as long as you don't need to change any of the fundamental data structures. Are there changes that could be submitted upstream to enable building OcamlScript purely on top of compiler-libs?

semantics of module import order

var x = require('x')
var y = require( 'y')
var y = require('y')
var x = require('x')

shall we clarify the order of importing module does not matter, user should not expect it?

support of bigarray

we need support bigarray since lots of existing library depends on it like omd etc

better beta reduction

when calculate Lambda.free_variables also return the occurence, suppose parameter expression has no side effect, if it is 0, don't do anything, if it is 1 (common cases for small function), do the substitution directly
also check:

  1. analyze the purity of the expression
  2. avoid global module

String.set has incorrect implementation in JS output.

You can see here that I've found an issue in the String.set implementation (in the interactive web version of the compiler).

https://news.ycombinator.com/item?id=10866113

JS Strings are immutable so using regular JS strings as OCaml strings will not work. However, it might be worth simplifying the problem by saying "OCamlScript is intended for use with newer versions of OCaml where Strings are not mutable". This observation then led to a larger general discussion about compatibility and how adhering to strictly compatible compilation might open up opportunities to push performance concerns onto other toolchains like js_of_ocaml (or even yet another JS compilation mode that makes use of the upcoming f-lambda optimizations), which I suggested could free up OCamlScript to focus on creating a world-class developer experience.

I'm excited that there's a fresh take on JS compilation and learning a ton from the discussions about this.

amd module also depends on exports

define(['exports', ...],function(exports,...){
}

instead of using return, the benefit is that the code between commonjs and amdjs will be more similar

calculate all js orders or generate .depends as a file

so that the third party tool can load js directly follow the order, this is helpful, for example, if we use requirejs as module loader, we can still keep commonjs syntax, but pre-load files instead, so we don't need generate amdjs and commonjs when debugging at the same time

Why GPL instead of LGPL? Why no linking exception?

I'm not an expert in OCaml or JavaScript, just someone who's exploring the various functional languages that compile to JavaScript for use in a long-term hobby project.

Your README says:

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

But the js_of_ocaml license is LGPL, not GPL. In https://github.com/ocsigen/js_of_ocaml/blob/master/LICENSE, the relevant statement is:

The Compiler and Library are distributed under the terms of the GNU
Library General Public License version 2 (included below).

[emphasis mine]

As I understand it (I'm not an expert by any means), using GPL instead of LGPL (for library/runtime files; for the compiler, it doesn't matter) prevents combining with commercial software, or with software under a license that's incompatible with the GPL, such as the Eclipse Public License. (Suppose someone wants to port something from the Clojure(Script) ecosystem, which is largely EPL.)

Secondly, the js_of_ocaml license also includes the following useful exception:

As a special exception to the GNU Library General Public License, you
may link, statically or dynamically, a "work that uses the Library"
with a publicly distributed version of the Library to produce an
executable file containing portions of the Library, and distribute
that executable file under terms of your choice, without any of the
additional requirements listed in clause 6 of the GNU Library General
Public License.

If I understand correctly, this exception is useful for (among other things) distributing open-source software via the Apple app store, whose terms are otherwise incompatible with the GPL or LGPL. While much software compiled to JavaScript is just distributed via a web server, where no app store licenses apply, one might also want to distribute compiled-to-JavaScript code (and the accompanying runtime and library) in a Cordova or React Native app.

ffi (calling js from ocaml)

note that call ocaml from js is very easy, and there is not much work to do. (see the runtime representation #24), we also plan to use some ppx_derivings to hide the internal representation.

calling js from ocaml is a bit hard, since you have to write type declarations, for binding simple functions

external array_map : 'a array -> ('a -> 'b) -> 'b array = "" [@@js.call "Array.prototype.map.call"]

for binding js objects we can do this

class type dom = object
   method getElementById : string -> node
end
external document : dom = ""[@@js.global "document"]

let f v = document#getElementById v

To make it more efficient user can write bindings

class type dom = object
   method getElementById : string -> node
   method getElementById_js_01 : string -> node
   method properties_js_set : string -> node
end
external document : dom = ""[@@js.global "document"]

let f v = document#getElementById_js_01 v 

Note that document#getElementById_js_01 and document#getElementByID compiles to js code which behaves exactly except that the former will be as efficient as handwritten js code

int32, int64, int operations

we need make sure int32 int64 semantics correct for sure.

for int (ocaml int is 31/63 bits), do we really need wrap those int everywhere, like

a+b --> a+b|0, the chance of overflow in ocaml often result in incorrect programs

Compiler Error

Hi when I try to compile in the jscomp folder I got this error

ocamlopt.opt -I +compiler-libs -I bin -c bin/compiler.mli bin/compiler.ml
File "bin/compiler.ml", line 1009, characters 32-48:
Error: This variant pattern is expected to have type Lambda.primitive
       The constructor Pbytes_to_string does not belong to type Lambda.primitive

Clarification on Typescript

One of the design goals in the readme says

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

Does this mean that typescript *.d.ts definition files can be automatically generated for the compiled JS?

check exception equality

other cases

  1. built-in exception
let v = Not_found
  1. exception equality (in the browser) the module might be evaluateed twice

Clarification around whole-program code size and ddead code elimination

I'm pleased that you list "Smaller code than hand written JavaScript" as a goal, as well as "dead code elimination". But I'm a little confused at the extent of this. As far as I can see, you're targeting separate module compilation which means that if I wanted to run this code in a browser, I'd need to combine my tiny hello.js with the 60k+ contents of stdlib/pervasives, caml_io, caml_string, caml_exceptions, etc.

So, can you shed some light on the plan? I'm sure there'splenty of stuff you just haven't got to yet, but I'm interested in your intent - are you planning to make ocamlscript able to produce a single browser-ready .js file including (dead-code-eliminated-version-of) the stdlib? Or are you planning to stick to 1:1 ocaml->js module symbols and have JS tooling take care of the dead code elimination, concatenation, etc?

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.