Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

playground: make jsoo_main compile #538

Merged
merged 33 commits into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0653696
playground: make jsoo_main compile
jchavarri Apr 7, 2023
bea1835
Merge branch 'main' into playground-1
jchavarri May 6, 2023
6944289
playground: updates after merging main
jchavarri May 6, 2023
eb98362
Merge branch 'main' into playground-1
jchavarri May 29, 2023
0809424
playground: use private melange comp libs
jchavarri May 29, 2023
9cbe9c5
playground: pick up change in translmod
jchavarri May 29, 2023
ec1fbe3
playground: better error handling
jchavarri May 29, 2023
ba38c05
playground: remove hardcoded BS_BROWSER
jchavarri May 29, 2023
ca209c4
opam: add jsoo
jchavarri May 30, 2023
d1ce4ed
playground: update in-code comment
jchavarri May 30, 2023
01c797b
playground: add new profile browser
jchavarri May 30, 2023
4e64b6f
playground: build in ci
jchavarri May 30, 2023
b178930
Revert "playground: pick up change in translmod"
jchavarri May 31, 2023
0137a6b
Merge branch 'main' into playground-1
jchavarri May 31, 2023
b9a2554
playground: add dev mode for faster builds
jchavarri May 31, 2023
08be825
playground: apply ppxlib driver on structure
jchavarri May 31, 2023
b23d4f4
playground: add comment
jchavarri May 31, 2023
5ef2d1f
Merge branch 'main' into playground-1
jchavarri Jun 1, 2023
e05becc
Merge branch 'main' into playground-1
jchavarri Jun 2, 2023
5f7c877
playground: fix errors after merging main
jchavarri Jun 2, 2023
dc56afc
Merge branch 'main' into playground-1
jchavarri Jun 5, 2023
529df6a
fixes after merge
jchavarri Jun 5, 2023
abdb6ae
remove unneeded exposure of ppx_entry
jchavarri Jun 5, 2023
df0a373
remove d_browser
jchavarri Jun 5, 2023
655102b
playground: update makefile with new paths
jchavarri Jun 5, 2023
ef574d0
add test for playground
jchavarri Jun 5, 2023
c4ad80d
playground: remove obsolete comment
jchavarri Jun 5, 2023
1620cbc
playground: open melange_comp_libs in flags
jchavarri Jun 5, 2023
f478585
playground: add more tests
jchavarri Jun 5, 2023
9329c87
playground: remove str_of_formatted
jchavarri Jun 5, 2023
68cc036
playground: add failing test with bs.deriving
jchavarri Jun 5, 2023
a255638
playground: fix test by replacing bs.deriving with deriving
jchavarri Jun 5, 2023
53dc2dc
fix: ppxlib AST conversion
anmonteiro Jun 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/opam-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ jobs:
opam update
make opam-install-test

- name: Test playground
working-directory: melange
run: |
make playground-test

- name: Clone melange-opam-template
run: |
git clone https://github.com/melange-re/melange-opam-template.git
Expand Down
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,19 @@ opam-install-dev: opam-install-test ## Install development dependencies

.PHONY: opam-init
opam-init: opam-create-switch opam-install-test ## Configure everything to develop this repository in local

.PHONY: playground
playground:
opam exec -- dune build --profile=browser bin/jsoo_main.bc.js

.PHONY: playground-dev
playground-dev:
opam exec -- dune build --profile=browser-dev bin/jsoo_main.bc.js

.PHONY: playground-dev-test
playground-dev-test:
opam exec -- dune build --profile=browser-dev @@test/blackbox-tests/playground

.PHONY: playground-test
playground-test:
opam exec -- dune build --profile=browser @@test/blackbox-tests/playground
7 changes: 7 additions & 0 deletions bin/dune
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@
(package melange)
(modules melppx)
(libraries melange.ppx ppxlib))

(executable
(name jsoo_main)
(flags :standard -open Melange_compiler_libs)
(modules jsoo_main jsoo_common)
(libraries core melange_compiler_libs melange_ppx)
(modes js))
21 changes: 17 additions & 4 deletions bin/jsoo_common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,33 @@ module Js = struct
external to_bytestring : js_string t -> string = "caml_js_to_byte_string"
end

