Giter VIP home page Giter VIP logo

grain's Introduction

Grain

Grain CI Workflow License: LGPL v3 Grain latest release version


Grain is a new programming language that compiles to WebAssembly via Binaryen. For more information about the language, check out grain-lang.org.

If it's your first time here, we recommend that you follow the Grain guide to get up and running.

Contributing

There are tons of ways to contribute to Grain. Check out our contributing guide for more info and come chat with us on Discord! All contributors are held to our contributor code of conduct.

Building

For instructions on how to build Grain from source, please consult the official documentation.

Other Commands

To link the CLI:

npm run cli link

To reset your compiler build:

npm run compiler clean

Copyright ©️ 2017-2024 Philip Blair, Oscar Spencer, & contributors.

grain's People

Contributors

alex-snezhko avatar bmakuh avatar cician avatar clovis1122 avatar dependabot[bot] avatar designsbysm avatar dony477 avatar fa7ad avatar github-actions[bot] avatar ibdafna avatar jacobginsparg avatar johnnyridout avatar jozanza avatar marcusroberts avatar miguelcarvalho13 avatar mscheibel avatar ng-marcus avatar nickbreaton avatar ohana54 avatar ospencer avatar peblair avatar phated avatar renatoalencar avatar saulecabrera avatar spotandjake avatar tatchi avatar technosophos avatar timgestson avatar tyreldenison avatar zweimach 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

grain's Issues

Better building instructions

Currently the build instructions say I need the following things on my path:

  • ocaml
  • opam
  • jbuilder

jbuilder is a little confusing as there are many softwares out there named jbuilder like:

Now if the refered jbuilder is the ruby gem, then the docs should mention to install ruby too along with ocaml and opam. All in all I feel a bit more details are needed.

I'll be happy to update the README with a PR once you can confirm which packages are to be installed when talking about jbuilder. I am assuming its the ruby gem you're talking about.

Correction: jbuilder refers to the jbuilder package to be installed from opam. Can we mention this in the document?

Implement Array.sort and List.sort

These functions should take the array/list and a comparator function as arguments and produce a sorted array/list.

Open questions:

  • should the array version be a sort in place?
  • should there be two array versions, a sort and sort! where the latter sorts in place?

Compiler Plugins

A fun addition to Grain would be the ability to extend the compiler via plugins (similar to GCC's plugin API). Users could write plugins with OCaml and the compiler could load them with Dynlink. A nice side effect of this is that supporting a useful plugin API would force us to have a clean separation of different compiler passes.

Fix GRAIN_ROOT

For some reason, the Grain_utils.Config.grain_root is being ignored when performing module resolution:

 λ grain git:(master) ✗ grainc test.gr -o test.wasm
File "", line 0:
Error: Unbound module pervasives
Backtrace:
Raised at file "src/typed/typetexp.ml", line 87, characters 16-43
Called from file "src/typed/typemod.ml", line 73, characters 13-66
Called from file "src/typed/typemod.ml", line 353, characters 22-48
Called from file "list.ml", line 96, characters 24-34
Called from file "src/typed/typemod.ml", line 370, characters 16-29
Called from file "src/compile.ml", line 123, characters 17-53
Called from file "src/compile.ml", line 151, characters 19-31
Called from file "grainc/grainc.ml", line 120, characters 13-49
 λ grain git:(master) ✗ grainc test.gr -o test.wasm -I _build/install/default/lib/grain/stdlib
# No problems

Shedding dependencies?

Interesting language! :-)

Since you don't have a roadmap, I'd like to ask:

  • Do you have any plans as far as shedding some of the big dependencies?

  • Specifically, do you plan on porting and bootstrapping the compiler?

  • Is the dependency on OCaml as intermediary language a permanent feature?

  • And are the Node and Yarn dependencies preliminary or permanent?

I really like where this language is going - but it seems like a lot of heavy machinery (two other languages + package managers) for a language that could potentially be very simple, e.g. compiler written in Grain, with a back-end that emits native WASM, and the only compiler + run-time dependency being a WASM/WASI run-time.

Perhaps even better, using something like Lucet to build native, stand-alone programs from the WASM output - including the compiler itself.

If this isn't what you have planned, can you say a bit about what you do have planned? 🙂

Thanks!

Compiled File Extension

Since the Grain .wasm files can't be run without the Grain runtime, they should probably have a more distinct default extension such as .gr.wasm to make them easier to distinguish from other .wasm files.

