Skip to content

Commit 43f90e9

Browse files
committed
Local let exceptions.
1 parent 8a4837e commit 43f90e9

28 files changed

+209
-53
lines changed

.depend

+18-16
Original file line numberDiff line numberDiff line change
@@ -347,23 +347,25 @@ typing/typeclass.cmi : typing/types.cmi typing/typedtree.cmi \
347347
parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
348348
typing/ident.cmi typing/env.cmi typing/ctype.cmi parsing/asttypes.cmi
349349
typing/typecore.cmo : utils/warnings.cmi typing/typetexp.cmi \
350-
typing/types.cmi typing/typedtree.cmi typing/subst.cmi typing/stypes.cmi \
351-
typing/printtyp.cmi typing/primitive.cmi typing/predef.cmi \
352-
typing/path.cmi parsing/parsetree.cmi typing/parmatch.cmi \
353-
typing/oprint.cmi utils/misc.cmi parsing/longident.cmi \
354-
parsing/location.cmi typing/ident.cmi typing/env.cmi typing/ctype.cmi \
355-
typing/cmt_format.cmi utils/clflags.cmi parsing/builtin_attributes.cmi \
356-
typing/btype.cmi parsing/asttypes.cmi parsing/ast_helper.cmi \
357-
typing/annot.cmi typing/typecore.cmi
350+
typing/types.cmi typing/typedtree.cmi typing/typedecl.cmi \
351+
typing/subst.cmi typing/stypes.cmi typing/printtyp.cmi \
352+
typing/primitive.cmi typing/predef.cmi typing/path.cmi \
353+
parsing/parsetree.cmi typing/parmatch.cmi typing/oprint.cmi \
354+
utils/misc.cmi parsing/longident.cmi parsing/location.cmi \
355+
typing/ident.cmi typing/env.cmi typing/ctype.cmi typing/cmt_format.cmi \
356+
utils/clflags.cmi parsing/builtin_attributes.cmi typing/btype.cmi \
357+
parsing/asttypes.cmi parsing/ast_helper.cmi typing/annot.cmi \
358+
typing/typecore.cmi
358359
typing/typecore.cmx : utils/warnings.cmx typing/typetexp.cmx \
359-
typing/types.cmx typing/typedtree.cmx typing/subst.cmx typing/stypes.cmx \
360-
typing/printtyp.cmx typing/primitive.cmx typing/predef.cmx \
361-
typing/path.cmx parsing/parsetree.cmi typing/parmatch.cmx \
362-
typing/oprint.cmx utils/misc.cmx parsing/longident.cmx \
363-
parsing/location.cmx typing/ident.cmx typing/env.cmx typing/ctype.cmx \
364-
typing/cmt_format.cmx utils/clflags.cmx parsing/builtin_attributes.cmx \
365-
typing/btype.cmx parsing/asttypes.cmi parsing/ast_helper.cmx \
366-
typing/annot.cmi typing/typecore.cmi
360+
typing/types.cmx typing/typedtree.cmx typing/typedecl.cmx \
361+
typing/subst.cmx typing/stypes.cmx typing/printtyp.cmx \
362+
typing/primitive.cmx typing/predef.cmx typing/path.cmx \
363+
parsing/parsetree.cmi typing/parmatch.cmx typing/oprint.cmx \
364+
utils/misc.cmx parsing/longident.cmx parsing/location.cmx \
365+
typing/ident.cmx typing/env.cmx typing/ctype.cmx typing/cmt_format.cmx \
366+
utils/clflags.cmx parsing/builtin_attributes.cmx typing/btype.cmx \
367+
parsing/asttypes.cmi parsing/ast_helper.cmx typing/annot.cmi \
368+
typing/typecore.cmi
367369
typing/typecore.cmi : typing/types.cmi typing/typedtree.cmi typing/path.cmi \
368370
parsing/parsetree.cmi parsing/longident.cmi parsing/location.cmi \
369371
typing/ident.cmi typing/env.cmi parsing/asttypes.cmi typing/annot.cmi

Changes

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ OCaml 4.04.0:
33

44
(Changes that can break existing programs are marked with a "*")
55

6+
Language features:
7+
- GPR#301: local exception declarations "let exception ... in"
8+
(Alain Frisch)
9+
610
Tools:
711
- GPR#452: Make the output of ocamldep is more stable (Alain Frisch)
812

