From 616690fd06d1c5d05de97b88119dd8d328522df0 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 26 Oct 2016 13:38:27 +0200 Subject: Implement support for testscript scopes --- build2/test/script/lexer.cxx | 2 +- build2/test/script/parser.cxx | 51 +++++++++++++----- tests/test/script/integration/testscript | 28 +++++----- unit-tests/test/script/lexer/first-token.test | 12 ++++- unit-tests/test/script/lexer/second-token.test | 2 +- unit-tests/test/script/parser/scope.test | 71 ++++++++++++++++++++++++-- 6 files changed, 133 insertions(+), 33 deletions(-) diff --git a/build2/test/script/lexer.cxx b/build2/test/script/lexer.cxx index 7442973..98d52e7 100644 --- a/build2/test/script/lexer.cxx +++ b/build2/test/script/lexer.cxx @@ -331,7 +331,7 @@ namespace build2 } } - // Plus/minus and left/right curly braces + // Plus/minus and left/right curly braces. // if (m == lexer_mode::first_token) { diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx index 85a77ce..25d3636 100644 --- a/build2/test/script/parser.cxx +++ b/build2/test/script/parser.cxx @@ -105,27 +105,45 @@ namespace build2 } case type::lcbrace: { - // @@ Nested scope. Get newlines after open/close. + // Nested scope. + // + next (t, tt); // Get '{'. + + if (next (t, tt) != type::newline) + fail (t) << "expected newline after '{'"; + + // Push group. Use line number as the scope id. + // + group* og (group_); + unique_ptr p ( + group_ = new group (to_string (ll.line), *og)); + og->scopes.push_back (move (p)); + + group_->start_loc_ = ll; + token e (pre_parse_scope_body ()); + group_->end_loc_ = get_location (e); - assert (false); + // Pop group. + // + group_ = og; - /* - group_->start_loc_ = get_location (t); + if (e.type != type::rcbrace) + fail (e) << "expected '}' at the end of the scope"; // Check that we don't expect more lines. // if (lines_ != nullptr) - fail (t) << "expected another line after semicolon"; + fail (e) << "expected another line after semicolon"; - group_->end_loc_ = get_location (t); - */ + if (next (t, tt) != type::newline) + fail (t) << "expected newline after '}'"; continue; } case type::plus: case type::minus: { - // This is a setup/teardown command. + // Setup/teardown command. // lt = (tt == type::plus ? line_type::setup : line_type::tdown); @@ -136,7 +154,7 @@ namespace build2 } default: { - // This is either a test command or a variable assignment. + // Either a test command or a variable assignment. // replay_save (); // Start saving tokens from the current one. next (t, tt); @@ -297,12 +315,14 @@ namespace build2 void parser:: parse_scope_body () { - auto play = [this] (lines& ls) // Note: destructive to lines. + size_t li (0); + + auto play = [&li, this] (lines& ls) // Note: destructive to lines. { token t; type tt; - for (size_t i (0), li (0), n (ls.size ()); i != n; ++i) + for (size_t i (0), n (ls.size ()); i != n; ++i) { line& l (ls[i]); @@ -322,9 +342,14 @@ namespace build2 } case line_type::setup: case line_type::tdown: + { + parse_command_line (t, tt, l.type, ++li); + break; + } case line_type::test: { // We use the 0 index to signal that this is the only command. + // Note that we only do this for test commands. // if (li == 0) { @@ -794,7 +819,7 @@ namespace build2 next (t, tt); if (tt != type::word || t.quoted) - fail (l) << "here-document end marker expected"; + fail (l) << "expected here-document end marker"; hd.push_back (here_doc {nullptr, move (t.value), nn}); break; @@ -1082,7 +1107,7 @@ namespace build2 catch (const exception&) {} // Fall through. if (es > 255) - fail (t) << "exit status expected instead of '" << ns << "'" << + fail (t) << "expected exit status instead of '" << ns << "'" << info << "exit status is an unsigned integer less than 256"; } diff --git a/tests/test/script/integration/testscript b/tests/test/script/integration/testscript index e98a25c..a9c29a7 100644 --- a/tests/test/script/integration/testscript +++ b/tests/test/script/integration/testscript @@ -14,28 +14,32 @@ test.arguments = test #EOI +cp $src_base/bootstrap.build build/ -# @@ TODO: redo as scope. -# -touch testscript foo.test bar.test; -$* <>EOE != 0; -./: test{testscript foo} +{ + +touch testscript foo.test bar.test + + $* <>EOE != 0 +./: test{../testscript ../foo} EOI error: both 'testscript' and other names specified for dir{./} info: while testing dir{./} EOE -$* <>EOE != 0; -./: test{foo testscript} + + $* <>EOE != 0 +./: test{../foo ../testscript} EOI error: both 'testscript' and other names specified for dir{./} info: while testing dir{./} EOE -$* <>EOE; -./: test{foo bar} + + $* <>EOE +./: test{../foo ../bar} EOI -test dir{./} with test{foo} -test dir{./} with test{bar} +test dir{./} with ../test{foo} +test dir{./} with ../test{bar} EOE -rm -f testscript foo.test bar.test + + -rm -f testscript foo.test bar.test +} # work-dir-not-empty-begin # diff --git a/unit-tests/test/script/lexer/first-token.test b/unit-tests/test/script/lexer/first-token.test index fb75c8b..a433362 100644 --- a/unit-tests/test/script/lexer/first-token.test +++ b/unit-tests/test/script/lexer/first-token.test @@ -2,11 +2,21 @@ # test.arguments += first-token -$* <";" >>EOO # semi-only +$* <";" >>EOO # semi ; EOO +$* <"{" >>EOO # lcbrace +{ + +EOO + +$* <"}" >>EOO # rcbrace +} + +EOO + $* <"+foo" >>EOO # setup + 'foo' diff --git a/unit-tests/test/script/lexer/second-token.test b/unit-tests/test/script/lexer/second-token.test index cc044dd..058dc65 100644 --- a/unit-tests/test/script/lexer/second-token.test +++ b/unit-tests/test/script/lexer/second-token.test @@ -2,7 +2,7 @@ # test.arguments += second-token -$* <";" >>EOO # semi-only +$* <";" >>EOO # semi ; EOO diff --git a/unit-tests/test/script/parser/scope.test b/unit-tests/test/script/parser/scope.test index 4e358f3..593dbb2 100644 --- a/unit-tests/test/script/parser/scope.test +++ b/unit-tests/test/script/parser/scope.test @@ -12,7 +12,68 @@ wd += foo; wd += 1; $* foo.test <'cmd $~' >"cmd $wd" # wd -$* -s <>EOO # compound-2 +$* -s <>EOO # group-empty +{ +} +EOI +{ + { + } +} +EOO + +$* -s <>EOO # group +{ + cmd1 + cmd2 +} +EOI +{ + { + { + cmd1 + } + { + cmd2 + } + } +} +EOO + +$* <:"{x" 2>>EOE != 0 # expected-newline-lcbrace +testscript:1:2: error: expected newline after '{' +EOE + +$* <"{" 2>>EOE != 0 # expected-rcbrace +testscript:2:1: error: expected '}' at the end of the scope +EOE + +$* <>EOE != 0 # expected-line-rcbrace +{ + cmd; +} +EOI +testscript:3:1: error: expected another line after semicolon +EOE + +$* <<:EOI 2>>EOE != 0 # expected-newline-rcbrace +{ +} +EOI +testscript:2:2: error: expected newline after '}' +EOE + +$* -s <>EOO # test-1 +cmd1 +EOI +{ + { + cmd1 + } +} +EOO + +$* -s <>EOO # test-2 cmd1; cmd2 EOI @@ -24,7 +85,7 @@ EOI } EOO -$* -s <>EOO # compound-3 +$* -s <>EOO # test-3 cmd1; cmd2; cmd3 @@ -38,7 +99,7 @@ EOI } EOO -$* -s <>EOO # compound-var +$* -s <>EOO # test-var cmd1; x = abc; cmd2 \$x @@ -51,7 +112,7 @@ EOI } EOO -$* -s <>EOO # compound-var-first +$* -s <>EOO # test-var-first x = abc; cmd \$x EOI @@ -83,7 +144,7 @@ testscript:3:1: error: test after teardown testscript:2:1: info: last teardown line appears here EOE -$* <>EOE != 0 # expected-line +$* <>EOE != 0 # expected-line-eof cmd; EOI testscript:2:1: error: expected another line after semicolon -- cgit v1.1