2 * Copyright (C) 2019 Richard W.M. Jones
3 * Copyright (C) 2019 Red Hat Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 (* There are several circular dependencies between the lexer
25 * (caused by includes) and eval. These references break
26 * the circular dependencies. They are initialized when
27 * the program starts, hence are never really None.
29 let lexer_read = ref None
30 let eval_substitute = ref None
32 let find_on_include_path filename =
33 if not (Filename.is_implicit filename) then filename
35 let rec loop = function
38 let path = inc // filename in
39 if Sys.file_exists path then path else loop incs
44 let do_include env loc filename optflag file =
46 match !eval_substitute with None -> assert false | Some f -> f in
47 let filename = eval_substitute env loc filename in
48 let filename = find_on_include_path filename in
49 if optflag && not (Sys.file_exists filename) then env
51 let fp = open_in filename in
52 let lexbuf = Lexing.from_channel fp in
53 lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = filename };
55 match !lexer_read with None -> assert false | Some r -> r in
56 let env' = file lexer_read lexbuf in
58 Ast.Env.merge env env'
63 %token <Ast.substs> CODE
81 %token <Ast.substs> STRING
84 %token <string> TACTIC
87 (* Start nonterminals. *)
88 %start <Ast.expr Ast.Env.t> file
89 %start <Ast.expr> expr
97 | (* none *) { Ast.Env.empty }
98 | stmts INCLUDE STRING option(SEMICOLON)
99 { do_include $1 $loc $3 false file }
100 | stmts OPTINCLUDE STRING option(SEMICOLON)
101 { do_include $1 $loc $3 true file }
102 | stmts stmt option(SEMICOLON)
103 { let name, expr = $2 in Ast.Env.add name expr $1 }
107 | option(goal_stmt) patterns COLON barelist option(CODE)
111 sprintf "_goal@%d" $startpos.pos_lnum, []
113 name, Ast.EGoalDefn ($loc, (params, $2, $4, $5))
117 let name, params = $1 in
118 name, Ast.EGoalDefn ($loc, (params, [], [], Some $2))
120 | FUNCTION ID params_decl return_decl EQUALS CODE
122 $2, Ast.EFuncDefn ($loc, ($3, $4, $6))
124 | TACTIC_KEYWORD TACTIC params_decl EQUALS CODE
126 $2, Ast.ETacticDefn ($loc, ($3, $5))
128 | LET ID EQUALS expr { $2, $4 }
132 | GOAL ID option(params_decl) EQUALS
133 { $2, match $3 with None -> [] | Some ps -> ps }
136 | LEFT_PAREN separated_list(COMMA, param_decl) RIGHT_PAREN { $2 }
142 | RETURNING EXPRESSION { RetExpr }
143 | RETURNING STRINGS { RetStrings }
144 | RETURNING STRING_KEYWORD { RetString }
147 | separated_list(COMMA, pattern) { $1 }
150 | STRING { Ast.PTactic ($loc, "*file", [$1]) }
151 | TACTIC pattern_params { Ast.PTactic ($loc, $1, $2) }
154 | LEFT_PAREN separated_list(COMMA, pattern_param) RIGHT_PAREN { $2 }
161 | ID params { Ast.ECall ($loc, $1, $2) }
162 | ID { Ast.EVar ($loc, $1) }
163 | TACTIC params { Ast.ETacticCtor ($loc, $1, $2) }
164 | STRING { Ast.ESubsts ($loc, $1) }
165 | LEFT_ARRAY barelist RIGHT_ARRAY { Ast.EList ($loc, $2) }
168 | right_flexible_list(COMMA, expr) { $1 }
171 | LEFT_PAREN separated_list(COMMA, expr) RIGHT_PAREN { $2 }
174 (* http://gallium.inria.fr/blog/lr-lists/ *)
175 right_flexible_list(delim, X):
176 | (* nothing *) { [] }
178 | x = X delim xs = right_flexible_list(delim, X) { x :: xs }