-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExpression.hs
138 lines (127 loc) · 5.41 KB
/
Expression.hs
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
module Expression where
import Data.Set (Set, toAscList)
import Data.Map (Map)
import Data.Monoid (Monoid(..), (<>))
-- The label of a variable
type Label = Maybe Char
-- Context anchor label; begins from 0
type AnchorLabel = Int
type Coord = (Int, Int) -- x, y
type Size = (Int, Int) -- w, h
type Rect = (Int, Int, Int, Int) -- x, y, w, h
type Range = (Int, Maybe Int)
-- Dihedral group D4 of orientations
-- Rot n is rotation by n*90 degrees
-- RefRot n is Rot n, then reflection by vertical line
data D4 = Rot Int | RefRot Int
deriving (Eq, Ord)
instance Show D4 where
show (Rot 0) = ""
show (Rot n) = "o" ++ show n
show (RefRot n) = "o" ++ show (n + 4)
axisPreserving :: D4 -> Bool
axisPreserving (Rot 0) = True
axisPreserving (Rot 2) = True
axisPreserving (RefRot 0) = True
axisPreserving (RefRot 2) = True
axisPreserving _ = False
instance Monoid D4 where
mempty = Rot 0
mappend (Rot m) (Rot n) = Rot $ (m + n) `mod` 4
mappend (RefRot m) (Rot n) = RefRot $ (m + n) `mod` 4
mappend (Rot m) (RefRot n) = RefRot $ (n - m) `mod` 4
mappend (RefRot m) (RefRot n) = Rot $ (n - m) `mod` 4
-- An expression that may or may not match a rectangle of characters
data Expr = Border -- Matches the rectangle border symbol
| Edge -- Matches an edge segment
| AnyRect -- Mathces any rectangle
| AnyChar -- Matches any single character (not border)
| SomeChar Bool
(Set (Maybe Char)) -- Matches if flag XOR char in set; Nothing matches border
| Var D4 Label -- Matches the given oriented variable
| Expr :> Expr -- Horizontal concatenation
| Expr :^ Expr -- Vertical concatenation
| Expr :| Expr -- Disjunction
| Expr :& Expr -- Conjunction
| Expr :~ Expr -- Exclusive OR
| Not Expr -- Negation
| Sized Range Range Expr -- Size range
| Grid Range Range Expr -- Grid of repetitions
| Count Range Expr -- Count number of matches
| InContext Expr -- Context brackets
| Anchor AnchorLabel -- Context anchor
| Fixed Expr -- Fixed orientation
deriving (Eq)
instance Show Expr where
show Border = "b"
show Edge = "e"
show AnyRect = "$"
show AnyChar = "."
show (SomeChar isPos charSet) =
if isPos
then "[p:" ++ concatMap (maybe "\\b" $ \c -> if c == '\\' then "\\\\" else [c]) (toAscList charSet) ++ "]"
else "[n:" ++ concatMap (maybe "\\b" $ \c -> if c == '\\' then "\\\\" else [c]) (toAscList charSet) ++ "]"
show (Var rot Nothing) = "_" ++ show rot
show (Var rot (Just a)) = [a] ++ show rot
show (e1 :> e2) = show e1 ++ show e2
show (e1 :^ e2) = "(" ++ show e1 ++ "/" ++ show e2 ++ ")"
show (e1 :| e2) = "(" ++ show e1 ++ "|" ++ show e2 ++ ")"
show (e1 :& e2) = "(" ++ show e1 ++ "&" ++ show e2 ++ ")"
show (e1 :~ e2) = "(" ++ show e1 ++ "~" ++ show e2 ++ ")"
show (Not e) = "(" ++ show e ++ ")!"
show (Sized (x1,x2) (y1,y2) e) =
"(" ++ show e ++ "){" ++ show x1 ++ "-" ++ sx2 ++ "," ++ show y1 ++ "-" ++ sy2 ++ "}"
where sx2 = case x2 of Nothing -> ""; Just x -> show x
sy2 = case y2 of Nothing -> ""; Just y -> show y
show (Grid (x1,x2) (y1,y2) e) =
"(" ++ show e ++ "):" ++ show x1 ++ "-" ++ sx2 ++ "," ++ show y1 ++ "-" ++ sy2 ++ "}"
where sx2 = case x2 of Nothing -> ""; Just x -> show x
sy2 = case y2 of Nothing -> ""; Just y -> show y
show (Count (low, high) e) =
"(" ++ show e ++ ")#" ++ show low ++ "-" ++ showHigh ++ "}"
where showHigh = case high of Nothing -> ""; Just n -> show n
show (InContext e) = "<" ++ show e ++ ">"
show (Anchor n) = show n
show (Fixed e) = "(" ++ show e ++ ")oF"
-- Rotate and/or reflect an expression
orient :: Expr -> D4 -> Expr
orient Border _ = Border
orient Edge _ = Edge
orient AnyRect _ = AnyRect
orient AnyChar _ = AnyChar
orient e@(SomeChar _ _) _ = e
orient (Var rot1 label) rot2 = Var (rot2 <> rot1) label
orient e@(e1 :> e2) rot = case rot of
Rot 0 -> e
Rot 1 -> orient e2 rot :^ orient e1 rot
Rot 2 -> orient e2 rot :> orient e1 rot
Rot 3 -> orient e1 rot :^ orient e2 rot
RefRot 0 -> orient e2 rot :> orient e1 rot
RefRot 1 -> orient e2 rot :^ orient e1 rot
RefRot 2 -> orient e1 rot :> orient e2 rot
RefRot 3 -> orient e1 rot :^ orient e2 rot
orient e@(e1 :^ e2) rot = case rot of
Rot 0 -> e
Rot 1 -> orient e1 rot :> orient e2 rot
Rot 2 -> orient e2 rot :^ orient e1 rot
Rot 3 -> orient e2 rot :> orient e1 rot
RefRot 0 -> orient e1 rot :^ orient e2 rot
RefRot 1 -> orient e2 rot :> orient e1 rot
RefRot 2 -> orient e2 rot :^ orient e1 rot
RefRot 3 -> orient e1 rot :> orient e2 rot
orient (e1 :| e2) rot = orient e1 rot :| orient e2 rot
orient (e1 :& e2) rot = orient e1 rot :& orient e2 rot
orient (e1 :~ e2) rot = orient e1 rot :~ orient e2 rot
orient (Not e) rot = Not $ orient e rot
orient (Sized (x1,x2) (y1,y2) e) rot =
if axisPreserving rot
then Sized (x1,x2) (y1,y2) $ orient e rot
else Sized (y1,y2) (x1,x2) $ orient e rot
orient (Grid (x1,x2) (y1,y2) e) rot =
if axisPreserving rot
then Grid (x1,x2) (y1,y2) $ orient e rot
else Grid (y1,y2) (x1,x2) $ orient e rot
orient (Count range e) rot = Count range $ orient e rot
orient (InContext e) rot = InContext $ orient e rot
orient e@(Anchor _) _ = e
orient e@(Fixed _) _ = e