dyp

Hi! I'm trying to make the thing. It says, I should install the dependencies. Then:

~/work/grain · (master)
⟩ opam install batteries cmdliner dyp extlib oUnit ocaml-migrate-parsetree ocamlgraph ppx_deriving ppx_sexp_conv sexplib stdint wasm
[ERROR] No package named dyp found.

What should I do next?

Specify Node engines for CLI

Right now, Grain requires Node 13, but we should probably set this to 14. We should potentially set engines for the compiler and runtime as well.

Support tail calls intra-module

This is an example transform that we believe is possible:

let rec is_even = lambda x:
  if x <= 1:
    x == 0
  else:
    is_odd(x - 1)
and is_odd = lambda x:
  if x <= 1:
    x == 1
  else:
    is_even(x - 1)
;;


let ie_x = ref false in
lee io_x = ref false in
let break_r = ref true in
let next_r = ref false in
let rec tc_is_even = lambda:
  if !ie_x <= 1:
    !ie_x == 0
  else:
    begin
      io_x := !ie_x - 1;
      break_r := false;
      next_r := tc_is_odd
    end
  in
and tc_is_odd = lambda:
  if !io_x <= 1:
    !io_x == 0
  else:
    begin
      ie_x := !io_x - 1;
      break_r := false;
      next_r := tc_is_even
    end
  in
let is_even = lambda x:
  begin
    ie_x := x;
    break_r := true;
    next_r := tc_is_even;
    let ret_v = ref false in
    while not !break_r do
      ret_v := !next_r()
    end;
    !ret_v;
  end
  in
let is_odd = lambda x:
  begin
    io_x := x;
    break_r := true;
    next_r := tc_is_odd;
    let ret_v = ref false in
    while not !break_r do
      ret_v := !next_r()
    end;
    !ret_v;
  end
;;

Grain Supports Separate Compilation

Modules in Grain are currently a bit of a hack; we essentially #include everything. It would be better if we could separately compile modules and link them separately. There are a few challenges here:

  • How do we want to store compiled modules? Should we have a Grain object file format (groff?...heh)? We need the compiled code along with the module's static information (so that we can throw compile errors for things like missing functions).
  • Where should the linking take place? One attractive option is having the separate compilation produce two files (one with just the WASM, and one with the static info) and using WebAssembly's native module support and just let WASM sort it out.
  • Could we maybe even support linking against modules written in Javascript? We could then theoretically implement the DOM functionality in idiomatic Javascript (or, more exotically, anything we could babelify appropriately) as opposed to the standard library.

Multi-Module Packaging

Currently, we require modules to be dynamically linked by the Grain runtime. It would make deployment (and certain dependency management) significantly easier if there was an option to statically link a module's dependencies. Bonus points if we can do this for specific subsets of dependencies (as opposed to requiring all dependencies be statically linked).

Type System

This is a tracking issue for adding type support to Grain. The initial goal is a simple Hindley-Milner Type system à la OCaml. From there, we may want to add fun things like refinement types.

Reimplement DOM stdlib

Back in the day (before we had proper modules), we had a DOM standard library. This should be rewritten so it is usable again, and with better types.

JavaScript FFI

Users should be able to reference JavaScript values (most notably, functions) via an FFI.

The syntax should be similar to the wasm FFI syntax and allow the user to reference a certain module and value from that module. The user must provide a type annotation.

For now, Grain will just assume that the type annotation is correct. Maybe in the future it could do some type of checking (maybe just for JavaScript primitives).

The user also must pass those values into the Grain runtime in the form of a plain JavaScript object, with keys as module names and values which are also plain JavaScript objects, with keys as value names, i.e.

{
  myLibrary: {
    myFunction () { ... }
  }
}

Suggested syntax:
foreign js myLibrary myFunction : String -> Number

__DEBUG Doesn't Work Correctly

In memory.js's trace function, we have a TRACE_MEMORY flag which determines whether the function should be active. This is currently not working, even on dev builds, as, for some reason, the __DEBUG flag is always unset. This should be fixed.

Build currently fails

$ make
./tools/get-deps.sh
jbuilder build
      ocamlc src/parsing/.grain_parsing.objs/grain_parsing__Identifier.{cmo,cmt} (exit 2)
