@@ -14,6 +14,8 @@ module LoopProgress = struct
1414 | _ :: rest -> rest
1515end
1616
17+ type ('a, 'b) spreadInline = Spread of 'a | Inline of 'b
18+
1719let mkLoc startLoc endLoc =
1820 Location. {loc_start = startLoc; loc_end = endLoc; loc_ghost = false }
1921
@@ -184,6 +186,7 @@ let taggedTemplateLiteralAttr =
184186 (Location. mknoloc " res.taggedTemplate" , Parsetree. PStr [] )
185187
186188let spreadAttr = (Location. mknoloc " res.spread" , Parsetree. PStr [] )
189+ let dictAttr = (Location. mknoloc " res.dict" , Parsetree. PStr [] )
187190
188191type argument = {
189192 dotted : bool ;
@@ -233,6 +236,7 @@ let getClosingToken = function
233236 | Lbrace -> Rbrace
234237 | Lbracket -> Rbracket
235238 | List -> Rbrace
239+ | Dict -> Rbrace
236240 | LessThan -> GreaterThan
237241 | _ -> assert false
238242
@@ -244,7 +248,7 @@ let rec goToClosing closingToken state =
244248 | GreaterThan , GreaterThan ->
245249 Parser. next state;
246250 ()
247- | ((Token. Lbracket | Lparen | Lbrace | List | LessThan ) as t ), _ ->
251+ | ((Token. Lbracket | Lparen | Lbrace | List | Dict | LessThan ) as t ), _ ->
248252 Parser. next state;
249253 goToClosing (getClosingToken t) state;
250254 goToClosing closingToken state
@@ -1055,6 +1059,7 @@ let rec parsePattern ?(alias = true) ?(or_ = true) p =
10551059 ppat_attributes = attrs @ pat.Parsetree. ppat_attributes;
10561060 }))
10571061 | Lbracket -> parseArrayPattern ~attrs p
1062+ (* | Dict -> parseDictPattern ~attrs p *)
10581063 | Lbrace -> parseRecordPattern ~attrs p
10591064 | Underscore ->
10601065 let endPos = p.endPos in
@@ -1921,6 +1926,9 @@ and parseAtomicExpr p =
19211926 | List ->
19221927 Parser. next p;
19231928 parseListExpr ~start Pos p
1929+ | Dict ->
1930+ Parser. next p;
1931+ parseDictExpr ~start Pos p
19241932 | Module ->
19251933 Parser. next p;
19261934 parseFirstClassModuleExpr ~start Pos p
@@ -3876,6 +3884,18 @@ and parseSpreadExprRegionWithLoc p =
38763884 Some (false , parseConstrainedOrCoercedExpr p, startPos, p.prevEndPos)
38773885 | _ -> None
38783886
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+
38793899and parseListExpr ~startPos p =
38803900 let split_by_spread exprs =
38813901 List. fold_left
@@ -3920,6 +3940,105 @@ and parseListExpr ~startPos p =
39203940 loc))
39213941 [(Asttypes. Nolabel , Ast_helper.Exp. array ~loc listExprs)]
39223942
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+
39234042(* Overparse ... and give a nice error message *)
39244043and parseNonSpreadExp ~msg p =
39254044 let () =
0 commit comments