Summary
The expression parser only recognizes a postfix .field access chain after a
plain lowercase variable (record.field). After every other kind of term that
can legally take a field access, the .field is instead parsed as a separate
accessor function term, turning the whole expression into a function
application:
| Source |
Parsed as |
Should be |
(f x).field |
Call (Parens (f x)) [Accessor .field] |
Access (Parens (f x)) "field" |
{ a = 1 }.a |
Call (Record …) [Accessor .a] |
Access (Record …) "a" |
{ r | a = 1 }.a |
Call (Update …) [Accessor .a] |
Access (Update …) "a" |
Config.default.timeout |
Call (VarQual Config.default) [Accessor .timeout] |
Access (VarQual Config.default) "timeout" |
The reference compiler (the Haskell gren binary) parses all four as field
access, and treats them differently from the space-separated forms
((f x) .field is an application of the accessor function). With this
parser, both spellings collapse into the same (application) AST, so the
distinction between two different programs is lost at parse time.
Reproduction
-
Save as Repro.gren:
module Repro exposing (..)
a r =
(get r).field
b =
{ x = 1 }.x
c r =
{ r | x = 1 }.x
d =
Config.default.timeout
-
Inspect the parse (e.g. gren format --pre-ast Repro.gren). Every body is
{"type": "call", ..., "args": [..., {"type": "accessor", ...}]} where it
should be {"type": "access", ...}.
Summary
The expression parser only recognizes a postfix
.fieldaccess chain after aplain lowercase variable (
record.field). After every other kind of term thatcan legally take a field access, the
.fieldis instead parsed as a separateaccessor function term, turning the whole expression into a function
application:
(f x).fieldCall (Parens (f x)) [Accessor .field]Access (Parens (f x)) "field"{ a = 1 }.aCall (Record …) [Accessor .a]Access (Record …) "a"{ r | a = 1 }.aCall (Update …) [Accessor .a]Access (Update …) "a"Config.default.timeoutCall (VarQual Config.default) [Accessor .timeout]Access (VarQual Config.default) "timeout"The reference compiler (the Haskell
grenbinary) parses all four as fieldaccess, and treats them differently from the space-separated forms
(
(f x) .fieldis an application of the accessor function). With thisparser, both spellings collapse into the same (application) AST, so the
distinction between two different programs is lost at parse time.
Reproduction
Save as
Repro.gren:Inspect the parse (e.g.
gren format --pre-ast Repro.gren). Every body is{"type": "call", ..., "args": [..., {"type": "accessor", ...}]}where itshould be
{"type": "access", ...}.