/* 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 #include #include #include "util/scoped_map.h" #include "util/script_state.h" #include "util/name_map.h" #include "util/exception.h" #include "kernel/environment.h" #include "kernel/expr_maps.h" #include "library/io_state.h" #include "library/io_state_stream.h" #include "library/kernel_bindings.h" #include "frontends/lean/scanner.h" #include "frontends/lean/parser_config.h" #include "frontends/lean/parser_pos_provider.h" namespace lean { struct parameter { pos_info m_pos; expr m_local; binder_info m_bi; parameter(pos_info const & p, expr const & l, binder_info const & bi): m_pos(p), m_local(l), m_bi(bi) {} parameter():m_pos(0, 0) {} }; /** \brief Exception used to track parsing erros, it does not leak outside of this class. */ struct parser_error : public exception { pos_info m_pos; parser_error(char const * msg, pos_info const & p):exception(msg), m_pos(p) {} parser_error(sstream const & msg, pos_info const & p):exception(msg), m_pos(p) {} virtual exception * clone() const { return new parser_error(m_msg.c_str(), m_pos); } virtual void rethrow() const { throw *this; } }; struct interrupt_parser {}; class parser { typedef std::pair local_entry; typedef std::pair local_level_entry; typedef scoped_map local_decls; typedef scoped_map local_level_decls; environment m_env; io_state m_ios; script_state * m_ss; bool m_verbose; bool m_use_exceptions; bool m_show_errors; scanner m_scanner; scanner::token_kind m_curr; local_decls m_local_decls; local_level_decls m_local_level_decls; pos_info m_last_cmd_pos; pos_info m_last_script_pos; unsigned m_next_tag_idx; bool m_found_errors; pos_info_table_ptr m_pos_table; enum class scope_kind { Scope, Namespace, Structure }; std::vector m_namespace_prefixes; std::vector m_scope_kinds; void display_error_pos(unsigned line, unsigned pos); void display_error_pos(pos_info p); void display_error(char const * msg, unsigned line, unsigned pos); void display_error(char const * msg, pos_info p); void display_error(exception const & ex); void throw_parser_exception(char const * msg, pos_info p); void throw_nested_exception(exception & ex, pos_info p); void sync_command(); void protected_call(std::function && f, std::function && sync); template typename std::result_of::type using_script(F && f) { return m_ss->apply([&](lua_State * L) { set_io_state set1(L, m_ios); set_environment set2(L, m_env); return f(L); }); } tag get_tag(expr e); expr copy_with_new_pos(expr const & e, pos_info p); void updt_options(); parser_config const & cfg() const { return get_parser_config(env()); } cmd_table const & cmds() const { return cfg().m_cmds; } parse_table const & nud() const { return cfg().m_nud; } parse_table const & led() const { return cfg().m_led; } /** \brief Return true if 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; void add_local_entry(name const & n, expr const & e); void add_local_decl(expr const & t); unsigned curr_level_lbp() const; level parse_max_imax(bool is_max); level parse_level_id(); level parse_level_nud(); level parse_level_led(level left); void parse_command(); void parse_script(bool as_expr = false); bool parse_commands(); unsigned curr_lbp() const; expr parse_notation(parse_table t, expr * left); expr parse_nud_notation(); expr parse_led_notation(expr left); expr parse_nud(); expr parse_led(expr left); expr parse_id(); expr parse_numeral_expr(); expr parse_decimal_expr(); expr parse_string_expr(); parameter parse_binder_core(binder_info const & bi); void parse_binder_block(buffer & r, binder_info const & bi); void parse_binders_core(buffer & r); expr mk_app(expr fn, expr arg, pos_info const & p); public: parser(environment const & env, io_state const & ios, std::istream & strm, char const * str_name, script_state * ss = nullptr, bool use_exceptions = false); environment const & env() const { return m_env; } io_state const & ios() const { return m_ios; } script_state * ss() const { return m_ss; } void parse_names(buffer> & result); unsigned parse_small_nat(); level parse_level(unsigned rbp = 0); level mk_new_level_param(); parameter parse_binder(); void parse_binders(buffer & r); expr parse_expr(unsigned rbp = 0); expr parse_scoped_expr(unsigned num_locals, expr const * locals, unsigned rbp = 0); expr parse_scoped_expr(unsigned num_params, parameter const * ps, unsigned rbp = 0); expr parse_scoped_expr(buffer & ps, unsigned rbp = 0) { return parse_scoped_expr(ps.size(), ps.data(), rbp); } expr abstract(unsigned num_params, parameter const * ps, expr const & e, bool lambda = true); expr abstract(buffer const & ps, expr const & e, bool lambda = true) { return abstract(ps.size(), ps.data(), e, lambda); } tactic parse_tactic(unsigned rbp = 0); /** \brief Return the current position information */ pos_info pos() const { return pos_info(m_scanner.get_line(), m_scanner.get_pos()); } expr save_pos(expr e, pos_info p); expr rec_save_pos(expr const & e, pos_info p); pos_info pos_of(expr const & e, pos_info default_pos); pos_info pos_of(expr const & e) { return pos_of(e, pos()); } pos_info cmd_pos() const { return m_last_cmd_pos; } /** \brief Read the next token. */ void scan() { m_curr = m_scanner.scan(m_env); } /** \brief Return the current token */ scanner::token_kind curr() const { return m_curr; } /** \brief Return true iff the current token is an identifier */ bool curr_is_identifier() const { return curr() == scanner::token_kind::Identifier; } /** \brief Return true iff the current token is a numeral */ bool curr_is_numeral() const { return curr() == scanner::token_kind::Numeral; } /** \brief Read the next token if the current one is not End-of-file. */ void next() { if (m_curr != scanner::token_kind::Eof) scan(); } /** \brief Return true iff the current token is a keyword (or command keyword) named \c tk */ bool curr_is_token(name const & tk) const; /** \brief Check current token, and move to next characther, throw exception if current token is not \c tk. */ void check_token_next(name const & tk, 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(); } regular regular_stream() const { return regular(env(), ios()); } diagnostic diagnostic_stream() const { return diagnostic(env(), ios()); } /** parse all commands in the input stream */ bool operator()() { return parse_commands(); } }; bool parse_commands(environment & env, io_state & ios, std::istream & in, char const * strm_name, script_state * S, bool use_exceptions); bool parse_commands(environment & env, io_state & ios, char const * fname, script_state * S, bool use_exceptions); }