grain-lang / grain Goto Github PK
View Code? Open in Web Editor NEWThe Grain compiler toolchain and CLI. Home of the modern web staple. 🌾
Home Page: https://grain-lang.org/
License: GNU Lesser General Public License v3.0
The Grain compiler toolchain and CLI. Home of the modern web staple. 🌾
Home Page: https://grain-lang.org/
License: GNU Lesser General Public License v3.0
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
;;
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.
These functions should take the array/list and a comparator function as arguments and produce a sorted array/list.
Open questions:
sort
and sort!
where the latter sorts in place?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
My intuition says no, but the grotesque crashes when doing so say yes. This needs further investigation. See this comment.
Functions added are from #141
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!
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?
All pages are empty except Intro and Bindings. Also, where is the language reference?
let fst, snd = ...
should be valid syntax.
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!).
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.
This program
2 # comment
2
results in a syntax error.
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).
After the docs were written (you can check them out here) it made it obvious that these functions were missing.
These functions should be similar to Array.map
and List.map
, but should also pass the index of each element to the map function.
We have some old functions (particularly in lists.gr
) that are in the old snake_case.
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).
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.
Hi folks, thanks for bringing ML family goodness to WebAssembly! I wonder why did you go on the path of creating a new language as opposed to adding WA as a target for OCaml?
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
There are some list stdlib functions that aren't tested. You can find the tests in test/stdlib/lists.test.gr
.
We should at the same time do some renaming:
stringAppend -> append
stringSlice -> slice
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
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.
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.
Are there plans to support browser APIs?
I would be great to remove it, as I saw in the docs, it doesn't looks neccesary.
Once this feature in Node.js is no longer experimental, we can remove this flag.
https://github.com/grain-lang/grain/blob/master/cli/bin/grain.js#L2
Currently the build instructions say I need the following things on my path:
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 fromopam
. Can we mention this in the document?
We set an initial function table size, but we should grow the table as modules are loaded.
https://github.com/grain-lang/grain/blob/master/runtime/src/runtime.js
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?
Append is fairly straightforward, though we should have a minor discussion about how to handle String.slice
because of the length vs. size issue.
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.
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
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:
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).babel
ify appropriately) as opposed to the standard library.$ 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
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!
The link for the Grain setup guide in "Getting up and Running" doesn't work. It's going to https://grain-lang.org/guide/getting_grain which doesn't exists. I think the guide moved to https://grain-lang.org/docs/getting_grain.
Our codebase still has remnants of the grand ol' SNEK project that needs to be cleaned up.
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.
We currently create a webassembly function that just returns the location of a lambda in memory when functions are exported from modules.
Since the mutable globals proposal has been finished we should just export the global.
This will probably require updating our wasm spec.
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.
Grain is licensed under LGPL.
The Grain compiler should be versioned, so the runtime can be deployed with each version.
Since WebAssembly doesn't allow for any sort of stack introspection, we suggest using reference counting.
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.
Now that we've implemented the type system, the DOM API should return DOM Options rather than returning the element or false.
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.
There's still some code lying around from when Grain's ancestors targeted x86. We should clean this out.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.