-
Notifications
You must be signed in to change notification settings - Fork 179
Expand file tree
/
Copy pathToTemplate.hs
More file actions
104 lines (97 loc) · 3.54 KB
/
ToTemplate.hs
File metadata and controls
104 lines (97 loc) · 3.54 KB
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
module ToTemplate where
import Obj
import Parsing
import Text.Parsec ((<|>))
import qualified Text.Parsec as Parsec
import Util
-- | High-level helper function for creating templates from strings of C code.
toTemplate :: String -> [Token]
toTemplate text = case Parsec.runParser templateSyntax 0 "(template)" text of
Right ok -> ok
Left err -> error (show err)
where
templateSyntax :: Parsec.Parsec String Int [Token]
templateSyntax = Parsec.many parseTok
parseTok =
Parsec.try parseTokDecl
<|> Parsec.try parseTokName --- $DECL
<|> Parsec.try parseTokTyGrouped --- $NAME
<|> Parsec.try parseTokTyRawGrouped --- i.e. $(Fn [Int] t)
<|> Parsec.try parseTokTy
<|> parseTokC --- i.e. $t
--- Anything else...
parseTokDecl :: Parsec.Parsec String Int Token
parseTokDecl = do
_ <- Parsec.string "$DECL"
pure TokDecl
parseTokName :: Parsec.Parsec String Int Token
parseTokName = do
_ <- Parsec.string "$NAME"
pure TokName
parseTokC :: Parsec.Parsec String Int Token
parseTokC = do
s <- Parsec.many1 validInSymbol
pure (TokC s)
where
validInSymbol = Parsec.choice [Parsec.letter, Parsec.digit, Parsec.oneOf validCharactersInTemplate]
validCharactersInTemplate = " ><{}()[]|;:.,_-+*#/'^!?€%&=@\"\n\t\\"
parseTokTy :: Parsec.Parsec String Int Token
parseTokTy = do
_ <- Parsec.char '$'
s <- Parsec.many1 Parsec.letter
pure (toTokTy Normal s)
parseTokTyGrouped :: Parsec.Parsec String Int Token
parseTokTyGrouped = do
_ <- Parsec.char '$'
toTokTy Normal <$> parseGrouping
parseTokTyRawGrouped :: Parsec.Parsec String Int Token
parseTokTyRawGrouped = do
_ <- Parsec.char '§'
toTokTy Raw <$> parseGrouping
parseGrouping :: Parsec.Parsec String Int String
parseGrouping = do
_ <- Parsec.char '('
Parsec.putState 1 -- One paren to close.
fmap ('(' :) (Parsec.many parseCharBalanced)
-- Note: The closing paren is read by parseCharBalanced.
parseCharBalanced :: Parsec.Parsec String Int Char
parseCharBalanced = do
balanceState <- Parsec.getState
if balanceState > 0
then
Parsec.try openParen
<|> Parsec.try closeParen
<|> Parsec.anyChar
else Parsec.char '\0' -- Should always fail which will end the string.
openParen :: Parsec.Parsec String Int Char
openParen = do
_ <- Parsec.char '('
Parsec.modifyState (+ 1)
pure '('
closeParen :: Parsec.Parsec String Int Char
closeParen = do
_ <- Parsec.char ')'
Parsec.modifyState (\x -> x - 1)
pure ')'
-- | Converts a string containing a type to a template token ('TokTy').
-- | i.e. the string "(Array Int)" becomes (TokTy (StructTy "Array" IntTy)).
toTokTy :: TokTyMode -> String -> Token
toTokTy mode s =
case parse s "" of
Left err -> error (show err)
Right [] -> error ("toTokTy got [] when parsing: '" ++ s ++ "'")
Right [xobj] -> case xobjToTy xobj of
Just ok -> TokTy ok mode
Nothing -> error ("toTokTy failed to convert this s-expression to a type: " ++ pretty xobj)
Right xobjs -> error ("toTokTy parsed too many s-expressions: " ++ joinWithSpace (map pretty xobjs))
templateLiteral :: String -> (a -> [Token])
templateLiteral = const . toTemplate
multilineTemplate :: [String] -> [Token]
multilineTemplate = toTemplate . unlines
templateReturn :: String -> [Token]
templateReturn x =
multilineTemplate
[ "$DECL { ",
" return " ++ x ++ ";",
"}"
]