diff --git a/grammar/type.js b/grammar/type.js index 6fdc4832..a8235809 100644 --- a/grammar/type.js +++ b/grammar/type.js @@ -235,11 +235,19 @@ module.exports = { _tyfam_equations: $ => layout($, alias($._type_instance, $.equation)), + /** + * This syntax is valid in `.hs-boot` files. + */ + abstract_family: $ => layout_single($, '..'), + decl_tyfam: $ => seq( 'type', 'family', $._tyfam, - optional_where_as($, $._tyfam_equations, $.equations), + optional_where($, choice( + alias($._tyfam_equations, $.equations), + $.abstract_family, + )), ), // ------------------------------------------------------------------------ diff --git a/grammar/util.js b/grammar/util.js index d6b0c678..ad50443a 100644 --- a/grammar/util.js +++ b/grammar/util.js @@ -31,6 +31,15 @@ semis = ($, rule) => sep1(semi($), rule), // layout // ------------------------------------------------------------------------ +/** + * More general variant of `layout_sort`. + */ +layout_sort_single = ($, start, rule) => seq( + choice(start, alias($._cmd_layout_start_explicit, '{')), + rule, + $._layout_end, +) + /** * Wrap a repeated rule in a layout. * This is used for `where`, `let`, `of`, `if` and `do`, and the toplevel module. @@ -47,7 +56,16 @@ layout_sort = ($, start, rule) => seq( semi_opt($), )), $._layout_end, -), +) + +/** + * Same as `layout`, but using `layout_sort_single`. + * This is necessary for braces without repeating layout elements. + * Usually it is enough to just use `braces` for this (e.g. records), but if the rule is in a choice with a full + * layout, we need to allow the layout start token since the scanner emits that unconditionally based on preceding + * tokens. + */ +layout_single = ($, rule) => layout_sort_single($, $._cmd_layout_start, rule) /** * Alias for `layout_sort` using the common layout type for the start token, which corresponds to declarations and GADT @@ -90,7 +108,10 @@ module.exports = { sep1, sep2, semis, + layout_sort, + layout_sort_single, layout, + layout_single, unboxed, unboxed_tuple, unboxed_sum, diff --git a/test/corpus/family.txt b/test/corpus/family.txt index 025882d0..5c8f6606 100644 --- a/test/corpus/family.txt +++ b/test/corpus/family.txt @@ -802,3 +802,20 @@ type instance ∀ a . A a = a (type_variable)))) (type_name (type_variable))))) + +================================================================================ +family: abstract closed family, hs-boot +================================================================================ + +type family A where + .. + +-------------------------------------------------------------------------------- + +(haskell + (declarations + (type_family + (head + (type_name + (type))) + (abstract_family))))