diff options
Diffstat (limited to 'lib/nix/parser.mly')
-rw-r--r-- | lib/nix/parser.mly | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/lib/nix/parser.mly b/lib/nix/parser.mly new file mode 100644 index 0000000..dc1638d --- /dev/null +++ b/lib/nix/parser.mly | |||
@@ -0,0 +1,310 @@ | |||
1 | /* Tokens with data */ | ||
2 | %token <string> INT | ||
3 | %token <string> FLOAT | ||
4 | /* A path */ | ||
5 | %token <string> PATH | ||
6 | /* Search path, enclosed in <> */ | ||
7 | %token <string> SPATH | ||
8 | /* Home path, starts with ~ */ | ||
9 | %token <string> HPATH | ||
10 | %token <string> URI | ||
11 | %token <string> STR_START | ||
12 | %token <string> STR_MID | ||
13 | %token STR_END | ||
14 | %token <string> ISTR_START | ||
15 | %token <string> ISTR_MID | ||
16 | %token <int> ISTR_END | ||
17 | %token <string> ID | ||
18 | /* Tokens that stand for themselves */ | ||
19 | %token SELECT "." | ||
20 | %token QMARK "?" | ||
21 | %token CONCAT "++" | ||
22 | %token NOT "!" | ||
23 | %token MERGE "//" | ||
24 | %token ASSIGN "=" | ||
25 | %token LT "<" | ||
26 | %token LTE "<=" | ||
27 | %token GT ">" | ||
28 | %token GTE ">=" | ||
29 | %token EQ "==" | ||
30 | %token NEQ "!=" | ||
31 | %token AND "&&" | ||
32 | %token OR "||" | ||
33 | %token IMPL "->" | ||
34 | %token AQUOTE_OPEN "${" | ||
35 | %token AQUOTE_CLOSE "}$" | ||
36 | %token LBRACE "{" | ||
37 | %token RBRACE "}" | ||
38 | %token LBRACK "[" | ||
39 | %token RBRACK "]" | ||
40 | %token PLUS "+" | ||
41 | %token MINUS "-" | ||
42 | %token TIMES "*" | ||
43 | %token SLASH "/" | ||
44 | %token LPAREN "(" | ||
45 | %token RPAREN ")" | ||
46 | %token COLON ":" | ||
47 | %token SEMICOLON ";" | ||
48 | %token COMMA "," | ||
49 | %token ELLIPSIS "..." | ||
50 | %token AS "@" | ||
51 | /* Keywords */ | ||
52 | %token WITH "with" | ||
53 | %token REC "rec" | ||
54 | %token LET "let" | ||
55 | %token IN "in" | ||
56 | %token INHERIT "inherit" | ||
57 | %token IF "if" | ||
58 | %token THEN "then" | ||
59 | %token ELSE "else" | ||
60 | %token ASSERT "assert" | ||
61 | %token ORDEF "or" | ||
62 | |||
63 | /* End of input */ | ||
64 | %token EOF | ||
65 | |||
66 | %{ | ||
67 | open Types | ||
68 | %} | ||
69 | |||
70 | %start <Types.expr> main | ||
71 | |||
72 | %% | ||
73 | |||
74 | main: | ||
75 | | e = expr0 EOF | ||
76 | { e } | ||
77 | |||
78 | expr0: | ||
79 | | "if"; e1 = expr0; "then"; e2 = expr0; "else"; e3 = expr0 | ||
80 | { Cond (e1, e2, e3) } | ||
81 | | "with"; e1 = expr0; ";"; e2 = expr0 | ||
82 | { With (e1, e2) } | ||
83 | | "assert"; e1 = expr0; ";"; e2 = expr0 | ||
84 | { Assert (e1, e2) } | ||
85 | | "let"; xs = delimited("{", list(binding), "}") | ||
86 | { SetLet xs } | ||
87 | | "let"; xs = list(binding); "in"; e = expr0 | ||
88 | { Let (xs, e) } | ||
89 | | l = lambda | ||
90 | { Val l } | ||
91 | | e = expr1 | ||
92 | { e } | ||
93 | |||
94 | /* Rules expr1-expr14 are almost direct translation of the operator | ||
95 | precedence table: | ||
96 | https://nixos.org/nix/manual/#sec-language-operators */ | ||
97 | |||
98 | %inline binary_expr(Lhs, Op, Rhs): | ||
99 | | lhs = Lhs; op = Op; rhs = Rhs | ||
100 | { BinaryOp (op, lhs, rhs) } | ||
101 | |||
102 | expr1: | ||
103 | | e = binary_expr(expr2, "->" {Impl}, expr1) | ||
104 | | e = expr2 | ||
105 | { e } | ||
106 | |||
107 | expr2: | ||
108 | | e = binary_expr(expr2, "||" {Or}, expr3) | ||
109 | | e = expr3 | ||
110 | { e } | ||
111 | |||
112 | expr3: | ||
113 | | e = binary_expr(expr3, "&&" {And}, expr4) | ||
114 | | e = expr4 | ||
115 | { e } | ||
116 | |||
117 | %inline expr4_ops: | ||
118 | | "==" { Eq } | ||
119 | | "!=" { Neq } | ||
120 | |||
121 | expr4: | ||
122 | | e = binary_expr(expr5, expr4_ops, expr5) | ||
123 | | e = expr5 | ||
124 | { e } | ||
125 | |||
126 | %inline expr5_ops: | ||
127 | | "<" { Lt } | ||
128 | | ">" { Gt } | ||
129 | | "<=" { Lte } | ||
130 | | ">=" { Gte } | ||
131 | |||
132 | expr5: | ||
133 | | e = binary_expr(expr6, expr5_ops, expr6) | ||
134 | | e = expr6 | ||
135 | { e } | ||
136 | |||
137 | expr6: | ||
138 | | e = binary_expr(expr7, "//" {Merge}, expr6) | ||
139 | | e = expr7 | ||
140 | { e } | ||
141 | |||
142 | expr7: | ||
143 | | e = preceded("!", expr7) | ||
144 | { UnaryOp (Not, e) } | ||
145 | | e = expr8 | ||
146 | { e } | ||
147 | |||
148 | %inline expr8_ops: | ||
149 | | "+" { Plus } | ||
150 | | "-" { Minus } | ||
151 | |||
152 | expr8: | ||
153 | | e = binary_expr(expr8, expr8_ops, expr9) | ||
154 | | e = expr9 | ||
155 | { e } | ||
156 | |||
157 | %inline expr9_ops: | ||
158 | | "*" { Mult } | ||
159 | | "/" { Div } | ||
160 | |||
161 | expr9: | ||
162 | | e = binary_expr(expr9, expr9_ops, expr10) | ||
163 | | e = expr10 | ||
164 | { e } | ||
165 | |||
166 | expr10: | ||
167 | | e = binary_expr(expr11, "++" {Concat}, expr10) | ||
168 | | e = expr11 | ||
169 | { e } | ||
170 | |||
171 | expr11: | ||
172 | | e = expr12 "?" p = attr_path | ||
173 | { Test (e, p) } | ||
174 | | e = expr12 | ||
175 | { e } | ||
176 | |||
177 | expr12: | ||
178 | | e = preceded("-", expr13) | ||
179 | { UnaryOp (Negate, e) } | ||
180 | | e = expr13 | ||
181 | { e } | ||
182 | |||
183 | expr13: | ||
184 | | f = expr13; arg = expr14 | ||
185 | { Apply (f, arg) } | ||
186 | | e = expr14 | ||
187 | { e } | ||
188 | |||
189 | %inline selectable: | ||
190 | | s = set | ||
191 | { Val s } | ||
192 | | id = ID | ||
193 | { Id id } | ||
194 | | e = delimited("(", expr0, ")") | ||
195 | { e } | ||
196 | |||
197 | expr14: | ||
198 | | e = selectable; "."; p = attr_path; o = option(preceded("or", expr14)) | ||
199 | { Select (e, p, o) } | ||
200 | | e = atomic_expr; "or" | ||
201 | { Apply (e, Id "or") } | ||
202 | | e = atomic_expr | ||
203 | { e } | ||
204 | |||
205 | atomic_expr: | ||
206 | | id = ID | ||
207 | { Id id } | ||
208 | | v = value | ||
209 | { Val v } | ||
210 | | e = delimited("(", expr0, ")") | ||
211 | { e } | ||
212 | |||
213 | attr_path: | ||
214 | | p = separated_nonempty_list(".", attr_path_component) | ||
215 | { p } | ||
216 | |||
217 | attr_path_component: | ||
218 | | "or" | ||
219 | { Id "or" } | ||
220 | | id = ID | ||
221 | { Id id } | ||
222 | | e = delimited("${", expr0, "}$") | ||
223 | { Aquote e } | ||
224 | | s = str | ||
225 | { Val s } | ||
226 | |||
227 | value: | ||
228 | | s = str | ||
229 | { s } | ||
230 | | s = istr | ||
231 | { s } | ||
232 | | i = INT | ||
233 | {Int i} | ||
234 | | f = FLOAT | ||
235 | { Float f } | ||
236 | | p = PATH | ||
237 | { Path p } | ||
238 | | sp = SPATH | ||
239 | { SPath sp } | ||
240 | | hp = HPATH | ||
241 | { HPath hp } | ||
242 | | uri = URI | ||
243 | { Uri uri } | ||
244 | | l = nixlist | ||
245 | { l } | ||
246 | | s = set | ||
247 | { s } | ||
248 | |||
249 | %inline str_mid(X): | ||
250 | | xs = list(pair(delimited("${", expr0, "}$"), X)) { xs } | ||
251 | |||
252 | /* Double-quoted string */ | ||
253 | str: | ||
254 | | start = STR_START; mids = str_mid(STR_MID); STR_END | ||
255 | { Str (start, mids) } | ||
256 | |||
257 | /* Indented string */ | ||
258 | istr: | ||
259 | | start = ISTR_START; mids = str_mid(ISTR_MID); i = ISTR_END | ||
260 | { IStr (i, start, mids) } | ||
261 | |||
262 | /* Lists and sets */ | ||
263 | nixlist: | ||
264 | | xs = delimited("[", list(expr14), "]") | ||
265 | { List xs } | ||
266 | |||
267 | empty_set: | ||
268 | | "{"; "}" {} | ||
269 | |||
270 | set: | ||
271 | | empty_set | ||
272 | { AttSet (Nonrec, []) } | ||
273 | | xs = delimited("{", nonempty_list(binding), "}") | ||
274 | { AttSet (Nonrec, xs) } | ||
275 | | xs = preceded("rec", delimited("{", list(binding), "}")) | ||
276 | { AttSet (Rec, xs) } | ||
277 | |||
278 | binding: | ||
279 | | kv = terminated(separated_pair(attr_path, "=", expr0), ";") | ||
280 | { let (k, v) = kv in AttrPath (k, v) } | ||
281 | | xs = delimited("inherit", pair(option(delimited("(", expr0, ")")), list(attr_path_component)), ";") | ||
282 | { let (prefix, ids) = xs in Inherit (prefix, ids) } | ||
283 | |||
284 | lambda: | ||
285 | | id = ID; "@"; p = param_set; ":"; e = expr0 | ||
286 | { Lambda (ParamSet (Some id, p), e) } | ||
287 | | p = param_set; "@"; id = ID; ":"; e = expr0 | ||
288 | { Lambda (ParamSet (Some id, p), e) } | ||
289 | | p = param_set; ":"; e = expr0 | ||
290 | { Lambda (ParamSet (None, p), e) } | ||
291 | | id = ID; ":"; e = expr0 | ||
292 | { Lambda (Alias id, e) } | ||
293 | |||
294 | %inline param_set: | ||
295 | | empty_set | ||
296 | { ([], Exact) } | ||
297 | | "{"; "..."; "}" | ||
298 | { ([], Loose) } | ||
299 | | ps = delimited("{", pair(pair(params, ","?), boption("...")), "}") | ||
300 | { let ((ps, _), ellipsis) = ps in (ps, if ellipsis then Loose else Exact) } | ||
301 | |||
302 | params: | ||
303 | | p = param | ||
304 | { [p] } | ||
305 | | ps = params; ","; p = param | ||
306 | { ps @ [p] } | ||
307 | |||
308 | %inline param: | ||
309 | p = pair(ID, option(preceded("?", expr0))) | ||
310 | { p } | ||