@@ -161,6 +161,15 @@ let jsxAttr = (Location.mknoloc "JSX", Parsetree.PStr [])
161
161
let uncurryAttr = (Location. mknoloc " bs" , Parsetree. PStr [] )
162
162
let ternaryAttr = (Location. mknoloc " ns.ternary" , Parsetree. PStr [] )
163
163
let ifLetAttr = (Location. mknoloc " ns.iflet" , Parsetree. PStr [] )
164
+ let optionalAttr = (Location. mknoloc " ns.optional" , Parsetree. PStr [] )
165
+
166
+ let makeExpressionOptional ~optional (e : Parsetree.expression ) =
167
+ if optional then {e with pexp_attributes = optionalAttr :: e .pexp_attributes}
168
+ else e
169
+ let makePatternOptional ~optional (p : Parsetree.pattern ) =
170
+ if optional then {p with ppat_attributes = optionalAttr :: p .ppat_attributes}
171
+ else p
172
+
164
173
let suppressFragileMatchWarningAttr =
165
174
( Location. mknoloc " warning" ,
166
175
Parsetree. PStr
@@ -1032,7 +1041,11 @@ let rec parsePattern ?(alias = true) ?(or_ = true) p =
1032
1041
| _ ->
1033
1042
Parser. expect Rparen p;
1034
1043
let loc = mkLoc startPos p.prevEndPos in
1035
- {pat with ppat_loc = loc}))
1044
+ {
1045
+ pat with
1046
+ ppat_loc = loc;
1047
+ ppat_attributes = attrs @ pat.Parsetree. ppat_attributes;
1048
+ }))
1036
1049
| Lbracket -> parseArrayPattern ~attrs p
1037
1050
| Lbrace -> parseRecordPattern ~attrs p
1038
1051
| Underscore ->
@@ -1196,6 +1209,13 @@ and parseConstrainedPatternRegion p =
1196
1209
| token when Grammar. isPatternStart token -> Some (parseConstrainedPattern p)
1197
1210
| _ -> None
1198
1211
1212
+ and parseOptionalLabel p =
1213
+ match p.Parser. token with
1214
+ | Question ->
1215
+ Parser. next p;
1216
+ true
1217
+ | _ -> false
1218
+
1199
1219
(* field ::=
1200
1220
* | longident
1201
1221
* | longident : pattern
@@ -1206,26 +1226,37 @@ and parseConstrainedPatternRegion p =
1206
1226
* | field , _
1207
1227
* | field , _,
1208
1228
*)
1209
- and parseRecordPatternField p =
1229
+ and parseRecordPatternRowField ~ attrs p =
1210
1230
let label = parseValuePath p in
1211
1231
let pattern =
1212
1232
match p.Parser. token with
1213
1233
| Colon ->
1214
1234
Parser. next p;
1215
- parsePattern p
1235
+ let optional = parseOptionalLabel p in
1236
+ let pat = parsePattern p in
1237
+ makePatternOptional ~optional pat
1216
1238
| _ ->
1217
- Ast_helper.Pat. var ~loc: label.loc
1239
+ Ast_helper.Pat. var ~loc: label.loc ~attrs
1218
1240
(Location. mkloc (Longident. last label.txt) label.loc)
1219
1241
in
1220
1242
(label, pattern)
1221
1243
1222
1244
(* TODO: there are better representations than PatField|Underscore ? *)
1223
- and parseRecordPatternItem p =
1245
+ and parseRecordPatternRow p =
1246
+ let attrs = parseAttributes p in
1224
1247
match p.Parser. token with
1225
1248
| DotDotDot ->
1226
1249
Parser. next p;
1227
- Some (true , PatField (parseRecordPatternField p))
1228
- | Uident _ | Lident _ -> Some (false , PatField (parseRecordPatternField p))
1250
+ Some (true , PatField (parseRecordPatternRowField ~attrs p))
1251
+ | Uident _ | Lident _ ->
1252
+ Some (false , PatField (parseRecordPatternRowField ~attrs p))
1253
+ | Question -> (
1254
+ Parser. next p;
1255
+ match p.token with
1256
+ | Uident _ | Lident _ ->
1257
+ let lid, pat = parseRecordPatternRowField ~attrs p in
1258
+ Some (false , PatField (lid, makePatternOptional ~optional: true pat))
1259
+ | _ -> None )
1229
1260
| Underscore ->
1230
1261
Parser. next p;
1231
1262
Some (false , PatUnderscore )
@@ -1236,7 +1267,7 @@ and parseRecordPattern ~attrs p =
1236
1267
Parser. expect Lbrace p;
1237
1268
let rawFields =
1238
1269
parseCommaDelimitedReversedList p ~grammar: PatternRecord ~closing: Rbrace
1239
- ~f: parseRecordPatternItem
1270
+ ~f: parseRecordPatternRow
1240
1271
in
1241
1272
Parser. expect Rbrace p;
1242
1273
let fields, closedFlag =
@@ -2735,6 +2766,10 @@ and parseBracedOrRecordExpr p =
2735
2766
let loc = mkLoc startPos p.prevEndPos in
2736
2767
let braces = makeBracesAttr loc in
2737
2768
{expr with pexp_attributes = braces :: expr .pexp_attributes}))
2769
+ | Question ->
2770
+ let expr = parseRecordExpr ~start Pos [] p in
2771
+ Parser. expect Rbrace p;
2772
+ expr
2738
2773
| Uident _ | Lident _ -> (
2739
2774
let startToken = p.token in
2740
2775
let valueOrConstructor = parseValueOrConstructor p in
@@ -2756,7 +2791,9 @@ and parseBracedOrRecordExpr p =
2756
2791
expr
2757
2792
| Colon -> (
2758
2793
Parser. next p;
2794
+ let optional = parseOptionalLabel p in
2759
2795
let fieldExpr = parseExpr p in
2796
+ let fieldExpr = makeExpressionOptional ~optional fieldExpr in
2760
2797
match p.token with
2761
2798
| Rbrace ->
2762
2799
Parser. next p;
@@ -2893,7 +2930,7 @@ and parseBracedOrRecordExpr p =
2893
2930
let braces = makeBracesAttr loc in
2894
2931
{expr with pexp_attributes = braces :: expr .pexp_attributes}
2895
2932
2896
- and parseRecordRowWithStringKey p =
2933
+ and parseRecordExprRowWithStringKey p =
2897
2934
match p.Parser. token with
2898
2935
| String s -> (
2899
2936
let loc = mkLoc p.startPos p.endPos in
@@ -2907,7 +2944,8 @@ and parseRecordRowWithStringKey p =
2907
2944
| _ -> Some (field, Ast_helper.Exp. ident ~loc: field.loc field))
2908
2945
| _ -> None
2909
2946
2910
- and parseRecordRow p =
2947
+ and parseRecordExprRow p =
2948
+ let attrs = parseAttributes p in
2911
2949
let () =
2912
2950
match p.Parser. token with
2913
2951
| Token. DotDotDot ->
@@ -2922,23 +2960,39 @@ and parseRecordRow p =
2922
2960
match p.Parser. token with
2923
2961
| Colon ->
2924
2962
Parser. next p;
2963
+ let optional = parseOptionalLabel p in
2925
2964
let fieldExpr = parseExpr p in
2965
+ let fieldExpr = makeExpressionOptional ~optional fieldExpr in
2926
2966
Some (field, fieldExpr)
2927
2967
| _ ->
2928
- let value = Ast_helper.Exp. ident ~loc: field.loc field in
2968
+ let value = Ast_helper.Exp. ident ~loc: field.loc ~attrs field in
2929
2969
let value =
2930
2970
match startToken with
2931
2971
| Uident _ -> removeModuleNameFromPunnedFieldValue value
2932
2972
| _ -> value
2933
2973
in
2934
2974
Some (field, value))
2975
+ | Question -> (
2976
+ Parser. next p;
2977
+ match p.Parser. token with
2978
+ | Lident _ | Uident _ ->
2979
+ let startToken = p.token in
2980
+ let field = parseValuePath p in
2981
+ let value = Ast_helper.Exp. ident ~loc: field.loc ~attrs field in
2982
+ let value =
2983
+ match startToken with
2984
+ | Uident _ -> removeModuleNameFromPunnedFieldValue value
2985
+ | _ -> value
2986
+ in
2987
+ Some (field, makeExpressionOptional ~optional: true value)
2988
+ | _ -> None )
2935
2989
| _ -> None
2936
2990
2937
2991
and parseRecordExprWithStringKeys ~startPos firstRow p =
2938
2992
let rows =
2939
2993
firstRow
2940
2994
:: parseCommaDelimitedRegion ~grammar: Grammar. RecordRowsStringKey
2941
- ~closing: Rbrace ~f: parseRecordRowWithStringKey p
2995
+ ~closing: Rbrace ~f: parseRecordExprRowWithStringKey p
2942
2996
in
2943
2997
let loc = mkLoc startPos p.endPos in
2944
2998
let recordStrExpr =
@@ -2950,7 +3004,7 @@ and parseRecordExprWithStringKeys ~startPos firstRow p =
2950
3004
and parseRecordExpr ~startPos ?(spread = None ) rows p =
2951
3005
let exprs =
2952
3006
parseCommaDelimitedRegion ~grammar: Grammar. RecordRows ~closing: Rbrace
2953
- ~f: parseRecordRow p
3007
+ ~f: parseRecordExprRow p
2954
3008
in
2955
3009
let rows = List. concat [rows; exprs] in
2956
3010
let () =
@@ -4224,15 +4278,19 @@ and parseFieldDeclarationRegion p =
4224
4278
| Lident _ ->
4225
4279
let lident, loc = parseLident p in
4226
4280
let name = Location. mkloc lident loc in
4281
+ let optional = parseOptionalLabel p in
4227
4282
let typ =
4228
4283
match p.Parser. token with
4229
4284
| Colon ->
4230
4285
Parser. next p;
4231
4286
parsePolyTypeExpr p
4232
4287
| _ ->
4233
- Ast_helper.Typ. constr ~loc: name.loc {name with txt = Lident name.txt} []
4288
+ Ast_helper.Typ. constr ~loc: name.loc ~attrs
4289
+ {name with txt = Lident name.txt}
4290
+ []
4234
4291
in
4235
4292
let loc = mkLoc startPos typ.ptyp_loc.loc_end in
4293
+ let attrs = if optional then optionalAttr :: attrs else attrs in
4236
4294
Some (Ast_helper.Type. field ~attrs ~loc ~mut name typ)
4237
4295
| _ -> None
4238
4296
0 commit comments