1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
--- This module defines a Symboltable optimized for the SQLNamer.
--- It contains two Maps, both using strings as keys and <
--- as comparison operation. It is parameterized over both value types.
--- Only the first Map is supporting a scope concept.
---@author Julia Krone
---@version 0.1
-- -----------------------------------------------------------------------

module Symboltab where

import qualified Data.Map as Map

--- A Symboltable consists of at least one pair of Maps.
--- There can be another table representing a surrounding scope.
data Symboltable a b = ST ((Map.Map String a),(Map.Map String b))
                          (Maybe (Symboltable a b))

---Constructor function.
emptyTable :: Symboltable _ _
emptyTable = ST (Map.empty, Map.empty) Nothing

--- Lookupfunction: First looks up the key in the current scope (first table)
--- if it is not found the surrounding scope will be used and so on.
--- Returns Nothing if no value was found.
lookupFirstTable :: String -> Symboltable a b -> Maybe a
lookupFirstTable k (ST (m,_) Nothing ) = Map.lookup k m
lookupFirstTable k (ST (m,_) (Just s)) = case Map.lookup k m of
                                       Just v -> Just v
                                       Nothing -> lookupFirstTable k s

--- Looks up the key just in the current scope of the first table.
lookupCurrentScope :: String -> Symboltable a b -> Maybe a
lookupCurrentScope k (ST (m,_) _) = Map.lookup k m

--- Looks up the key in the second table (which does not support scopes).
lookupSecondTable :: String -> Symboltable a b -> Maybe b
lookupSecondTable k (ST (_,n) _ ) = Map.lookup k n

--- Inserts a key-value-pair into the current scope (first table).
insertFirstTable :: String -> a -> Symboltable a b -> Symboltable a b
insertFirstTable k v (ST (m,n) ms) = ST ((Map.insert k v m),n) ms

--- Inserts a key-value-pair into the current scope (first table)
--- without throwing away previous bindings. Values are combined
--- by given combinator.
insertDefFirstTab :: String ->
                     a ->
                     (a -> a -> a) ->
                     Symboltable a b ->
                     Symboltable a b
insertDefFirstTab k v c (ST (m,n) ms) = ST ((Map.insertWith c k v m),n) ms

--- Inserts a key-value-pair into the second table
--- (which does not support scopes).
insertSecondTable :: String -> b -> Symboltable a b -> Symboltable a b
insertSecondTable k v (ST (m,n) ms) = ST (m,(Map.insert k v n)) ms

--- Create a new scope inside the last one
--- (first table, leaving the secong one unchanged).
enterScope :: Symboltable a b  -> Symboltable a b
enterScope s@(ST (_,n) _ ) = ST (Map.empty ,n) (Just s)

--- Exits current scope, so that the surrounding one will be used.
--- If the current scope is the most general one, nothing will be changed.
exitScope :: Symboltable a b -> Symboltable a b
exitScope s@(ST _ Nothing ) = s
exitScope (ST _   (Just s)) = s

--- Combines two Symboltables. The current Scopes will be merged,
--- all the remaining scopes are taken from the first table.
--- Bindings for the same key will be overwritten by the
--- binding in the current scope.
combineST :: Symboltable k v -> Symboltable k v -> Symboltable k v
combineST (ST (m1,n1) ms) (ST (m2,n2) _) =
     ST ((Map.union m2 m1), (Map.union n2 n1)) ms