我一直在尝试构建Haskell AST,以便我可以找出源文件的哪些行存在哪些AST节点。到目前为止,我使用的是Language.Haskell.Parser
和Language.Haskell.Syntax
,它们看起来效果相当不错。我可以生成一个树,然后遍历它的每一部分,使用srcLine loc
(其中loc
是SrcLoc)获取行号。
但是,当解析的文件如下所示时,我遇到了问题:
文件1
1| rangeLeq :: Integer -> NonnegRange
2| rangeLeq n =
3| Range BoundaryBelowAll (BoundaryAbove n)
该文件可以很容易地写成:
文件2
1| rangeLeq :: Integer -> NonnegRange
2| rangeLeq n = Range BoundaryBelowAll (BoundaryAbove n)
问题是解析器认为这两个是等价的。它不会将SrcLoc分配给所有内容,只分配给AST的某些部分。所以我最终得到的是文件1和文件2的以下输出:
line 1: HsTypeSig
|--HsIdent (rangeLeq)
|--HsQualType
|--HsContext
|--HsTyFun
|--HsTyCon
|--HsUnQual
|--HsIdent (Integer)
|--HsTyCon
|--HsUnQual
|--HsIdent (NonnegRange)
line 2: HsMatch
|--HsIdent (rangeLeq)
|--HsPVar
|--HsIdent (n)
|--HsUnGuardedRhs
|--HsApp
|--HsApp
|--HsCon
|--HsUnQual
|--HsIdent (Range)
|--HsCon
|--HsUnQual
|--HsIdent (BoundaryBelowAll)
|--HsParen
|--HsApp
|--HsCon
|--HsUnQual
|--HsIdent (BoundaryAbove)
|--HsVar
|--HsUnQual
|--HsIdent (n)
所以这里的问题是大多数节点上没有位置信息,因此它将函数定义(HsMatch
)视为一行。如果不清楚,HsMatch
代表代码中的rangeLeq n = Range BoundaryBelowAll (BoundaryAbove n)
。由于SrcLoc
附带的AST的唯一部分是HsMatch
本身,因此解析器假设HsMatch
的所有部分都在同一行。
tl;dr
如何获得正确的解析,以便源文件中不必要地拆分的行仍然会被标记为相应的行? Id est,我想要一个用<{1}}标记每个节点的解析,而不仅仅是某些节点。
答案 0 :(得分:0)
haskell-src-exts
在SrcSpanInfo
上有一个位置标记(默认为every subexpression);它应该有足够的细节来消除你的两个例子的歧义。