@@ -14,6 +14,8 @@ module LoopProgress = struct
14
14
| _ :: rest -> rest
15
15
end
16
16
17
+ type ('a, 'b) spreadInline = Spread of 'a | Inline of 'b
18
+
17
19
let mkLoc startLoc endLoc =
18
20
Location. {loc_start = startLoc; loc_end = endLoc; loc_ghost = false }
19
21
@@ -184,6 +186,7 @@ let taggedTemplateLiteralAttr =
184
186
(Location. mknoloc " res.taggedTemplate" , Parsetree. PStr [] )
185
187
186
188
let spreadAttr = (Location. mknoloc " res.spread" , Parsetree. PStr [] )
189
+ let dictAttr = (Location. mknoloc " res.dict" , Parsetree. PStr [] )
187
190
188
191
type argument = {
189
192
dotted : bool ;
@@ -233,6 +236,7 @@ let getClosingToken = function
233
236
| Lbrace -> Rbrace
234
237
| Lbracket -> Rbracket
235
238
| List -> Rbrace
239
+ | Dict -> Rbrace
236
240
| LessThan -> GreaterThan
237
241
| _ -> assert false
238
242
@@ -244,7 +248,7 @@ let rec goToClosing closingToken state =
244
248
| GreaterThan , GreaterThan ->
245
249
Parser. next state;
246
250
()
247
- | ((Token. Lbracket | Lparen | Lbrace | List | LessThan ) as t ), _ ->
251
+ | ((Token. Lbracket | Lparen | Lbrace | List | Dict | LessThan ) as t ), _ ->
248
252
Parser. next state;
249
253
goToClosing (getClosingToken t) state;
250
254
goToClosing closingToken state
@@ -1055,6 +1059,7 @@ let rec parsePattern ?(alias = true) ?(or_ = true) p =
1055
1059
ppat_attributes = attrs @ pat.Parsetree. ppat_attributes;
1056
1060
}))
1057
1061
| Lbracket -> parseArrayPattern ~attrs p
1062
+ (* | Dict -> parseDictPattern ~attrs p *)
1058
1063
| Lbrace -> parseRecordPattern ~attrs p
1059
1064
| Underscore ->
1060
1065
let endPos = p.endPos in
@@ -1921,6 +1926,9 @@ and parseAtomicExpr p =
1921
1926
| List ->
1922
1927
Parser. next p;
1923
1928
parseListExpr ~start Pos p
1929
+ | Dict ->
1930
+ Parser. next p;
1931
+ parseDictExpr ~start Pos p
1924
1932
| Module ->
1925
1933
Parser. next p;
1926
1934
parseFirstClassModuleExpr ~start Pos p
@@ -3876,6 +3884,18 @@ and parseSpreadExprRegionWithLoc p =
3876
3884
Some (false , parseConstrainedOrCoercedExpr p, startPos, p.prevEndPos)
3877
3885
| _ -> None
3878
3886
3887
+ and parseSpreadRecordExprRowWithStringKeyRegionWithLoc p =
3888
+ let startPos = p.Parser. prevEndPos in
3889
+ match p.Parser. token with
3890
+ | DotDotDot ->
3891
+ Parser. next p;
3892
+ let expr = parseConstrainedOrCoercedExpr p in
3893
+ Some (Spread expr, startPos, p.prevEndPos)
3894
+ | token when Grammar. isExprStart token ->
3895
+ parseRecordExprRowWithStringKey p
3896
+ |> Option. map (fun parsedRow -> (Inline parsedRow, startPos, p.prevEndPos))
3897
+ | _ -> None
3898
+
3879
3899
and parseListExpr ~startPos p =
3880
3900
let split_by_spread exprs =
3881
3901
List. fold_left
@@ -3920,6 +3940,105 @@ and parseListExpr ~startPos p =
3920
3940
loc))
3921
3941
[(Asttypes. Nolabel , Ast_helper.Exp. array ~loc listExprs)]
3922
3942
3943
+ and parseDictExpr ~startPos p =
3944
+ let makeDictRowTuples ~loc idExps =
3945
+ idExps
3946
+ |> List. map (fun ((id , exp ) : Ast_helper. lid * Parsetree. expression ) ->
3947
+ Ast_helper.Exp. tuple
3948
+ [
3949
+ Ast_helper.Exp. constant ~loc: id.loc
3950
+ (Pconst_string (Longident. last id.txt, None ));
3951
+ exp;
3952
+ ])
3953
+ |> Ast_helper.Exp. array ~loc
3954
+ in
3955
+
3956
+ let makeSpreadDictRowTuples ~loc spreadDict =
3957
+ Ast_helper.Exp. apply ~loc
3958
+ (Ast_helper.Exp. ident ~loc ~attrs: [dictAttr]
3959
+ (Location. mkloc
3960
+ (Longident. Ldot
3961
+ (Longident. Ldot (Longident. Lident " Js" , " Dict" ), " entries" ))
3962
+ loc))
3963
+ [(Asttypes. Nolabel , spreadDict)]
3964
+ in
3965
+
3966
+ let concatManyExpr ~loc listExprs =
3967
+ Ast_helper.Exp. apply ~loc
3968
+ (Ast_helper.Exp. ident ~loc ~attrs: [spreadAttr]
3969
+ (Location. mkloc
3970
+ (Longident. Ldot
3971
+ (Longident. Ldot (Longident. Lident " Belt" , " Array" ), " concatMany" ))
3972
+ loc))
3973
+ [(Asttypes. Nolabel , Ast_helper.Exp. array ~loc listExprs)]
3974
+ in
3975
+
3976
+ let makeDictFromRowTuples ~loc arrayEntriesExp =
3977
+ Ast_helper.Exp. apply ~loc
3978
+ (Ast_helper.Exp. ident ~loc ~attrs: [dictAttr]
3979
+ (Location. mkloc
3980
+ (Longident. Ldot
3981
+ (Longident. Ldot (Longident. Lident " Js" , " Dict" ), " fromArray" ))
3982
+ loc))
3983
+ [(Asttypes. Nolabel , arrayEntriesExp)]
3984
+ in
3985
+ let split_by_spread exprs =
3986
+ List. fold_left
3987
+ (fun acc curr ->
3988
+ match (curr, acc) with
3989
+ | (Spread expr , startPos , endPos ), _ ->
3990
+ (* find a spread expression, prepend a new sublist *)
3991
+ ([] , Some expr, startPos, endPos) :: acc
3992
+ | ( (Inline fieldExprTuple, startPos, _endPos),
3993
+ (no_spreads, spread, _accStartPos, accEndPos) :: acc ) ->
3994
+ (* find a non-spread expression, and the accumulated is not empty,
3995
+ * prepend to the first sublist, and update the loc of the first sublist *)
3996
+ (fieldExprTuple :: no_spreads, spread, startPos, accEndPos) :: acc
3997
+ | (Inline fieldExprTuple , startPos , endPos ), [] ->
3998
+ (* find a non-spread expression, and the accumulated is empty *)
3999
+ [([fieldExprTuple], None , startPos, endPos)])
4000
+ [] exprs
4001
+ in
4002
+ let rec getListOfEntryArraysReversed ?(accum = [] ) ~loc spreadSplit =
4003
+ match spreadSplit with
4004
+ | [] -> accum
4005
+ | (idExps , None, _ , _ ) :: tail ->
4006
+ let accum = (idExps |> makeDictRowTuples ~loc ) :: accum in
4007
+ tail |> getListOfEntryArraysReversed ~loc ~accum
4008
+ | ([] , Some spread , _ , _ ) :: tail ->
4009
+ let accum = (spread |> makeSpreadDictRowTuples ~loc ) :: accum in
4010
+ tail |> getListOfEntryArraysReversed ~loc ~accum
4011
+ | (idExps , Some spread , _ , _ ) :: tail ->
4012
+ let accum =
4013
+ (spread |> makeSpreadDictRowTuples ~loc )
4014
+ :: (idExps |> makeDictRowTuples ~loc )
4015
+ :: accum
4016
+ in
4017
+ tail |> getListOfEntryArraysReversed ~loc ~accum
4018
+ in
4019
+
4020
+ let dictExprsRev =
4021
+ parseCommaDelimitedReversedList ~grammar: Grammar. RecordRowsStringKey
4022
+ ~closing: Rbrace ~f: parseSpreadRecordExprRowWithStringKeyRegionWithLoc p
4023
+ in
4024
+ Parser. expect Rbrace p;
4025
+ let loc = mkLoc startPos p.prevEndPos in
4026
+ let arrDictEntries =
4027
+ match
4028
+ dictExprsRev |> split_by_spread |> getListOfEntryArraysReversed ~loc
4029
+ with
4030
+ | [] -> Ast_helper.Exp. array ~loc []
4031
+ (* empty case*)
4032
+ (* TODO: Disallow empty dict? *)
4033
+ (* single case*)
4034
+ (* multiple case*)
4035
+ (* | [] -> makeDictKeyTuplesArray loc [] None *)
4036
+ | [singleArrDictEntries] -> singleArrDictEntries
4037
+ | multipleArrDictEntries ->
4038
+ multipleArrDictEntries |> List. rev |> concatManyExpr ~loc
4039
+ in
4040
+ makeDictFromRowTuples ~loc arrDictEntries
4041
+
3923
4042
(* Overparse ... and give a nice error message *)
3924
4043
and parseNonSpreadExp ~msg p =
3925
4044
let () =
0 commit comments