2
2
-- | Position lookup in the AST.
3
3
module Curry.LanguageServer.Utils.Lookup
4
4
( findQualIdentAtPos
5
+ , findExprIdentAtPos
5
6
, findModuleIdentAtPos
6
7
, findTypeAtPos
7
8
, findScopeAtPos
9
+ , showScope
8
10
, Scope
9
11
) where
10
12
11
13
-- Curry Compiler Libraries + Dependencies
12
14
import qualified Curry.Base.Ident as CI
13
15
import qualified Curry.Base.SpanInfo as CSPI
14
16
import qualified Curry.Syntax as CS
17
+ import qualified Curry.Base.Position as CP
15
18
16
19
import Control.Applicative (Alternative ((<|>) ))
17
20
import Control.Monad (when )
@@ -28,19 +31,24 @@ import Curry.LanguageServer.Utils.Syntax
28
31
)
29
32
import Curry.LanguageServer.Utils.Sema
30
33
( HasTypedSpanInfos (typedSpanInfos ), TypedSpanInfo )
34
+ import Data.Bifunctor (Bifunctor (.. ))
31
35
import qualified Data.Map as M
32
36
import qualified Language.LSP.Protocol.Types as J
33
37
34
38
-- | A collectScope of bound identifiers.
35
- type Scope a = M. Map CI. Ident ( Maybe a )
39
+ type Scope a = M. Map String ( CI. Ident, Maybe a )
36
40
37
41
-- | Finds identifier and (occurrence) span info at a given position.
38
42
findQualIdentAtPos :: CS. Module a -> J. Position -> Maybe (CI. QualIdent , CSPI. SpanInfo )
39
43
findQualIdentAtPos ast pos = qualIdent <|> exprIdent <|> basicIdent
40
44
where qualIdent = withSpanInfo <$> elementAt pos (qualIdentifiers ast)
41
- exprIdent = joinFst $ qualIdentifier <.$> withSpanInfo <$> elementAt pos (expressions ast)
45
+ exprIdent = findExprIdentAtPos ast pos
42
46
basicIdent = CI. qualify <.$> withSpanInfo <$> elementAt pos (identifiers ast)
43
47
48
+ --- | Finds expression identifier and (occurrence) span info at a given position.
49
+ findExprIdentAtPos :: CS. Module a -> J. Position -> Maybe (CI. QualIdent , CSPI. SpanInfo )
50
+ findExprIdentAtPos ast pos = joinFst $ qualIdentifier <.$> withSpanInfo <$> elementAt pos (expressions ast)
51
+
44
52
-- | Finds module identifier and (occurrence) span info at a given position.
45
53
findModuleIdentAtPos :: CS. Module a -> J. Position -> Maybe (CI. ModuleIdent , CSPI. SpanInfo )
46
54
findModuleIdentAtPos ast pos = withSpanInfo <$> elementAt pos (moduleIdentifiers ast)
@@ -65,12 +73,17 @@ containsPos x pos = maybe False (rangeElem pos) $ currySpanInfo2Range x
65
73
66
74
-- | Binds an identifier in the innermost scope.
67
75
bindInScopes :: CI. Ident -> Maybe a -> [Scope a ] -> [Scope a ]
68
- bindInScopes i t (sc: scs) = M. insert (CI. unRenameIdent i) t sc : scs
76
+ bindInScopes i t (sc: scs) = M. insert (CI. idName i') (i', t) sc : scs
77
+ where i' = CI. unRenameIdent i
69
78
bindInScopes _ _ _ = error " Cannot bind without a scope!"
70
79
80
+ -- | Shows a scope with line numbers (for debugging).
81
+ showScope :: Scope a -> String
82
+ showScope = show . map (second (CP. line . CSPI. getStartPosition . CI. idSpanInfo . fst )) . M. toList
83
+
71
84
-- | Flattens the given scopes, preferring earlier binds.
72
85
flattenScopes :: [Scope a ] -> Scope a
73
- flattenScopes = foldr M. union M. empty
86
+ flattenScopes = M. unions
74
87
75
88
-- | Stores nested scopes and a cursor position. The head of the list is always the innermost collectScope.
76
89
data ScopeState a = ScopeState
@@ -98,7 +111,7 @@ updateEnvs :: CSPI.HasSpanInfo e => e -> ScopeM a ()
98
111
updateEnvs (CSPI. getSpanInfo -> spi) = do
99
112
pos <- gets (. position)
100
113
when (spi `containsPos` pos) $
101
- modify $ \ s -> s { matchingEnv = M. union (flattenScopes s. currentEnv) s . matchingEnv }
114
+ modify $ \ s -> s { matchingEnv = M. union s . matchingEnv (flattenScopes s. currentEnv) }
102
115
103
116
class CollectScope e a where
104
117
collectScope :: e -> ScopeM a ()
0 commit comments