let mk_js_error (loc : Location.t) (msg : string) =
let mk_js_error (error : Location.report) =
let kind, type_ =
match error.kind with
| Location.Report_error -> ("Error", "error")
| Report_warning w -> (Printf.sprintf "Warning: %s" w, "warning")
| Report_warning_as_error w ->
(Printf.sprintf "Error: (warning %s)" w, "warning_as_error")
| Report_alert w -> (Printf.sprintf "Alert: %s" w, "alert")
| Report_alert_as_error w ->
(Printf.sprintf "Error: (alert %s)" w, "alert_as_error")
in
let txt = Format.asprintf "@[%t@]" error.main.txt in
let loc = error.main.loc in
let _file, line, startchar = Location.get_pos_info loc.Location.loc_start in
let _file, endline, endchar = Location.get_pos_info loc.Location.loc_end in
Js.Unsafe.(
obj
[|
( "js_error_msg",
inject
@@ Js.string (Printf.sprintf "Line %d, %d:\n %s" line startchar msg)
@@ Js.string
(Printf.sprintf "Line %d, %d:\n %s %s" line startchar kind txt)
);
("row", inject (line - 1));
("column", inject startchar);
("endRow", inject (endline - 1));
("endColumn", inject endchar);
("text", inject @@ Js.string msg);
("type", inject @@ Js.string "error");
("text", inject @@ Js.string txt);
("type", inject @@ Js.string type_);
|])
4 changes: 2 additions & 2 deletions bin/jsoo_common.mli
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ module Js : sig
end

(*
Creates a Js Error object for given location with and a certain error message
Creates a Js Error object for given location report
*)
val mk_js_error : Location.t -> string -> Js.Unsafe.obj
val mk_js_error : Location.report -> Js.Unsafe.obj
54 changes: 25 additions & 29 deletions bin/jsoo_main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)

module Js = Jsoo_common.Js
(** *)

(*
Error:
Expand All @@ -43,7 +42,12 @@ let error_of_exn e =
| Some (`Ok e) -> Some e
| Some `Already_displayed | None -> None

let implementation ~use_super_errors impl str : Js.Unsafe.obj =
module Convert =
Ppxlib_ast.Convert
(Ppxlib_ast__.Versions.OCaml_414)
(Ppxlib_ast__.Versions.OCaml_current)

let compile impl str : Js.Unsafe.obj =
let modulename = "Test" in
(* let env = !Toploop.toplevel_env in *)
(* Res_compmisc.init_path false; *)
Expand All @@ -54,52 +58,52 @@ let implementation ~use_super_errors impl str : Js.Unsafe.obj =
(* Question ?? *)
(* let finalenv = ref Env.empty in *)
let types_signature = ref [] in
if use_super_errors then (
Misc.Color.setup (Some Always);
Lazy.force Super_main.setup);

try
Js_config.jsx_version := 3;
(* default *)
let ast = impl (Lexing.from_string str) in
let ast = Ppx_entry.rewrite_implementation ast in
let ast : Parsetree.structure =
let ppxlib_ast : Ppxlib_ast__.Versions.OCaml_414.Ast.Parsetree.structure =
Obj.magic (ast : Parsetree.structure)
in
let converted =
Convert.copy_structure (Ppxlib.Driver.map_structure ppxlib_ast)
in
(Obj.magic converted : Parsetree.structure)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure this is wrong. You probably copied it from melc.ml.

This is applying the PPXes and converting the preprocessed AST to the current switch version. Also Parsetree.structure isn't what you think it is because you opened Melange_compiler_libs globally.

In the playground, we just need this AST version to be the Melange_compiler_libs parsetree, I think? so we might not need to make the copy at all?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just pushed 53dc2dc fixing this

Copy link
Member Author

@jchavarri jchavarri Jun 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably copied it from melc.ml.

Yes.

In the playground, we just need this AST version to be the Melange_compiler_libs parsetree, I think? so we might not need to make the copy at all?

Just curious, I noticed you left the copy_structurecalls, why does ppxlib need them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ppxlib has its own version of the AST. So we need to convert from the melange version to its internal AST version and back. Right now that’s 4.14 so we technically don’t need these. But it’s better to avoid bugs when ppxlib bumps AST versions.

in
let typed_tree =
let a, b, _, signature =
let { Typedtree.structure; coercion; shape = _; signature }, _finalenv =
Typemod.type_implementation_more modulename modulename modulename env
ast
in
(* finalenv := c ; *)
types_signature := signature;
(a, b)
(structure, coercion)
in
typed_tree |> Translmod.transl_implementation modulename
|> (* Printlambda.lambda ppf *) fun { Lambda.code = lam } ->
|> (* Printlambda.lambda ppf *) fun { Lambda.code = lam; _ } ->
let buffer = Buffer.create 1000 in
let () =
Js_dump_program.pp_deps_program ~output_prefix:""
(* does not matter here *) NodeJS
(Lam_compile_main.compile "" lam)
~package_info:Js_packages_info.empty
~output_info:{ Js_packages_info.module_system = NodeJS; suffix = Js }
(Ext_pp.from_buffer buffer)
(Lam_compile_main.compile "" lam)
in
let v = Buffer.contents buffer in
Js.Unsafe.(obj [| ("js_code", inject @@ Js.string v) |])
(* Format.fprintf output_ppf {| { "js_code" : %S }|} v ) *)
with e -> (
match error_of_exn e with
| Some error ->
Location.report_error Format.err_formatter error;
Jsoo_common.mk_js_error error.loc error.msg
| Some error -> Jsoo_common.mk_js_error error
| None ->
Js.Unsafe.(
obj [| ("js_error_msg", inject @@ Js.string (Printexc.to_string e)) |]))

let compile impl ~use_super_errors = implementation ~use_super_errors impl
let export (field : string) v = Js.Unsafe.set Js.Unsafe.global field v

(* To add a directory to the load path *)

let dir_directory d = Config.load_path := d :: !Config.load_path
let () = dir_directory "/static"
let () = Load_path.add_dir "/static"

let make_compiler name impl =
export name
Expand All @@ -109,16 +113,8 @@ let make_compiler name impl =
( "compile",
inject
@@ Js.wrap_meth_callback (fun _ code ->
compile impl ~use_super_errors:false (Js.to_string code)) );
( "compile_super_errors",
inject
@@ Js.wrap_meth_callback (fun _ code ->
compile impl ~use_super_errors:true (Js.to_string code)) );
("version", Js.Unsafe.inject (Js.string Bs_version.version));
compile impl (Js.to_string code)) );
("version", Js.Unsafe.inject (Js.string Melange_version.version));
|])