(cd _build/default && /usr/bin/ocamlc -w -40 -g -bin-annot -I src/parsing/.grain_parsing.objs -I /root/.opam/system/lib/batteries -I /root/.opam/system/lib/bytes -I /root/.opam/system/lib/cmdliner -I /root/.opam/system/lib/dyp -I /root/.opam/system/lib/extlib -I /root/.opam/system/lib/num -I /root/.opam/system/lib/ppx_core -I /root/.opam/system/lib/ppx_deriving -I /root/.opam/system/lib/ppx_driver -I /root/.opam/system/lib/ppx_optcomp -I /root/.opam/system/lib/ppx_sexp_conv -I /root/.opam/system/lib/ppx_type_conv -I /root/.opam/system/lib/result -I /root/.opam/system/lib/sexplib -I /root/.opam/system/lib/stdint -I /root/.opam/system/lib/wasm -I /usr/lib/ocaml/compiler-libs -I /usr/lib/ocaml/threads -I src/utils/.grain_utils.objs -no-alias-deps -open Grain_parsing -o src/parsing/.grain_parsing.objs/grain_parsing__Identifier.cmo -c -impl src/parsing/identifier.pp.ml)
File "src/parsing/identifier.ml", line 13, characters 38-50:
Error: Unbound value String.equal
      ocamlc src/parsing/.grain_parsing.objs/grain_parsing__Location.{cmo,cmt} (exit 2)
(cd _build/default && /usr/bin/ocamlc -w -40 -g -bin-annot -I src/parsing/.grain_parsing.objs -I /root/.opam/system/lib/batteries -I /root/.opam/system/lib/bytes -I /root/.opam/system/lib/cmdliner -I /root/.opam/system/lib/dyp -I /root/.opam/system/lib/extlib -I /root/.opam/system/lib/num -I /root/.opam/system/lib/ppx_core -I /root/.opam/system/lib/ppx_deriving -I /root/.opam/system/lib/ppx_driver -I /root/.opam/system/lib/ppx_optcomp -I /root/.opam/system/lib/ppx_sexp_conv -I /root/.opam/system/lib/ppx_type_conv -I /root/.opam/system/lib/result -I /root/.opam/system/lib/sexplib -I /root/.opam/system/lib/stdint -I /root/.opam/system/lib/wasm -I /usr/lib/ocaml/compiler-libs -I /usr/lib/ocaml/threads -I src/utils/.grain_utils.objs -no-alias-deps -open Grain_parsing -o src/parsing/.grain_parsing.objs/grain_parsing__Location.cmo -c -impl src/parsing/location.pp.ml)
File "src/parsing/location.ml", line 93, characters 4-13:
Error: Unbound value sexp_of_t
Hint: Did you mean sexp_of_int or sexp_of_mat?
    ocamlopt src/parsing/.grain_parsing.objs/grain_parsing__Identifier.{cmx,o} (exit 2)
(cd _build/default && /usr/bin/ocamlopt -w -40 -g -I src/parsing/.grain_parsing.objs -I /root/.opam/system/lib/batteries -I /root/.opam/system/lib/bytes -I /root/.opam/system/lib/cmdliner -I /root/.opam/system/lib/dyp -I /root/.opam/system/lib/extlib -I /root/.opam/system/lib/num -I /root/.opam/system/lib/ppx_core -I /root/.opam/system/lib/ppx_deriving -I /root/.opam/system/lib/ppx_driver -I /root/.opam/system/lib/ppx_optcomp -I /root/.opam/system/lib/ppx_sexp_conv -I /root/.opam/system/lib/ppx_type_conv -I /root/.opam/system/lib/result -I /root/.opam/system/lib/sexplib -I /root/.opam/system/lib/stdint -I /root/.opam/system/lib/wasm -I /usr/lib/ocaml/compiler-libs -I /usr/lib/ocaml/threads -I src/utils/.grain_utils.objs -no-alias-deps -open Grain_parsing -o src/parsing/.grain_parsing.objs/grain_parsing__Identifier.cmx -c -impl src/parsing/identifier.pp.ml)
File "src/parsing/identifier.ml", line 13, characters 38-50:
Error: Unbound value String.equal
         ppx src/typed/subst.pp.ml (exit 1)
(cd _build/default && .ppx/jbuild/ppx_sexp_conv+ppx_deriving/ppx.exe --cookie 'library-name="grain_typed"' -o src/typed/subst.pp.ml --impl src/typed/subst.ml --dump-ast)
File "src/typed/subst.ml", line 26, characters 21-22:
Error: Syntax error
    ocamlopt src/parsing/.grain_parsing.objs/grain_parsing__Location.{cmx,o} (exit 2)
