These keywords are followed by a name, like:
import Array
type Bar
type alias Foo
port baz
The name's row is assigned to the AST node instead of the keyword's row. Usually these are on the same row, so we haen't noticed, but it is legal to put a newline between the keyword and the name.
Example:
module PosBug exposing (Foo)
import
Array
type
alias Foo =
{ x : Int }
Line numbers: import is on line 4, Array on line 5; type is on
line 8, alias Foo on line 9.
Parse it and inspect the start of each declaration (here via gren format --pre-ast, but it is the raw parser output):
| Declaration |
reported Located.start |
leading keyword is actually on |
name start |
import Array |
{ row: 5, col: 1 } |
row 4 (import) |
{ row: 5, col: 5 } |
type alias Foo |
{ row: 9, col: 1 } |
row 8 (type) |
{ row: 9, col: 11 } |
For example, the import node:
"imports": [
{
"start": {
"row": 5,
"col": 1
},
"end": {
"row": 5,
"col": 10
},
"value": {
"module_": {
"start": {
"row": 5,
"col": 5
},
"end": {
"row": 5,
"col": 10
},
"value": "Array"
},
"alias": null,
"expose": []
}
}
],
This causes a problem in "gren format" if the user does put that legal newline between the keyword and the name. We cannot produce canonical output.
Root cause
The four conversion sites derive start from the name, not from the keyword
that was already consumed:
src/Compiler/Parse/Module.gren:366 — importLoopParser
SourcePosition.at { moduleName.start | col = 1 } … (the import token is
skipped just below, its position never captured).
src/Compiler/Parse/Module.gren:497 — declarationToModuleAlias
{ row = v.name.start.row, col = 1 }
src/Compiler/Parse/Module.gren:519 — declarationToModuleUnion
{ row = v.name.start.row, col = 1 }
src/Compiler/Parse/Module.gren:535 — declarationToModulePort
{ row = v.name.start.row, col = 1 }
For aliases/unions/ports the keyword's position isn't available at the
conversion site at all: Compiler.Parse.Declaration.parser consumes the
type/port keyword (typeParser/portParser) but never records where it
was, and Declaration carries only { docs, value }.
These keywords are followed by a name, like:
The name's row is assigned to the AST node instead of the keyword's row. Usually these are on the same row, so we haen't noticed, but it is legal to put a newline between the keyword and the name.
Example:
Line numbers:
importis on line 4,Arrayon line 5;typeis online 8,
alias Fooon line 9.Parse it and inspect the
startof each declaration (here viagren format --pre-ast, but it is the raw parser output):Located.startstartimport Array{ row: 5, col: 1 }import){ row: 5, col: 5 }type alias Foo{ row: 9, col: 1 }type){ row: 9, col: 11 }For example, the import node:
This causes a problem in "gren format" if the user does put that legal newline between the keyword and the name. We cannot produce canonical output.
Root cause
The four conversion sites derive
startfrom the name, not from the keywordthat was already consumed:
src/Compiler/Parse/Module.gren:366—importLoopParserSourcePosition.at { moduleName.start | col = 1 } …(theimporttoken isskipped just below, its position never captured).
src/Compiler/Parse/Module.gren:497—declarationToModuleAlias{ row = v.name.start.row, col = 1 }src/Compiler/Parse/Module.gren:519—declarationToModuleUnion{ row = v.name.start.row, col = 1 }src/Compiler/Parse/Module.gren:535—declarationToModulePort{ row = v.name.start.row, col = 1 }For aliases/unions/ports the keyword's position isn't available at the
conversion site at all:
Compiler.Parse.Declaration.parserconsumes thetype/portkeyword (typeParser/portParser) but never records where itwas, and
Declarationcarries only{ docs, value }.