Makefile.shared

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ TYPING=typing/ident.cmo typing/path.cmo \
6666
typing/tast_mapper.cmo \
6767
typing/cmt_format.cmo typing/untypeast.cmo \
6868
typing/includemod.cmo typing/typetexp.cmo typing/parmatch.cmo \
69-
typing/stypes.cmo typing/typecore.cmo \
70-
typing/typedecl.cmo typing/typeclass.cmo \
69+
typing/stypes.cmo typing/typedecl.cmo typing/typecore.cmo \
70+
typing/typeclass.cmo \
7171
typing/typemod.cmo
7272

7373
COMP=bytecomp/lambda.cmo bytecomp/printlambda.cmo \

bytecomp/translcore.ml

+23
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,26 @@ let transl_object =
4444
ref (fun id s cl -> assert false :
4545
Ident.t -> string list -> class_expr -> lambda)
4646

47+
(* Compile an exception/extension definition *)
48+
49+
let prim_fresh_oo_id =
50+
Pccall (Primitive.simple ~name:"caml_fresh_oo_id" ~arity:1 ~alloc:false)
51+
52+
let transl_extension_constructor env path ext =
53+
let name =
54+
match path, !Clflags.for_package with
55+
None, _ -> Ident.name ext.ext_id
56+
| Some p, None -> Path.name p
57+
| Some p, Some pack -> Printf.sprintf "%s.%s" pack (Path.name p)
58+
in
59+
match ext.ext_kind with
60+
Text_decl(args, ret) ->
61+
Lprim (Pmakeblock (Obj.object_tag, Immutable),
62+
[Lconst (Const_base (Const_string (name, None)));
63+
Lprim (prim_fresh_oo_id, [Lconst (Const_base (Const_int 0))])])
64+
| Text_rebind(path, lid) ->
65+
transl_path ~loc:ext.ext_loc env path
66+
4767
(* Translation of primitives *)
4868

4969
let comparisons_table = create_hashtable 11 [
@@ -957,6 +977,9 @@ and transl_exp0 e =
957977
(Lvar cpy))
958978
| Texp_letmodule(id, _, modl, body) ->
959979
Llet(Strict, id, !transl_module Tcoerce_none None modl, transl_exp body)
980+
| Texp_letexception(cd, body) ->
981+
Llet(Strict, cd.ext_id, transl_extension_constructor e.exp_env None cd,
982+
transl_exp body)
960983
| Texp_pack modl ->
961984
!transl_module Tcoerce_none None modl
962985
| Texp_assert {exp_desc=Texp_construct(_, {cstr_name="false"}, _)} ->

bytecomp/translcore.mli

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ val transl_let: rec_flag -> value_binding list -> lambda -> lambda
3030
val transl_primitive: Location.t -> Primitive.description -> Env.t
3131
-> Types.type_expr -> Path.t option -> lambda
3232

33+
val transl_extension_constructor: Env.t -> Path.t option ->
34+
extension_constructor -> lambda
35+
3336
val check_recursive_lambda: Ident.t list -> lambda -> bool
3437

3538
val used_primitives: (Path.t, Location.t) Hashtbl.t

bytecomp/translmod.ml

-18
Original file line numberDiff line numberDiff line change
@@ -48,24 +48,6 @@ let field_path path field =
4848

4949
(* Compile type extensions *)
5050

