@@ -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
@@ -180,6 +182,7 @@ let taggedTemplateLiteralAttr =
180
182
(Location. mknoloc " res.taggedTemplate" , Parsetree. PStr [] )
181
183
182
184
let spreadAttr = (Location. mknoloc " res.spread" , Parsetree. PStr [] )
185
+ let dictAttr = (Location. mknoloc " res.dict" , Parsetree. PStr [] )
183
186
184
187
type argument = {
185
188
dotted : bool ;
@@ -229,6 +232,7 @@ let getClosingToken = function
229
232
| Lbrace -> Rbrace
230
233
| Lbracket -> Rbracket
231
234
| List -> Rbrace
235
+ | Dict -> Rbrace
232
236
| LessThan -> GreaterThan
233
237
| _ -> assert false
234
238
@@ -240,7 +244,7 @@ let rec goToClosing closingToken state =
240
244
| GreaterThan , GreaterThan ->
241
245
Parser. next state;
242
246
()
243
- | ((Token. Lbracket | Lparen | Lbrace | List | LessThan ) as t ), _ ->
247
+ | ((Token. Lbracket | Lparen | Lbrace | List | Dict | LessThan ) as t ), _ ->
244
248
Parser. next state;
245
249
goToClosing (getClosingToken t) state;
246
250
goToClosing closingToken state
@@ -1917,6 +1921,9 @@ and parseAtomicExpr p =
1917
1921
| List ->
1918
1922
Parser. next p;
1919
1923
parseListExpr ~start Pos p
1924
+ | Dict ->
1925
+ Parser. next p;
1926
+ parseDictExpr ~start Pos p
1920
1927
| Module ->
1921
1928
Parser. next p;
1922
1929
parseFirstClassModuleExpr ~start Pos p
@@ -3876,6 +3883,18 @@ and parseSpreadExprRegionWithLoc p =
3876
3883
Some (false , parseConstrainedOrCoercedExpr p, startPos, p.prevEndPos)
3877
3884
| _ -> None
3878
3885
3886
+ and parseSpreadRecordExprRowWithStringKeyRegionWithLoc p =
3887
+ let startPos = p.Parser. prevEndPos in
3888
+ match p.Parser. token with
3889
+ | DotDotDot ->
3890
+ Parser. next p;
3891
+ let expr = parseConstrainedOrCoercedExpr p in
3892
+ Some (Spread expr, startPos, p.prevEndPos)
3893
+ | token when Grammar. isExprStart token ->
3894
+ parseRecordExprRowWithStringKey p
3895
+ |> Option. map (fun parsedRow -> (Inline parsedRow, startPos, p.prevEndPos))
3896
+ | _ -> None
3897
+
3879
3898
and parseListExpr ~startPos p =
3880
3899
let split_by_spread exprs =
3881
3900
List. fold_left
@@ -3920,6 +3939,121 @@ and parseListExpr ~startPos p =
3920
3939
loc))
3921
3940
[(Asttypes. Nolabel , Ast_helper.Exp. array ~loc listExprs)]
3922
3941
3942
+ and parseDictExpr ~startPos p =
3943
+ let makeDictRowTuples ~loc idExps =
3944
+ idExps
3945
+ |> List. map (fun ((id , exp ) : Ast_helper. lid * Parsetree. expression ) ->
3946
+ Ast_helper.Exp. tuple
3947
+ [
3948
+ Ast_helper.Exp. constant ~loc: id.loc
3949
+ (Pconst_string (Longident. last id.txt, None ));
3950
+ exp;
3951
+ ])
3952
+ |> Ast_helper.Exp. array ~loc
3953
+ in
3954
+
3955
+ let makeSpreadDictRowTuples ~loc spreadDict =
3956
+ Ast_helper.Exp. apply ~loc
3957
+ (Ast_helper.Exp. ident ~loc ~attrs: [dictAttr]
3958
+ (Location. mkloc
3959
+ (Longident. Ldot
3960
+ (Longident. Ldot (Longident. Lident " Js" , " Dict" ), " entries" ))
3961
+ loc))
3962
+ [(Asttypes. Nolabel , spreadDict)]
3963
+ in
3964
+
3965
+ let concatManyExpr ~loc listExprs =
3966
+ Ast_helper.Exp. apply ~loc
3967
+ (Ast_helper.Exp. ident ~loc ~attrs: [spreadAttr]
3968
+ (Location. mkloc
3969
+ (Longident. Ldot
3970
+ (Longident. Ldot (Longident. Lident " Belt" , " Array" ), " concatMany" ))
3971
+ loc))
3972
+ [(Asttypes. Nolabel , Ast_helper.Exp. array ~loc listExprs)]
3973
+ in
3974
+
3975
+ let makeDictFromRowTuples ~loc arrayEntriesExp =
3976
+ Ast_helper.Exp. apply ~loc
3977
+ (Ast_helper.Exp. ident ~loc ~attrs: [dictAttr]
3978
+ (Location. mkloc
3979
+ (Longident. Ldot
3980
+ (Longident. Ldot (Longident. Lident " Js" , " Dict" ), " fromArray" ))
3981
+ loc))
3982
+ [(Asttypes. Nolabel , arrayEntriesExp)]
3983
+ in
3984
+ let split_by_spread exprs =
3985
+ List. fold_left
3986
+ (fun acc curr ->
3987
+ match (curr, acc) with
3988
+ | (Spread expr , startPos , endPos ), _ ->
3989
+ (* find a spread expression, prepend a new sublist *)
3990
+ ([] , Some expr, startPos, endPos) :: acc
3991
+ | ( (Inline fieldExprTuple, startPos, _endPos),
3992
+ (no_spreads, spread, _accStartPos, accEndPos) :: acc ) ->
3993
+ (* find a non-spread expression, and the accumulated is not empty,
3994
+ * prepend to the first sublist, and update the loc of the first sublist *)
3995
+ (fieldExprTuple :: no_spreads, spread, startPos, accEndPos) :: acc
3996
+ | (Inline fieldExprTuple , startPos , endPos ), [] ->
3997
+ (* find a non-spread expression, and the accumulated is empty *)
3998
+ [([fieldExprTuple], None , startPos, endPos)])
3999
+ [] exprs
4000
+ in
4001
+ let rec getListOfEntryArraysReversed ?(accum = [] ) ~loc spreadSplit =
4002
+ match spreadSplit with
4003
+ | [] -> accum
4004
+ | (idExps , None, _ , _ ) :: tail ->
4005
+ let accum = (idExps |> makeDictRowTuples ~loc ) :: accum in
4006
+ tail |> getListOfEntryArraysReversed ~loc ~accum
4007
+ | ([] , Some spread , _ , _ ) :: tail ->
4008
+ let accum = (spread |> makeSpreadDictRowTuples ~loc ) :: accum in
4009
+ tail |> getListOfEntryArraysReversed ~loc ~accum
4010
+ | (idExps , Some spread , _ , _ ) :: tail ->
4011
+ let accum =
4012
+ (spread |> makeSpreadDictRowTuples ~loc )
4013
+ :: (idExps |> makeDictRowTuples ~loc )
4014
+ :: accum
4015
+ in
4016
+ tail |> getListOfEntryArraysReversed ~loc ~accum
4017
+ in
4018
+
4019
+ let dictExprsRev =
4020
+ parseCommaDelimitedReversedList ~grammar: Grammar. RecordRowsStringKey
4021
+ ~closing: Rbrace ~f: parseSpreadRecordExprRowWithStringKeyRegionWithLoc p
4022
+ in
4023
+ Parser. expect Rbrace p;
4024
+ let loc = mkLoc startPos p.prevEndPos in
4025
+ let arrDictEntries =
4026
+ match
4027
+ dictExprsRev |> split_by_spread |> getListOfEntryArraysReversed ~loc
4028
+ with
4029
+ | [] -> Ast_helper.Exp. array ~loc []
4030
+ | [singleArrDictEntries] -> singleArrDictEntries
4031
+ | multipleArrDictEntries ->
4032
+ multipleArrDictEntries |> List. rev |> concatManyExpr ~loc
4033
+ in
4034
+ makeDictFromRowTuples ~loc arrDictEntries
4035
+
4036
+ (* Overparse ... and give a nice error message *)
4037
+ and parseNonSpreadExp ~msg p =
4038
+ let () =
4039
+ match p.Parser. token with
4040
+ | DotDotDot ->
4041
+ Parser. err p (Diagnostics. message msg);
4042
+ Parser. next p
4043
+ | _ -> ()
4044
+ in
4045
+ match p.Parser. token with
4046
+ | token when Grammar. isExprStart token -> (
4047
+ let expr = parseExpr p in
4048
+ match p.Parser. token with
4049
+ | Colon ->
4050
+ Parser. next p;
4051
+ let typ = parseTypExpr p in
4052
+ let loc = mkLoc expr.pexp_loc.loc_start typ.ptyp_loc.loc_end in
4053
+ Some (Ast_helper.Exp. constraint_ ~loc expr typ)
4054
+ | _ -> Some expr)
4055
+ | _ -> None
4056
+
3923
4057
and parseArrayExp p =
3924
4058
let startPos = p.Parser. startPos in
3925
4059
Parser. expect Lbracket p;
0 commit comments