(cd _build/default && /usr/bin/ocamlopt -w -40 -g -I src/parsing/.grain_parsing.objs -I /root/.opam/system/lib/batteries -I /root/.opam/system/lib/bytes -I /root/.opam/system/lib/cmdliner -I /root/.opam/system/lib/dyp -I /root/.opam/system/lib/extlib -I /root/.opam/system/lib/num -I /root/.opam/system/lib/ppx_core -I /root/.opam/system/lib/ppx_deriving -I /root/.opam/system/lib/ppx_driver -I /root/.opam/system/lib/ppx_optcomp -I /root/.opam/system/lib/ppx_sexp_conv -I /root/.opam/system/lib/ppx_type_conv -I /root/.opam/system/lib/result -I /root/.opam/system/lib/sexplib -I /root/.opam/system/lib/stdint -I /root/.opam/system/lib/wasm -I /usr/lib/ocaml/compiler-libs -I /usr/lib/ocaml/threads -I src/utils/.grain_utils.objs -no-alias-deps -open Grain_parsing -o src/parsing/.grain_parsing.objs/grain_parsing__Location.cmx -c -impl src/parsing/location.pp.ml)
File "src/parsing/location.ml", line 93, characters 4-13:
Error: Unbound value sexp_of_t
Hint: Did you mean sexp_of_int or sexp_of_mat?
      ocamlc src/typed/.grain_typed.objs/grain_typed__Ident.{cmi,cmti} (exit 2)
(cd _build/default && /usr/bin/ocamlc -w -40 -g -bin-annot -I src/typed/.grain_typed.objs -I /root/.opam/system/lib/batteries -I /root/.opam/system/lib/bytes -I /root/.opam/system/lib/cmdliner -I /root/.opam/system/lib/dyp -I /root/.opam/system/lib/extlib -I /root/.opam/system/lib/num -I /root/.opam/system/lib/ppx_core -I /root/.opam/system/lib/ppx_deriving -I /root/.opam/system/lib/ppx_driver -I /root/.opam/system/lib/ppx_optcomp -I /root/.opam/system/lib/ppx_sexp_conv -I /root/.opam/system/lib/ppx_type_conv -I /root/.opam/system/lib/result -I /root/.opam/system/lib/sexplib -I /root/.opam/system/lib/stdint -I /root/.opam/system/lib/wasm -I /usr/lib/ocaml/compiler-libs -I /usr/lib/ocaml/threads -I src/parsing/.grain_parsing.objs -I src/utils/.grain_utils.objs -no-alias-deps -open Grain_typed -o src/typed/.grain_typed.objs/grain_typed__Ident.cmi -c -intf src/typed/ident.pp.mli)
File "src/typed/ident.mli", line 22, characters 8-22:
Error: Unbound module Identifiable
      ocamlc src/parsing/.grain_parsing.objs/grain_parsing__Driver.{cmo,cmt} (exit 2)
(cd _build/default && /usr/bin/ocamlc -w -40 -g -bin-annot -I src/parsing/.grain_parsing.objs -I /root/.opam/system/lib/batteries -I /root/.opam/system/lib/bytes -I /root/.opam/system/lib/cmdliner -I /root/.opam/system/lib/dyp -I /root/.opam/system/lib/extlib -I /root/.opam/system/lib/num -I /root/.opam/system/lib/ppx_core -I /root/.opam/system/lib/ppx_deriving -I /root/.opam/system/lib/ppx_driver -I /root/.opam/system/lib/ppx_optcomp -I /root/.opam/system/lib/ppx_sexp_conv -I /root/.opam/system/lib/ppx_type_conv -I /root/.opam/system/lib/result -I /root/.opam/system/lib/sexplib -I /root/.opam/system/lib/stdint -I /root/.opam/system/lib/wasm -I /usr/lib/ocaml/compiler-libs -I /usr/lib/ocaml/threads -I src/utils/.grain_utils.objs -no-alias-deps -open Grain_parsing -o src/parsing/.grain_parsing.objs/grain_parsing__Driver.cmo -c -impl src/parsing/driver.pp.ml)
File "src/parsing/driver.ml", line 14, characters 74-106:
Error: Unbound value Parsetree.sexp_of_parsed_program
      ocamlc src/typed/.grain_typed.objs/grain_typed__Oprint.{cmo,cmt} (exit 2)
