-
Notifications
You must be signed in to change notification settings - Fork 81
/
parser.h
702 lines (604 loc) · 34.6 KB
/
parser.h
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
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <string>
#include <utility>
#include <vector>
#include "util/flet.h"
#include "util/name_map.h"
#include "util/exception.h"
#include "util/task.h"
#include "kernel/environment.h"
#include "kernel/expr_maps.h"
#include "library/util.h"
#include "library/module.h"
#include "library/abstract_parser.h"
#include "library/io_state.h"
#include "library/io_state_stream.h"
#include "library/message_builder.h"
#include "library/tactic/tactic_log.h"
#include "library/tactic/tactic_state.h"
#include "frontends/lean/parser_state.h"
#include "frontends/lean/local_decls.h"
#include "frontends/lean/local_level_decls.h"
#include "frontends/lean/parser_config.h"
#include "frontends/lean/local_context_adapter.h"
#include "frontends/lean/decl_util.h"
namespace lean {
struct interrupt_parser {};
typedef environment local_environment;
class metavar_context;
class local_context_adapter;
class scope_message_context;
#define AST_TOP_ID 1
class parser_info {
protected:
environment m_env;
local_expr_decls m_local_decls;
name_set m_level_variables;
name_set m_variables; // subset of m_local_decls that is marked as variables
local_level_decls m_local_level_decls;
bool m_has_params; // true context context contains parameters
name_set m_include_vars; // subset of m_local_decls that is marked as include
bool m_in_quote;
bool m_in_pattern;
io_state m_ios;
parser_scope_stack m_parser_scope_stack;
unsigned m_next_inst_idx;
bool m_show_errors;
// profiling
bool m_profile;
noncomputable_policy m_noncomputable_policy;
// error recovery
bool m_error_recovery = true;
public:
parser_info(environment const & env, io_state const & ios) :
m_env(env), m_ios(ios) {}
bool is_local_decl_user_name(expr const & l) const { return is_local(l) && m_local_decls.contains(mlocal_pp_name(l)); }
bool is_local_decl(expr const & l);
bool is_local_level_variable(name const & n) const { return m_level_variables.contains(n); }
bool is_local_variable(expr const & e) const { return m_variables.contains(mlocal_name(e)); }
bool is_local_variable_user_name(name const & n) const {
if (expr const * d = m_local_decls.find(n))
return is_local(*d) && m_variables.contains(mlocal_name(*d));
else
return false;
}
void clear_expr_locals();
bool has_locals() const { return !m_local_decls.empty() || !m_local_level_decls.empty(); }
void add_local_level(name const & n, level const & l, bool is_variable = false);
void add_local_expr(name const & n, expr const & p, bool is_variable = false);
environment add_local_ref(environment const & env, name const & n, expr const & ref);
void add_variable(name const & n, expr const & p);
void add_parameter(name const & n, expr const & p);
void add_local(expr const & p, bool is_variable = false) {
return add_local_expr(mlocal_pp_name(p), p, is_variable); }
bool has_params() const { return m_has_params; }
/** \brief Update binder information for the section parameter n, return true if success, and false if n is not a section parameter. */
bool update_local_binder_info(name const & n, binder_info const & bi);
void include_variable(name const & n) { m_include_vars.insert(n); }
void omit_variable(name const & n) { m_include_vars.erase(n); }
bool is_include_variable(name const & n) const { return m_include_vars.contains(n); }
void get_include_variables(buffer<expr> & vars) const;
void get_include_var_names(buffer<name> & vars) const;
void get_available_include_var_names(buffer<expr> & vars) const;
/** \brief Position of the local level declaration named \c n in the sequence of local level decls. */
unsigned get_local_level_index(name const & n) const { return m_local_level_decls.find_idx(n); }
bool is_local_level(name const & n) const { return m_local_level_decls.contains(n); }
/** \brief Position of the local declaration named \c n in the sequence of local decls. */
unsigned get_local_index(name const & n) const;
unsigned get_local_index(expr const & e) const { return get_local_index(mlocal_pp_name(e)); }
/** \brief Return the local parameter named \c n */
expr const * get_local(name const & n) const { return m_local_decls.find(n); }
/** \brief Return local declarations as a list of local constants. */
list<expr> locals_to_context() const;
/** \brief Return all local declarations and aliases */
list<pair<name, expr>> const & get_local_entries() const { return m_local_decls.get_entries(); }
virtual pos_info pos() const = 0;
virtual void maybe_throw_error(parser_error && err) = 0;
environment const & env() const { return m_env; }
void set_env(environment const & env) { m_env = env; }
io_state const & ios() const { return m_ios; }
struct local_scope {
parser_info & m_p; environment m_env;
local_scope(parser_info & p, bool save_options = false);
local_scope(parser_info & p, environment const & env);
local_scope(parser_info & p, optional<environment> const & env);
~local_scope();
};
bool has_local_scopes() const { return !is_nil(m_parser_scope_stack); }
void push_local_scope(bool save_options = true);
void pop_local_scope();
protected:
parser_scope mk_parser_scope(optional<options> const & opts = optional<options>());
void restore_parser_scope(parser_scope const & s);
virtual std::tuple<expr, expr, name> parse_definition(ast_data * parent, buffer<name> & lp_names, buffer<expr> & params,
bool is_example, bool is_instance, bool, bool) = 0;
friend environment single_definition_cmd_core(parser_info & p, decl_cmd_kind kind, ast_data * parent, cmd_meta meta);
public:
void updt_options();
options get_options() const { return m_ios.get_options(); }
template<typename T> void set_option(name const & n, T const & v) { m_ios.set_option(n, v); }
virtual expr save_pos(expr const & e, pos_info p) = 0;
virtual expr rec_save_pos(expr const & e, pos_info p) = 0;
virtual expr rec_save_pos(expr const & e, optional<pos_info> p) = 0;
virtual optional<pos_info> get_pos_info(expr const & e) const = 0;
virtual message_builder mk_message(pos_info const &p, message_severity severity) const = 0;
virtual message_builder mk_message(message_severity severity) const = 0;
noncomputable_policy get_noncomputable_policy() const { return m_noncomputable_policy; }
void set_noncomputable_policy(noncomputable_policy p) { m_noncomputable_policy = p; }
virtual char const * get_file_name() const = 0;
virtual pos_info cmd_pos() const = 0;
virtual optional<pos_info> const & get_break_at_pos() const = 0;
virtual parser_pos_provider get_parser_pos_provider(pos_info const & some_pos) const = 0;
virtual std::shared_ptr<tactic_log> get_tactic_log() { return nullptr; }
expr mk_sorry(pos_info const & p, bool synthetic = false);
bool has_error_recovery() const { return m_error_recovery; }
};
typedef rb_map<unsigned, ast_id, unsigned_cmp> tag_ast_table;
class parser : public abstract_parser, public parser_info {
name_generator m_ngen;
bool m_use_exceptions;
module_loader m_import_fn;
std::string m_file_name;
scanner m_scanner;
token_kind m_curr;
bool m_imports_parsed = false;
bool m_scanner_inited = false;
parser_scope_stack m_quote_stack;
pos_info m_last_cmd_pos;
unsigned m_next_tag_idx;
ast_id m_vm_parser_ast_id = 0;
pos_info_table m_pos_table;
tag_ast_table m_tag_ast_table;
std::vector<ast_data*> m_ast;
bool m_ast_invalid = false;
ast_id m_commands = 0;
std::shared_ptr<tactic_log> m_tactic_log;
// By default, when the parser finds a unknown identifier, it signs an error.
// When the following flag is true, it creates a constant.
// This flag is when we are trying to parse mutually recursive declarations.
id_behavior m_id_behavior;
optional<pos_info> m_break_at_pos;
// auto completing
bool m_complete{false};
bool m_error_since_last_cmd = false;
pos_info m_last_recovered_error_pos {0, 0};
optional<pos_info> m_backtracking_pos;
void sync_command();
tag get_tag(expr e);
unsigned curr_level_lbp() const;
pair<ast_id, level> parse_max_imax(bool is_max);
pair<ast_id, level> parse_level_id();
pair<ast_id, level> parse_level_nud();
pair<ast_id, level> parse_level_led(pair<ast_id, level> left);
ast_id parse_mod_doc_block();
void process_imports(ast_data * parent);
void process_postponed(buffer<expr> const & args, bool is_left, buffer<notation::action_kind> const & kinds,
buffer<list<expr>> const & nargs, buffer<expr> const & ps, buffer<pair<unsigned, pos_info>> const & scoped_info,
list<notation::action> const & postponed, pos_info const & p, buffer<expr> & new_args);
expr parse_notation(parse_table t, expr * left);
expr parse_nud_notation();
expr parse_led_notation(expr left);
expr parse_inaccessible();
expr parse_placeholder();
// expr parse_anonymous_var_pattern();
expr parse_nud();
bool curr_starts_expr();
expr parse_numeral_expr(bool user_notation = true);
expr parse_decimal_expr();
expr parse_string_expr();
expr parse_char_expr();
pair<ast_id, expr> parse_inst_implicit_decl();
void parse_inst_implicit_decl(ast_data * parent, buffer<expr> & r);
expr parse_binder_core(binder_info const & bi, unsigned rbp);
ast_id parse_binder_collection(buffer<pair<pos_info, name>> const & names, binder_info const & bi, buffer<expr> & r);
ast_id parse_binder_block(buffer<expr> & r, binder_info const & bi, unsigned rbp, bool allow_default);
struct parse_binders_config {
/* (input) If m_allow_empty is true, then parse_binders will succeed even if not binder is parsed. */
bool m_allow_empty{false};
/* (input) right binding power */
unsigned m_rbp{0};
/* (input) If m_simple_only, then binder modifiers '{', '[' and '⦃' are not allowed. */
bool m_simple_only{false};
/* (input) If true, it will allow binders of the form (x : T := v), and they will be converted
into (x : opt_param T v) */
bool m_allow_default{false};
/* (input) If true, then all binders must be surrounded with some kind of bracket. (e.g., '()', '{}', '[]').
We use this feature when parsing examples/definitions/theorems. The goal is to avoid counter-intuitive
declarations such as:
example p : false := trivial
def main proof : false := trivial
which would be parsed as
example (p : false) : _ := trivial
def main (proof : false) : _ := trivial
where `_` in both cases is elaborated into `true`. This issue was raised by @gebner in the slack channel.
Remark: we still want implicit delimiters for lambda/pi expressions. That is, we want to
write
fun x : t, s
or
fun x, s
instead of
fun (x : t), s
*/
bool m_explicit_delimiters{false};
/* (input and output)
If m_infer_kind != nullptr, then a sequence of binders can be prefixed with '{}' or '()'
Moreover, *m_infer_kind will be updated with
- implicit_infer_kind::None if prefix is '()'
- implicit_infer_kind::RelaxedImplicit if prefix is '{}'
- implicit_infer_kind::Implicit, if prefix is '[]'.
The default is `RelaxedImplicit` */
implicit_infer_kind * m_infer_kind{nullptr};
/* (output) The AST ID associated to the m_infer_kind */
ast_id * m_infer_kind_id{nullptr};
/* (output) It is set to true if the last binder is surrounded
with some kind of bracket (e.g., '()', '{}', '[]'). */
bool m_last_block_delimited{false};
/* (output) If m_nentries != nullptr, then local notation declarations are stored here */
buffer<notation_entry> * m_nentries{nullptr};
};
void parse_binders_core(ast_data * parent, buffer<expr> & r, parse_binders_config & cfg);
local_environment parse_binders(ast_data * parent, buffer<expr> & r, parse_binders_config & cfg);
ast_id parse_local_notation_decl(buffer<notation_entry> * entries);
std::tuple<ast_id, optional<name>, expr> parse_id_tk_expr(name const & tk, unsigned rbp);
friend environment section_cmd(parser & p, ast_id &);
friend environment namespace_cmd(parser & p, ast_id &);
friend environment end_scoped_cmd(parser & p, ast_id &);
std::shared_ptr<snapshot> mk_snapshot();
optional<expr> resolve_local(name const & id, pos_info const & p, list<name> const & extra_locals);
friend class module_parser;
friend class patexpr_to_expr_fn;
struct backtracking_exception {};
flet<optional<pos_info>> backtracking_scope() {
return flet<optional<pos_info>>(m_backtracking_pos, optional<pos_info>(pos()));
}
bool consumed_input() {
return *m_backtracking_pos != pos();
}
public:
parser(environment const & env, io_state const & ios,
module_loader const & import_fn,
std::istream & strm, std::string const & file_name,
bool use_exceptions = false);
parser(parser const &) = delete;
~parser();
void init_scanner();
ast_data & new_ast(name type, pos_info start, name value = {});
void finalize_ast(ast_id id, expr const & e);
bool is_ast_invalid() { return m_ast_invalid; }
void set_ast_expr(ast_id id, expr e);
ast_data & get_ast(ast_id id) { return *m_ast[id]; }
ast_id get_id(expr const & e) const;
ast_data & expr_ast(expr const & e) { return get_ast(get_id(e)); }
const char * ast_string(ast_id id) const { return m_ast[id]->m_value.get_string(); }
pos_info ast_pos(ast_id id) const { return m_ast[id]->m_start; }
void push_from_vm_parse(ast_id id) { if (m_vm_parser_ast_id) get_ast(m_vm_parser_ast_id).push(id); }
ast_id get_vm_parse_parent() { return m_vm_parser_ast_id; }
ast_id set_vm_parse_parent(ast_id id) {
auto old = m_vm_parser_ast_id;
m_vm_parser_ast_id = id;
return old;
}
ast_data & new_modifiers(cmd_meta & meta);
friend void export_ast(parser const &);
void from_snapshot(snapshot const & snap);
name next_name() { return m_ngen.next(); }
void set_break_at_pos(pos_info const & pos) { m_break_at_pos = some(pos); }
optional<pos_info> const & get_break_at_pos() const override { return m_break_at_pos; }
template <class T>
T without_break_at_pos(std::function<T()> const & f) {
flet<optional<pos_info>> l(m_break_at_pos, {});
return f();
}
template <class T>
pair<T, pos_info> with_input(std::istream & input, std::function<T()> const & f) {
flet<token_kind> l(m_curr, token_kind::Eof);
flet<scanner> l1(m_scanner, scanner(input, m_scanner.get_stream_name().c_str()));
m_curr = m_scanner.scan(m_env);
T t = f();
return {t, pos()};
}
bool get_complete() { return m_complete; }
void set_complete(bool complete) { m_complete = complete; }
/** \brief Throw \c break_at_pos_exception with given context if \c m_break_at_pos is inside current token. */
void check_break_at_pos(break_at_pos_exception::token_context ctxt = break_at_pos_exception::token_context::none);
/** \brief Throw \c break_at_pos_exception with empty token and given context if \c m_break_at_pos is before current
position. */
void check_break_before(break_at_pos_exception::token_context ctxt = break_at_pos_exception::token_context::none);
bool in_pattern() const { return m_in_pattern; }
name mk_anonymous_inst_name();
unsigned curr_lbp() const;
cmd_table const & cmds() const { return get_cmd_table(env()); }
message_builder mk_message(pos_info const & p, message_severity severity) const override;
message_builder mk_message(pos_info const & start_pos, pos_info const & end_pos, message_severity severity) const;
message_builder mk_message(message_severity severity) const override;
local_level_decls const & get_local_level_decls() const { return m_local_level_decls; }
local_expr_decls const & get_local_expr_decls() const { return m_local_decls; }
/** \brief Return the current position information */
virtual pos_info pos() const override final { return m_scanner.get_pos_info(); }
pos_info end_pos() const { return m_scanner.get_last_end_pos_info(); }
virtual expr save_pos(expr const & e, pos_info p) override final;
expr rec_save_pos(expr const & e, pos_info p) override final;
expr rec_save_pos(expr const & e, optional<pos_info> p) override final { return p ? rec_save_pos(e, *p) : e; }
expr update_pos(expr e, pos_info p);
void erase_pos(expr const & e);
pos_info pos_of(expr const & e, pos_info default_pos) const;
pos_info pos_of(expr const & e) const { return pos_of(e, pos()); }
pos_info cmd_pos() const override { return m_last_cmd_pos; }
parser_pos_provider get_parser_pos_provider(pos_info const & some_pos) const override {
return parser_pos_provider(m_pos_table, m_file_name, some_pos, m_next_tag_idx);
}
std::shared_ptr<tactic_log> get_tactic_log() override;
expr mk_app(expr fn, expr arg, pos_info const & p);
expr mk_app(expr fn, buffer<expr> const & args, pos_info const & p);
expr mk_app(std::initializer_list<expr> const & args, pos_info const & p);
parse_table const & nud() const { return get_nud_table(env()); }
parse_table const & led() const { return get_led_table(env()); }
expr copy_with_new_pos(expr const & e, pos_info p);
/** \brief Read the next token. */
void scan();
/** \brief Return the current token */
token_kind curr() const { return m_curr; }
/** \brief Return true iff the current token is an identifier */
bool curr_is_identifier() const { return curr() == token_kind::Identifier; }
/** \brief Return true iff the current token is a numeral */
virtual bool curr_is_numeral() const final override { return curr() == token_kind::Numeral; }
bool curr_is_decimal() const { return curr() == token_kind::Decimal; }
/** \brief Return true iff the current token is a string */
bool curr_is_string() const { return curr() == token_kind::String; }
/** \brief Return true iff the current token is a keyword */
bool curr_is_keyword() const { return curr() == token_kind::Keyword; }
/** \brief Return true iff the current token is a keyword */
bool curr_is_command() const { return curr() == token_kind::CommandKeyword; }
/** \brief Return true iff the current token is EOF */
bool curr_is_eof() const { return curr() == token_kind::Eof; }
/** \brief Return true iff the current token is a keyword */
bool curr_is_quoted_symbol() const { return curr() == token_kind::QuotedSymbol; }
/** \brief Return true iff the current token is a keyword named \c tk or an identifier named \c tk */
bool curr_is_token_or_id(name const & tk) const;
/** \brief Return true iff the current token is a command, EOF, period or script block */
bool curr_is_command_like() const;
/** \brief Read the next token if the current one is not End-of-file. */
virtual void next() override final { if (m_curr != token_kind::Eof) scan(); }
/** \brief Return true iff the current token is a keyword (or command keyword) named \c tk */
virtual bool curr_is_token(name const & tk) const override final;
/** \brief Returns the n-th token ahead, where the 0th one is the next one (after \c curr()). */
token_kind ahead(int n = 0);
/** \brief Lookahead version of \c curr_is_token. See \c ahead(). */
bool ahead_is_token(name const & tk, int n = 0);
/** \brief Check current token, and move to next character, throw exception if current token is not \c tk. Returns true if succesful. */
bool check_token_next(name const & tk, char const * msg);
void check_token_or_id_next(name const & tk, char const * msg);
/** \brief Check if the current token is an identifier, if it is return it and move to next token,
otherwise throw an exception. */
pair<ast_id, name> check_id_next(char const * msg, break_at_pos_exception::token_context ctxt =
break_at_pos_exception::token_context::none);
void check_not_internal(name const & n, pos_info const & pos);
/** \brief Similar to check_id_next, but also ensures the identifier is *not* an internal/reserved name. */
pair<ast_id, name> check_decl_id_next(char const * msg, break_at_pos_exception::token_context ctxt =
break_at_pos_exception::token_context::none);
/** \brief Check if the current token is an atomic identifier, if it is, return it and move to next token,
otherwise throw an exception. */
pair<ast_id, name> check_atomic_id_next(char const * msg);
pair<ast_id, name> check_atomic_decl_id_next(char const * msg);
list<name> to_constants(name const & id, char const * msg, pos_info const & p) const;
name to_constant(name const & id, char const * msg, pos_info const & p);
/** \brief Check if the current token is a constant, if it is, return it and move to next token, otherwise throw an exception. */
pair<ast_id, name> check_constant_next(char const * msg);
mpq const & get_num_val() const { return m_scanner.get_num_val(); }
name const & get_name_val() const { return m_scanner.get_name_val(); }
std::string const & get_str_val() const { return m_scanner.get_str_val(); }
token_info const & get_token_info() const { return m_scanner.get_token_info(); }
std::string const & get_stream_name() const { return m_scanner.get_stream_name(); }
std::vector<ast_comment> const & get_comments() const { return m_scanner.get_comments(); }
unsigned get_small_nat();
virtual pair<ast_id, unsigned> parse_small_nat() override final;
virtual pair<ast_id, std::string> parse_string_lit() override final;
pair<ast_id, double> parse_double();
/** \brief Parses a documentation block (`/-- TEXT -/`). For example, `/-- Doc\ndoc -/` returns " Doc\ndoc ". */
pair<ast_id, std::string> parse_doc_block();
ast_id parse_local_notation_decl() { return parse_local_notation_decl(nullptr); }
pair<ast_id, level> parse_level(unsigned rbp = 0);
expr parse_binder(unsigned rbp);
local_environment parse_binders(ast_data * parent, buffer<expr> & r, bool & last_block_delimited) {
parse_binders_config cfg;
auto new_env = parse_binders(parent, r, cfg);
last_block_delimited = cfg.m_last_block_delimited;
return new_env;
}
local_environment parse_binders(ast_data * parent, buffer<expr> & r, unsigned rbp, bool allow_default = false) {
parse_binders_config cfg;
cfg.m_rbp = rbp;
cfg.m_allow_default = allow_default;
return parse_binders(parent, r, cfg);
}
void parse_simple_binders(ast_data * parent, buffer<expr> & r, unsigned rbp) {
parse_binders_config cfg;
cfg.m_simple_only = true;
cfg.m_rbp = rbp;
parse_binders(parent, r, cfg);
}
local_environment parse_optional_binders(ast_data * parent, buffer<expr> & r, bool allow_default = false, bool explicit_delimiters = false) {
parse_binders_config cfg;
cfg.m_allow_empty = true;
cfg.m_allow_default = allow_default;
cfg.m_explicit_delimiters = explicit_delimiters;
return parse_binders(parent, r, cfg);
}
local_environment parse_optional_binders(ast_data * parent, buffer<expr> & r, ast_id & kind_id, implicit_infer_kind & kind) {
parse_binders_config cfg;
cfg.m_allow_empty = true;
cfg.m_infer_kind = &kind;
cfg.m_infer_kind_id = &kind_id;
return parse_binders(parent, r, cfg);
}
local_environment parse_binders(ast_data * parent, buffer<expr> & r, buffer<notation_entry> & nentries) {
parse_binders_config cfg;
cfg.m_nentries = &nentries;
return parse_binders(parent, r, cfg);
}
optional<binder_info> parse_optional_binder_info(bool simple_only = false);
binder_info parse_binder_info(bool simple_only = false);
void parse_close_binder_info(optional<binder_info> const & bi);
void parse_close_binder_info(binder_info const & bi) { return parse_close_binder_info(optional<binder_info>(bi)); }
/** \brief Convert an identifier into an expression (constant or local constant) based on the current scope */
expr id_to_expr(name const & id, ast_data & data,
bool resolve_only = false, bool allow_field_notation = true,
list<name> const & extra_locals = list<name>());
/** Always parses an expression. Returns a synthetic sorry even if no input is consumed. */
expr parse_expr(unsigned rbp = 0);
/** Tries to parse an expression, or else consumes no input. */
optional<expr> maybe_parse_expr(unsigned rbp = 0);
/** Tries to parse a pattern in equation-based specifications,
or else consumes no input. */
optional<expr> maybe_parse_pattern(unsigned rbp);
/** \brief Parse an (optionally) qualified expression.
If the input is of the form <id> : <expr>, then return the pair (some(id), expr).
Otherwise, parse the next expression and return (none, expr). */
std::tuple<ast_id, optional<name>, expr> parse_qualified_expr(unsigned rbp = 0);
/** \brief If the input is of the form <id> := <expr>, then return the pair (some(id), expr).
Otherwise, parse the next expression and return (none, expr). */
std::tuple<ast_id, optional<name>, expr> parse_optional_assignment(unsigned rbp = 0);
/** \brief Parse a pattern or expression */
expr parse_pattern_or_expr(unsigned rbp = 0);
/** \brief Convert an expression parsed using parse_pattern_or_expr into a pattern.
The new local constants declared by the pattern are stored at new_locals.
If skip_main_fn == true, then in the top-level application (f ...), the function f
is not processed. */
expr patexpr_to_pattern(expr const & pat_or_expr, bool skip_main_fn, buffer<expr> & new_locals);
/** \brief Convert an expression parsed using parse_pattern_or_expr into a regular term. */
expr patexpr_to_expr(expr const & pat_or_expr);
expr patexpr_to_expr_core(expr const & pat_or_expr);
expr parse_pattern(buffer<expr> & new_locals, unsigned rbp = 0) {
return patexpr_to_pattern(parse_pattern_or_expr(rbp), false, new_locals);
}
/* \brief Set pattern mode, and invoke fn. The new locals are stored in new_locals */
expr parse_pattern(std::function<expr(parser &)> const & fn, buffer<expr> & new_locals);
expr parse_id(bool allow_field_notation = true);
expr parse_led(expr left);
expr parse_led_loop(expr left, unsigned rbp);
expr parse_scoped_expr(unsigned num_params, expr const * ps, local_environment const & lenv, unsigned rbp = 0);
expr parse_scoped_expr(buffer<expr> const & ps, local_environment const & lenv, unsigned rbp = 0) {
return parse_scoped_expr(ps.size(), ps.data(), lenv, rbp);
}
expr parse_scoped_expr(unsigned num_params, expr const * ps, unsigned rbp = 0) {
return parse_scoped_expr(num_params, ps, local_environment(m_env), rbp);
}
expr parse_scoped_expr(buffer<expr> const & ps, unsigned rbp = 0) { return parse_scoped_expr(ps.size(), ps.data(), rbp); }
expr parse_expr_with_env(local_environment const & lenv, unsigned rbp = 0);
bool parse_command_like(ast_data * parent = nullptr);
ast_id parse_command(cmd_meta const & meta);
bool parse_imports(unsigned & fingerprint, ast_data * parent, std::vector<module_name> &);
bool imports_parsed() const { return m_imports_parsed; }
struct quote_scope {
parser & m_p;
id_behavior m_id_behavior;
bool m_old_in_quote;
bool m_in_quote;
bool m_saved_in_pattern;
quote_scope(parser & p, bool q, id_behavior i = id_behavior::AssumeLocalIfNotLocal);
~quote_scope();
};
bool in_quote() const { return m_in_quote; }
void maybe_throw_error(parser_error && err) override;
pair<ast_id, level> parser_error_or_level(parser_error && err);
expr parser_error_or_expr(parser_error && err);
void throw_invalid_open_binder(pos_info const & pos);
flet<bool> error_recovery_scope(bool enable_recovery) {
return flet<bool>(m_error_recovery, enable_recovery);
}
flet<bool> no_error_recovery_scope() { return error_recovery_scope(false); }
flet<bool> no_error_recovery_scope_if(bool cond) {
return error_recovery_scope(m_error_recovery && !cond);
}
/* This is the default mode. We also use it when converting a pre-term that can be a pattern_or_expression
into an expression.
\remark By default, when the parser finds a unknown identifier, it signs an error. */
struct error_if_undef_scope : public flet<id_behavior> { error_if_undef_scope(parser & p); };
/* We use this mode when parsing patterns (and a pre-term that can be a pattern or expression). */
struct all_id_local_scope : public flet<id_behavior> { all_id_local_scope(parser & p); };
/* We use this mode when converting a pre-term that can be a pattern_or_expression into a pattern. */
struct undef_id_to_local_scope : public flet<id_behavior> { undef_id_to_local_scope(parser &); };
private:
pair<expr, level_param_names> elaborate(name const & decl_name, metavar_context & mctx, local_context_adapter const & adapter,
expr const & e, bool check_unassigned = true, bool freeze_instances = true);
public:
local_context_adapter mk_local_context_adapter() { return local_context_adapter(m_local_decls); }
pair<expr, level_param_names> elaborate(name const & decl_name, metavar_context & mctx, expr const & e, bool check_unassigned = true, bool freeze_instances = true);
pair<expr, level_param_names> elaborate(name const & decl_name, metavar_context & mctx, list<expr> const & lctx, expr const & e, bool check_unassigned, bool freeze_instances);
pair<expr, level_param_names> elaborate(name const & decl_name, list<expr> const & ctx, expr const & e);
pair<expr, level_param_names> elaborate_type(name const & decl_name, list<expr> const & lctx, expr const & e, bool freeze_instances = true);
/* Elaborate \c e as a type using the given metavariable context, and using m_local_decls as the local context */
pair<expr, level_param_names> elaborate_type(name const & decl_name, metavar_context & mctx, expr const & e, bool freeze_instances = true);
/** return true iff profiling is enabled */
bool profiling() const { return m_profile; }
void get_imports(std::vector<module_name> &);
class in_notation_ctx {
scanner::in_notation_ctx m_ctx;
public:
in_notation_ctx(parser & p):m_ctx(p.m_scanner) {}
};
bool in_notation() const { return m_scanner.in_notation(); }
public:
/* pos_info_provider API */
virtual optional<pos_info> get_pos_info(expr const & e) const override;
virtual pos_info get_some_pos() const override;
virtual char const * get_file_name() const override;
protected:
virtual std::tuple<expr, expr, name> parse_definition(ast_data * parent, buffer<name> & lp_names, buffer<expr> & params,
bool is_example, bool is_instance, bool, bool) override;
};
bool parse_commands(environment & env, io_state & ios, char const * fname);
class dummy_def_parser : public parser_info {
public:
pos_info m_pos;
std::string m_file_name;
name m_name;
buffer<name> m_lp_params;
buffer<expr> m_params;
expr m_type;
buffer<pair<buffer<expr>, expr>> m_val;
optional<expr> m_wf_tac;
optional<pos_info> m_break_at_pos;
public:
dummy_def_parser(environment const & env, options const & opts) :
parser_info(env, io_state(io_state(), opts))
{ m_error_recovery = false; }
char const * get_file_name() const override { return m_file_name.c_str(); }
options get_options() const { return m_ios.get_options(); }
message_builder mk_message(pos_info const &p, message_severity severity) const override {
std::shared_ptr<abstract_type_context> tc = std::make_shared<type_context_old>(m_env, get_options());
return message_builder(tc, m_env, m_ios, get_file_name(), p, severity); }
message_builder mk_message(message_severity severity) const override {
return mk_message(pos(), severity); }
pos_info pos() const override { return m_pos; }
pos_info cmd_pos() const override { return m_pos; }
environment const & env() const { return m_env; }
optional<pos_info> const & get_break_at_pos() const override { return m_break_at_pos; }
parser_pos_provider get_parser_pos_provider(pos_info const & some_pos) const override {
return parser_pos_provider(rb_map<unsigned, pos_info, unsigned_cmp>(), m_file_name, some_pos, 0);
}
bool is_local_level(name const & n) const { return m_local_level_decls.contains(n); }
bool is_local_level_variable(name const & n) const { return m_level_variables.contains(n); }
void maybe_throw_error(parser_error && err) override;
buffer<name> const & get_univ_params() const { return m_lp_params; }
name get_name() const { return m_name; }
buffer<expr> const & get_binders() { return m_params; }
expr const & get_type() { return m_type; }
const buffer<pair<buffer<expr>, expr>> & get_val() const { return m_val; }
virtual expr save_pos(expr const & e, pos_info) override { return e; }
virtual expr rec_save_pos(expr const & e, pos_info) override { return e; }
virtual expr rec_save_pos(expr const & e, optional<pos_info>) override { return e; }
virtual optional<pos_info> get_pos_info(expr const &) const override { return optional<pos_info>(m_pos); }
optional<expr> get_well_founded_tac() const { return m_wf_tac; }
protected:
virtual std::tuple<expr, expr, name> parse_definition(ast_data * parent, buffer<name> & lp_names, buffer<expr> & params,
bool is_example, bool is_instance, bool, bool) override;
};
void initialize_parser();
void finalize_parser();
}