11 /* Work around a problem on FreeBSD where Bison looks for _STDLIB_H
12 * to see if stdlib.h has been included, but the system includes
15 #if HAVE_STDLIB_H && ! defined _STDLIB_H
22 int augl_parse_file(struct augeas *aug, const char *name, struct term **term);
24 typedef void *yyscan_t;
25 typedef struct info YYLTYPE;
26 #define YYLTYPE_IS_DECLARED 1
27 /* The lack of reference counting on filename is intentional */
28 # define YYLLOC_DEFAULT(Current, Rhs, N) \
30 (Current).filename = augl_get_info(scanner)->filename; \
31 (Current).error = augl_get_info(scanner)->error; \
33 (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
34 (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
35 (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
36 (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
38 (Current).first_line = (Current).last_line = \
39 YYRHSLOC (Rhs, 0).last_line; \
40 (Current).first_column = (Current).last_column = \
41 YYRHSLOC (Rhs, 0).last_column; \
49 /* Track custom scanner state */
52 unsigned int comment_depth;
62 %parse-param {struct term **term}
63 %parse-param {yyscan_t scanner}
64 %lex-param {yyscan_t scanner}
71 @$.filename = augl_get_info(scanner)->filename;
72 @$.error = augl_get_info(scanner)->error;
75 %token <string> DQUOTED /* "foo" */
76 %token <regexp> REGEXP /* /[ \t]+/ */
77 %token <string> LIDENT UIDENT QIDENT
83 %token KW_LET KW_LET_REC KW_IN
87 %token KW_TEST KW_GET KW_PUT KW_AFTER
100 enum quant_tag quant;
103 %type<term> start decls
104 %type<term> exp composeexp unionexp minusexp catexp appexp rexp aexp
105 %type<term> param param_list
106 %type<string> qid id autoload
107 %type<type> type atype
110 %type<intval> test_special_res
111 %type<tree> tree_const tree_const2 tree_branch
112 %type<string> tree_label
116 extern int augl_lex (YYSTYPE * yylval_param,struct info * yylloc_param ,yyscan_t yyscanner);
117 int augl_init_lexer(struct state *state, yyscan_t * scanner);
118 void augl_close_lexer(yyscan_t *scanner);
119 int augl_lex_destroy (yyscan_t yyscanner );
120 int augl_get_lineno (yyscan_t yyscanner );
121 int augl_get_column (yyscan_t yyscanner);
122 struct info *augl_get_info(yyscan_t yyscanner);
123 char *augl_get_text (yyscan_t yyscanner );
125 static void augl_error(struct info *locp, struct term **term,
126 yyscan_t scanner, const char *s);
128 /* TERM construction */
129 static struct info *clone_info(struct info *locp);
130 static struct term *make_module(char *ident, char *autoload,
134 static struct term *make_bind(char *ident, struct term *params,
135 struct term *exp, struct term *decls,
137 static struct term *make_bind_rec(char *ident, struct term *exp,
138 struct term *decls, struct info *locp);
139 static struct term *make_let(char *ident, struct term *params,
140 struct term *exp, struct term *body,
142 static struct term *make_binop(enum term_tag tag,
143 struct term *left, struct term *right,
145 static struct term *make_unop(enum term_tag tag,
146 struct term *exp, struct info *locp);
147 static struct term *make_ident(char *qname, struct info *locp);
148 static struct term *make_unit_term(struct info *locp);
149 static struct term *make_string_term(char *value, struct info *locp);
150 static struct term *make_regexp_term(char *pattern,
151 int nocase, struct info *locp);
152 static struct term *make_rep(struct term *exp, enum quant_tag quant,
155 static struct term *make_get_test(struct term *lens, struct term *arg,
157 static struct term *make_put_test(struct term *lens, struct term *arg,
158 struct term *cmds, struct info *info);
159 static struct term *make_test(struct term *test, struct term *result,
160 enum test_result_tag tr_tag,
161 struct term *decls, struct info *locp);
162 static struct term *make_tree_value(struct tree *, struct info*);
163 static struct tree *tree_concat(struct tree *, struct tree *);
165 #define LOC_MERGE(a, b, c) \
167 (a).filename = (b).filename; \
168 (a).first_line = (b).first_line; \
169 (a).first_column = (b).first_column; \
170 (a).last_line = (c).last_line; \
171 (a).last_column = (c).last_column; \
172 (a).error = (b).error; \
179 start: KW_MODULE UIDENT '=' autoload decls
180 { (*term) = make_module($2, $4, $5, &@1); }
182 autoload: KW_AUTOLOAD LIDENT
187 decls: KW_LET LIDENT param_list '=' exp decls
189 LOC_MERGE(@1, @1, @5);
190 $$ = make_bind($2, $3, $5, $6, &@1);
192 | KW_LET_REC LIDENT '=' exp decls
194 LOC_MERGE(@1, @1, @4);
195 $$ = make_bind_rec($2, $4, $5, &@1);
197 | KW_TEST test_exp '=' exp decls
199 LOC_MERGE(@1, @1, @4);
200 $$ = make_test($2, $4, TR_CHECK, $5, &@1);
202 | KW_TEST test_exp '=' test_special_res decls
204 LOC_MERGE(@1, @1, @4);
205 $$ = make_test($2, NULL, $4, $5, &@1);
210 /* Test expressions and results */
212 test_exp: aexp KW_GET exp
213 { $$ = make_get_test($1, $3, &@$); }
214 | aexp KW_PUT aexp KW_AFTER exp
215 { $$ = make_put_test($1, $3, $5, &@$); }
217 test_special_res: '?'
222 /* General expressions */
223 exp: KW_LET LIDENT param_list '=' exp KW_IN exp
225 LOC_MERGE(@1, @1, @6);
226 $$ = make_let($2, $3, $5, $7, &@1);
230 composeexp: composeexp ';' unionexp
231 { $$ = make_binop(A_COMPOSE, $1, $3, &@$); }
235 unionexp: unionexp '|' minusexp
236 { $$ = make_binop(A_UNION, $1, $3, &@$); }
240 { $$ = make_tree_value($1, &@1); }
242 minusexp: minusexp '-' catexp
243 { $$ = make_binop(A_MINUS, $1, $3, &@$); }
247 catexp: catexp '.' appexp
248 { $$ = make_binop(A_CONCAT, $1, $3, &@$); }
253 { $$ = make_binop(A_APP, $1, $2, &@$); }
258 { $$ = make_ident($1, &@1); }
260 { $$ = make_string_term($1, &@1); }
262 { $$ = make_regexp_term($1.pattern, $1.nocase, &@1); }
266 { $$ = make_unop(A_BRACKET, $2, &@$); }
268 { $$ = make_unit_term(&@$); }
271 { $$ = make_rep($1, $2, &@$); }
287 { $$ = strdup("get"); }
289 { $$ = strdup("put"); }
291 param_list: param param_list
292 { $$ = $2; list_cons($$, $1); }
296 param: '(' id ':' type ')'
297 { $$ = make_param($2, $4, clone_info(&@1)); }
302 { $$ = strdup("get"); }
304 { $$ = strdup("put"); }
306 type: atype ARROW type
307 { $$ = make_arrow_type($1, $3); }
312 { $$ = make_base_type(T_STRING); }
314 { $$ = make_base_type(T_REGEXP); }
316 { $$ = make_base_type(T_LENS); }
320 tree_const: tree_const '{' tree_branch '}'
321 { $$ = tree_concat($1, $3); }
322 | '{' tree_branch '}'
323 { $$ = tree_concat($2, NULL); }
325 tree_const2: tree_const2 '{' tree_branch '}'
327 $$ = tree_concat($1, $3);
332 tree_branch: tree_label tree_const2
334 $$ = make_tree($1, NULL, NULL, $2);
336 | tree_label '=' DQUOTED tree_const2
338 $$ = make_tree($1, $3, NULL, $4);
345 int augl_parse_file(struct augeas *aug, const char *name,
346 struct term **term) {
349 struct string *sname = NULL;
357 ERR_NOMEM(r < 0, aug);
359 sname->str = strdup(name);
360 ERR_NOMEM(sname->str == NULL, aug);
364 info.filename = sname;
365 info.error = aug->error;
369 state.comment_depth = 0;
371 if (augl_init_lexer(&state, &scanner) < 0) {
372 augl_error(&info, term, NULL, "file not found");
376 yydebug = getenv("YYDEBUG") != NULL;
377 r = augl_parse(term, scanner);
378 augl_close_lexer(scanner);
379 augl_lex_destroy(scanner);
381 augl_error(&info, term, NULL, "syntax error");
384 augl_error(&info, term, NULL, "parser ran out of memory");
390 unref(sname, string);
395 // FIXME: Nothing here checks for alloc errors.
396 static struct info *clone_info(struct info *locp) {
399 info->filename = ref(locp->filename);
400 info->first_line = locp->first_line;
401 info->first_column = locp->first_column;
402 info->last_line = locp->last_line;
403 info->last_column = locp->last_column;
404 info->error = locp->error;
408 static struct term *make_term_locp(enum term_tag tag, struct info *locp) {
409 struct info *info = clone_info(locp);
410 return make_term(tag, info);
413 static struct term *make_module(char *ident, char *autoload,
416 struct term *term = make_term_locp(A_MODULE, locp);
418 term->autoload = autoload;
423 static struct term *make_bind(char *ident, struct term *params,
424 struct term *exp, struct term *decls,
426 struct term *term = make_term_locp(A_BIND, locp);
428 exp = build_func(params, exp);
432 list_cons(decls, term);
436 static struct term *make_bind_rec(char *ident, struct term *exp,
437 struct term *decls, struct info *locp) {
438 /* Desugar let rec IDENT = EXP as
440 * let RLENS = (lns_make_rec) in
441 * lns_check_rec ((lambda IDENT: EXP) RLENS) RLENS
442 * where RLENS is a brandnew recursive lens.
444 * That only works since we know that 'let rec' is only defined for lenses,
445 * not general purposes functions, i.e. we know that IDENT has type 'lens'
447 * The point of all this is that we make it possible to put a recursive
448 * lens (which is a placeholder for the actual recursion) into arbitrary
449 * places in some bigger lens and then have LNS_CHECK_REC rattle through
450 * to do the special-purpose typechecking.
453 struct info *info = exp->info;
454 struct term *lambda = NULL, *rlens = NULL;
455 struct term *app1 = NULL, *app2 = NULL, *app3 = NULL;
458 if (id == NULL) goto error;
460 lambda = make_param(id, make_base_type(T_LENS), ref(info));
461 if (lambda == NULL) goto error;
464 build_func(lambda, exp);
466 rlens = make_term(A_VALUE, ref(exp->info));
467 if (rlens == NULL) goto error;
468 rlens->value = lns_make_rec(ref(exp->info));
469 if (rlens->value == NULL) goto error;
470 rlens->type = make_base_type(T_LENS);
472 app1 = make_app_term(lambda, rlens, ref(info));
473 if (app1 == NULL) goto error;
475 id = strdup(LNS_CHECK_REC_NAME);
476 if (id == NULL) goto error;
477 app2 = make_app_ident(id, app1, ref(info));
478 if (app2 == NULL) goto error;
481 app3 = make_app_term(app2, ref(rlens), ref(info));
482 if (app3 == NULL) goto error;
484 return make_bind(ident, NULL, app3, decls, locp);
496 static struct term *make_let(char *ident, struct term *params,
497 struct term *exp, struct term *body,
499 /* let f (x:string) = "f " . x in
501 /* (lambda f: f "a" . f "b") (lambda x: "f " . x) */
502 /* (lambda IDENT: BODY) (lambda PARAMS: EXP) */
503 /* Desugar as (lambda IDENT: BODY) (lambda PARAMS: EXP) */
504 struct term *term = make_term_locp(A_LET, locp);
505 struct term *p = make_param(ident, NULL, ref(term->info));
506 term->left = build_func(p, body);
508 term->right = build_func(params, exp);
514 static struct term *make_binop(enum term_tag tag,
515 struct term *left, struct term *right,
517 assert(tag == A_COMPOSE || tag == A_CONCAT
518 || tag == A_UNION || tag == A_APP || tag == A_MINUS);
519 struct term *term = make_term_locp(tag, locp);
525 static struct term *make_unop(enum term_tag tag, struct term *exp,
527 assert(tag == A_BRACKET);
528 struct term *term = make_term_locp(tag, locp);
533 static struct term *make_ident(char *qname, struct info *locp) {
534 struct term *term = make_term_locp(A_IDENT, locp);
535 term->ident = make_string(qname);
539 static struct term *make_unit_term(struct info *locp) {
540 struct term *term = make_term_locp(A_VALUE, locp);
541 term->value = make_unit(ref(term->info));
545 static struct term *make_string_term(char *value, struct info *locp) {
546 struct term *term = make_term_locp(A_VALUE, locp);
547 term->value = make_value(V_STRING, ref(term->info));
548 term->value->string = make_string(value);
552 static struct term *make_regexp_term(char *pattern, int nocase,
554 struct term *term = make_term_locp(A_VALUE, locp);
555 term->value = make_value(V_REGEXP, ref(term->info));
556 term->value->regexp = make_regexp(term->info, pattern, nocase);
560 static struct term *make_rep(struct term *exp, enum quant_tag quant,
562 struct term *term = make_term_locp(A_REP, locp);
568 static struct term *make_get_test(struct term *lens, struct term *arg,
570 /* Return a term for "get" LENS ARG */
571 struct info *info = clone_info(locp);
572 struct term *term = make_app_ident(strdup("get"), lens, info);
573 term = make_app_term(term, arg, ref(info));
577 static struct term *make_put_test(struct term *lens, struct term *arg,
578 struct term *cmds, struct info *locp) {
579 /* Return a term for "put" LENS (CMDS ("get" LENS ARG)) ARG */
580 struct term *term = make_get_test(lens, arg, locp);
581 term = make_app_term(cmds, term, ref(term->info));
582 struct term *put = make_app_ident(strdup("put"), ref(lens), ref(term->info));
583 put = make_app_term(put, term, ref(term->info));
584 put = make_app_term(put, ref(arg), ref(term->info));
588 static struct term *make_test(struct term *test, struct term *result,
589 enum test_result_tag tr_tag,
590 struct term *decls, struct info *locp) {
591 struct term *term = make_term_locp(A_TEST, locp);
592 term->tr_tag = tr_tag;
594 term->result = result;
599 static struct term *make_tree_value(struct tree *tree, struct info *locp) {
600 struct term *term = make_term_locp(A_VALUE, locp);
601 struct value *value = make_value(V_TREE, ref(term->info));
602 value->origin = make_tree_origin(tree);
607 static struct tree *tree_concat(struct tree *t1, struct tree *t2) {
613 void augl_error(struct info *locp,
618 struct string string;
620 info.ref = string.ref = UINT_MAX;
621 info.filename = &string;
624 info.first_line = locp->first_line;
625 info.first_column = locp->first_column;
626 info.last_line = locp->last_line;
627 info.last_column = locp->last_column;
628 info.filename->str = locp->filename->str;
629 info.error = locp->error;
630 } else if (scanner != NULL) {
631 info.first_line = augl_get_lineno(scanner);
632 info.first_column = augl_get_column(scanner);
633 info.last_line = augl_get_lineno(scanner);
634 info.last_column = augl_get_column(scanner);
635 info.filename = augl_get_info(scanner)->filename;
636 info.error = augl_get_info(scanner)->error;
637 } else if (*term != NULL && (*term)->info != NULL) {
638 memcpy(&info, (*term)->info, sizeof(info));
640 info.first_line = info.last_line = 0;
641 info.first_column = info.last_column = 0;
643 syntax_error(&info, "%s", s);