aboutsummaryrefslogtreecommitdiffstats
path: root/lib/nix/parser.mly
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nix/parser.mly')
-rw-r--r--lib/nix/parser.mly310
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
74main:
75| e = expr0 EOF
76 { e }
77
78expr0:
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
102expr1:
103| e = binary_expr(expr2, "->" {Impl}, expr1)
104| e = expr2
105 { e }
106
107expr2:
108| e = binary_expr(expr2, "||" {Or}, expr3)
109| e = expr3
110 { e }
111
112expr3:
113| e = binary_expr(expr3, "&&" {And}, expr4)
114| e = expr4
115 { e }
116
117%inline expr4_ops:
118| "==" { Eq }
119| "!=" { Neq }
120
121expr4:
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
132expr5:
133| e = binary_expr(expr6, expr5_ops, expr6)
134| e = expr6
135 { e }
136
137expr6:
138| e = binary_expr(expr7, "//" {Merge}, expr6)
139| e = expr7
140 { e }
141
142expr7:
143| e = preceded("!", expr7)
144 { UnaryOp (Not, e) }
145| e = expr8
146 { e }
147
148%inline expr8_ops:
149| "+" { Plus }
150| "-" { Minus }
151
152expr8:
153| e = binary_expr(expr8, expr8_ops, expr9)
154| e = expr9
155 { e }
156
157%inline expr9_ops:
158| "*" { Mult }
159| "/" { Div }
160
161expr9:
162| e = binary_expr(expr9, expr9_ops, expr10)
163| e = expr10
164 { e }
165
166expr10:
167| e = binary_expr(expr11, "++" {Concat}, expr10)
168| e = expr11
169 { e }
170
171expr11:
172| e = expr12 "?" p = attr_path
173 { Test (e, p) }
174| e = expr12
175 { e }
176
177expr12:
178| e = preceded("-", expr13)
179 { UnaryOp (Negate, e) }
180| e = expr13
181 { e }
182
183expr13:
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
197expr14:
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
205atomic_expr:
206| id = ID
207 { Id id }
208| v = value
209 { Val v }
210| e = delimited("(", expr0, ")")
211 { e }
212
213attr_path:
214| p = separated_nonempty_list(".", attr_path_component)
215 { p }
216
217attr_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
227value:
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 */
253str:
254| start = STR_START; mids = str_mid(STR_MID); STR_END
255 { Str (start, mids) }
256
257/* Indented string */
258istr:
259| start = ISTR_START; mids = str_mid(ISTR_MID); i = ISTR_END
260 { IStr (i, start, mids) }
261
262/* Lists and sets */
263nixlist:
264| xs = delimited("[", list(expr14), "]")
265 { List xs }
266
267empty_set:
268| "{"; "}" {}
269
270set:
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
278binding:
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
284lambda:
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
302params:
303| p = param
304 { [p] }
305| ps = params; ","; p = param
306 { ps @ [p] }
307
308%inline param:
309p = pair(ID, option(preceded("?", expr0)))
310 { p }