(cd _build/default && /usr/bin/ocamlc -w -40 -g -bin-annot -I src/typed/.grain_typed.objs -I /root/.opam/system/lib/batteries -I /root/.opam/system/lib/bytes -I /root/.opam/system/lib/cmdliner -I /root/.opam/system/lib/dyp -I /root/.opam/system/lib/extlib -I /root/.opam/system/lib/num -I /root/.opam/system/lib/ppx_core -I /root/.opam/system/lib/ppx_deriving -I /root/.opam/system/lib/ppx_driver -I /root/.opam/system/lib/ppx_optcomp -I /root/.opam/system/lib/ppx_sexp_conv -I /root/.opam/system/lib/ppx_type_conv -I /root/.opam/system/lib/result -I /root/.opam/system/lib/sexplib -I /root/.opam/system/lib/stdint -I /root/.opam/system/lib/wasm -I /usr/lib/ocaml/compiler-libs -I /usr/lib/ocaml/threads -I src/parsing/.grain_parsing.objs -I src/utils/.grain_utils.objs -no-alias-deps -open Grain_typed -o src/typed/.grain_typed.objs/grain_typed__Oprint.cmo -c -impl src/typed/oprint.pp.ml)
File "src/typed/oprint.ml", line 125, characters 10-24:
Error: Unbound value Sys.getenv_opt
Makefile:4: recipe for target 'default' failed
make: *** [default] Error 1

Make the CI run faster

Right now, the CI builds the OCaml compiler on every run. We can probably cache it so it doesn't have to build every time.

Use gran with existing frontend frameworks.

Hi! Grain looks super interesting. Will it be possible to use grain with existing frontend frameworks like React or Hyperapp or will it be necessary to port/rewrite such libraries to Grain first?

Cheers!

Fix DOM API

Now that we've implemented the type system, the DOM API should return DOM Options rather than returning the element or false.

Documentation

All pages are empty except Intro and Bindings. Also, where is the language reference?

Update to OCaml 4.09.0

Our README says that we require OCaml 4.05. This is a bit dated now; we should check that we're compatible with the latest OCaml and update (plus, then we can use monadic binding operators!).

Feature Request: Webpack plugin

The Grain Lang looks awesome! It would be awesome too to have a Webpack plugin that compiles the .gr files to .wasm, so then we can use them in Javascript using something like the wasm-loader plugin

Clean up compcore.re

It would be nice to have compiler support for stdlib functions in separate files, rather than just hanging around in compcore. This should (for example) move a lot of code introduced in #82 into separate files.

grain chat?

Is there a place to chat to get assitance with grain? I have not found a room on freenode or gitter or in the readme and I think such a place would be helpful.

URL Imports

Currently, all modules need to be on the local Grain PATH in order for compilation to take place. I would like imports to be able to be specified by a URL as well as the current import scheme.

I'm thinking this can play into a larger and more extensible Racket-like import system, in which one can write a custom import specifier; however, this would require support for either compiler plugins or macros.

Add new list methods

Let's add methods for these:

some # checks that at least one item in the list is true for a given condition
nth # gets the nth item in the list
filter
reject # opposite of filter
count # counts how many elements satisfy a given condition
hd # gets the first item in the list
tl # returns the list without the first item
flatten # takes a list of lists and combines them into a single list
insert # takes a list, item, index. inserts the item at the index-th position
rotate # takes a list, count. item at count-th position becomes the first item. should work for negative counts as well
uniq
part # takes a list and and a number. returns a tuple containing the first n items and the rest of the list

Support recursive data bindings

Statements like let rec ones = [1, ...ones] should be allowed. This expression should result a list containing a head of the element 1, and a tail of that same list.

#96 was done to address this as a bug.

Additional info:
While in theory this could work with minimal code change, it doesn't because we currently create lists as the result of function calls. If we just used the normal data constructors, it would be fairly straightforward to do the proper backpatching, but pervasives.gr is currently loaded as an external module instead of being injected directly into the program, and thus the data constructors are brought in as functions. Maybe the list cons function can be optimized into a normal data construction?

Garbage Collection

Since WebAssembly doesn't allow for any sort of stack introspection, we suggest using reference counting.

Clean Up Example Site & JS Runtime

Right now, the example site is under script, which is a little silly. Moreover, run-prog.js should be pulled out into a separate file (maybe grain-runtime.js or something) in the main repository which the example just uses; the current structure implies that Grain users need to implement the runtime themselves (which isn't very ergonomic).

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.