diff options
author | Vladislav Zavialov <vlad.z.4096@gmail.com> | 2020-07-22 16:24:28 +0300 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-08-06 13:34:05 -0400 |
commit | 686e06c59c3aa6b66895e8a501c7afb019b09e36 (patch) | |
tree | be3e7cf27fceacaddd39fcb2fbea05dd5c444b55 /testsuite/tests/parser/should_fail | |
parent | fbcb886d503dd7aaebc4c40e59615068b3fd0bd7 (diff) | |
download | haskell-686e06c59c3aa6b66895e8a501c7afb019b09e36.tar.gz |
Grammar for types and data/newtype constructors
Before this patch, we parsed types into a reversed sequence
of operators and operands. For example, (F x y + G a b * X)
would be parsed as [X, *, b, a, G, +, y, x, F],
using a simple grammar:
tyapps
: tyapp
| tyapps tyapp
tyapp
: atype
| PREFIX_AT atype
| tyop
| unpackedness
Then we used a hand-written state machine to assemble this
either into a type, using 'mergeOps',
or into a constructor, using 'mergeDataCon'.
This is due to a syntactic ambiguity:
data T1 a = MkT1 a
data T2 a = Ord a => MkT2 a
In T1, what follows after the = sign is a data/newtype constructor
declaration. However, in T2, what follows is a type (of kind
Constraint). We don't know which of the two we are parsing until we
encounter =>, and we cannot check for => without unlimited lookahead.
This poses a few issues when it comes to e.g. infix operators:
data I1 = Int :+ Bool :+ Char -- bad
data I2 = Int :+ Bool :+ Char => MkI2 -- fine
By this issue alone we are forced into parsing into an intermediate
representation and doing a separate validation pass.
However, should that intermediate representation be as low-level as a
flat sequence of operators and operands?
Before GHC Proposal #229, the answer was Yes, due to some particularly
nasty corner cases:
data T = ! A :+ ! B -- used to be fine, hard to parse
data T = ! A :+ ! B => MkT -- bad
However, now the answer is No, as this corner case is gone:
data T = ! A :+ ! B -- bad
data T = ! A :+ ! B => MkT -- bad
This means we can write a proper grammar for types, overloading it in
the DisambECP style, see Note [Ambiguous syntactic categories].
With this patch, we introduce a new class, DisambTD. Just like
DisambECP is used to disambiguate between expressions, commands, and patterns,
DisambTD is used to disambiguate between types and data/newtype constructors.
This way, we get a proper, declarative grammar for constructors and
types:
infixtype
: ftype
| ftype tyop infixtype
| unpackedness infixtype
ftype
: atype
| tyop
| ftype tyarg
| ftype PREFIX_AT tyarg
tyarg
: atype
| unpackedness atype
And having a grammar for types means we are a step closer to using a
single grammar for types and expressions.
Diffstat (limited to 'testsuite/tests/parser/should_fail')
6 files changed, 11 insertions, 9 deletions
diff --git a/testsuite/tests/parser/should_fail/T12045d.stderr b/testsuite/tests/parser/should_fail/T12045d.stderr index 128cf58d86..a731352f10 100644 --- a/testsuite/tests/parser/should_fail/T12045d.stderr +++ b/testsuite/tests/parser/should_fail/T12045d.stderr @@ -1,4 +1,3 @@ T12045d.hs:11:16: error: - Unexpected kind application in a data/newtype declaration: - MkD @Nat Bool + Unexpected kind application in a data/newtype declaration: MkD @Nat diff --git a/testsuite/tests/parser/should_fail/strictnessDataCon_B.stderr b/testsuite/tests/parser/should_fail/strictnessDataCon_B.stderr index 47f85eae8c..04ea0c8b18 100644 --- a/testsuite/tests/parser/should_fail/strictnessDataCon_B.stderr +++ b/testsuite/tests/parser/should_fail/strictnessDataCon_B.stderr @@ -1,3 +1,2 @@ -strictnessDataCon_B.hs:1:27: error: - {-# UNPACK #-} cannot appear inside a type. +strictnessDataCon_B.hs:1:42: error: parse error on input ‘}’ diff --git a/testsuite/tests/parser/should_fail/typeops_A.stderr b/testsuite/tests/parser/should_fail/typeops_A.stderr index 69f7aac6be..8558729f2f 100644 --- a/testsuite/tests/parser/should_fail/typeops_A.stderr +++ b/testsuite/tests/parser/should_fail/typeops_A.stderr @@ -1,2 +1,3 @@ -typeops_A.hs:1:12: error: Operator applied to too few arguments: + +typeops_A.hs:2:1: error: + parse error (possibly incorrect indentation or mismatched brackets) diff --git a/testsuite/tests/parser/should_fail/typeops_C.stderr b/testsuite/tests/parser/should_fail/typeops_C.stderr index 280323bb67..75372a8a2a 100644 --- a/testsuite/tests/parser/should_fail/typeops_C.stderr +++ b/testsuite/tests/parser/should_fail/typeops_C.stderr @@ -1,2 +1,2 @@ -typeops_C.hs:1:12: error: Operator applied to too few arguments: + +typeops_C.hs:1:14: error: Operator applied to too few arguments: + diff --git a/testsuite/tests/parser/should_fail/unpack_empty_type.stderr b/testsuite/tests/parser/should_fail/unpack_empty_type.stderr index fe520c9317..dbc73c87ff 100644 --- a/testsuite/tests/parser/should_fail/unpack_empty_type.stderr +++ b/testsuite/tests/parser/should_fail/unpack_empty_type.stderr @@ -1,3 +1,2 @@ -unpack_empty_type.hs:3:19: error: - {-# UNPACK #-} must be applied to a type. +unpack_empty_type.hs:3:34: error: parse error on input ‘}’ diff --git a/testsuite/tests/parser/should_fail/unpack_inside_type.stderr b/testsuite/tests/parser/should_fail/unpack_inside_type.stderr index 0c09e63b71..60d7ba87a3 100644 --- a/testsuite/tests/parser/should_fail/unpack_inside_type.stderr +++ b/testsuite/tests/parser/should_fail/unpack_inside_type.stderr @@ -1,3 +1,7 @@ unpack_inside_type.hs:3:25: error: - {-# UNPACK #-} cannot appear inside a type. + • Unexpected UNPACK annotation: {-# UNPACK #-}Int + UNPACK annotation cannot appear nested inside a type + • In the first argument of ‘Maybe’, namely ‘({-# UNPACK #-}Int)’ + In the type ‘Maybe ({-# UNPACK #-}Int)’ + In the definition of data constructor ‘T’ |