51-
let prim_fresh_oo_id =
52-
Pccall (Primitive.simple ~name:"caml_fresh_oo_id" ~arity:1 ~alloc:false)
53-
54-
let transl_extension_constructor env path ext =
55-
let name =
56-
match path, !Clflags.for_package with
57-
None, _ -> Ident.name ext.ext_id
58-
| Some p, None -> Path.name p
59-
| Some p, Some pack -> Printf.sprintf "%s.%s" pack (Path.name p)
60-
in
61-
match ext.ext_kind with
62-
Text_decl(args, ret) ->
63-
Lprim (Pmakeblock (Obj.object_tag, Immutable),
64-
[Lconst (Const_base (Const_string (name, None)));
65-
Lprim (prim_fresh_oo_id, [Lconst (Const_base (Const_int 0))])])
66-
| Text_rebind(path, lid) ->
67-
transl_path ~loc:ext.ext_loc env path
68-
6951
let transl_type_extension env rootpath tyext body =
7052
List.fold_right
7153
(fun ext body ->

manual/manual/refman/exten.etex

+23-1
Original file line numberDiff line numberDiff line change
@@ -1503,7 +1503,7 @@ typedef: ...
15031503
| typedef item-attribute
15041504
;
15051505
exception-definition:
1506-
'exception' constr-name { attribute } [ 'of' typexpr { '*' typexpr } ]
1506+
'exception' constr-decl
15071507
| 'exception' constr-name '=' constr
15081508
;
15091509
module-items:
@@ -2096,3 +2096,25 @@ let invalid = function
20962096
| Point p -> p (* INVALID *)
20972097
| ...
20982098
\end{verbatim}
2099+
2100+
2101+
\section{Local exceptions}
2102+
\ikwd{let\@\texttt{let}}
2103+
\ikwd{exception\@\texttt{exception}}
2104+
2105+
(Introduced in OCaml 4.04)
2106+
2107+
It is possible to define local exceptions in expressions:
2108+
2109+
\begin{syntax}
2110+
expr:
2111+
...
2112+
| "let" "exception" constr-decl "in" expr
2113+
\end{syntax}
2114+
2115+
2116+
The syntactic scope of the exception constructor is the inner
2117+
expression, but nothing prevents exception values created with this
2118+
constructor from escaping this scope. Two executions of the definition
2119+
above result in two incompatible exception constructors (as for any
2120+
exception definition).

manual/manual/refman/typedecl.etex

+2-2
Original file line numberDiff line numberDiff line change
@@ -201,15 +201,15 @@ appear in the type equation and the type declaration.
201201

202202
\begin{syntax}
203203
exception-definition:
204-
'exception' constr-name [ 'of' typexpr { '*' typexpr } ]
204+
'exception' constr-decl
205205
| 'exception' constr-name '=' constr
206206
\end{syntax}
207207

208208
Exception definitions add new constructors to the built-in variant
209209
type \verb"exn" of exception values. The constructors are declared as
210210
for a definition of a variant type.
211211

212-
The form @'exception' constr-name ['of' typexpr {'*' typexpr}]@
212+
The form @'exception' constr-decl@
213213
generates a new exception, distinct from all other exceptions in the system.
214214
The form @'exception' constr-name '=' constr@
215215
gives an alternate name to an existing exception.

parsing/ast_helper.ml

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ module Exp = struct
122122
let setinstvar ?loc ?attrs a b = mk ?loc ?attrs (Pexp_setinstvar (a, b))
123123
let override ?loc ?attrs a = mk ?loc ?attrs (Pexp_override a)
124124
let letmodule ?loc ?attrs a b c= mk ?loc ?attrs (Pexp_letmodule (a, b, c))
125+
let letexception ?loc ?attrs a b = mk ?loc ?attrs (Pexp_letexception (a, b))
125126
let assert_ ?loc ?attrs a = mk ?loc ?attrs (Pexp_assert a)
126127
let lazy_ ?loc ?attrs a = mk ?loc ?attrs (Pexp_lazy a)
127128
let poly ?loc ?attrs a b = mk ?loc ?attrs (Pexp_poly (a, b))

parsing/ast_helper.mli

+2
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ module Exp:
149149
-> expression
150150
val letmodule: ?loc:loc -> ?attrs:attrs -> str -> module_expr -> expression
151151
-> expression
152+
val letexception: ?loc:loc -> ?attrs:attrs -> extension_constructor -> expression
153+
-> expression
152154
val assert_: ?loc:loc -> ?attrs:attrs -> expression -> expression
153155
val lazy_: ?loc:loc -> ?attrs:attrs -> expression -> expression
154156
val poly: ?loc:loc -> ?attrs:attrs -> expression -> core_type option

parsing/ast_iterator.ml

+3
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ module E = struct
355355
| Pexp_letmodule (s, me, e) ->
356356
iter_loc sub s; sub.module_expr sub me;
357357
sub.expr sub e
358+
| Pexp_letexception (cd, e) ->
359+
sub.extension_constructor sub cd;
360+
sub.expr sub e
358361
| Pexp_assert e -> sub.expr sub e
359362
| Pexp_lazy e -> sub.expr sub e
360363
| Pexp_poly (e, t) ->

parsing/ast_mapper.ml

+4
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@ module E = struct
370370
| Pexp_letmodule (s, me, e) ->
371371
letmodule ~loc ~attrs (map_loc sub s) (sub.module_expr sub me)
372372
(sub.expr sub e)
373+
| Pexp_letexception (cd, e) ->
374+
letexception ~loc ~attrs
375+
(sub.extension_constructor sub cd)
376+
(sub.expr sub e)
373377
| Pexp_assert e -> assert_ ~loc ~attrs (sub.expr sub e)
374378
| Pexp_lazy e -> lazy_ ~loc ~attrs (sub.expr sub e)
375379
| Pexp_poly (e, t) ->

parsing/parser.mly

+49-13
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,15 @@ expr:
13541354
{ expr_of_let_bindings $1 $3 }
13551355
| LET MODULE ext_attributes UIDENT module_binding_body IN seq_expr
13561356
{ mkexp_attrs (Pexp_letmodule(mkrhs $4 4, $5, $7)) $3 }
1357+
| LET EXCEPTION ext_attributes constr_ident generalized_constructor_arguments
1358+
attributes IN seq_expr
1359+
{ let args, res = $5 in
1360+
let ex =
1361+
Te.decl (mkrhs $4 4) ~args ?res ~attrs:$6
1362+
~loc:(symbol_rloc())
1363+
in
1364+
mkexp_attrs (Pexp_letexception(ex, $8)) $3
1365+
}
13571366
| LET OPEN override_flag ext_attributes mod_longident IN seq_expr
13581367
{ mkexp_attrs (Pexp_open($3, mkrhs $5 5, $7)) $4 }
13591368
| FUNCTION ext_attributes opt_bar match_cases
@@ -1616,7 +1625,7 @@ let_binding_body:
16161625
| val_ident COLON TYPE lident_list DOT core_type EQUAL seq_expr
16171626
{ let exp, poly = wrap_type_annotation $4 $6 $8 in
16181627
(ghpat(Ppat_constraint(mkpatvar $1 1, poly)), exp) }
1619-
| pattern EQUAL seq_expr
1628+
| pattern_no_exn EQUAL seq_expr
16201629
{ ($1, $3) }
16211630
| simple_pattern_not_ident COLON core_type EQUAL seq_expr
16221631
{ (ghpat(Ppat_constraint($1, $3)), $5) }
@@ -1722,36 +1731,58 @@ opt_type_constraint:
17221731
/* Patterns */
17231732
17241733
pattern:
1725-
simple_pattern
1726-
{ $1 }
17271734
| pattern AS val_ident
17281735
{ mkpat(Ppat_alias($1, mkrhs $3 3)) }
17291736
| pattern AS error
17301737
{ expecting 3 "identifier" }
17311738
| pattern_comma_list %prec below_COMMA
17321739
{ mkpat(Ppat_tuple(List.rev $1)) }
1733-
| constr_longident pattern %prec prec_constr_appl
1734-
{ mkpat(Ppat_construct(mkrhs $1 1, Some $2)) }
1735-
| name_tag pattern %prec prec_constr_appl
1736-
{ mkpat(Ppat_variant($1, Some $2)) }
17371740
| pattern COLONCOLON pattern
17381741
{ mkpat_cons (rhs_loc 2) (ghpat(Ppat_tuple[$1;$3])) (symbol_rloc()) }
17391742
| pattern COLONCOLON error
17401743
{ expecting 3 "pattern" }
1741-
| LPAREN COLONCOLON RPAREN LPAREN pattern COMMA pattern RPAREN
1742-
{ mkpat_cons (rhs_loc 2) (ghpat(Ppat_tuple[$5;$7])) (symbol_rloc()) }
1743-
| LPAREN COLONCOLON RPAREN LPAREN pattern COMMA pattern error
1744-
{ unclosed "(" 4 ")" 8 }
17451744
| pattern BAR pattern
17461745
{ mkpat(Ppat_or($1, $3)) }
17471746
| pattern BAR error
17481747
{ expecting 3 "pattern" }
1749-
| LAZY ext_attributes simple_pattern
1750-
{ mkpat_attrs (Ppat_lazy $3) $2}
17511748
| EXCEPTION ext_attributes pattern %prec prec_constr_appl
17521749
{ mkpat_attrs (Ppat_exception $3) $2}
17531750
| pattern attribute
17541751
{ Pat.attr $1 $2 }
1752+
| pattern_gen { $1 }
1753+
;
1754+
pattern_no_exn:
1755+
| pattern_no_exn AS val_ident
1756+
{ mkpat(Ppat_alias($1, mkrhs $3 3)) }
1757+
| pattern_no_exn AS error
1758+
{ expecting 3 "identifier" }
1759+
| pattern_no_exn_comma_list %prec below_COMMA
1760+
{ mkpat(Ppat_tuple(List.rev $1)) }
1761+
| pattern_no_exn COLONCOLON pattern
1762+
{ mkpat_cons (rhs_loc 2) (ghpat(Ppat_tuple[$1;$3])) (symbol_rloc()) }
1763+
| pattern_no_exn COLONCOLON error
1764+
{ expecting 3 "pattern" }
1765+
| pattern_no_exn BAR pattern
1766+
{ mkpat(Ppat_or($1, $3)) }
1767+
| pattern_no_exn BAR error
1768+
{ expecting 3 "pattern" }
1769+
| pattern_no_exn attribute
1770+
{ Pat.attr $1 $2 }
1771+
| pattern_gen { $1 }
1772+
;
1773+
pattern_gen:
1774+
simple_pattern
1775+
{ $1 }
1776+
| constr_longident pattern %prec prec_constr_appl
1777+
{ mkpat(Ppat_construct(mkrhs $1 1, Some $2)) }
1778+
| name_tag pattern %prec prec_constr_appl
1779+
{ mkpat(Ppat_variant($1, Some $2)) }
1780+
| LPAREN COLONCOLON RPAREN LPAREN pattern COMMA pattern RPAREN
1781+
{ mkpat_cons (rhs_loc 2) (ghpat(Ppat_tuple[$5;$7])) (symbol_rloc()) }
1782+
| LPAREN COLONCOLON RPAREN LPAREN pattern COMMA pattern error
1783+
{ unclosed "(" 4 ")" 8 }
1784+
| LAZY ext_attributes simple_pattern
1785+
{ mkpat_attrs (Ppat_lazy $3) $2}
17551786
;
17561787
simple_pattern:
17571788
val_ident %prec below_EQUAL
@@ -1813,6 +1844,11 @@ pattern_comma_list:
18131844
| pattern COMMA pattern { [$3; $1] }
18141845
| pattern COMMA error { expecting 3 "pattern" }
18151846
;
1847+
pattern_no_exn_comma_list:
1848+
pattern_no_exn_comma_list COMMA pattern { $3 :: $1 }
1849+
| pattern_no_exn COMMA pattern { [$3; $1] }
1850+
| pattern_no_exn COMMA error { expecting 3 "pattern" }
1851+
;
18161852
pattern_semi_list:
18171853
pattern { [$1] }
18181854
| pattern_semi_list SEMI pattern { $3 :: $1 }

parsing/parsetree.mli

+2
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ and expression_desc =
318318
(* {< x1 = E1; ...; Xn = En >} *)
319319
| Pexp_letmodule of string loc * module_expr * expression
320320
(* let module M = ME in E *)
321+
| Pexp_letexception of extension_constructor * expression
322+
(* let exception C in E *)
321323
| Pexp_assert of expression
322324
(* assert E
323325
Note: "assert false" is treated in a special way by the

parsing/pprintast.ml

+5-1
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ class printer ()= object(self:'self)
475475
self#paren true self#reset#expression f x
476476
| Pexp_ifthenelse _ | Pexp_sequence _ when ifthenelse ->
477477
self#paren true self#reset#expression f x
478-
| Pexp_let _ | Pexp_letmodule _ when semi ->
478+
| Pexp_let _ | Pexp_letmodule _ | Pexp_letexception _ when semi ->
479479
self#paren true self#reset#expression f x
480480
| Pexp_fun (l, e0, p, e) ->
481481
pp f "@[<2>fun@;%a@;->@;%a@]"
@@ -571,6 +571,10 @@ class printer ()= object(self:'self)
571571
| Pexp_letmodule (s, me, e) ->
572572
pp f "@[<hov2>let@ module@ %s@ =@ %a@ in@ %a@]" s.txt
573573
self#reset#module_expr me self#expression e
574+
| Pexp_letexception (cd, e) ->
575+
pp f "@[<hov2>let@ exception@ %a@ in@ %a@]"
576+
self#extension_constructor cd
577+
self#expression e
574578
| Pexp_assert e ->
575579
pp f "@[<hov2>assert@ %a@]" self#simple_expr e
576580
| Pexp_lazy (e) ->

parsing/printast.ml

+4
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,10 @@ and expression i ppf x =
341341
line i ppf "Pexp_letmodule %a\n" fmt_string_loc s;
342342
module_expr i ppf me;
343343
expression i ppf e;
344+
| Pexp_letexception (cd, e) ->
345+
line i ppf "Pexp_letexception\n";
346+
extension_constructor i ppf cd;
347+
expression i ppf e;
344348
| Pexp_assert (e) ->
345349
line i ppf "Pexp_assert\n";
346350
expression i ppf e;

0 commit comments

Comments
 (0)