From 3ee432e25081bad5deb92dbbbab37af569abcaaa Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 2 Nov 2011 08:46:38 +0000 Subject: [PATCH] Quickbook: Parse templates using the version they were defined for. Needs to store the version in the file object, since it's only known after the file is read in, had to make files non-const. Put some checks in to make sure this isn't abused but pretty messy. [SVN r75260] --- src/actions.cpp | 107 +++++++++++++++++++++----------------- src/actions_class.hpp | 3 ++ src/code_snippet.cpp | 8 +-- src/doc_info_actions.cpp | 3 ++ src/files.cpp | 25 +++++---- src/files.hpp | 30 +++++++++-- src/quickbook.cpp | 3 +- src/values.cpp | 11 ++-- src/values.hpp | 2 +- src/values_parse.hpp | 7 --- test/unit/values_test.cpp | 4 +- 11 files changed, 123 insertions(+), 80 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index fd8d78b..2b7e6b9 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -677,10 +677,10 @@ namespace quickbook if (program.size() == 0) return; // Nothing left to do here. The program is empty. - file fake_file; - - fake_file.path = actions.current_file->path; - fake_file.source = program; + file fake_file( + actions.current_file->path, + program, + qbk_version_n); parse_iterator first_(fake_file.source.begin()); parse_iterator last_(fake_file.source.end()); @@ -852,7 +852,8 @@ namespace quickbook // fit in a tiny box (IE7). // - attributes.insert(attribute_map::value_type("format", qbk_value("SVG"))); + attributes.insert(attribute_map::value_type("format", + qbk_value("SVG", qbk_version_n))); // // Image paths are relative to the html subdirectory: @@ -890,7 +891,8 @@ namespace quickbook { attributes.insert(std::make_pair( "contentwidth", qbk_value(std::string( - svg_text.begin() + a + 1, svg_text.begin() + b)) + svg_text.begin() + a + 1, svg_text.begin() + b), + qbk_version_n) )); } a = svg_text.find("height"); @@ -901,7 +903,8 @@ namespace quickbook { attributes.insert(std::make_pair( "contentdepth", qbk_value(std::string( - svg_text.begin() + a + 1, svg_text.begin() + b)) + svg_text.begin() + a + 1, svg_text.begin() + b), + qbk_version_n) )); } } @@ -1135,47 +1138,32 @@ namespace quickbook bool parse_template( template_body const& body - , bool escape , quickbook::actions& actions ) { - if (escape) - { - // TODO: Should this be surrounded in escape comments? - // escape the body of the template - // we just copy out the literal body - (body.is_block() ? actions.out : actions.phrase) << body.content.get_quickbook(); - return true; - } - else if (body.type == template_body::raw_output) - { - (body.is_block() ? actions.out : actions.phrase) << body.content.get_boostbook(); - return true; - } - else - { - file const* saved_current_file = actions.current_file; + assert(body.type != template_body::raw_output); - actions.current_file = body.content.get_file(); - string_ref source = body.content.get_quickbook(); + file const* saved_current_file = actions.current_file; - parse_iterator first(source.begin()); - parse_iterator last(source.end()); + actions.current_file = body.content.get_file(); + string_ref source = body.content.get_quickbook(); - bool r = cl::parse(first, last, - body.is_block() ? - actions.grammar().block : - actions.grammar().simple_phrase - ).full; + parse_iterator first(source.begin()); + parse_iterator last(source.end()); - boost::swap(actions.current_file, saved_current_file); + bool r = cl::parse(first, last, + body.is_block() ? + actions.grammar().block : + actions.grammar().simple_phrase + ).full; - return r; - } + boost::swap(actions.current_file, saved_current_file); + + return r; } } - void call_template(quickbook::actions& actions, bool template_escape, + void call_template(quickbook::actions& actions, template_symbol const* symbol, std::vector const& args, string_iterator first) @@ -1193,6 +1181,8 @@ namespace quickbook { template_state state(actions); + qbk_version_n = symbol->body.content.get_file()->version(); + ++actions.template_depth; if (actions.template_depth > actions.max_template_depth) { @@ -1206,7 +1196,7 @@ namespace quickbook // [section] and [endsect] tags in the template are balanced. actions.min_section_level = actions.ids.section_level(); - // Quickbook 1.4-: When expanding the tempalte continue to use the + // Quickbook 1.4-: When expanding the template continue to use the // current scope (the dynamic scope). // Quickbook 1.5+: Use the scope the template was defined in // (the static scope). @@ -1228,7 +1218,7 @@ namespace quickbook /////////////////////////////////// // parse the template body: - if (!parse_template(symbol->body, template_escape, actions)) + if (!parse_template(symbol->body, actions)) { detail::outerr(actions.current_file, first) << "Expanding " @@ -1269,7 +1259,6 @@ namespace quickbook } void call_code_snippet(quickbook::actions& actions, - bool template_escape, template_symbol const* symbol, string_iterator first) { @@ -1296,7 +1285,7 @@ namespace quickbook callout_ids.push_back(callout_id2); } - call_template(actions, template_escape, symbol, args, first); + call_template(actions, symbol, args, first); std::string block; @@ -1314,8 +1303,7 @@ namespace quickbook template_state state(actions); ++actions.template_depth; - bool r = parse_template( - template_body(c), false, actions); + bool r = parse_template(template_body(c), actions); if(!r) { @@ -1368,6 +1356,30 @@ namespace quickbook template_symbol const* symbol = actions.templates.find(identifier); BOOST_ASSERT(symbol); + // Deal with raw templates and escaped templates. + + if (symbol->body.type == template_body::raw_output) + { + // Note: 'raw_output' is currently only used for callouts in code_snippets. + (symbol->body.is_block() ? actions.out : actions.phrase) + << symbol->body.content.get_boostbook(); + return; + } + else if (template_escape) + { + if (!args.empty()) + { + detail::outerr(actions.current_file, first) + << "Arguments for escaped template." + <body.is_block() ? actions.out : actions.phrase) + << symbol->body.content.get_quickbook(); + return; + } + /////////////////////////////////// // Initialise the arguments @@ -1391,7 +1403,7 @@ namespace quickbook return; } - call_template(actions, template_escape, symbol, args, first); + call_template(actions, symbol, args, first); } else { @@ -1405,7 +1417,7 @@ namespace quickbook args.clear(); } - call_code_snippet(actions, template_escape, symbol, first); + call_code_snippet(actions, symbol, first); } } @@ -1807,7 +1819,8 @@ namespace quickbook qbk_version_n >= 106u ? file_state::scope_callables : file_state::scope_macros); - actions.current_file = load(paths.filename); // Throws load_error + actions.current_file_tmp = load(paths.filename); // Throws load_error + actions.current_file = actions.current_file_tmp; actions.filename_relative = paths.filename_relative; actions.imported = (load_type == block_tags::import); @@ -1871,7 +1884,7 @@ namespace quickbook if (tname == "!") { ts.parent = &actions.templates.top_scope(); - call_code_snippet(actions, false, &ts, first); + call_code_snippet(actions, &ts, first); } } diff --git a/src/actions_class.hpp b/src/actions_class.hpp index f654dc0..eecf335 100644 --- a/src/actions_class.hpp +++ b/src/actions_class.hpp @@ -49,6 +49,9 @@ namespace quickbook int context; bool conditional; id_manager& ids; + file* current_file_tmp; // Temporary non-const pointer to new + // current_file so that the + // version can be written to. // state saved for files and templates. bool imported; diff --git a/src/code_snippet.cpp b/src/code_snippet.cpp index 50dd406..d19e034 100644 --- a/src/code_snippet.cpp +++ b/src/code_snippet.cpp @@ -26,7 +26,7 @@ namespace quickbook struct code_snippet_actions { code_snippet_actions(std::vector& storage, - file const* source_file, + file* source_file, char const* source_type) : callout_id(0) , storage(storage) @@ -84,7 +84,7 @@ namespace quickbook std::string code; std::string id; std::vector& storage; - file const* source_file; + file* source_file; char const* const source_type; }; @@ -321,7 +321,7 @@ namespace quickbook load_type == block_tags::import); bool is_python = extension == ".py"; - code_snippet_actions a(storage, load(filename), is_python ? "[python]" : "[c++]"); + code_snippet_actions a(storage, load(filename, qbk_version_n), is_python ? "[python]" : "[c++]"); // TODO: Should I check that parse succeeded? @@ -461,7 +461,7 @@ namespace quickbook } // TODO: Save position in start_snippet - template_symbol symbol(snippet->id, params, qbk_value(body, template_tags::block)); + template_symbol symbol(snippet->id, params, qbk_value(body, qbk_version_n, template_tags::block)); symbol.callouts = callouts; storage.push_back(symbol); diff --git a/src/doc_info_actions.cpp b/src/doc_info_actions.cpp index 40cb678..d4a22e0 100644 --- a/src/doc_info_actions.cpp +++ b/src/doc_info_actions.cpp @@ -146,6 +146,7 @@ namespace quickbook if (!docinfo_type) { + actions.current_file_tmp->version(qbk_version_n); actions.ids.start_file(include_doc_id_, id_, actions.doc_title_qbk); return; @@ -193,6 +194,8 @@ namespace quickbook ++actions.error_count; } + actions.current_file_tmp->version(qbk_version_n); + id_manager::start_file_info start_file_info = actions.ids.start_file_with_docinfo( qbk_version_n, include_doc_id_, id_, diff --git a/src/files.cpp b/src/files.cpp index ac313f7..2103ef3 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -96,17 +96,13 @@ namespace quickbook boost::unordered_map files; } - file const* load(fs::path const& filename) + file* load(fs::path const& filename, unsigned qbk_version) { - boost::unordered_map::iterator pos; - bool inserted; + boost::unordered_map::iterator pos + = files.find(filename); - boost::tie(pos, inserted) = files.emplace(filename, file()); - - if (inserted) + if (pos == files.end()) { - pos->second.path = filename; - fs::ifstream in(filename, std::ios_base::in); if (!in) @@ -115,10 +111,21 @@ namespace quickbook // Turn off white space skipping on the stream in.unsetf(std::ios::skipws); + std::string source; normalize( std::istream_iterator(in), std::istream_iterator(), - std::back_inserter(pos->second.source)); + std::back_inserter(source)); + + bool inserted; + + boost::tie(pos, inserted) = files.emplace( + boost::unordered::piecewise_construct, + boost::make_tuple(filename), + boost::make_tuple(filename, source, qbk_version) + ); + + assert(inserted); } return &pos->second; diff --git a/src/files.hpp b/src/files.hpp index c5b5ca7..d23f65c 100644 --- a/src/files.hpp +++ b/src/files.hpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace quickbook { @@ -27,11 +28,34 @@ namespace quickbook { struct file { - fs::path path; - std::string source; + fs::path const path; + std::string const source; + private: + unsigned qbk_version; + public: + + file(fs::path const& path, std::string const& source, + unsigned qbk_version) : + path(path), source(source), qbk_version(qbk_version) + {} + + unsigned version() const { + assert(qbk_version); + return qbk_version; + } + + void version(unsigned v) { + // Check that either version hasn't been set, or it was + // previously set to the same version (because the same + // file has been loaded twice). + assert(!qbk_version || qbk_version == v); + qbk_version = v; + } }; - file const* load(fs::path const& filename); + // If version isn't supplied then it must be set later. + file* load(fs::path const& filename, + unsigned qbk_version = 0); } #endif // BOOST_QUICKBOOK_FILES_HPP diff --git a/src/quickbook.cpp b/src/quickbook.cpp index 2af0647..1cfba23 100644 --- a/src/quickbook.cpp +++ b/src/quickbook.cpp @@ -130,7 +130,8 @@ namespace quickbook actions actor(filein_, xinclude_base_, buffer, ids); set_macros(actor); - actor.current_file = load(filein_); // Throws load_error + actor.current_file_tmp = load(filein_); // Throws load_error + actor.current_file = actor.current_file_tmp; parse_file(actor); diff --git a/src/values.cpp b/src/values.cpp index 7d32cc1..fd82241 100644 --- a/src/values.cpp +++ b/src/values.cpp @@ -315,7 +315,7 @@ namespace quickbook struct value_qbk_string_impl : public value_node { public: - explicit value_qbk_string_impl(std::string const&, value::tag_type); + explicit value_qbk_string_impl(std::string const&, unsigned qbk_version, value::tag_type); explicit value_qbk_string_impl(file const&, value::tag_type); private: char const* type_name() const { return "quickbook"; } @@ -427,12 +427,11 @@ namespace quickbook value_qbk_string_impl::value_qbk_string_impl( std::string const& v, + unsigned qbk_version, value::tag_type tag) : value_node(tag) - , fake_file_() + , fake_file_("(generated code)", v, qbk_version) { - fake_file_.source = v; - fake_file_.path = "(generated code)"; } value_qbk_string_impl::value_qbk_string_impl( @@ -584,9 +583,9 @@ namespace quickbook return value(new detail::value_qbk_ref_impl(f, x, y, t)); } - value qbk_value(std::string const& x, value::tag_type t) + value qbk_value(std::string const& x, unsigned qbk_version, value::tag_type t) { - return value(new detail::value_qbk_string_impl(x, t)); + return value(new detail::value_qbk_string_impl(x, qbk_version, t)); } value bbk_value(std::string const& x, value::tag_type t) diff --git a/src/values.hpp b/src/values.hpp index 8111a6e..d0a564f 100644 --- a/src/values.hpp +++ b/src/values.hpp @@ -240,7 +240,7 @@ namespace quickbook // Boostbook and quickbook strings value qbk_value_ref(file const*, string_iterator, string_iterator, value::tag_type = value::default_tag); - value qbk_value(std::string const&, value::tag_type = value::default_tag); + value qbk_value(std::string const&, unsigned qbk_version, value::tag_type = value::default_tag); value bbk_value(std::string const&, value::tag_type = value::default_tag); value qbk_bbk_value(file const*, string_iterator, string_iterator, std::string const&, value::tag_type = value::default_tag); diff --git a/src/values_parse.hpp b/src/values_parse.hpp index 7ae3196..dc3d65b 100644 --- a/src/values_parse.hpp +++ b/src/values_parse.hpp @@ -66,13 +66,6 @@ namespace quickbook { b.insert(qbk_value_ref(*current_file, begin.base(), end.base(), tag)); } - void operator()(parse_iterator begin, parse_iterator, - std::string const& v, - value::tag_type tag = value::default_tag) const - { - b.insert(qbk_value(v, tag)); - } - void operator()(int v, value::tag_type tag = value::default_tag) const { diff --git a/test/unit/values_test.cpp b/test/unit/values_test.cpp index 8747f40..e8085d0 100644 --- a/test/unit/values_test.cpp +++ b/test/unit/values_test.cpp @@ -25,8 +25,8 @@ void empty_tests() void qbk_tests() { - quickbook::file fake_file; - fake_file.source = "Source"; + quickbook::file fake_file( + "(fake file)", "Source", 105u); quickbook::value q = quickbook::qbk_value_ref( &fake_file, fake_file.source.begin(),