Skip to content

Commit ff28a6f

Browse files
authored
Full blown Jane Syntax for mode exprs (#2335)
* Full blown jane syntax for mode exprs * Add some comments * small adjustment to printing of typedtree * Change the way that value binding elaboration encodes modes on Pexp_constraint to allow Jane Syntax to be stricter in validation * rename variable
1 parent 96be100 commit ff28a6f

18 files changed

+208
-105
lines changed

ocaml/.depend

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,8 +1138,7 @@ typing/mode.cmi : \
11381138
typing/mode_intf.cmi
11391139
typing/mode_intf.cmi : \
11401140
typing/solver_intf.cmi \
1141-
typing/solver.cmi \
1142-
utils/misc.cmi
1141+
typing/solver.cmi
11431142
typing/mtype.cmo : \
11441143
typing/types.cmi \
11451144
typing/subst.cmi \
@@ -1991,6 +1990,7 @@ typing/typedtree.cmo : \
19911990
parsing/longident.cmi \
19921991
parsing/location.cmi \
19931992
typing/jkind.cmi \
1993+
parsing/jane_syntax.cmi \
19941994
parsing/jane_asttypes.cmi \
19951995
typing/ident.cmi \
19961996
typing/env.cmi \
@@ -2006,6 +2006,7 @@ typing/typedtree.cmx : \
20062006
parsing/longident.cmx \
20072007
parsing/location.cmx \
20082008
typing/jkind.cmx \
2009+
parsing/jane_syntax.cmx \
20092010
parsing/jane_asttypes.cmx \
20102011
typing/ident.cmx \
20112012
typing/env.cmx \
@@ -2021,6 +2022,7 @@ typing/typedtree.cmi : \
20212022
parsing/longident.cmi \
20222023
parsing/location.cmi \
20232024
typing/jkind.cmi \
2025+
parsing/jane_syntax.cmi \
20242026
parsing/jane_asttypes.cmi \
20252027
typing/ident.cmi \
20262028
typing/env.cmi \
@@ -4176,13 +4178,11 @@ lambda/transl_array_comprehension.cmi : \
41764178
lambda/debuginfo.cmi
41774179
lambda/transl_comprehension_utils.cmo : \
41784180
utils/targetint.cmi \
4179-
typing/primitive.cmi \
41804181
lambda/lambda.cmi \
41814182
typing/ident.cmi \
41824183
lambda/transl_comprehension_utils.cmi
41834184
lambda/transl_comprehension_utils.cmx : \
41844185
utils/targetint.cmx \
4185-
typing/primitive.cmx \
41864186
lambda/lambda.cmx \
41874187
typing/ident.cmx \
41884188
lambda/transl_comprehension_utils.cmi

ocaml/boot/menhir/parser.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ let mkexp_with_modes ?(ghost=false) ~loc modes exp =
379379
let loc =
380380
if ghost then ghost_loc loc else make_loc loc
381381
in
382-
Mode.expr_of_coerce ~loc modes exp
382+
Jane_syntax.Modes.expr_of ~loc (Coerce (modes, exp))
383383

384384
(* For modes-related attributes, no need to call [register_attr] because they
385385
result from native syntax which is only parsed at proper places that are

ocaml/parsing/ast_invariants.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ let iterator =
147147
| Jexp_comprehension _
148148
| Jexp_immutable_array _
149149
| Jexp_layout _
150+
| Jexp_modes _
150151
-> ()
151152
in
152153
let expr self exp =

ocaml/parsing/ast_iterator.ml

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ type iterator = {
4343
constructor_declaration: iterator -> constructor_declaration -> unit;
4444
expr: iterator -> expression -> unit;
4545
expr_jane_syntax: iterator -> Jane_syntax.Expression.t -> unit;
46-
expr_mode_syntax: iterator -> Jane_syntax.Mode_expr.t -> expression -> unit;
4746
extension: iterator -> extension -> unit;
4847
extension_constructor: iterator -> extension_constructor -> unit;
4948
include_declaration: iterator -> include_declaration -> unit;
@@ -467,6 +466,7 @@ module E = struct
467466
module L = Jane_syntax.Layouts
468467
module N_ary = Jane_syntax.N_ary_functions
469468
module LT = Jane_syntax.Labeled_tuples
469+
module Modes = Jane_syntax.Modes
470470

471471
let iter_iterator sub : C.iterator -> _ = function
472472
| Range { start; stop; direction = _ } ->
@@ -543,24 +543,22 @@ module E = struct
543543
let iter_labeled_tuple sub : LT.expression -> _ = function
544544
| el -> List.iter (iter_snd (sub.expr sub)) el
545545

546+
let iter_modes_exp sub : Modes.expression -> _ = function
547+
| Coerce (modes, expr) ->
548+
sub.modes sub modes;
549+
sub.expr sub expr
550+
546551
let iter_jst sub : Jane_syntax.Expression.t -> _ = function
547552
| Jexp_comprehension comp_exp -> iter_comp_exp sub comp_exp
548553
| Jexp_immutable_array iarr_exp -> iter_iarr_exp sub iarr_exp
549554
| Jexp_layout layout_exp -> iter_layout_exp sub layout_exp
550555
| Jexp_n_ary_function n_ary_exp -> iter_n_ary_function sub n_ary_exp
551556
| Jexp_tuple lt_exp -> iter_labeled_tuple sub lt_exp
552-
553-
let iter_mode sub modes expr =
554-
sub.modes sub modes;
555-
sub.expr sub expr
557+
| Jexp_modes mode_exp -> iter_modes_exp sub mode_exp
556558

557559
let iter sub
558560
({pexp_loc = loc; pexp_desc = desc; pexp_attributes = attrs} as expr)=
559561
sub.location sub loc;
560-
match Jane_syntax.Mode_expr.coerce_of_expr expr with
561-
| Some (modes, e) ->
562-
sub.expr_mode_syntax sub modes e
563-
| None ->
564562
match Jane_syntax.Expression.of_ast expr with
565563
| Some (jexp, attrs) ->
566564
sub.attributes sub attrs;
@@ -827,7 +825,6 @@ let default_iterator =
827825
pat_mode_syntax = P.iter_mode;
828826
expr = E.iter;
829827
expr_jane_syntax = E.iter_jst;
830-
expr_mode_syntax = E.iter_mode;
831828
binding_op = E.iter_binding_op;
832829

833830
module_declaration =

ocaml/parsing/ast_iterator.mli

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ type iterator = {
4646
constructor_declaration: iterator -> constructor_declaration -> unit;
4747
expr: iterator -> expression -> unit;
4848
expr_jane_syntax : iterator -> Jane_syntax.Expression.t -> unit;
49-
expr_mode_syntax: iterator -> Jane_syntax.Mode_expr.t -> expression -> unit;
5049
extension: iterator -> extension -> unit;
5150
extension_constructor: iterator -> extension_constructor -> unit;
5251
include_declaration: iterator -> include_declaration -> unit;

ocaml/parsing/ast_mapper.ml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,18 @@ let map_loc sub {loc; txt} = {loc = sub.location sub loc; txt}
105105
let map_loc_txt sub f {loc; txt} =
106106
{loc = sub.location sub loc; txt = f sub txt}
107107

108+
let map_mode_expr sub (mode_expr : Jane_syntax.Mode_expr.t)
109+
: Jane_syntax.Mode_expr.t =
110+
map_loc_txt sub
111+
(fun sub modes ->
112+
List.map
113+
(fun (mode : Jane_syntax.Mode_expr.Const.t) ->
114+
let { loc; txt } = (mode :> string loc) in
115+
let loc = sub.location sub loc in
116+
Jane_syntax.Mode_expr.Const.mk txt loc)
117+
modes)
118+
mode_expr
119+
108120
module C = struct
109121
(* Constants *)
110122

@@ -536,6 +548,7 @@ module E = struct
536548
module L = Jane_syntax.Layouts
537549
module N_ary = Jane_syntax.N_ary_functions
538550
module LT = Jane_syntax.Labeled_tuples
551+
module Modes = Jane_syntax.Modes
539552

540553
let map_iterator sub : C.iterator -> C.iterator = function
541554
| Range { start; stop; direction } ->
@@ -629,13 +642,19 @@ module E = struct
629642
(* CR labeled tuples: Eventually mappers may want to see the labels. *)
630643
| el -> List.map (map_snd (sub.expr sub)) el
631644

645+
let map_modes_exp sub : Modes.expression -> Modes.expression = function
646+
(* CR modes: One day mappers might want to see the modes *)
647+
| Coerce (modes, exp) ->
648+
Coerce (map_mode_expr sub modes, sub.expr sub exp)
649+
632650
let map_jst sub : Jane_syntax.Expression.t -> Jane_syntax.Expression.t =
633651
function
634652
| Jexp_comprehension x -> Jexp_comprehension (map_cexp sub x)
635653
| Jexp_immutable_array x -> Jexp_immutable_array (map_iaexp sub x)
636654
| Jexp_layout x -> Jexp_layout (map_layout_exp sub x)
637655
| Jexp_n_ary_function x -> Jexp_n_ary_function (map_n_ary_exp sub x)
638656
| Jexp_tuple ltexp -> Jexp_tuple (map_ltexp sub ltexp)
657+
| Jexp_modes mode_exp -> Jexp_modes (map_modes_exp sub mode_exp)
639658

640659
let map sub
641660
({pexp_loc = loc; pexp_desc = desc; pexp_attributes = attrs} as exp) =

ocaml/parsing/depend.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,11 @@ and add_expr_jane_syntax bv : Jane_syntax.Expression.t -> _ = function
332332
| Jexp_layout x -> add_layout_expr bv x
333333
| Jexp_n_ary_function n_ary -> add_n_ary_function bv n_ary
334334
| Jexp_tuple x -> add_labeled_tuple_expr bv x
335+
| Jexp_modes x -> add_modes_expr bv x
336+
337+
and add_modes_expr bv : Jane_syntax.Modes.expression -> _ =
338+
function
339+
| Coerce (_modes, exp) -> add_expr bv exp
335340

336341
and add_comprehension_expr bv : Jane_syntax.Comprehensions.expression -> _ =
337342
function

ocaml/parsing/jane_syntax.ml

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,6 @@ module Mode_expr = struct
459459

460460
let attribute_name = attribute_or_extension_name
461461

462-
let extension_name = attribute_or_extension_name
463-
464462
let payload_of { txt; _ } =
465463
match txt with
466464
| [] -> None
@@ -508,26 +506,38 @@ module Mode_expr = struct
508506
let loc = { loc with loc_ghost = true } in
509507
let txt = List.map Const.ghostify txt in
510508
{ loc; txt }
509+
end
510+
511+
(** Some mode-related constructs *)
512+
module Modes = struct
513+
let feature : Feature.t = Language_extension Mode
514+
515+
type nonrec expression = Coerce of Mode_expr.t * expression
511516

512-
let coerce_of_expr { pexp_desc; _ } =
517+
let extension_name = Mode_expr.attribute_or_extension_name
518+
519+
let of_expr ({ pexp_desc; pexp_attributes; _ } as expr) =
513520
match pexp_desc with
514521
| Pexp_apply
515522
( { pexp_desc = Pexp_extension ({ txt; _ }, payload); pexp_loc; _ },
516523
[(Nolabel, body)] )
517524
when txt = extension_name ->
518-
let modes = of_payload ~loc:pexp_loc payload in
519-
Some (modes, body)
520-
| _ -> None
521-
522-
let expr_of_coerce ~loc modes body =
523-
match payload_of modes with
525+
let modes = Mode_expr.of_payload ~loc:pexp_loc payload in
526+
Coerce (modes, body), pexp_attributes
527+
| _ ->
528+
Misc.fatal_errorf "Improperly encoded modes expression: %a"
529+
(Printast.expression 0) expr
530+
531+
let expr_of ~loc (Coerce (modes, body)) =
532+
match Mode_expr.payload_of modes with
524533
| None -> body
525534
| Some payload ->
526535
let ext =
527536
Ast_helper.Exp.extension ~loc:modes.loc
528537
(Location.mknoloc extension_name, payload)
529538
in
530-
Ast_helper.Exp.apply ~loc ext [Nolabel, body]
539+
Expression.make_entire_jane_syntax ~loc feature (fun () ->
540+
Ast_helper.Exp.apply ~loc ext [Nolabel, body])
531541
end
532542

533543
(** List and array comprehensions *)
@@ -1911,6 +1921,7 @@ module Expression = struct
19111921
| Jexp_layout of Layouts.expression
19121922
| Jexp_n_ary_function of N_ary_functions.expression
19131923
| Jexp_tuple of Labeled_tuples.expression
1924+
| Jexp_modes of Modes.expression
19141925

19151926
let of_ast_internal (feat : Feature.t) expr =
19161927
match feat with
@@ -1930,6 +1941,9 @@ module Expression = struct
19301941
| Language_extension Labeled_tuples ->
19311942
let expr, attrs = Labeled_tuples.of_expr expr in
19321943
Some (Jexp_tuple expr, attrs)
1944+
| Language_extension Mode ->
1945+
let expr, attrs = Modes.of_expr expr in
1946+
Some (Jexp_modes expr, attrs)
19331947
| _ -> None
19341948

19351949
let of_ast = Expression.make_of_ast ~of_ast_internal
@@ -1942,6 +1956,7 @@ module Expression = struct
19421956
| Jexp_layout x -> Layouts.expr_of ~loc x
19431957
| Jexp_n_ary_function x -> N_ary_functions.expr_of ~loc x
19441958
| Jexp_tuple x -> Labeled_tuples.expr_of ~loc x
1959+
| Jexp_modes x -> Modes.expr_of ~loc x
19451960
in
19461961
(* Performance hack: save an allocation if [attrs] is empty. *)
19471962
match attrs with

ocaml/parsing/jane_syntax.mli

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,20 +159,27 @@ module Mode_expr : sig
159159
attribute is found. *)
160160
val of_attrs : Parsetree.attributes -> t * Parsetree.attributes
161161

162-
(** Decode mode coercion and returns the mode and the body.
163-
For example, return [Some (local, expr)] on input [local_ expr].
164-
Returns [None] if the given expression is not a mode coercion. *)
165-
val coerce_of_expr : Parsetree.expression -> (t * Parsetree.expression) option
166-
167-
(** Encode a mode coercion like [local_ expr] into an expression *)
168-
val expr_of_coerce :
169-
loc:Location.t -> t -> Parsetree.expression -> Parsetree.expression
170-
171162
(** In some cases, a single mode expression appears twice in the parsetree;
172163
one of them needs to be made ghost to make our internal tools happy. *)
173164
val ghostify : t -> t
174165
end
175166

167+
(** A subset of the mode-related syntax extensions that is embedded
168+
using full-blown Jane Syntax. By "full-blown" Jane Syntax, we
169+
mean the [Expression], [Pattern], (etc.) modules below that
170+
attempt to create a variant of all possible Jane Street syntax
171+
for the syntactic form.
172+
173+
We avoid full-blown Jane Syntax when it isn't very lightweight to fit the
174+
new construct into the (somewhat opinionated) framework. Mode coercions are
175+
lightweight to fit into full-blown Jane Syntax.
176+
*)
177+
module Modes : sig
178+
type expression = Coerce of Mode_expr.t * Parsetree.expression
179+
180+
val expr_of : loc:Location.t -> expression -> Parsetree.expression
181+
end
182+
176183
module N_ary_functions : sig
177184
(** These types use the [P] prefix to match how they are represented in the
178185
upstream compiler *)
@@ -586,6 +593,7 @@ module Expression : sig
586593
| Jexp_layout of Layouts.expression
587594
| Jexp_n_ary_function of N_ary_functions.expression
588595
| Jexp_tuple of Labeled_tuples.expression
596+
| Jexp_modes of Modes.expression
589597

590598
include
591599
AST

ocaml/parsing/parser.mly

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ let mkexp_with_modes ?(ghost=false) ~loc modes exp =
154154
let loc =
155155
if ghost then ghost_loc loc else make_loc loc
156156
in
157-
Mode.expr_of_coerce ~loc modes exp
157+
Jane_syntax.Modes.expr_of ~loc (Coerce (modes, exp))
158158

159159
(* For modes-related attributes, no need to call [register_attr] because they
160160
result from native syntax which is only parsed at proper places that are

ocaml/parsing/pprintast.ml

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -788,10 +788,6 @@ and sugar_expr ctxt f e =
788788
expressions that aren't already self-delimiting.
789789
*)
790790
and expression ?(jane_syntax_parens = false) ctxt f x =
791-
match Jane_syntax.Mode_expr.coerce_of_expr x with
792-
| Some (m, body) ->
793-
pp f "@[<2>%s %a@]" (modes m) (expression ctxt) body
794-
| None ->
795791
match Jane_syntax.Expression.of_ast x with
796792
| Some (jexpr, attrs) ->
797793
jane_syntax_expr ctxt attrs f jexpr ~parens:jane_syntax_parens
@@ -1484,9 +1480,6 @@ and payload ctxt f = function
14841480
pp f " when "; expression ctxt f e
14851481

14861482
and pp_print_pexp_function ctxt sep f x =
1487-
(* do not print [@jane.erasable.mode] on expressions *)
1488-
let _, attrs = maybe_modes_of_attrs x.pexp_attributes in
1489-
let x = { x with pexp_attributes = attrs } in
14901483
(* We go to some trouble to print nested [Pexp_newtype]/[Lexp_newtype] as
14911484
newtype parameters of the same "fun" (rather than printing several nested
14921485
"fun (type a) -> ..."). This isn't necessary for round-tripping -- it just
@@ -1586,15 +1579,35 @@ and binding ctxt f {pvb_pat=p; pvb_expr=x; pvb_constraint = ct; _} =
15861579
(* [in] is not printed *)
15871580
and bindings ctxt f (rf,l) =
15881581
let binding kwd rf f x =
1589-
let modes, attrs = maybe_modes_of_attrs x.pvb_attributes in
1582+
let modes_on_binding, attrs =
1583+
Jane_syntax.Mode_expr.maybe_of_attrs x.pvb_attributes
1584+
in
15901585
let x =
1591-
match modes, Jane_syntax.Mode_expr.coerce_of_expr x.pvb_expr with
1592-
| Some _ , Some (_, sbody) ->
1593-
{x with pvb_expr = sbody}
1586+
(* For [let local_ x = e in ...] and [let x @ local = e in ...],
1587+
the parser puts attributes on both the let-binding and on e.
1588+
1589+
The below code is meant to print the modes only in one place,
1590+
not both. (We print it on the let-binding, not the expression.)
1591+
*)
1592+
match modes_on_binding, Jane_syntax.Expression.of_ast x.pvb_expr with
1593+
| Some modes_on_binding,
1594+
Some (Jexp_modes (Coerce (modes_on_expr, sbody)), _) ->
1595+
(* Sanity check: only suppress the printing of one mode expression if
1596+
the mode expressions are in fact identical.
1597+
*)
1598+
let mode_names (modes : Jane_syntax.Mode_expr.t) =
1599+
List.map Location.get_txt (modes.txt :> string loc list)
1600+
in
1601+
if
1602+
List.equal String.equal
1603+
(mode_names modes_on_binding)
1604+
(mode_names modes_on_expr)
1605+
then {x with pvb_expr = sbody}
1606+
else x
15941607
| _ -> x
15951608
in
15961609
pp f "@[<2>%s %a%s%a@]%a" kwd rec_flag rf
1597-
(match modes with Some s -> s ^ " " | None -> "")
1610+
(match modes_on_binding with Some s -> modes s ^ " " | None -> "")
15981611
(binding ctxt) x (item_attributes ctxt) attrs
15991612
in
16001613
match l with
@@ -2006,6 +2019,11 @@ and jane_syntax_expr ctxt attrs f (jexp : Jane_syntax.Expression.t) ~parens =
20062019
if parens then pp f "(%a)" (n_ary_function_expr reset_ctxt) x
20072020
else n_ary_function_expr ctxt f x
20082021
| Jexp_tuple ltexp -> labeled_tuple_expr ctxt f ltexp
2022+
| Jexp_modes mexp -> mode_expr ctxt f mexp
2023+
2024+
and mode_expr ctxt f (mexp : Jane_syntax.Modes.expression) =
2025+
match mexp with
2026+
| Coerce (m, body) -> pp f "@[<2>%s %a@]" (modes m) (expression ctxt) body
20092027

20102028
and comprehension_expr ctxt f (cexp : Jane_syntax.Comprehensions.expression) =
20112029
let punct, comp = match cexp with

0 commit comments

Comments
 (0)