From 2a1473fd306cbb9f73d67b7c8ca3d494472f80c8 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Sat, 13 Jul 2019 12:04:22 +0200 Subject: [PATCH] Adds line numbers to parser errors in isoltest. --- test/TestCase.cpp | 12 +++- test/TestCase.h | 1 + test/libsolidity/SemanticTest.cpp | 5 +- test/libsolidity/SemanticTest.h | 1 + test/libsolidity/util/TestFileParser.cpp | 56 ++++++++++++------- test/libsolidity/util/TestFileParser.h | 8 ++- test/libsolidity/util/TestFileParserTests.cpp | 2 +- 7 files changed, 60 insertions(+), 25 deletions(-) diff --git a/test/TestCase.cpp b/test/TestCase.cpp index 76c27d41a..e3671e4db 100644 --- a/test/TestCase.cpp +++ b/test/TestCase.cpp @@ -62,16 +62,19 @@ bool TestCase::validateSettings(langutil::EVMVersion) return true; } -string TestCase::parseSourceAndSettings(istream& _stream) +pair TestCase::parseSourceAndSettingsWithLineNumbers(istream& _stream) { string source; string line; + size_t lineNumber = 1; static string const comment("// "); static string const settingsDelimiter("// ===="); static string const delimiter("// ----"); bool sourcePart = true; while (getline(_stream, line)) { + lineNumber++; + if (boost::algorithm::starts_with(line, delimiter)) break; else if (boost::algorithm::starts_with(line, settingsDelimiter)) @@ -92,7 +95,12 @@ string TestCase::parseSourceAndSettings(istream& _stream) else throw runtime_error(string("Expected \"//\" or \"// ---\" to terminate settings and source.")); } - return source; + return make_pair(source, lineNumber); +} + +string TestCase::parseSourceAndSettings(istream& _stream) +{ + return get<0>(parseSourceAndSettingsWithLineNumbers(_stream)); } string TestCase::parseSimpleExpectations(std::istream& _file) diff --git a/test/TestCase.h b/test/TestCase.h index c08f2d77e..4a9c728ca 100644 --- a/test/TestCase.h +++ b/test/TestCase.h @@ -89,6 +89,7 @@ public: virtual bool validateSettings(langutil::EVMVersion /*_evmVersion*/); protected: + std::pair parseSourceAndSettingsWithLineNumbers(std::istream& _file); std::string parseSourceAndSettings(std::istream& _file); static void expect(std::string::iterator& _it, std::string::iterator _end, std::string::value_type _c); diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index adc3e0650..346da84fc 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -43,7 +43,8 @@ SemanticTest::SemanticTest(string const& _filename, string const& _ipcPath, lang soltestAssert(file, "Cannot open test contract: \"" + _filename + "\"."); file.exceptions(ios::badbit); - m_source = parseSourceAndSettings(file); + std::tie(m_source, m_lineOffset) = parseSourceAndSettingsWithLineNumbers(file); + if (m_settings.count("compileViaYul")) { if (m_settings["compileViaYul"] == "also") @@ -163,7 +164,7 @@ void SemanticTest::printUpdatedExpectations(ostream& _stream, string const&) con void SemanticTest::parseExpectations(istream& _stream) { TestFileParser parser{_stream}; - auto functionCalls = parser.parseFunctionCalls(); + auto functionCalls = parser.parseFunctionCalls(m_lineOffset); std::move(functionCalls.begin(), functionCalls.end(), back_inserter(m_tests)); } diff --git a/test/libsolidity/SemanticTest.h b/test/libsolidity/SemanticTest.h index ac9fb7dba..5ad452da1 100644 --- a/test/libsolidity/SemanticTest.h +++ b/test/libsolidity/SemanticTest.h @@ -64,6 +64,7 @@ public: private: std::string m_source; + std::size_t m_lineOffset; std::vector m_tests; bool m_runWithYul = false; bool m_runWithoutYul = true; diff --git a/test/libsolidity/util/TestFileParser.cpp b/test/libsolidity/util/TestFileParser.cpp index e2c56685e..cb71c2c95 100644 --- a/test/libsolidity/util/TestFileParser.cpp +++ b/test/libsolidity/util/TestFileParser.cpp @@ -48,7 +48,7 @@ char TestFileParser::Scanner::peek() const noexcept return *next; } -vector TestFileParser::parseFunctionCalls() +vector TestFileParser::parseFunctionCalls(size_t _lineOffset) { vector calls; if (!accept(Token::EOS)) @@ -70,32 +70,47 @@ vector TestFileParser::parseFunctionCalls() if (calls.empty()) expect(Token::Newline); else - accept(Token::Newline, true); + if (accept(Token::Newline, true)) + m_lineNumber++; - call.signature = parseFunctionSignature(); - if (accept(Token::Comma, true)) - call.value = parseFunctionCallValue(); - if (accept(Token::Colon, true)) - call.arguments = parseFunctionCallArguments(); + try + { + call.signature = parseFunctionSignature(); + if (accept(Token::Comma, true)) + call.value = parseFunctionCallValue(); + if (accept(Token::Colon, true)) + call.arguments = parseFunctionCallArguments(); - if (accept(Token::Newline, true)) - call.displayMode = FunctionCall::DisplayMode::MultiLine; + if (accept(Token::Newline, true)) + { + call.displayMode = FunctionCall::DisplayMode::MultiLine; + m_lineNumber++; + } - call.arguments.comment = parseComment(); + call.arguments.comment = parseComment(); - if (accept(Token::Newline, true)) - call.displayMode = FunctionCall::DisplayMode::MultiLine; + if (accept(Token::Newline, true)) + { + call.displayMode = FunctionCall::DisplayMode::MultiLine; + m_lineNumber++; + } - expect(Token::Arrow); - call.expectations = parseFunctionCallExpectations(); + expect(Token::Arrow); + call.expectations = parseFunctionCallExpectations(); - accept(Token::Newline, true); - call.expectations.comment = parseComment(); + if (accept(Token::Newline, true)) + m_lineNumber++; + call.expectations.comment = parseComment(); - if (call.signature == "constructor()") - call.isConstructor = true; + if (call.signature == "constructor()") + call.isConstructor = true; - calls.emplace_back(std::move(call)); + calls.emplace_back(std::move(call)); + } + catch (Error const& _e) + { + throw Error{_e.type(), "Line " + to_string(_lineOffset + m_lineNumber) + ": " + _e.what()}; + } } } } @@ -207,7 +222,10 @@ Parameter TestFileParser::parseParameter() { Parameter parameter; if (accept(Token::Newline, true)) + { parameter.format.newline = true; + m_lineNumber++; + } bool isSigned = false; diff --git a/test/libsolidity/util/TestFileParser.h b/test/libsolidity/util/TestFileParser.h index 21915564e..9ff513a6b 100644 --- a/test/libsolidity/util/TestFileParser.h +++ b/test/libsolidity/util/TestFileParser.h @@ -59,7 +59,9 @@ public: /// Throws an exception if a function call cannot be parsed because of its /// incorrect structure, an invalid or unsupported encoding /// of its arguments or expected results. - std::vector parseFunctionCalls(); + /// Passes the source line offset, such that parsing errors can be enhanced + /// with a line number it occurred in. + std::vector parseFunctionCalls(std::size_t _lineOffset); private: using Token = soltest::Token; @@ -179,6 +181,10 @@ private: /// A scanner instance Scanner m_scanner; + + /// The current line number. Incremented when Token::Newline (//) is found and + /// used to enhance parser error messages. + size_t m_lineNumber = 0; }; } diff --git a/test/libsolidity/util/TestFileParserTests.cpp b/test/libsolidity/util/TestFileParserTests.cpp index ce9e434ed..1ab147b57 100644 --- a/test/libsolidity/util/TestFileParserTests.cpp +++ b/test/libsolidity/util/TestFileParserTests.cpp @@ -44,7 +44,7 @@ vector parse(string const& _source) { istringstream stream{_source, ios_base::out}; TestFileParser parser{stream}; - return parser.parseFunctionCalls(); + return parser.parseFunctionCalls(0); } void testFunctionCall(