From dfb1415d5eaf006ee45235f275d17f52d3db38e5 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 18 May 2020 12:06:16 +0300 Subject: Add dump(ostream,script::lines) (partial implementation) --- libbuild2/build/script/lexer.test.cxx | 2 +- libbuild2/build/script/parser+line.test.testscript | 39 +++++++++++++ libbuild2/build/script/parser.test.cxx | 21 +++++-- libbuild2/build/script/token.cxx | 4 +- libbuild2/build/script/token.hxx | 2 +- libbuild2/lexer.test.cxx | 2 +- libbuild2/script/lexer.test.cxx | 2 +- libbuild2/script/script.cxx | 68 ++++++++++++++++++++++ libbuild2/script/script.hxx | 3 + libbuild2/script/token.cxx | 6 +- libbuild2/script/token.hxx | 2 +- libbuild2/test/script/lexer.test.cxx | 2 +- libbuild2/test/script/token.cxx | 6 +- libbuild2/test/script/token.hxx | 2 +- libbuild2/token.cxx | 39 +++++++++++-- libbuild2/token.hxx | 27 ++++++++- 16 files changed, 199 insertions(+), 28 deletions(-) create mode 100644 libbuild2/build/script/parser+line.test.testscript diff --git a/libbuild2/build/script/lexer.test.cxx b/libbuild2/build/script/lexer.test.cxx index 15c0954..1c47442 100644 --- a/libbuild2/build/script/lexer.test.cxx +++ b/libbuild2/build/script/lexer.test.cxx @@ -55,7 +55,7 @@ namespace build2 { // Print each token on a separate line without quoting operators. // - t.printer (cout, t, false); + t.printer (cout, t, print_mode::normal); cout << endl; } } diff --git a/libbuild2/build/script/parser+line.test.testscript b/libbuild2/build/script/parser+line.test.testscript new file mode 100644 index 0000000..df4e77b --- /dev/null +++ b/libbuild2/build/script/parser+line.test.testscript @@ -0,0 +1,39 @@ +# file : libbuild2/build/script/parser+line.test.testscript +# license : MIT; see accompanying LICENSE file + +test.options += -d + +#\ +: if-else +: +$* <| + if foo + bar + elif fox + baz + end + if! foo + bar + elif! fox + baz + end + EOI + +: command +: +$* <| + foo >| 2>- &a &?b + foo >=c 2>~/error:.*/ &!c + foo >>:/~%EOF% + %.* + abc + %xyz.*% + EOF + EOI + +: quoting +: +$* <| + foo 'bar' "baz" '' "" + EOI +#\ diff --git a/libbuild2/build/script/parser.test.cxx b/libbuild2/build/script/parser.test.cxx index 2763464..77f6596 100644 --- a/libbuild2/build/script/parser.test.cxx +++ b/libbuild2/build/script/parser.test.cxx @@ -67,7 +67,10 @@ namespace build2 bool line_; }; - // Usage: argv[0] [-l] + // Usages: + // + // argv[0] [-l] + // argv[0] -d // int main (int argc, char* argv[]) @@ -86,6 +89,7 @@ namespace build2 context ctx (sched, mutexes); bool line (false); + bool dump (false); for (int i (1); i != argc; ++i) { @@ -93,10 +97,14 @@ namespace build2 if (a == "-l") line = true; + else if (a == "-d") + dump = true; else assert (false); } + assert (!dump || !line); + try { cin.exceptions (istream::failbit | istream::badbit); @@ -123,9 +131,14 @@ namespace build2 parser p (ctx); p.pre_parse (cin, nm, 11 /* line */, s); - environment e (s, tt); - print_runner r (line); - p.execute (e, r); + if (!dump) + { + environment e (s, tt); + print_runner r (line); + p.execute (e, r); + } + else + build2::script::dump (cout, "", s.lines); } catch (const failed&) { diff --git a/libbuild2/build/script/token.cxx b/libbuild2/build/script/token.cxx index 289dfd2..7c15dff 100644 --- a/libbuild2/build/script/token.cxx +++ b/libbuild2/build/script/token.cxx @@ -12,11 +12,11 @@ namespace build2 namespace script { void - token_printer (ostream& os, const token& t, bool d) + token_printer (ostream& os, const token& t, print_mode m) { // No build script-specific tokens so far. // - build2::script::token_printer (os, t, d); + build2::script::token_printer (os, t, m); } } } diff --git a/libbuild2/build/script/token.hxx b/libbuild2/build/script/token.hxx index 4cd90d7..90c1379 100644 --- a/libbuild2/build/script/token.hxx +++ b/libbuild2/build/script/token.hxx @@ -28,7 +28,7 @@ namespace build2 }; void - token_printer (ostream&, const token&, bool); + token_printer (ostream&, const token&, print_mode); } } } diff --git a/libbuild2/lexer.test.cxx b/libbuild2/lexer.test.cxx index 5e39e43..443622c 100644 --- a/libbuild2/lexer.test.cxx +++ b/libbuild2/lexer.test.cxx @@ -62,7 +62,7 @@ namespace build2 // Print each token on a separate line without quoting operators. // - t.printer (cout, t, false); + t.printer (cout, t, print_mode::normal); if (quote) { diff --git a/libbuild2/script/lexer.test.cxx b/libbuild2/script/lexer.test.cxx index 85304ea..24fe335 100644 --- a/libbuild2/script/lexer.test.cxx +++ b/libbuild2/script/lexer.test.cxx @@ -45,7 +45,7 @@ namespace build2 { // Print each token on a separate line without quoting operators. // - t.printer (cout, t, false); + t.printer (cout, t, print_mode::normal); cout << endl; } } diff --git a/libbuild2/script/script.cxx b/libbuild2/script/script.cxx index b5456f9..db34084 100644 --- a/libbuild2/script/script.cxx +++ b/libbuild2/script/script.cxx @@ -33,6 +33,74 @@ namespace build2 return o << s; } + void + dump (ostream& os, const string& ind, const lines& ls) + { + for (const line& l: ls) + { + os << ind; + + // @@ Should be across lines? + // + // We will consider mixed quoting as a double quoting since the + // information is lost and we won't be able to restore the token + // original representation. + // +// char qseq ('\0'); // Can be used as bool. + + for (const replay_token& rt: l.tokens) + { + const token& t (rt.token); + + // Left and right quotes (can be used as bool). + // + char lq ('\0'); + char rq ('\0'); + + /* + if (t.qtype != quote_type::unquoted) + { + auto quote = [&t] () + { + return t.qtype == quote_type::single ? '\'' : '"'; + } + + if (t.qcomp) // Complete quoting. + { + // If we are inside quoted token sequence then we do noting. + // Otherwise we just quote the token not starting a sequence. + // + if (!qseq) + { + lq = quote (); + rq = lq; + } + } + else // Partial quoting. + { + if (!qseq) + lq = + + } + } + */ + // @@ Add 2 spaces indentation for if block contents. + + if (t.separated && + t.type != token_type::newline && + &rt != &l.tokens[0]) // Not first in the line. + os << ' '; + + if (lq) os << lq; + t.printer (os, t, print_mode::raw); + if (rq) os << rq; + +// prev_qcomp = t.qcomp; +// prev_qtype = t.qtype; + } + } + } + // Quote if empty or contains spaces or any of the special characters. // Note that we use single quotes since double quotes still allow // expansion. diff --git a/libbuild2/script/script.hxx b/libbuild2/script/script.hxx index 96c1343..f02583c 100644 --- a/libbuild2/script/script.hxx +++ b/libbuild2/script/script.hxx @@ -48,6 +48,9 @@ namespace build2 // using lines = small_vector; + void + dump (ostream&, const string& ind, const lines&); + // Parse object model. // diff --git a/libbuild2/script/token.cxx b/libbuild2/script/token.cxx index be0aa54..6c9de87 100644 --- a/libbuild2/script/token.cxx +++ b/libbuild2/script/token.cxx @@ -10,13 +10,13 @@ namespace build2 namespace script { void - token_printer (ostream& os, const token& t, bool d) + token_printer (ostream& os, const token& t, print_mode m) { const string& v (t.value); // Only quote non-name tokens for diagnostics. // - const char* q (d ? "'" : ""); + const char* q (m == print_mode::diagnostics ? "'" : ""); switch (t.type) { @@ -39,7 +39,7 @@ namespace build2 case token_type::out_file_ovr: os << q << ">=" << v << q; break; case token_type::out_file_app: os << q << ">+" << v << q; break; - default: build2::token_printer (os, t, d); + default: build2::token_printer (os, t, m); } } } diff --git a/libbuild2/script/token.hxx b/libbuild2/script/token.hxx index 0630e46..a2ccaee 100644 --- a/libbuild2/script/token.hxx +++ b/libbuild2/script/token.hxx @@ -49,7 +49,7 @@ namespace build2 }; void - token_printer (ostream&, const token&, bool); + token_printer (ostream&, const token&, print_mode); } } diff --git a/libbuild2/test/script/lexer.test.cxx b/libbuild2/test/script/lexer.test.cxx index c728d68..9c64616 100644 --- a/libbuild2/test/script/lexer.test.cxx +++ b/libbuild2/test/script/lexer.test.cxx @@ -56,7 +56,7 @@ namespace build2 { // Print each token on a separate line without quoting operators. // - t.printer (cout, t, false); + t.printer (cout, t, print_mode::normal); cout << endl; } } diff --git a/libbuild2/test/script/token.cxx b/libbuild2/test/script/token.cxx index df5493f..efeb17b 100644 --- a/libbuild2/test/script/token.cxx +++ b/libbuild2/test/script/token.cxx @@ -12,11 +12,11 @@ namespace build2 namespace script { void - token_printer (ostream& os, const token& t, bool d) + token_printer (ostream& os, const token& t, print_mode m) { // Only quote non-name tokens for diagnostics. // - const char* q (d ? "'" : ""); + const char* q (m == print_mode::diagnostics ? "'" : ""); switch (t.type) { @@ -27,7 +27,7 @@ namespace build2 case token_type::plus: os << q << '+' << q; break; case token_type::minus: os << q << '-' << q; break; - default: build2::script::token_printer (os, t, d); + default: build2::script::token_printer (os, t, m); } } } diff --git a/libbuild2/test/script/token.hxx b/libbuild2/test/script/token.hxx index 5bb2319..dead796 100644 --- a/libbuild2/test/script/token.hxx +++ b/libbuild2/test/script/token.hxx @@ -37,7 +37,7 @@ namespace build2 }; void - token_printer (ostream&, const token&, bool); + token_printer (ostream&, const token&, print_mode); } } } diff --git a/libbuild2/token.cxx b/libbuild2/token.cxx index 4975a02..ebbdd83 100644 --- a/libbuild2/token.cxx +++ b/libbuild2/token.cxx @@ -8,18 +8,45 @@ using namespace std; namespace build2 { void - token_printer (ostream& os, const token& t, bool d) + token_printer (ostream& os, const token& t, print_mode m) { // Only quote non-name tokens for diagnostics. // - const char* q (d ? "'" : ""); + const char* q (m == print_mode::diagnostics ? "'" : ""); + bool r (m == print_mode::raw); switch (t.type) { - case token_type::eos: os << ""; break; - case token_type::newline: os << ""; break; - case token_type::pair_separator: os << ""; break; - case token_type::word: os << '\'' << t.value << '\''; break; + case token_type::eos: + { + if (!r) + os <<""; + + break; + } + case token_type::newline: + { + os << (r ? "\n" : ""); + break; + } + case token_type::pair_separator: + { + if (r) + os << t.value[0]; + else + os << ""; + + break; + } + case token_type::word: + { + if (r) + os << t.value; + else + os << '\'' << t.value << '\''; + + break; + } case token_type::colon: os << q << ':' << q; break; case token_type::dollar: os << q << '$' << q; break; diff --git a/libbuild2/token.hxx b/libbuild2/token.hxx index c950ea3..c486193 100644 --- a/libbuild2/token.hxx +++ b/libbuild2/token.hxx @@ -84,13 +84,30 @@ namespace build2 class token; + enum class print_mode + { + // Print eos, newline, and pair separator in the form and other + // tokens as literals, single-quoting the word token. + // + normal, + + // Same as normal but all literals are quoted. + // + diagnostics, + + // Print all tokens as literals with newline represented as '\n' and eos + // as an empty string. + // + raw + }; + LIBBUILD2_SYMEXPORT void - token_printer (ostream&, const token&, bool); + token_printer (ostream&, const token&, print_mode); class token { public: - using printer_type = void (ostream&, const token&, bool diag); + using printer_type = void (ostream&, const token&, print_mode); token_type type; bool separated; // Whitespace-separated from the previous token. @@ -145,7 +162,11 @@ namespace build2 // Output the token value in a format suitable for diagnostics. // inline ostream& - operator<< (ostream& o, const token& t) {t.printer (o, t, true); return o;} + operator<< (ostream& o, const token& t) + { + t.printer (o, t, print_mode::diagnostics); + return o; + } // Context-dependent lexing (see lexer_mode for details). // -- cgit v1.1