Skip to content

Commit 6f0c22a

Browse files
authored
Add syntax surface, module type name and tests for dynamic import (#6188)
1 parent ae62547 commit 6f0c22a

File tree

8 files changed

+141
-40
lines changed

8 files changed

+141
-40
lines changed

jscomp/frontend/bs_builtin_ppx.ml

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -424,15 +424,12 @@ let local_module_name =
424424
incr v;
425425
"local_" ^ string_of_int !v
426426

427-
(* Unpack requires core_type package for type inference;
428-
use module type bindings and a function to create safe local names instead. *)
429-
let local_module_type_name =
430-
let v = ref 0 in
431-
fun ({txt} : Longident.t Location.loc) ->
432-
incr v;
433-
"__"
434-
^ (Longident.flatten txt |> List.fold_left (fun ll l -> ll ^ l) "")
435-
^ string_of_int !v ^ "__"
427+
(* Unpack requires core_type package for type inference:
428+
Generate a module type name eg. __Belt_List__*)
429+
let local_module_type_name txt =
430+
"_"
431+
^ (Longident.flatten txt |> List.fold_left (fun ll l -> ll ^ "_" ^ l) "")
432+
^ "__"
436433

437434
let expand_reverse (stru : Ast_structure.t) (acc : Ast_structure.t) :
438435
Ast_structure.t =
@@ -466,14 +463,15 @@ let expand_reverse (stru : Ast_structure.t) (acc : Ast_structure.t) :
466463
}
467464
:: acc)
468465

469-
let rec structure_mapper (self : mapper) (stru : Ast_structure.t) =
466+
let rec structure_mapper ~await_context (self : mapper) (stru : Ast_structure.t)
467+
=
470468
match stru with
471469
| [] -> []
472470
| item :: rest -> (
473471
match item.pstr_desc with
474472
| Pstr_extension (({txt = "bs.raw" | "raw"; loc}, payload), _attrs) ->
475473
Ast_exp_handle_external.handle_raw_structure loc payload
476-
:: structure_mapper self rest
474+
:: structure_mapper ~await_context self rest
477475
(* | Pstr_extension (({txt = "i"}, _),_)
478476
->
479477
structure_mapper self rest *)
@@ -493,7 +491,7 @@ let rec structure_mapper (self : mapper) (stru : Ast_structure.t) =
493491
next
494492
| PSig _ | PTyp _ | PPat _ ->
495493
Location.raise_errorf ~loc "private extension is not support")
496-
| _ -> expand_reverse acc (structure_mapper self rest)
494+
| _ -> expand_reverse acc (structure_mapper ~await_context self rest)
497495
in
498496
aux [] stru
499497
(* Dynamic import of module transformation: module M = @res.await Belt.List *)
@@ -502,30 +500,49 @@ let rec structure_mapper (self : mapper) (stru : Ast_structure.t) =
502500
as mb)
503501
when Res_parsetree_viewer.hasAwaitAttribute pmod_attributes ->
504502
let item = self.structure_item self item in
505-
let safe_module_type_name = local_module_type_name {txt; loc} in
503+
let safe_module_type_name = local_module_type_name txt in
504+
let has_local_module_name =
505+
Hashtbl.find_opt !await_context safe_module_type_name
506+
in
507+
(* module __Belt_List__ = module type of Belt.List *)
506508
let module_type_decl =
507-
let open Ast_helper in
508-
Str.modtype ~loc
509-
(Mtd.mk ~loc
510-
{txt = safe_module_type_name; loc}
511-
~typ:(Mty.typeof_ ~loc me))
509+
match has_local_module_name with
510+
| Some _ -> []
511+
| None ->
512+
let open Ast_helper in
513+
Hashtbl.add !await_context safe_module_type_name safe_module_type_name;
514+
[
515+
Str.modtype ~loc
516+
(Mtd.mk ~loc
517+
{txt = safe_module_type_name; loc}
518+
~typ:(Mty.typeof_ ~loc me));
519+
]
512520
in
513-
(* module __BeltList1__ = module type of Belt.List *)
514521
module_type_decl
515-
:: {
516-
item with
517-
pstr_desc =
518-
Pstr_module
519-
{
520-
mb with
521-
pmb_expr =
522-
Ast_await.create_await_module_expression
523-
~module_type_name:safe_module_type_name mb.pmb_expr;
524-
};
525-
}
526-
(* module M = @res.await Belt.List *)
527-
:: structure_mapper self rest
528-
| _ -> self.structure_item self item :: structure_mapper self rest)
522+
@ (* module M = @res.await Belt.List *)
523+
{
524+
item with
525+
pstr_desc =
526+
Pstr_module
527+
{
528+
mb with
529+
pmb_expr =
530+
Ast_await.create_await_module_expression
531+
~module_type_name:safe_module_type_name mb.pmb_expr;
532+
};
533+
}
534+
:: structure_mapper ~await_context self rest
535+
| _ ->
536+
self.structure_item self item :: structure_mapper ~await_context self rest
537+
)
538+
539+
let structure_mapper ~await_context (self : mapper) (stru : Ast_structure.t) =
540+
let await_saved = !await_context in
541+
let result =
542+
structure_mapper ~await_context:(ref (Hashtbl.create 10)) self stru
543+
in
544+
await_context := await_saved;
545+
result
529546

