[Haskell] constructors(or constants) are highlighted as types(storage.type)
What happened?
As the following image shows, for codes of Haskell, constructors(or constants) are highlighted as storage.type.

That's a known limitation as it is not yet very clear how to reliably distinguish constants and types in normal expressions.
That's a known limitation as it is not yet very clear how to reliably distinguish constants and types in normal expressions.
I think in normal expressions, there are no types, types are only occurs in type declarations. Maybe I am wrong, but for most case, that's it.
The punctuations :: and = can be used to identify and distinguish between type expressions and normal expressions.
The type and value should be evaluated separately, that is, a normal expression should not have a type as an argument, except as an annotation that indicates the type of the argument's value.
And there some other problem, see the following comparison.
GitHub
data Node = Node Int Node Node | Leaf
isLeaf, isNode :: Node -> Bool
isNode (Node value left right) = True
isNode _ = False
isLeaf node = not (isNode (node :: Node))
SublimeText

I believe GitHub also uses push-down automata for syntactic highlighting, not semantic highlighting.
This code can be compiled by GHC. I don't know why the comma is marked red and the token Leaf is marked as storage.type in the image above, but normal in the image below

There are several situations Github's and all those other TextMate syntaxes' highlighting fails, too, especially if expressions like types use several lines.
Haskell just doesn't provide enough boundaries to pop a context off stack reliably. It mainly works based on indentation level, which ST's engine can't make use of. Most syntaxes use a couple of heuristics to pop off those contexts, which often heavily depend on coding style. Or they just use naive patterns, which fail as soon as an expression requires 2 or more lines.
It's even not reliably possible to find the end of type expressions, without introducing a bunch of edge cases. The illegal comma you complain about is only one of them. In order to highlight constructor definitions a dedicated context needs to pushed on stack, but how to know isLeaf not being a type variable with more type expression terms following? The pattern, which looks for the end of this context, just assumes a simple assignment (ident = ) or function definition (ident ::).
Trying to distinguish more stuff, will likely just introduce more highlighting issues.
In order to highlight constructor definitions a dedicated context needs to pushed on stack, but how to know
isLeafnot being a type variable with more type expression terms following?
isLeaf is at the begin of one line, so it can't be a type variable.
In addition, Leaf is marked as storage.type, which is also a problem.
There are several situations Github's and all those other TextMate syntaxes' highlighting fails, too, especially if expressions like types use several lines.
It's actually not that easy to fail.
data Node = Node
Int Node Node | Leaf
isLeaf, isNode :: Node -> Bool
isNode (Node value left right) = True
isNode _ = False
isLeaf node = not (isNode (node :: Node))
f :: Node ->
Node ->
Node -> Bool
f n1 n2 n3 = False
g :: Node ->
Node -> Node ->
Node -> Bool
g n1 n2 n3 n4 = False
h :: Node ->
Node -> Node
-> Node -> Bool
h n1 n2 n3 n4 = False
If it is so easy - hey - it's an open source project. Everyone can contribute valuable improvements.