@@ -36,6 +36,10 @@ type id = loc(Identifier.t);
3636type str = loc (string );
3737type loc = Location . t ;
3838
39+ type array_concat_item =
40+ | ArrayConcatItems (list (expression ))
41+ | ArrayConcatSpread (expression );
42+
3943let ident_empty = {
4044 txt: Identifier . IdentName (Location . mknoloc("[]" )),
4145 loc: Location . dummy_loc,
@@ -390,41 +394,49 @@ module Expression = {
390394 tuple_construct(~loc, ~attributes? , ident_cons, [ expr, empty] )
391395 | ListSpread (expr , _ ) => expr
392396 };
393- if (List . exists(
394- expr =>
395- switch (expr) {
396- | ListSpread (_ ) => true
397- | ListItem (_ ) => false
398- },
399- rest,
400- )) {
401- collection_concat(
402- ~loc,
403- ~attributes? ,
404- PExpListConcat ,
405- List . map(
406- expr =>
397+ let has_nonfinal_spread =
398+ List . exists(
399+ expr =>
400+ switch (expr) {
401+ | ListSpread (_ ) => true
402+ | ListItem (_ ) => false
403+ },
404+ rest,
405+ );
406+ if (has_nonfinal_spread) {
407+ let grouped =
408+ List . fold_left(
409+ (acc, expr) => {
407410 switch (expr) {
408- | ListSpread (expr , loc ) => (
409- PExpSpreadExpr ,
411+ | ListSpread (expr , loc ) => [
410412 {... expr, pexp_loc: loc},
411- )
412- | ListItem (expr ) => (
413- PExpNonSpreadExpr ,
414- // Still convert to a single-element list to make later compilation steps easier
413+ ... acc,
414+ ]
415+ | ListItem (expr ) =>
416+ let (first , rest ) =
417+ switch (acc) {
418+ | [ first , ... rest ] => (first, rest)
419+ | _ => assert (false )
420+ };
421+ [
415422 tuple_construct(
416- ~loc= expr . pexp_loc ,
423+ ~loc,
417424 ~attributes? ,
418425 ident_cons,
419- [
420- expr,
421- tuple_construct(~loc= expr. pexp_loc, ident_empty, [] ),
422- ] ,
426+ [ expr, first] ,
423427 ),
424- )
425- },
426- a,
427- ),
428+ ... rest,
429+ ] ;
430+ }
431+ },
432+ [ base] ,
433+ rest,
434+ );
435+ collection_concat(
436+ ~loc,
437+ ~attributes? ,
438+ PExpListConcat ,
439+ List . map(expr => (PExpSpreadExpr , expr), grouped),
428440 );
429441 } else {
430442 List . fold_left(
@@ -446,51 +458,70 @@ module Expression = {
446458 {... list, pexp_loc: loc};
447459 };
448460 let array_items = (~loc, ~attributes=?, a) => {
449- let no_spreads =
450- List . for_all (
461+ let has_spread =
462+ List . exists (
451463 x => {
452464 switch (x) {
453- | ArrayItem (_ ) => true
454- | ArraySpread (_ ) => false
465+ | ArraySpread (_ ) => true
466+ | ArrayItem (_ ) => false
455467 }
456468 },
457469 a,
458470 );
459- if (no_spreads) {
460- array(
461- ~loc,
462- ~attributes? ,
463- List . map(
464- expr =>
471+ if (has_spread) {
472+ let grouped =
473+ List . fold_right(
474+ (expr, acc) => {
465475 switch (expr) {
466- | ArraySpread (_ ) =>
467- failwith (
468- "Impossible: spread in array when existence has been disproven" ,
469- )
470- | ArrayItem (expr ) => expr
471- },
476+ | ArrayItem (expr ) =>
477+ switch (acc) {
478+ | [ArrayConcatItems (exprs ), ... rest ] => [
479+ ArrayConcatItems ([ expr, ... exprs] ),
480+ ... rest,
481+ ]
482+ | _ => [ ArrayConcatItems ([ expr] ), ... acc]
483+ }
484+ | ArraySpread (expr , loc ) => [
485+ ArrayConcatSpread ({... expr, pexp_loc: loc}),
486+ ... acc,
487+ ]
488+ }
489+ },
472490 a,
473- ),
474- );
475- } else {
491+ [] ,
492+ );
476493 collection_concat(
477494 ~loc,
478495 ~attributes? ,
479496 PExpArrayConcat ,
480497 List . map(
481498 x => {
482499 switch (x) {
483- | ArrayItem ( expr ) => (
500+ | ArrayConcatItems ( [ first , ... rest ] as exprs ) => (
484501 PExpNonSpreadExpr ,
485- // Still convert to a single-element array to make later compilation steps easier
486- array(~loc= expr. pexp_loc, ~attributes? , [ expr] ),
487- )
488- | ArraySpread (expr , loc ) => (
489- PExpSpreadExpr ,
490- {... expr, pexp_loc: loc},
502+ array(~loc= first. pexp_loc, ~attributes? , exprs),
491503 )
504+ | ArrayConcatItems ([] ) =>
505+ failwith ("Impossible: empty ArrayConcatItems" )
506+ | ArrayConcatSpread (expr ) => (PExpSpreadExpr , expr)
492507 }
493508 },
509+ grouped,
510+ ),
511+ );
512+ } else {
513+ array(
514+ ~loc,
515+ ~attributes? ,
516+ List . map(
517+ expr =>
518+ switch (expr) {
519+ | ArraySpread (_ ) =>
520+ failwith (
521+ "Impossible: spread in array when existence has been disproven" ,
522+ )
523+ | ArrayItem (expr ) => expr
524+ },
494525 a,
495526 ),
496527 );
0 commit comments