530547
let mapper : mapper =
531548
{
@@ -536,7 +553,7 @@ let mapper : mapper =
536553
signature_item = signature_item_mapper;
537554
value_bindings = Ast_tuple_pattern_flatten.value_bindings_mapper;
538555
structure_item = structure_item_mapper;
539-
structure = structure_mapper;
556+
structure = structure_mapper ~await_context:(ref (Hashtbl.create 10));
540557
(* Ad-hoc way to internalize stuff *)
541558
label_declaration =
542559
(fun self lbl ->

jscomp/test/Import.js

Lines changed: 36 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jscomp/test/Import.res

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,27 @@ let beltAsModule = await Js.import(module(Belt.List: BeltList))
1313

1414
// module type BeltList0 = module type of Belt.List
1515
// module M = unpack(@res.await Js.import(module(Belt.List: BeltList0)))
16-
module M = @res.await Belt.List
17-
let each = M.forEach
16+
module M = await Belt.List
17+
let each = M.forEach
18+
19+
module N = {
20+
module N0 = await Belt.List
21+
let each = N0.forEach
22+
23+
module N1 = {
24+
module O = await Belt.List
25+
let each = O.forEach
26+
}
27+
28+
module N2 = await Belt.List
29+
let each = N2.forEach
30+
}
31+
32+
module M0 = await Belt.List
33+
let each = M0.forEach
34+
35+
module M1 = await Belt.List
36+
let each = M1.forEach
37+
38+
module M2 = N.N1.O
39+
let each2 = M2.forEach

res_syntax/src/res_core.ml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5783,7 +5783,22 @@ and parseFunctorModuleExpr p =
57835783
* | extension
57845784
* | attributes module-expr *)
57855785
and parseModuleExpr p =
5786+
let hasAwait, loc_await =
5787+
let startPos = p.startPos in
5788+
match p.Parser.token with
5789+
| Await ->
5790+
Parser.expect Await p;
5791+
let endPos = p.endPos in
5792+
(true, mkLoc startPos endPos)
5793+
| _ -> (false, mkLoc startPos startPos)
5794+
in
57865795
let attrs = parseAttributes p in
5796+
let attrs =
5797+
if hasAwait then
5798+
(({txt = "res.await"; loc = loc_await}, PStr []) : Parsetree.attribute)
5799+
:: attrs
5800+
else attrs
5801+
in
57875802
let modExpr =
57885803
if isEs6ArrowFunctor p then parseFunctorModuleExpr p
57895804
else parsePrimaryModExpr p

res_syntax/src/res_grammar.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ let isFunctorArgStart = function
215215
| _ -> false
216216

217217
let isModExprStart = function
218-
| Token.At | Percent | Uident _ | Lbrace | Lparen | Lident "unpack" -> true
218+
| Token.At | Percent | Uident _ | Lbrace | Lparen | Lident "unpack" | Await ->
219+
true
219220
| _ -> false
220221

221222
let isRecordRowStart = function

res_syntax/src/res_printer.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,11 @@ and printModuleBinding ~state ~isRec moduleBinding cmtTbl i =
710710
Doc.concat [Doc.text ": "; printModType ~state modType cmtTbl] )
711711
| modExpr -> (printModExpr ~state modExpr cmtTbl, Doc.nil)
712712
in
713+
let modExprDoc =
714+
if ParsetreeViewer.hasAwaitAttribute moduleBinding.pmb_expr.pmod_attributes
715+
then Doc.concat [Doc.text "await "; modExprDoc]
716+
else modExprDoc
717+
in
713718
let modName =
714719
let doc = Doc.text moduleBinding.pmb_name.Location.txt in
715720
printComments doc cmtTbl moduleBinding.pmb_name.loc

res_syntax/tests/parsing/grammar/expressions/await.res

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@ let () = {
2323
let () = {
2424
await delay(10)
2525
await delay(20)
26-
}
26+
}
27+
28+
let forEach = await @a @b Js.Import(Belt.List.forEach)
29+
30+
module M = await @a @b Belt.List

res_syntax/tests/parsing/grammar/expressions/expected/await.res.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ let () =
1515
[@res.braces ])
1616
let () = ((delay 10)[@res.braces ][@res.await ])
1717
let () = ((((delay 10)[@res.await ]); ((delay 20)[@res.await ]))
18-
[@res.braces ])
18+
[@res.braces ])
19+
let forEach = ((Js.Import Belt.List.forEach)[@res.await ][@a ][@b ])
20+
module M = ((Belt.List)[@res.await ][@a ][@b ])

0 commit comments

Comments
 (0)