let () = make_compiler "ocaml" Parse.implementation

(* local variables: *)
(* compile-command: "ocamlbuild -use-ocamlfind -pkg compiler-libs -no-hygiene driver.cmo" *)
(* end: *)
10 changes: 9 additions & 1 deletion dune
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,12 @@
(env-vars
(CPPO_FLAGS -D=BS_RELEASE_BUILD))
(ocamlopt_flags
(:standard -O3 -unbox-closures))))
(:standard -O3 -unbox-closures)))
(browser
(env-vars
(CPPO_FLAGS -D=BS_BROWSER)))
(browser-dev
(js_of_ocaml
(compilation_mode separate))
(env-vars
(CPPO_FLAGS -D=BS_BROWSER))))
1 change: 1 addition & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
(cppo :build)
(ounit :with-test)
(reason :with-test)
(js_of_ocaml :with-test)
ppxlib
menhir
(reactjs-jsx-ppx :with-test)))
Expand Down
8 changes: 8 additions & 0 deletions jscomp/core/js_dump_program.mli
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ val dump_deps_program :
J.deps_program ->
out_channel ->
unit

val pp_deps_program :
package_info:Js_packages_info.t ->
output_info:Js_packages_info.output_info ->
output_prefix:string ->
Ext_pp.t ->
J.deps_program ->
unit
27 changes: 14 additions & 13 deletions jscomp/core/js_name_of_module_id.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@
let (=) (x : int) (y:float) = assert false
*)

#ifdef BS_BROWSER

let string_of_module_id_in_browser (x : Lam_module_ident.t) =
match x.kind with
| External { name } -> name
| Runtime | Ml -> "./stdlib/" ^ String.uncapitalize_ascii (Lam_module_ident.name x) ^ ".js"

let string_of_module_id ~package_info:_ ~output_info:_ (id : Lam_module_ident.t)
~output_dir:(_ : string) : string =
string_of_module_id_in_browser id
;;

#else

let ( // ) = Ext_path.( // )

let fix_path_for_windows : string -> string =
Expand Down Expand Up @@ -161,17 +175,4 @@ let string_of_module_id ~package_info ~output_info
| None -> Bs_exception.error (Js_not_found js_file))))
;;

(* Override it in browser *)
#ifdef BS_BROWSER

let string_of_module_id_in_browser (x : Lam_module_ident.t) =
match x.kind with
| External { name } -> name
| Runtime | Ml -> "./stdlib/" ^ String.uncapitalize_ascii x.id.name ^ ".js"

let string_of_module_id ~package_info:_ ~output_info:_ (id : Lam_module_ident.t)
~output_dir:(_ : string) : string =
string_of_module_id_in_browser id
;;

