/*============================================================================= Boost.Wave: A Standard compliant C++ preprocessor library http://www.boost.org/ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #if !defined(BOOST_WAVE_LIBS_WAVE_TEST_COLLECT_HOOKS_INFORMATION_HPP) #define BOOST_WAVE_LIBS_WAVE_TEST_COLLECT_HOOKS_INFORMATION_HPP #include #include #include #include /////////////////////////////////////////////////////////////////////////////// // workaround for missing ostringstream #ifdef BOOST_NO_STRINGSTREAM #include #define BOOST_WAVETEST_OSSTREAM std::ostrstream std::string BOOST_WAVETEST_GETSTRING(std::ostrstream& ss) { ss << ends; std::string rval = ss.str(); ss.freeze(false); return rval; } #else #include #define BOOST_WAVETEST_GETSTRING(ss) ss.str() #define BOOST_WAVETEST_OSSTREAM std::ostringstream #endif /////////////////////////////////////////////////////////////////////////////// template String handle_filepath(String const &name) { using boost::wave::util::impl::unescape_lit; String unesc_name (unescape_lit(name)); typename String::size_type p = unesc_name.find_last_of("/\\"); if (p != unesc_name.npos) unesc_name = unesc_name.substr(p+1); return unesc_name; } /////////////////////////////////////////////////////////////////////////////// template inline String repr(boost::wave::util::file_position const& pos) { std::string linenum = boost::lexical_cast(pos.get_line()); return handle_filepath(pos.get_file()) + String("(") + linenum.c_str() + ")"; } template inline String repr(String const& value) { String result; typename String::const_iterator end = value.end(); for (typename String::const_iterator it = value.begin(); it != end; ++it) { typedef typename String::value_type char_type; char_type c = *it; if (c == static_cast('\a')) result.append("\\a"); else if (c == static_cast('\b')) result.append("\\b"); else if (c == static_cast('\f')) result.append("\\f"); else if (c == static_cast('\n')) result.append("\\n"); else if (c == static_cast('\r')) result.append("\\r"); else if (c == static_cast('\t')) result.append("\\t"); else if (c == static_cast('\v')) result.append("\\v"); else result += static_cast(c); } return result; } #if defined(BOOST_WINDOWS) template inline String replace_slashes(String value, char const* lookfor = "\\", char replace_with = '/') { typename String::size_type p = value.find_first_of(lookfor); while (p != value.npos) { value[p] = replace_with; p = value.find_first_of(lookfor, p+1); } return value; } #endif /////////////////////////////////////////////////////////////////////////////// template class collect_hooks_information : public boost::wave::context_policies::eat_whitespace { typedef boost::wave::context_policies::eat_whitespace base_type; public: collect_hooks_information(std::string& trace) : hooks_trace(trace), skipped_token_hooks(false) {} void set_skipped_token_hooks(bool flag) { skipped_token_hooks = flag; } /////////////////////////////////////////////////////////////////////////// // // The function 'expanding_function_like_macro' is called, whenever a // function-like macro is to be expanded. // // The parameter 'macrodef' marks the position, where the macro to expand // is defined. // // The parameter 'formal_args' holds the formal arguments used during the // definition of the macro. // // The parameter 'definition' holds the macro definition for the macro to // trace. // // The parameter 'macro_call' marks the position, where this macro invoked. // // The parameter 'arguments' holds the macro arguments used during the // invocation of the macro // // The parameters 'seqstart' and 'seqend' point into the input token // stream allowing to access the whole token sequence comprising the macro // invocation (starting with the opening parenthesis and ending after the // closing one). // // The return value defines, whether the corresponding macro will be // expanded (return false) or will be copied to the output (return true). // Note: the whole argument list is copied unchanged to the output as well // without any further processing. // /////////////////////////////////////////////////////////////////////////// template bool expanding_function_like_macro(Context const& ctx, Token const& macro, std::vector const& formal_args, Container const& definition, Token const& macrocall, std::vector const& arguments, Iterator const& seqstart, Iterator const& seqend) { BOOST_WAVETEST_OSSTREAM strm; // trace real macro call strm << "00: " << repr(macrocall.get_position()) << ": " << macrocall.get_value() << "("; for (typename std::vector::size_type i = 0; i < arguments.size(); ++i) { strm << boost::wave::util::impl::as_string(arguments[i]); if (i < arguments.size()-1) strm << ","; } strm << "), "; // trace macro definition strm << "[" << repr(macro.get_position()) << ": " << macro.get_value() << "("; for (typename std::vector::size_type i = 0; i < formal_args.size(); ++i) { strm << formal_args[i].get_value(); if (i < formal_args.size()-1) strm << ", "; } strm << ")=" << boost::wave::util::impl::as_string(definition) << "]" << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; // default is to normally expand the macro } /////////////////////////////////////////////////////////////////////////// // // The function 'expanding_object_like_macro' is called, whenever a // object-like macro is to be expanded . // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'macro' marks the position, where the macro to expand // is defined. // // The definition 'definition' holds the macro definition for the macro to // trace. // // The parameter 'macrocall' marks the position, where this macro invoked. // // The return value defines, whether the corresponding macro will be // expanded (return false) or will be copied to the output (return true). // /////////////////////////////////////////////////////////////////////////// template bool expanding_object_like_macro(Context const& ctx, Token const& macro, Container const& definition, Token const& macrocall) { BOOST_WAVETEST_OSSTREAM strm; strm << "01: " << repr(macro.get_position()) << ": " << macro.get_value() << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; // default is to normally expand the macro } /////////////////////////////////////////////////////////////////////////// // // The function 'expanded_macro' is called, whenever the expansion of a // macro is finished but before the rescanning process starts. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'result' contains the token sequence generated as the // result of the macro expansion. // /////////////////////////////////////////////////////////////////////////// template void expanded_macro(Context const& ctx, Container const& result) { BOOST_WAVETEST_OSSTREAM strm; strm << "02: " << boost::wave::util::impl::as_string(result) << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } /////////////////////////////////////////////////////////////////////////// // // The function 'rescanned_macro' is called, whenever the rescanning of a // macro is finished. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'result' contains the token sequence generated as the // result of the rescanning. // /////////////////////////////////////////////////////////////////////////// template void rescanned_macro(Context const& ctx, Container const& result) { BOOST_WAVETEST_OSSTREAM strm; strm << "03: " << boost::wave::util::impl::as_string(result) << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } /////////////////////////////////////////////////////////////////////////// // // The function 'found_include_directive' is called, whenever a #include // directive was located. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'filename' contains the (expanded) file name found after // the #include directive. This has the format '', '"file"' or // 'file'. // The formats '' or '"file"' are used for #include directives found // in the preprocessed token stream, the format 'file' is used for files // specified through the --force_include command line argument. // // The parameter 'include_next' is set to true if the found directive was // a #include_next directive and the BOOST_WAVE_SUPPORT_INCLUDE_NEXT // preprocessing constant was defined to something != 0. // // The return value defines, whether the found file will be included // (return false) or will be skipped (return true). // /////////////////////////////////////////////////////////////////////////// template bool found_include_directive(Context const& ctx, std::string filename, bool include_next) { BOOST_WAVETEST_OSSTREAM strm; strm << "04: " << filename; if (include_next) strm << " (include_next)"; strm << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; // ok to include this file } /////////////////////////////////////////////////////////////////////////// // // The function 'opened_include_file' is called, whenever a file referred // by an #include directive was successfully located and opened. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'filename' contains the file system path of the // opened file (this is relative to the directory of the currently // processed file or a absolute path depending on the paths given as the // include search paths). // // The include_depth parameter contains the current include file depth. // // The is_system_include parameter denotes, whether the given file was // found as a result of a #include <...> directive. // /////////////////////////////////////////////////////////////////////////// template void opened_include_file(Context const& ctx, std::string relname, std::string absname, bool is_system_include) { using boost::wave::util::impl::escape_lit; #if defined(BOOST_WINDOWS) relname = replace_slashes(relname); absname = replace_slashes(absname); #endif BOOST_WAVETEST_OSSTREAM strm; strm << "05: " << escape_lit(relname) << " (" << escape_lit(absname) << ")" << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } /////////////////////////////////////////////////////////////////////////// // // The function 'returning_from_include_file' is called, whenever an // included file is about to be closed after it's processing is complete. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // /////////////////////////////////////////////////////////////////////////// template void returning_from_include_file(Context const& ctx) { BOOST_WAVETEST_OSSTREAM strm; strm << "06: " << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } /////////////////////////////////////////////////////////////////////////// // // The function 'interpret_pragma' is called, whenever a #pragma command // directive is found which isn't known to the core Wave library, where // command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant // which defaults to "wave". // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'pending' may be used to push tokens back into the input // stream, which are to be used as the replacement text for the whole // #pragma directive. // // The parameter 'option' contains the name of the interpreted pragma. // // The parameter 'values' holds the values of the parameter provided to // the pragma operator. // // The parameter 'act_token' contains the actual #pragma token, which may // be used for error output. // // If the return value is 'false', the whole #pragma directive is // interpreted as unknown and a corresponding error message is issued. A // return value of 'true' signs a successful interpretation of the given // #pragma. // /////////////////////////////////////////////////////////////////////////// template bool interpret_pragma(Context const& ctx, Container &pending, Token const& option, Container const& values, Token const& act_token) { BOOST_WAVETEST_OSSTREAM strm; strm << "07: " << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; } /////////////////////////////////////////////////////////////////////////// // // The function 'defined_macro' is called, whenever a macro was defined // successfully. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'name' is a reference to the token holding the macro name. // // The parameter 'is_functionlike' is set to true, whenever the newly // defined macro is defined as a function like macro. // // The parameter 'parameters' holds the parameter tokens for the macro // definition. If the macro has no parameters or if it is a object like // macro, then this container is empty. // // The parameter 'definition' contains the token sequence given as the // replacement sequence (definition part) of the newly defined macro. // // The parameter 'is_predefined' is set to true for all macros predefined // during the initialization phase of the library. // /////////////////////////////////////////////////////////////////////////// template void defined_macro(Context const& ctx, Token const& macro, bool is_functionlike, std::vector const& pars, Container const& definition, bool is_predefined) { // do not trace the definition of the internal helper macros if (!is_predefined) { BOOST_WAVETEST_OSSTREAM strm; strm << "08: " << repr(macro.get_position()) << ": " << macro.get_value(); if (is_functionlike) { // list the parameter names for function style macros strm << "("; for (typename std::vector::size_type i = 0; i < pars.size(); ++i) { strm << pars[i].get_value(); if (i < pars.size()-1) strm << ", "; } strm << ")"; } strm << "=" << boost::wave::util::impl::as_string(definition) << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } } /////////////////////////////////////////////////////////////////////////// // // The function 'undefined_macro' is called, whenever a macro definition // was removed successfully. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'name' holds the name of the macro, which definition was // removed. // /////////////////////////////////////////////////////////////////////////// template void undefined_macro(Context const& ctx, Token const& macro) { BOOST_WAVETEST_OSSTREAM strm; strm << "09: " << repr(macro.get_position()) << ": " << macro.get_value() << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } /////////////////////////////////////////////////////////////////////////// // // The function 'found_directive' is called, whenever a preprocessor // directive was encountered, but before the corresponding action is // executed. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'directive' is a reference to the token holding the // preprocessing directive. // // The return value defines, whether the given expression has to be // to be executed in a normal way (return 'false'), or if it has to be // skipped altogether (return 'true'), which means it gets replaced in the // output by a single newline. // /////////////////////////////////////////////////////////////////////////// template bool found_directive(Context const& ctx, Token const& directive) { BOOST_WAVETEST_OSSTREAM strm; strm << "10: " << repr(directive.get_position()) << ": " << directive.get_value() << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; // by default we never skip any directives } /////////////////////////////////////////////////////////////////////////// // // The function 'evaluated_conditional_expression' is called, whenever a // conditional preprocessing expression was evaluated (the expression // given to a #if, #elif, #ifdef or #ifndef directive) // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'directive' is a reference to the token holding the // corresponding preprocessing directive. // // The parameter 'expression' holds the non-expanded token sequence // comprising the evaluated expression. // // The parameter expression_value contains the result of the evaluation of // the expression in the current preprocessing context. // // The return value defines, whether the given expression has to be // evaluated again, allowing to decide which of the conditional branches // should be expanded. You need to return 'true' from this hook function // to force the expression to be re-evaluated. // /////////////////////////////////////////////////////////////////////////// template bool evaluated_conditional_expression(Context const& ctx, Token const& directive, Container const& expression, bool expression_value) { BOOST_WAVETEST_OSSTREAM strm; strm << "11: " << repr(directive.get_position()) << ": " << directive.get_value() << " " << boost::wave::util::impl::as_string(expression) << ": " << expression_value << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; // ok to continue, do not re-evaluate expression } /////////////////////////////////////////////////////////////////////////// // // The function 'skipped_token' is called, whenever a token is about to be // skipped due to a false preprocessor condition (code fragments to be // skipped inside the not evaluated conditional #if/#else/#endif branches). // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'token' refers to the token to be skipped. // /////////////////////////////////////////////////////////////////////////// template void skipped_token(Context const& ctx, Token const& token) { // this normally generates a lot of noise if (skipped_token_hooks) { BOOST_WAVETEST_OSSTREAM strm; strm << "12: " << repr(token.get_position()) << ": >" << repr(token.get_value()) << "<" << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } } /////////////////////////////////////////////////////////////////////////// // // The function 'generated_token' will be called by the library whenever a // token is about to be returned from the library. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 't' is the token about to be returned from the library. // This function may alter the token, but in this case it must be // implemented with a corresponding signature: // // Token const& // generated_token(Context const& ctx, Token& t); // // which makes it possible to modify the token in place. // // The default behavior is to return the token passed as the parameter // without modification. // /////////////////////////////////////////////////////////////////////////// template Token const& generated_token(Context const& ctx, Token const& t) { // this generates a lot of noise // BOOST_WAVETEST_OSSTREAM strm; // strm << "13: " << std::endl; // hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return t; } /////////////////////////////////////////////////////////////////////////// // // The function 'may_skip_whitespace' will be called by the // library, whenever it must be tested whether a specific token refers to // whitespace and this whitespace has to be skipped. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The 'token' parameter holds a reference to the current token. The policy // is free to change this token if needed. // // The 'skipped_newline' parameter holds a reference to a boolean value // which should be set to true by the policy function whenever a newline // is going to be skipped. // // If the return value is true, the given token is skipped and the // preprocessing continues to the next token. If the return value is // false, the given token is returned to the calling application. // // ATTENTION! // Caution has to be used, because by returning true the policy function // is able to force skipping even significant tokens, not only whitespace. // /////////////////////////////////////////////////////////////////////////// template bool may_skip_whitespace(Context const& ctx, Token& token, bool& skipped_newline) { // this generates a lot of noise // BOOST_WAVETEST_OSSTREAM strm; // strm << "14: " << std::endl; // hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return this->base_type::may_skip_whitespace(ctx, token, skipped_newline); } #if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0 /////////////////////////////////////////////////////////////////////////// // // The function 'found_warning_directive' will be called by the library // whenever a #warning directive is found. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'message' references the argument token sequence of the // encountered #warning directive. // // If the return value is false, the library throws a preprocessor // exception of the type 'warning_directive', if the return value is true // the execution continues as if no #warning directive has been found. // /////////////////////////////////////////////////////////////////////////// template bool found_warning_directive(Context const& ctx, Container const& message) { BOOST_WAVETEST_OSSTREAM strm; strm << "15: " << boost::wave::util::impl::as_string(message) << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; } #endif /////////////////////////////////////////////////////////////////////////// // // The function 'found_error_directive' will be called by the library // whenever a #error directive is found. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'message' references the argument token sequence of the // encountered #error directive. // // If the return value is false, the library throws a preprocessor // exception of the type 'error_directive', if the return value is true // the execution continues as if no #error directive has been found. // /////////////////////////////////////////////////////////////////////////// template bool found_error_directive(Context const& ctx, Container const& message) { BOOST_WAVETEST_OSSTREAM strm; strm << "16: " << boost::wave::util::impl::as_string(message) << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; } /////////////////////////////////////////////////////////////////////////// // // The function 'found_line_directive' will be called by the library // whenever a #line directive is found. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'arguments' references the argument token sequence of the // encountered #line directive. // // The parameter 'line' contains the recognized line number from the #line // directive. // // The parameter 'filename' references the recognized file name from the // #line directive (if there was one given). // /////////////////////////////////////////////////////////////////////////// template void found_line_directive(Context const& ctx, Container const& arguments, unsigned int line, std::string const& filename) { BOOST_WAVETEST_OSSTREAM strm; strm << "17: " << boost::wave::util::impl::as_string(arguments) << " (" << line << ", \"" << filename << "\")" << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } /////////////////////////////////////////////////////////////////////////// // // The function 'throw_exception' will be called by the library whenever a // preprocessing exception occurs. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'e' is the exception object containing detailed error // information. // // The default behavior is to call the function boost::throw_exception. // /////////////////////////////////////////////////////////////////////////// template void throw_exception(Context const& ctx, Exception const& e) { BOOST_WAVETEST_OSSTREAM strm; strm << "18: " << e.what() << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return this->base_type::throw_exception(ctx, e); } #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 /////////////////////////////////////////////////////////////////////////// // // The function 'detected_include_guard' is called whenever either a // include file is about to be added to the list of #pragma once headers. // That means this header file will not be opened and parsed again even // if it is specified in a later #include directive. // This function is called as the result of a detected include guard // scheme. // // The implemented heuristics for include guards detects two forms of // include guards: // // #ifndef INCLUDE_GUARD_MACRO // #define INCLUDE_GUARD_MACRO // ... // #endif // // or // // if !defined(INCLUDE_GUARD_MACRO) // #define INCLUDE_GUARD_MACRO // ... // #endif // // note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO // will work as well). The code allows for any whitespace, newline and single // '#' tokens before the #if/#ifndef and after the final #endif. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'filename' contains the file system path of the // opened file (this is relative to the directory of the currently // processed file or a absolute path depending on the paths given as the // include search paths). // // The parameter contains the name of the detected include guard. // /////////////////////////////////////////////////////////////////////////// template void detected_include_guard(ContextT const& ctx, std::string filename, std::string const& include_guard) { using boost::wave::util::impl::escape_lit; #if defined(BOOST_WINDOWS) filename = replace_slashes(filename); #endif BOOST_WAVETEST_OSSTREAM strm; strm << "19: " << escape_lit(filename) << ": " << include_guard << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } /////////////////////////////////////////////////////////////////////////// // // The function 'detected_pragma_once' is called whenever either a // include file is about to be added to the list of #pragma once headers. // That means this header file will not be opened and parsed again even // if it is specified in a later #include directive. // This function is called as the result of a detected directive // #pragma once. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter pragma_token refers to the token "#pragma" triggering // this preprocessing hook. // // The parameter 'filename' contains the file system path of the // opened file (this is relative to the directory of the currently // processed file or a absolute path depending on the paths given as the // include search paths). // /////////////////////////////////////////////////////////////////////////// template void detected_pragma_once(ContextT const& ctx, TokenT const& pragma_token, std::string filename) { using boost::wave::util::impl::escape_lit; #if defined(BOOST_WINDOWS) filename = replace_slashes(filename); #endif BOOST_WAVETEST_OSSTREAM strm; strm << "20: " << repr(pragma_token.get_position()) << ": " << pragma_token.get_value() << ": " << escape_lit(filename) << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); } #endif /////////////////////////////////////////////////////////////////////////// // // The function 'found_unknown_directive' is called, whenever an unknown // preprocessor directive was encountered. // // The parameter 'ctx' is a reference to the context object used for // instantiating the preprocessing iterators by the user. // // The parameter 'line' holds the tokens of the entire source line // containing the unknown directive. // // The parameter 'pending' may be used to push tokens back into the input // stream, which are to be used as the replacement text for the whole // line containing the unknown directive. // // The return value defines, whether the given expression has been // properly interpreted by the hook function or not. If this function // returns 'false', the library will raise an 'ill_formed_directive' // preprocess_exception. Otherwise the tokens pushed back into 'pending' // are passed on to the user program. // /////////////////////////////////////////////////////////////////////////// template bool found_unknown_directive(ContextT const& ctx, ContainerT const& line, ContainerT& pending) { BOOST_WAVETEST_OSSTREAM strm; strm << "21: " << repr((*line.begin()).get_position()) << ": " << boost::wave::util::impl::as_string(line) << std::endl; hooks_trace += BOOST_WAVETEST_GETSTRING(strm); return false; } private: std::string& hooks_trace; bool skipped_token_hooks; }; #endif