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
|
{
-- This parser is based on ParsedPkgConf.y in compiler/main/
-- It's supposed to do the same thing, but without depending on other GHC modules.
-- The disadvantage is the less sophisticated error reporting, and it's probably
-- slower because it doesn't use FastStrings.
module ParsePkgConfLite{- ( parsePackageConfig, parseOnePackageConfig ) -}where
import Package ( PackageConfig(..), defaultPackageConfig )
import Char(isSpace, isAlpha, isAlphaNum, isUpper)
import List(break)
}
%token
'{' { ITocurly }
'}' { ITccurly }
'[' { ITobrack }
']' { ITcbrack }
',' { ITcomma }
'=' { ITequal }
VARID { ITvarid $$ }
CONID { ITconid $$ }
STRING { ITstring $$ }
%name parse pkgconf
%name parseOne pkg
%tokentype { Token }
%%
pkgconf :: { [ PackageConfig ] }
: '[' ']' { [] }
| '[' pkgs ']' { reverse $2 }
pkgs :: { [ PackageConfig ] }
: pkg { [ $1 ] }
| pkgs ',' pkg { $3 : $1 }
pkg :: { PackageConfig }
: CONID '{' fields '}' { $3 defaultPackageConfig }
fields :: { PackageConfig -> PackageConfig }
: field { \p -> $1 p }
| fields ',' field { \p -> $1 ($3 p) }
field :: { PackageConfig -> PackageConfig }
: VARID '=' STRING
{\p -> case $1 of
"name" -> p{name = $3}
_ -> error "unknown key in config file" }
| VARID '=' strlist
{\p -> case $1 of
"import_dirs" -> p{import_dirs = $3}
"library_dirs" -> p{library_dirs = $3}
"hs_libraries" -> p{hs_libraries = $3}
"extra_libraries" -> p{extra_libraries = $3}
"include_dirs" -> p{include_dirs = $3}
"c_includes" -> p{c_includes = $3}
"package_deps" -> p{package_deps = $3}
"extra_ghc_opts" -> p{extra_ghc_opts = $3}
"extra_cc_opts" -> p{extra_cc_opts = $3}
"extra_ld_opts" -> p{extra_ld_opts = $3}
"framework_dirs" -> p{framework_dirs = $3}
"extra_frameworks"-> p{extra_frameworks= $3}
_other -> p
}
strlist :: { [String] }
: '[' ']' { [] }
| '[' strs ']' { reverse $2 }
strs :: { [String] }
: STRING { [ $1 ] }
| strs ',' STRING { $3 : $1 }
{
data Token =
ITocurly
| ITccurly
| ITobrack
| ITcbrack
| ITcomma
| ITequal
| ITvarid String
| ITconid String
| ITstring String
lexer :: String -> [Token]
lexer [] = []
lexer ('{':cs) = ITocurly : lexer cs
lexer ('}':cs) = ITccurly : lexer cs
lexer ('[':cs) = ITobrack : lexer cs
lexer (']':cs) = ITcbrack : lexer cs
lexer (',':cs) = ITcomma : lexer cs
lexer ('=':cs) = ITequal : lexer cs
lexer ('"':cs) = lexString cs ""
lexer (c:cs)
| isSpace c = lexer cs
| isAlpha c = lexID (c:cs) where
lexer _ = error "Unexpected token"
lexID cs = (if isUpper (head cs) then ITconid else ITvarid) id : lexer rest
where
(id,rest) = break (\c -> c /= '_' && not (isAlphaNum c)) cs
lexString ('"':cs) s = ITstring (reverse s) : lexer cs
lexString ('\\':c:cs) s = lexString cs (c:s)
lexString (c:cs) s = lexString cs (c:s)
happyError _ = error "Couldn't parse package configuration."
parsePackageConfig :: String -> [PackageConfig]
parsePackageConfig = parse . lexer
parseOnePackageConfig :: String -> PackageConfig
parseOnePackageConfig = parseOne . lexer
}
|