diff options
Diffstat (limited to 'libbuild2/test')
-rw-r--r-- | libbuild2/test/init.cxx | 4 | ||||
-rw-r--r-- | libbuild2/test/operation.cxx | 2 | ||||
-rw-r--r-- | libbuild2/test/rule.cxx | 78 | ||||
-rw-r--r-- | libbuild2/test/script/builtin.cxx | 10 | ||||
-rw-r--r-- | libbuild2/test/script/parser.cxx | 32 | ||||
-rw-r--r-- | libbuild2/test/script/parser.hxx | 4 | ||||
-rw-r--r-- | libbuild2/test/script/parser.test.cxx | 32 | ||||
-rw-r--r-- | libbuild2/test/script/runner.cxx | 55 | ||||
-rw-r--r-- | libbuild2/test/script/script.cxx | 46 | ||||
-rw-r--r-- | libbuild2/test/script/script.hxx | 19 |
10 files changed, 150 insertions, 132 deletions
diff --git a/libbuild2/test/init.cxx b/libbuild2/test/init.cxx index a5afea0..3fb4df6 100644 --- a/libbuild2/test/init.cxx +++ b/libbuild2/test/init.cxx @@ -39,7 +39,7 @@ namespace build2 // Enter module variables. Do it during boot in case they get assigned // in bootstrap.build. // - auto& vp (var_pool.rw (rs)); + auto& vp (rs.ctx.var_pool.rw (rs)); common_data d { @@ -109,7 +109,7 @@ namespace build2 value& v (rs.assign (d.test_target)); if (!v || v.empty ()) - v = cast<target_triplet> ((*global_scope)["build.host"]); + v = cast<target_triplet> (rs.ctx.global_scope["build.host"]); } mod.reset (new module (move (d))); diff --git a/libbuild2/test/operation.cxx b/libbuild2/test/operation.cxx index 3ff7702..0ca8da0 100644 --- a/libbuild2/test/operation.cxx +++ b/libbuild2/test/operation.cxx @@ -4,6 +4,8 @@ #include <libbuild2/test/operation.hxx> +#include <libbuild2/variable.hxx> + using namespace std; using namespace butl; diff --git a/libbuild2/test/rule.cxx b/libbuild2/test/rule.cxx index 1d11063..c216e66 100644 --- a/libbuild2/test/rule.cxx +++ b/libbuild2/test/rule.cxx @@ -364,7 +364,7 @@ namespace build2 build2::test::script::script s (t, ts, wd); { - parser p; + parser p (t.ctx); p.pre_parse (s); default_runner r (c); @@ -384,6 +384,8 @@ namespace build2 target_state rule:: perform_script (action a, const target& t, size_t pass_n) const { + context& ctx (t.ctx); + // First pass through. // if (pass_n != 0) @@ -433,10 +435,10 @@ namespace build2 const path& buildignore_file (rs.root_extra->buildignore_file); dir_path bl; - if (cast_false<bool> (rs.vars[var_forwarded])) + if (cast_false<bool> (rs.vars[ctx.var_forwarded])) { bl = bs.src_path () / wd.leaf (bs.out_path ()); - clean_backlink (bl, verb_never); + clean_backlink (ctx, bl, verb_never); } // If this is a (potentially) multi-testscript test, then create (and @@ -477,7 +479,7 @@ namespace build2 // Remove the directory itself not to confuse the runner which tries // to detect when tests stomp on each others feet. // - build2::rmdir_r (wd, true, 2); + rmdir_r (ctx, wd, true, 2); } // Delay actually creating the directory in case all the tests are @@ -489,8 +491,8 @@ namespace build2 // wait_guard wg; - if (!dry_run) - wg = wait_guard (target::count_busy (), t[a].task_count); + if (!ctx.dry_run) + wg = wait_guard (ctx, ctx.count_busy (), t[a].task_count); // Result vector. // @@ -514,11 +516,11 @@ namespace build2 // don't clean the existing one), we are going to ignore it for // dry-run. // - if (!dry_run) + if (!ctx.dry_run) { if (mk) { - mkdir_buildignore (wd, buildignore_file, 2); + mkdir_buildignore (ctx, wd, buildignore_file, 2); mk = false; } } @@ -532,40 +534,42 @@ namespace build2 dr << ' ' << t; } - res.push_back (dry_run ? scope_state::passed : scope_state::unknown); + res.push_back (ctx.dry_run + ? scope_state::passed + : scope_state::unknown); - if (!dry_run) + if (!ctx.dry_run) { scope_state& r (res.back ()); - if (!sched.async (target::count_busy (), - t[a].task_count, - [this] (const diag_frame* ds, - scope_state& r, - const target& t, - const testscript& ts, - const dir_path& wd) - { - diag_frame::stack_guard dsg (ds); - r = perform_script_impl (t, ts, wd, *this); - }, - diag_frame::stack (), - ref (r), - cref (t), - cref (ts), - cref (wd))) + if (!ctx.sched.async (ctx.count_busy (), + t[a].task_count, + [this] (const diag_frame* ds, + scope_state& r, + const target& t, + const testscript& ts, + const dir_path& wd) + { + diag_frame::stack_guard dsg (ds); + r = perform_script_impl (t, ts, wd, *this); + }, + diag_frame::stack (), + ref (r), + cref (t), + cref (ts), + cref (wd))) { // Executed synchronously. If failed and we were not asked to // keep going, bail out. // - if (r == scope_state::failed && !keep_going) + if (r == scope_state::failed && !ctx.keep_going) break; } } } } - if (!dry_run) + if (!ctx.dry_run) wg.wait (); // Re-examine. @@ -586,7 +590,7 @@ namespace build2 // Cleanup. // - if (!dry_run) + if (!ctx.dry_run) { if (!bad && !one && !mk && after == output_after::clean) { @@ -594,7 +598,7 @@ namespace build2 fail << "working directory " << wd << " is not empty at the " << "end of the test"; - rmdir_buildignore (wd, buildignore_file, 2); + rmdir_buildignore (ctx, wd, buildignore_file, 2); } } @@ -603,8 +607,10 @@ namespace build2 // If we dry-run then presumably all tests passed and we shouldn't // have anything left unless we are keeping the output. // - if (!bl.empty () && (dry_run ? after == output_after::keep : exists (wd))) - update_backlink (wd, bl, true /* changed */); + if (!bl.empty () && (ctx.dry_run + ? after == output_after::keep + : exists (wd))) + update_backlink (ctx, wd, bl, true /* changed */); if (bad) throw failed (); @@ -677,6 +683,8 @@ namespace build2 target_state rule:: perform_test (action a, const target& tt, size_t pass_n) const { + context& ctx (tt.ctx); + // First pass through. // if (pass_n != 0) @@ -777,7 +785,7 @@ namespace build2 cat = process (process_exit (0)); // Successfully exited. - if (!dry_run) + if (!ctx.dry_run) { try { @@ -798,7 +806,7 @@ namespace build2 // If dry-run, the target may not exist. // - process_path pp (!dry_run + process_path pp (!ctx.dry_run ? run_search (p, true /* init */) : try_run_search (p, true)); args.push_back (pp.empty () ? p.string ().c_str () : pp.recall_string ()); @@ -863,7 +871,7 @@ namespace build2 else if (verb) text << "test " << tt; - if (!dry_run) + if (!ctx.dry_run) { diag_record dr; if (!run_test (tt, diff --git a/libbuild2/test/script/builtin.cxx b/libbuild2/test/script/builtin.cxx index ae979da..06b0cec 100644 --- a/libbuild2/test/script/builtin.cxx +++ b/libbuild2/test/script/builtin.cxx @@ -956,7 +956,7 @@ namespace build2 auto mv = [ops, &wd, &sp, &error] (const path& from, const path& to) { - const dir_path& rwd (sp.root->wd_path); + const dir_path& rwd (sp.root.wd_path); if (!from.sub (rwd) && !ops.force ()) error () << "'" << from << "' is out of working directory '" @@ -1158,7 +1158,7 @@ namespace build2 error () << "missing file"; const dir_path& wd (sp.wd_path); - const dir_path& rwd (sp.root->wd_path); + const dir_path& rwd (sp.root.wd_path); while (scan.more ()) { @@ -1259,7 +1259,7 @@ namespace build2 error () << "missing directory"; const dir_path& wd (sp.wd_path); - const dir_path& rwd (sp.root->wd_path); + const dir_path& rwd (sp.root.wd_path); while (scan.more ()) { @@ -1583,7 +1583,7 @@ namespace build2 // Note: can be executed synchronously. // static uint8_t - sleep (scope&, + sleep (scope& s, const strings& args, auto_fd in, auto_fd out, auto_fd err) noexcept try @@ -1637,7 +1637,7 @@ namespace build2 // If/when required we could probably support the precise sleep mode // (e.g., via an option). // - sched.sleep (chrono::seconds (n)); + s.root.test_target.ctx.sched.sleep (chrono::seconds (n)); r = 0; } diff --git a/libbuild2/test/script/parser.cxx b/libbuild2/test/script/parser.cxx index 260bc88..8b8f705 100644 --- a/libbuild2/test/script/parser.cxx +++ b/libbuild2/test/script/parser.cxx @@ -2866,7 +2866,7 @@ namespace build2 { try { - parser p; + parser p (scr.test_target.ctx); p.execute (s, scr, r); } catch (const failed&) @@ -2896,7 +2896,7 @@ namespace build2 if (exec_scope) { atomic_count task_count (0); - wait_guard wg (task_count); + wait_guard wg (g->root.test_target.ctx, task_count); // Start asynchronous execution of inner scopes keeping track of // how many we have handled. @@ -3016,24 +3016,24 @@ namespace build2 // UBSan workaround. // const diag_frame* df (diag_frame::stack ()); - if (!sched.async (task_count, - [] (const diag_frame* ds, - scope& s, - script& scr, - runner& r) - { - diag_frame::stack_guard dsg (ds); - execute_impl (s, scr, r); - }, - df, - ref (*chain), - ref (*script_), - ref (*runner_))) + if (!ctx.sched.async (task_count, + [] (const diag_frame* ds, + scope& s, + script& scr, + runner& r) + { + diag_frame::stack_guard dsg (ds); + execute_impl (s, scr, r); + }, + df, + ref (*chain), + ref (*script_), + ref (*runner_))) { // Bail out if the scope has failed and we weren't instructed // to keep going. // - if (chain->state == scope_state::failed && !keep_going) + if (chain->state == scope_state::failed && !ctx.keep_going) throw failed (); } } diff --git a/libbuild2/test/script/parser.hxx b/libbuild2/test/script/parser.hxx index 1beee49..e4d1f3a 100644 --- a/libbuild2/test/script/parser.hxx +++ b/libbuild2/test/script/parser.hxx @@ -16,6 +16,8 @@ namespace build2 { + class context; + namespace test { namespace script @@ -28,6 +30,8 @@ namespace build2 // Pre-parse. Issue diagnostics and throw failed in case of an error. // public: + parser (context& c): build2::parser (c) {} + void pre_parse (script&); diff --git a/libbuild2/test/script/parser.test.cxx b/libbuild2/test/script/parser.test.cxx index ab1f295..56630fe 100644 --- a/libbuild2/test/script/parser.test.cxx +++ b/libbuild2/test/script/parser.test.cxx @@ -9,7 +9,7 @@ #include <libbuild2/utility.hxx> #include <libbuild2/target.hxx> -#include <libbuild2/context.hxx> // reset() +#include <libbuild2/context.hxx> #include <libbuild2/scheduler.hxx> #include <libbuild2/test/target.hxx> @@ -155,8 +155,8 @@ namespace build2 // init_diag (1); init (nullptr, argv[0]); - sched.startup (1); // Serial execution. - reset (strings ()); // No command line variables. + scheduler sched (1); // Serial execution. + context ctx (sched); bool scope (false); bool id (false); @@ -195,32 +195,32 @@ namespace build2 // really care. // file& tt ( - targets.insert<file> (work, - dir_path (), - "driver", - string (), - trace)); + ctx.targets.insert<file> (work, + dir_path (), + "driver", + string (), + trace)); value& v ( tt.assign ( - var_pool.rw ().insert<target_triplet> ( + ctx.var_pool.rw ().insert<target_triplet> ( "test.target", variable_visibility::project))); - v = cast<target_triplet> ((*global_scope)["build.host"]); + v = cast<target_triplet> (ctx.global_scope["build.host"]); testscript& st ( - targets.insert<testscript> (work, - dir_path (), - name.leaf ().base ().string (), - name.leaf ().extension (), - trace)); + ctx.targets.insert<testscript> (work, + dir_path (), + name.leaf ().base ().string (), + name.leaf ().extension (), + trace)); tt.path (path ("driver")); st.path (name); // Parse and run. // - parser p; + parser p (ctx); script s (tt, st, dir_path (work) /= "test-driver"); p.pre_parse (cin, s); diff --git a/libbuild2/test/script/runner.cxx b/libbuild2/test/script/runner.cxx index f0c089b..53f6741 100644 --- a/libbuild2/test/script/runner.cxx +++ b/libbuild2/test/script/runner.cxx @@ -299,7 +299,7 @@ namespace build2 else { eop = path (op + ".orig"); - save (eop, transform (rd.str, false, rd.modifiers, *sp.root), ll); + save (eop, transform (rd.str, false, rd.modifiers, sp.root), ll); sp.clean_special (eop); } @@ -312,7 +312,7 @@ namespace build2 // Ignore Windows newline fluff if that's what we are running on. // - if (test_target (*sp.root).class_ == "windows") + if (test_target (sp.root).class_ == "windows") args.push_back ("--strip-trailing-cr"); args.push_back (eop.string ().c_str ()); @@ -451,14 +451,14 @@ namespace build2 if (l.regex) // Regex (possibly empty), { r += rl.intro; - r += transform (l.value, true, rd.modifiers, *sp.root); + r += transform (l.value, true, rd.modifiers, sp.root); r += rl.intro; r += l.flags; } else if (!l.special.empty ()) // Special literal. r += rl.intro; else // Textual literal. - r += transform (l.value, false, rd.modifiers, *sp.root); + r += transform (l.value, false, rd.modifiers, sp.root); r += l.special; return r; @@ -534,7 +534,7 @@ namespace build2 { try { - string s (transform (l.value, true, rd.modifiers, *sp.root)); + string s (transform (l.value, true, rd.modifiers, sp.root)); c = line_char ( char_regex (s, gf | parse_flags (l.flags)), pool); @@ -571,7 +571,7 @@ namespace build2 // Append literal line char. // rls += line_char ( - transform (l.value, false, rd.modifiers, *sp.root), pool); + transform (l.value, false, rd.modifiers, sp.root), pool); } for (char c: l.special) @@ -693,12 +693,14 @@ namespace build2 bool default_runner:: test (scope& s) const { - return common_.test (s.root->test_target, s.id_path); + return common_.test (s.root.test_target, s.id_path); } void default_runner:: enter (scope& sp, const location&) { + context& ctx (sp.root.target_scope.ctx); + auto df = make_diag_frame ( [&sp](const diag_record& dr) { @@ -723,8 +725,9 @@ namespace build2 fs_status<mkdir_status> r ( sp.parent == nullptr ? mkdir_buildignore ( + ctx, sp.wd_path, - sp.root->target_scope.root_scope ()->root_extra->buildignore_file, + sp.root.target_scope.root_scope ()->root_extra->buildignore_file, 2) : mkdir (sp.wd_path, 2)); @@ -744,6 +747,8 @@ namespace build2 void default_runner:: leave (scope& sp, const location& ll) { + context& ctx (sp.root.target_scope.ctx); + auto df = make_diag_frame ( [&sp](const diag_record& dr) { @@ -766,7 +771,7 @@ namespace build2 { // Remove the file if exists. Fail otherwise. // - if (rmfile (p, 3) == rmfile_status::not_exist) + if (rmfile (ctx, p, 3) == rmfile_status::not_exist) fail (ll) << "registered for cleanup special file " << p << " does not exist"; } @@ -800,9 +805,8 @@ namespace build2 { bool removed (false); - auto rm = [&cp, recursive, &removed, &sp, &ll] (path&& pe, - const string&, - bool interm) + auto rm = [&cp, recursive, &removed, &sp, &ll, &ctx] + (path&& pe, const string&, bool interm) { if (!interm) { @@ -819,7 +823,7 @@ namespace build2 if (!recursive) { - rmdir_status r (rmdir (d, 3)); + rmdir_status r (rmdir (ctx, d, 3)); if (r != rmdir_status::not_empty) return true; @@ -839,9 +843,7 @@ namespace build2 // Cast to uint16_t to avoid ambiguity with // libbutl::rmdir_r(). // - rmdir_status r (rmdir_r (d, - d != sp.wd_path, - static_cast<uint16_t> (3))); + rmdir_status r (rmdir_r (ctx, d, d != sp.wd_path, 3)); if (r != rmdir_status::not_empty) return true; @@ -854,7 +856,7 @@ namespace build2 } } else - rmfile (pe, 3); + rmfile (ctx, pe, 3); } return true; @@ -921,13 +923,14 @@ namespace build2 // rmdir_status r ( recursive - ? rmdir_r (d, !wd, static_cast <uint16_t> (v)) + ? rmdir_r (ctx, d, !wd, static_cast <uint16_t> (v)) : (wd && sp.parent == nullptr ? rmdir_buildignore ( + ctx, d, - sp.root->target_scope.root_scope ()->root_extra->buildignore_file, + sp.root.target_scope.root_scope ()->root_extra->buildignore_file, v) - : rmdir (d, v))); + : rmdir (ctx, d, v))); if (r == rmdir_status::success || (r == rmdir_status::not_exist && t == cleanup_type::maybe)) @@ -948,7 +951,7 @@ namespace build2 // Remove the file if exists. Fail otherwise. Removal of // non-existing file is not an error for 'maybe' cleanup type. // - if (rmfile (p, 3) == rmfile_status::not_exist && + if (rmfile (ctx, p, 3) == rmfile_status::not_exist && t == cleanup_type::always) fail (ll) << "registered for cleanup file " << p << " does not exist"; @@ -1097,8 +1100,8 @@ namespace build2 // locking as the variable pool is an associative container // (underneath) and we are only adding new variables into it. // - ulock ul (sp.root->var_pool_mutex); - const variable& var (sp.root->var_pool.insert (move (vname))); + ulock ul (sp.root.var_pool_mutex); + const variable& var (sp.root.var_pool.insert (move (vname))); ul.unlock (); value& lhs (sp.assign (var)); @@ -1123,7 +1126,7 @@ namespace build2 dr << info (ll) << "while parsing attributes '" << *ats << "'"; }); - parser p; + parser p (sp.root.test_target.ctx); p.apply_value_attributes (&var, lhs, value (move (ns)), @@ -1175,7 +1178,7 @@ namespace build2 const string& ls (np.leaf ().string ()); bool wc (ls == "*" || ls == "**" || ls == "***"); const path& cp (wc ? np.directory () : np); - const dir_path& wd (sp.root->wd_path); + const dir_path& wd (sp.root.wd_path); if (!cp.sub (wd)) fail (ll) << (wc @@ -1360,7 +1363,7 @@ namespace build2 isp = std_path ("stdin"); save ( - isp, transform (in.str, false, in.modifiers, *sp.root), ll); + isp, transform (in.str, false, in.modifiers, sp.root), ll); sp.clean_special (isp); diff --git a/libbuild2/test/script/script.cxx b/libbuild2/test/script/script.cxx index b879eb4..af9ba82 100644 --- a/libbuild2/test/script/script.cxx +++ b/libbuild2/test/script/script.cxx @@ -418,12 +418,12 @@ namespace build2 // scope // scope:: - scope (const string& id, scope* p, script* r) + scope (const string& id, scope* p, script& r) : parent (p), root (r), - vars (false /* global */), - id_path (cast<path> (assign (root->id_var) = path ())), - wd_path (cast<dir_path> (assign (root->wd_var) = dir_path ())) + vars (r.test_target.ctx, false /* global */), + id_path (cast<path> (assign (root.id_var) = path ())), + wd_path (cast<dir_path> (assign (root.wd_var) = dir_path ())) { // Construct the id_path as a string to ensure POSIX form. In fact, @@ -455,7 +455,7 @@ namespace build2 assert (!implicit || c.type == cleanup_type::always); const path& p (c.path); - if (!p.sub (root->wd_path)) + if (!p.sub (root.wd_path)) { if (implicit) return; @@ -481,8 +481,11 @@ namespace build2 // script_base // script_base:: - script_base () - : // Enter the test.* variables with the same variable types as in + script_base (const target& tt, const testscript& st) + : test_target (tt), + target_scope (tt.base_scope ()), + script_target (st), + // Enter the test.* variables with the same variable types as in // buildfiles except for test: while in buildfiles it can be a // target name, in testscripts it should be resolved to a path. // @@ -515,10 +518,8 @@ namespace build2 script (const target& tt, const testscript& st, const dir_path& rwd) - : group (st.name == "testscript" ? string () : st.name, this), - test_target (tt), - target_scope (tt.base_scope ()), - script_target (st) + : script_base (tt, st), + group (st.name == "testscript" ? string () : st.name, *this) { // Set the script working dir ($~) to $out_base/test/<id> (id_path // for root is just the id which is empty if st is 'testscript'). @@ -634,12 +635,11 @@ namespace build2 // in parallel). Plus, if there is no such variable, then we cannot // possibly find any value. // - const variable* pvar (build2::var_pool.find (n)); + const variable* pvar (root.test_target.ctx.var_pool.find (n)); if (pvar == nullptr) return lookup (); - const script& s (static_cast<const script&> (*root)); const variable& var (*pvar); // First check the target we are testing. @@ -649,12 +649,12 @@ namespace build2 // value. In this case, presumably the override also affects the // script target and we will pick it up there. A bit fuzzy. // - auto p (s.test_target.find_original (var, target_only)); + auto p (root.test_target.find_original (var, target_only)); if (p.first) { if (var.overrides != nullptr) - p = s.target_scope.find_override (var, move (p), true); + p = root.target_scope.find_override (var, move (p), true); return p.first; } @@ -665,7 +665,7 @@ namespace build2 // in different scopes which brings the question of which scopes we // should search. // - return s.script_target[var]; + return root.script_target[var]; } value& scope:: @@ -696,30 +696,30 @@ namespace build2 s.insert (s.end (), v.begin (), v.end ()); }; - if (lookup l = find (root->test_var)) + if (lookup l = find (root.test_var)) s.push_back (cast<path> (l).representation ()); - if (lookup l = find (root->options_var)) + if (lookup l = find (root.options_var)) append (cast<strings> (l)); - if (lookup l = find (root->arguments_var)) + if (lookup l = find (root.arguments_var)) append (cast<strings> (l)); // Keep redirects/cleanups out of $N. // size_t n (s.size ()); - if (lookup l = find (root->redirects_var)) + if (lookup l = find (root.redirects_var)) append (cast<strings> (l)); - if (lookup l = find (root->cleanups_var)) + if (lookup l = find (root.cleanups_var)) append (cast<strings> (l)); // Set the $N values if present. // for (size_t i (0); i <= 9; ++i) { - value& v (assign (*root->cmdN_var[i])); + value& v (assign (*root.cmdN_var[i])); if (i < n) { @@ -734,7 +734,7 @@ namespace build2 // Set $*. // - assign (root->cmd_var) = move (s); + assign (root.cmd_var) = move (s); } } } diff --git a/libbuild2/test/script/script.hxx b/libbuild2/test/script/script.hxx index e3f8251..8b34be8 100644 --- a/libbuild2/test/script/script.hxx +++ b/libbuild2/test/script/script.hxx @@ -343,7 +343,7 @@ namespace build2 { public: scope* const parent; // NULL for the root (script) scope. - script* const root; // Self for the root (script) scope. + script& root; // Self for the root (script) scope. // The chain of if-else scope alternatives. See also if_cond_ below. // @@ -424,7 +424,7 @@ namespace build2 ~scope () = default; protected: - scope (const string& id, scope* parent, script* root); + scope (const string& id, scope* parent, script& root); // Pre-parse data. // @@ -452,7 +452,7 @@ namespace build2 group (const string& id, group& p): scope (id, &p, p.root) {} protected: - group (const string& id, script* r): scope (id, nullptr, r) {} + group (const string& id, script& r): scope (id, nullptr, r) {} // Pre-parse data. // @@ -505,7 +505,13 @@ namespace build2 class script_base // Make sure certain things are initialized early. { protected: - script_base (); + script_base (const target& test_target, + const testscript& script_target); + + public: + const target& test_target; // Target we are testing. + const build2::scope& target_scope; // Base scope of test target. + const testscript& script_target; // Target of the testscript file. public: variable_pool var_pool; @@ -535,11 +541,6 @@ namespace build2 script& operator= (script&&) = delete; script& operator= (const script&) = delete; - public: - const target& test_target; // Target we are testing. - const build2::scope& target_scope; // Base scope of test target. - const testscript& script_target; // Target of the testscript file. - // Pre-parse data. // private: |