#endif
2 changes: 1 addition & 1 deletion jscomp/core/lam_util.ml
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ let generate_label ?(name="") () =
Printf.sprintf "%s_tailcall_%04d" name !count

#if (defined BS_BROWSER || defined BS_RELEASE_BUILD)
let dump ext lam =
let dump _ext _lam =
()
#else
let log_counter = ref 0
Expand Down
1 change: 1 addition & 0 deletions melange.opam
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ depends: [
"cppo" {build}
"ounit" {with-test}
"reason" {with-test}
"js_of_ocaml" {with-test}
"ppxlib"
"menhir"
"reactjs-jsx-ppx" {with-test}
Expand Down
8 changes: 8 additions & 0 deletions test/blackbox-tests/dune
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,11 @@
(env_var MELANGE_LIB)
setup.sh
(package melange)))

(cram
(applies_to playground)
(enabled_if
(or
(= %{profile} browser)
(= %{profile} browser-dev)))
(deps %{bin:js_of_ocaml} ../../bin/jsoo_main.bc.js))
96 changes: 96 additions & 0 deletions test/blackbox-tests/playground.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
Generate runtime cmijs for building against melange libs from the playground

$ find $DUNE_SOURCEROOT/_build/default/jscomp/stdlib/.stdlib.objs/melange -name "*.cmi" -or -name "*.cmj" | xargs js_of_ocaml build-fs -o stdlib-cmijs.js
$ find $DUNE_SOURCEROOT/_build/default/jscomp/runtime/.runtime.objs/melange -name "*.cmi" -or -name "*.cmj" | xargs js_of_ocaml build-fs -o runtime-cmijs.js
$ find $DUNE_SOURCEROOT/_build/default/jscomp/others/.belt.objs/melange -name "*.cmi" -or -name "*.cmj" | xargs js_of_ocaml build-fs -o belt-cmijs.js

Prepare an input file to test some snippets to exercise common functionality

$ cat > input.js <<EOF
> require(process.env.DUNE_SOURCEROOT + '/_build/default/bin/jsoo_main.bc.js');
> require('./stdlib-cmijs.js');
> require('./runtime-cmijs.js');
> require('./belt-cmijs.js');
> console.log(ocaml.compile("let t = 1"));
> console.log(ocaml.compile(\`let john = [%bs.obj { name = "john"; age = 99 }] let t = john##name\`));
> console.log(ocaml.compile(\`let foo = Belt.List.map\`));
> console.log(ocaml.compile(\`let +foo\`));
> console.log(ocaml.compile(\`let foo = "" + 2\`));
> console.log(ocaml.compile(\`type person = {
> name: string ;
> age: int
> }[@@deriving abstract]
>
> let person1: person = person ~name:"joe" ~age:10\`));
> EOF

$ node input.js
{
js_code: '// Generated by Melange\n' +
"'use strict';\n" +
'\n' +
'\n' +
'var t = 1;\n' +
'\n' +
'exports.t = t;\n' +
'/* No side effect */\n'
}
{
js_code: '// Generated by Melange\n' +
"'use strict';\n" +
'\n' +
'\n' +
'var john = {\n' +
' name: "john",\n' +
' age: 99\n' +
'};\n' +
'\n' +
'var t = john.name;\n' +
'\n' +
'exports.john = john;\n' +
'exports.t = t;\n' +
'/* t Not a pure module */\n'
}
{
js_code: '// Generated by Melange\n' +
"'use strict';\n" +
'\n' +
'var Belt_List = require("./stdlib/belt_List.js");\n' +
'\n' +
'var foo = Belt_List.map;\n' +
'\n' +
'exports.foo = foo;\n' +
'/* No side effect */\n'
}
{
js_error_msg: 'Line 1, 5:\n Error Syntax error',
row: 0,
column: 5,
endRow: 0,
endColumn: 8,
text: 'Syntax error',
type: 'error'
}
{
js_error_msg: 'Line 1, 10:\n' +
' Error This expression has type string but an expression was expected of type int',
row: 0,
column: 10,
endRow: 0,
endColumn: 12,
text: 'This expression has type string but an expression was expected of type int',
type: 'error'
}
{
js_code: '// Generated by Melange\n' +
"'use strict';\n" +
'\n' +
'\n' +
'var person1 = {\n' +
' name: "joe",\n' +
' age: 10\n' +
'};\n' +
'\n' +
'exports.person1 = person1;\n' +
'/* No side effect */\n'
}