/
buildOCPParser.mly
283 lines (243 loc) · 7.02 KB
/
buildOCPParser.mly
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/******************************************************************************/
/* */
/* TypeRex OCaml Tools */
/* */
/* OCamlPro */
/* */
/* Copyright 2011-2012 OCamlPro */
/* All rights reserved. See accompanying files for the terms under */
/* which this file is distributed. In doubt, contact us at */
/* contact@ocamlpro.com (http://www.ocamlpro.com/) */
/* */
/******************************************************************************/
%{
open BuildOCPTree
(* TODO: location of the type in ocamlyacc is erroneous, for example here token "main"
type is located in the .mli/.ml file instead of the .mly file. *)
%}
%token <string> STRING
%token <int> INT
%token EOF
%token <float> FLOAT
%token <char> CHAR
%token SEMI
%token BEGIN
%token END
%token <string> IDENT
%token LBRACKET
%token RBRACKET
%token LBRACE
%token RBRACE
%token PLUSEQUAL
%token MINUSEQUAL
%token TRUE
%token FALSE
%token INCLUDE
%token <BuildOCPTree.statement list> INCLUDED
%token OBJECTS
%token LIBRARY
%token PROGRAM
%token CONFIG
%token EQUAL
%token LPAREN
%token RPAREN
%token FILES
%token REQUIRES
%token TYPE
%token USE
%token PACK
%token IF
%token THEN
%token ELSE
%token NOT
%token COND_OR
%token COND_AND
%token SYNTAXES
%token CAMLP4
%token CAMLP5
%start main
%type <BuildOCPTree.statement list> main
%%
main:
toplevel_statements EOF { $1 }
;
toplevel_statements:
{ [] }
| INCLUDED toplevel_statements { $1 @ $2 }
| toplevel_statement toplevel_statements { $1 :: $2 }
| SEMI toplevel_statements { $2 }
;
package_type:
PROGRAM { ProgramPackage }
| LIBRARY { LibraryPackage }
| OBJECTS { ObjectsPackage }
;
toplevel_statement:
| BEGIN CONFIG STRING options END { StmtDefineConfig ($3, $4) }
| BEGIN package_type STRING statements END { StmtDefinePackage ($2, $3, $4) }
| BEGIN toplevel_statements END { StmtBlock $2 }
| IF condition THEN one_toplevel_statement maybe_else_one_toplevel_statement { StmtIfThenElse($2,$4,$5) }
| simple_statement { $1 }
/* for backward compatibility */
| BEGIN STRING TYPE EQUAL package_type statements END { StmtDefinePackage ($5, $2, $6) }
;
one_toplevel_statement:
| toplevel_statement { [$1] }
| LBRACE toplevel_statements RBRACE { $2 }
;
statements:
| statement statements { $1 :: $2 }
| { [] }
| SEMI statements { $2 }
;
statement:
| BEGIN statements END { StmtBlock $2 }
| IF condition THEN one_statement maybe_else_one_statement { StmtIfThenElse($2, $4, $5) }
| simple_statement { $1 }
;
one_statement:
| statement { [$1] }
| LBRACE statements RBRACE { $2 }
;
simple_statement:
| simple_option { StmtOption $1 }
| FILES EQUAL list_of_files { StmtFilesSet $3 }
/* | FILE EQUAL STRING { StmtFilesSet [$3, []] } */
| FILES PLUSEQUAL list_of_files { StmtFilesAppend $3 }
/* The two next ones only for backward compatibility */
| REQUIRES list_of_requires { StmtRequiresAppend $2 }
| SYNTAXES list_of_syntaxes { StmtRequiresAppend $2 }
| REQUIRES EQUAL list_of_requires { StmtRequiresAppend $3 }
| SYNTAXES EQUAL list_of_syntaxes { StmtRequiresAppend $3 }
| REQUIRES PLUSEQUAL list_of_requires { StmtRequiresAppend $3 }
| SYNTAXES PLUSEQUAL list_of_syntaxes { StmtRequiresAppend $3 }
;
list_of_files:
| list_of_string_attributes { $1 }
;
list_of_requires:
| list_of_string_attributes {
List.map (fun (x, options) -> (x, OptionBoolSet("link", true) :: options)) $1 }
;
list_of_syntaxes:
| list_of_string_attributes {
List.map (fun (x, options) -> (x, OptionBoolSet("syntax", true) :: options)) $1 }
;
camlp4_or_camlp5:
| CAMLP4 { Camlp4 }
| CAMLP5 { Camlp5 }
;
simple_option:
| USE STRING { OptionConfigSet $2 }
| IDENT EQUAL string_or_list { OptionListSet ($1,$3) }
| IDENT PLUSEQUAL string_or_list { OptionListAppend ($1,$3) }
| IDENT MINUSEQUAL string_or_list { OptionListRemove ($1,$3) }
| IDENT EQUAL TRUE { OptionBoolSet ($1, true) }
| IDENT EQUAL FALSE { OptionBoolSet ($1, false) }
/* | SYNTAX EQUAL STRING { OptionListSet ("syntax", [$3]) } */
| IDENT { OptionBoolSet ($1, true) }
;
string_or_list:
| STRING { [$1] }
| list_of_strings { $1 }
;
option:
| BEGIN options END { OptionBlock $2 }
| IF condition THEN one_option maybe_else_one_option { OptionIfThenElse($2, $4, $5) }
| simple_option { $1 }
;
one_option:
| option { [$1] }
| LBRACE options RBRACE { $2 }
;
maybe_else_one_option:
| { None }
| ELSE one_option { Some $2 }
;
maybe_else_one_statement:
| { None }
| ELSE one_statement { Some $2 }
;
maybe_else_one_toplevel_statement:
| { None }
| ELSE one_toplevel_statement { Some $2 }
;
condition:
| IDENT EQUAL string_or_list { IsEqualStringList($1, $3) }
| NOT simple_condition { NotCondition $2 }
| simple_condition COND_AND simple_condition { AndConditions ($1, $3) }
| simple_condition COND_OR simple_condition { OrConditions ($1, $3) }
| simple_condition { $1 }
;
simple_condition:
| LPAREN condition RPAREN { $2 }
| IDENT { IsTrue $1 }
;
options:
| { [] }
| option options { $1 :: $2 }
| SEMI options { $2 }
;
list_of_options:
| { [] }
| LPAREN options RPAREN { $2 }
;
list_of_strings:
| LBRACKET strings RBRACKET { $2 }
;
strings:
{ [] }
| STRING strings { $1 :: $2 }
| IDENT strings { $1 :: $2 }
| SEMI strings { $2 }
;
list_of_string_attributes:
| LBRACKET files RBRACKET { $2 }
;
packer:
| PACK STRING { $2 }
| PACK IDENT { let s = $2 in s.[0] <- Char.lowercase s.[0]; s ^ ".ml" }
;
/* TODO: currently, we use this rule both for "files" and "requires".
This is bad, as "pack" has no meaning for "requires". Thus, we should
use a different rule. */
files:
{ [] }
| STRING list_of_options files { ($1, $2) :: $3 }
| SEMI files { $2 }
| BEGIN list_of_options files END files
{ let shared_options = $2 in
let inner_files = $3 in
let outter_files = $5 in
let inner_files =
List.map (fun (file, file_options) ->
(file, shared_options @ file_options)
) inner_files in
inner_files @ outter_files
}
| packer list_of_options list_of_files list_of_options files {
let packname = $1 in
let pack_options1 = $2 in
let files = $3 in
let pack_options2 = $4 in
let other_files = $5 in
let pack_options = pack_options1 @ pack_options2 in
let packmodname = BuildOCPTree.modname_of_fullname packname in
let modnames = ref [] in
let packed_files =
List.map (fun (file, file_options) ->
begin
match file_options with
OptionListAppend ( "packed", _ ) :: _ -> ()
| _ ->
modnames := Filename.basename file :: !modnames
end;
(file, OptionListAppend ("packed", [packmodname]) :: pack_options @ file_options)
) files;
in
packed_files @
[ packname, OptionListSet ("pack", List.rev !modnames) :: pack_options] @
other_files
}
;
%%