blob: 86c17a3d8be2c0fba222d016e9c2a415cab408ef (
plain)
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
139
140
141
142
143
144
145
146
147
148
149
150
151
|
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
import Control.Applicative
import Control.Monad.State
import Data.Attoparsec.Text hiding ( take )
import Data.Char ( isAlpha
, isDigit
)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import Prelude hiding ( print
, takeWhile
)
data Tokens = Wrd {unwrd :: T.Text} | Cmd T.Text | BSq [Tokens] | BCr [Tokens] | NL | Cmt T.Text | Nobs | IMath T.Text | Math T.Text
deriving Show
isCtrl x = not $ isAlpha x || isDigit x
-- tokens to strings
toStr (Wrd w) = do
if T.length w >= 1 && T.head w `elem` (".,;:!?)" :: [Char])
then print' w
else print w
when (w == "(") suppress
when (T.last w == '.') printnl
toStr (Cmd c) = if T.length c > 0 && isCtrl (T.head c) || T.length c == 1
then print' $ "\\" `T.append` c
else do
printnl'
when (c == "end") unindent
print $ "\\" `T.append` c
when (c == "begin") indent
toStr (BSq ts) = do
print' "["
suppress
indent
mapM_ toStr ts
unindent
print' "]"
toStr (BCr ts) = do
print' "{"
suppress
indent
mapM_ toStr ts
unindent
print' "}"
toStr NL = printnl' >> printnl
toStr (Cmt c) = do
print "%"
print' c
toStr Nobs = do
print' "~"
suppress
toStr (Math m) = do
printnl
print "\\["
print' m
println "\\]"
toStr (IMath m) = do
print "\\("
print' m
print' "\\)"
-- Tokeniser
ws = inClass " \t\n"
pad = takeWhile ws
token = nl <|> pad *> (nobs <|> math <|> cmd <|> bsq <|> bcr <|> cmt <|> wrd)
nobs = string "~" *> pure Nobs
nl = string "\n" *> takeWhile (inClass " \t") *> string "\n" *> pure NL
cmd :: Parser Tokens
cmd = Cmd <$> (string "\\" *> ((unwrd <$> wrd) <|> pure ""))
bsq = BSq <$> (string "[" *> many' token) <* pad <* string "]"
bcr = BCr <$> (string "{" *> many' token) <* pad <* string "}"
wrd = Wrd <$> takeWhile1 (notInClass " \t\n[]{}\\~")
cmt = Cmt <$> (takeWhile1 (== '%') *> takeWhile (/= '\n'))
math = oldmath <|> newmath <|> oldimath <|> newimath
oldmath = Math <$> (string "$$" *> takeWhile (/= '$')) <* string "$$"
newmath = Math . T.pack <$> (string "\\[" *> manyTill' anyChar (string "\\]"))
oldimath = IMath <$> (string "$" *> takeWhile (/= '$')) <* string "$"
newimath = IMath . T.pack <$> (string "\\(" *> manyTill' anyChar (string "\\)"))
-- indented printer
type Beginning = Bool
type Indent = Int
type SuppressSpace = Bool
data Printer = Printer Beginning SuppressSpace Indent T.Text
deriving Show
print :: T.Text -> State Printer ()
print str = do
(Printer beg sup i s) <- get
if sup
then print' str
else do
let indent = T.pack . take (2 * i) $ repeat ' '
str' = T.concat [s, if beg then indent else " ", str]
put $ Printer False False i str'
-- force unindented
print' :: T.Text -> State Printer ()
print' str = do
(Printer beg _ i s) <- get
let indent = T.pack . take (2 * i) $ repeat ' '
str' = T.concat [s, if beg then indent else "", str]
put $ Printer False False i str'
printnl :: State Printer ()
printnl = do
(Printer beg sup i str) <- get
when (not sup) $ put $ Printer True False i $ str `T.append` "\n"
printnl' :: State Printer ()
printnl' = do
(Printer beg sup i str) <- get
when (not beg && not sup) $ put $ Printer True False i $ str `T.append` "\n"
println :: T.Text -> State Printer ()
println str = do
print str
printnl
println' :: T.Text -> State Printer ()
println' str = do
print' str
printnl
indent :: State Printer ()
indent = do
(Printer b sup i s) <- get
put $ Printer b sup (i + 1) s
unindent :: State Printer ()
unindent = do
(Printer b sup i s) <- get
put $ Printer b sup (i - 1) s
suppress :: State Printer ()
suppress = do
(Printer b _ i s) <- get
put $ Printer b True i s
-- entry
main = do
str <- T.getContents
let Right toks = parseOnly (many' token) str
Printer _ _ _ str' =
flip execState (Printer True False 0 "") $ mapM_ toStr toks
T.putStr str'
|