diff --git a/src/VerilogConstructor.cpp b/src/VerilogConstructor.cpp index 3b1291d..eab6751 100644 --- a/src/VerilogConstructor.cpp +++ b/src/VerilogConstructor.cpp @@ -56,10 +56,12 @@ void VerilogConstructor::parse(const std::filesystem::path& path) { } currentPath_ = path; std::ifstream inFile(path); + //LCOV_EXCL_START if (not inFile.good()) { std::string reason(path.string() + " is not a readable file"); throw VerilogException(reason); } + //LCOV_EXCL_STOP internalParse(inFile); } diff --git a/src/VerilogParser.yy b/src/VerilogParser.yy index 8962664..03e19f5 100644 --- a/src/VerilogParser.yy +++ b/src/VerilogParser.yy @@ -233,18 +233,31 @@ list_of_module_instances: module_instance number : CONSTVAL_TK BASE_TK BASED_CONSTVAL_TK { if ($2.size() == 2) { - if ($2[0] == 's' || $2[0] == 'S') { + //LCOV_EXCL_START + if (not ($2[0] == 's' || $2[0] == 'S')) { + //Following should not happen as long as lexer is correct + //should this be replaced by an assertion ? + std::ostringstream reason; + reason << "Parser error: " + << $1 << $2 << $3 << " is not a valid number: wrong size character.\n" + << " begin at line " << @$.begin.line << " col " << @$.begin.column << '\n' + << " end at line " << @$.end.line << " col " << @$.end.column << "\n"; + throw VerilogException(reason.str()); } + //LCOV_EXCL_STOP $$ = Number($1, true, $2[1], $3); } else if ($2.size() == 1) { $$ = Number($1, false, $2[0], $3); } else { + //LCOV_EXCL_START + //Same as previously: should not be accessible, as this is filtered by lexer. std::ostringstream reason; reason << "Parser error: " - << $1 << $2 << $3 << " is not a valid number\n" - << " begin at line " << @$.begin.line << " col " << @$.begin.column << '\n' - << " end at line " << @$.end.line << " col " << @$.end.column << "\n"; + << $1 << $2 << $3 << " is not a valid number\n" + << " begin at line " << @$.begin.line << " col " << @$.begin.column << '\n' + << " end at line " << @$.end.line << " col " << @$.end.column << "\n"; throw VerilogException(reason.str()); + //LCOV_EXCL_STOP } } | CONSTVAL_TK { @@ -389,4 +402,4 @@ void naja::verilog::VerilogParser::error( << " begin at line " << l.begin.line << " col " << l.begin.column << '\n' << " end at line " << l.end.line << " col " << l.end.column << "\n"; throw VerilogException(reason.str()); -} +} \ No newline at end of file diff --git a/src/VerilogScanner.ll b/src/VerilogScanner.ll index 9fd6682..58ddb44 100644 --- a/src/VerilogScanner.ll +++ b/src/VerilogScanner.ll @@ -17,6 +17,9 @@ %{ /* C++ string header, for string ops below */ #include +#include + +#include "VerilogException.h" /* Implementation of yyFlexScanner */ #include "VerilogScanner.h" @@ -88,20 +91,26 @@ ESCAPED_IDENTIFIER \\[\\^!"#$%&',()*+\-.a-zA-Z0-9/{|}~[\]_:;<=>?@]+[\t\f ] {COMMENT_BEGIN} { BEGIN(in_comment); } <> { - BEGIN(INITIAL); - std::cerr << "Unclosed comment at line " << loc->end.line << " col " << loc->end.column << '\n'; - yyterminate(); - } + BEGIN(INITIAL); + std::ostringstream reason; + reason << "Unclosed comment at line " + << loc->end.line << " col " << loc->end.column; + throw VerilogException(reason.str()); +} + {NEWLINE} { loc->lines(); } . { /* ignore characters in comment */ } {COMMENT_END} { BEGIN(INITIAL); } {ATTRIBUTE_BEGIN} { BEGIN(in_attribute); } <> { - BEGIN(INITIAL); - std::cerr << "Unclosed attribute at line " << loc->end.line << " col " << loc->end.column << '\n'; - yyterminate(); - } + BEGIN(INITIAL); + std::ostringstream reason; + reason << "Unclosed attribute at line " + << loc->end.line << " col " << loc->end.column; + throw VerilogException(reason.str()); +} + {NEWLINE} { loc->lines(); } . { /* ignore characters in comment */ } {ATTRIBUTE_END} { BEGIN(INITIAL); } @@ -134,6 +143,7 @@ assign { return token::ASSIGN_KW; } \'[sS]?[bodhBODH] { BEGIN(based_const); //we don't need the "'" first character and we are sure that yytext is 's?b|o|... + std::cerr << "LEX: " << std::string(yytext+1) << std::endl; yylval->build(yytext+1); return token::BASE_TK; } @@ -145,9 +155,13 @@ assign { return token::ASSIGN_KW; } } /* Last rule catches everything */ + /* LCOV_EXCL_START */ . { - std::cerr << "Failed to match : " << yytext << '\n'; - yyterminate(); + std::ostringstream reason; + reason << "Failed to match: " << yytext << " at line " + << loc->end.line << " col " << loc->end.column; + throw VerilogException(reason.str()); } + /* LCOV_EXCL_STOP */ %% \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index de21b12..1375400 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,6 +8,7 @@ set(tests NajaVerilogTest5.cpp NajaVerilogTest6.cpp NajaVerilogTest7.cpp + NajaVerilogTestMultipleFiles.cpp NajaVerilogTestErrors.cpp ) diff --git a/test/NajaVerilogTest6.cpp b/test/NajaVerilogTest6.cpp index 4b8f1d5..7458dad 100644 --- a/test/NajaVerilogTest6.cpp +++ b/test/NajaVerilogTest6.cpp @@ -23,7 +23,99 @@ TEST(NajaVerilogTest6, test) { ASSERT_EQ(1, constructor.modules_.size()); auto test = constructor.modules_[0]; EXPECT_EQ("test", test->name_); + EXPECT_EQ(1, constructor.modules_.size()); + { + auto mod = constructor.modules_[0]; + EXPECT_TRUE(mod->assigns_.empty()); + } constructor.setFirstPass(false); constructor.parse(test6Path); -} \ No newline at end of file + EXPECT_EQ(1, constructor.modules_.size()); + auto mod = constructor.modules_[0]; + EXPECT_FALSE(mod->assigns_.empty()); + EXPECT_EQ(4, mod->assigns_.size()); + + { + auto assign = mod->assigns_[0]; + EXPECT_EQ(1, assign.identifiers_.size()); + auto identifier = assign.identifiers_[0]; + EXPECT_EQ("n0", identifier.name_); + EXPECT_FALSE(identifier.range_.valid_); + auto expression = assign.expression_; + EXPECT_TRUE(expression.valid_); + EXPECT_EQ(naja::verilog::Expression::Type::IDENTIFIER, expression.value_.index()); + auto leftId = std::get(expression.value_); + EXPECT_EQ("n1", leftId.name_); + EXPECT_FALSE(leftId.range_.valid_); + } + + { + auto assign = mod->assigns_[1]; + EXPECT_EQ(1, assign.identifiers_.size()); + auto identifier = assign.identifiers_[0]; + EXPECT_EQ("n1", identifier.name_); + EXPECT_FALSE(identifier.range_.valid_); + auto expression = assign.expression_; + EXPECT_TRUE(expression.valid_); + EXPECT_EQ(naja::verilog::Expression::Type::NUMBER, expression.value_.index()); + auto leftId = std::get(expression.value_); + EXPECT_TRUE(leftId.sign_); + EXPECT_EQ(naja::verilog::Number::BASED, leftId.value_.index()); + auto leftBaseNumber = std::get(leftId.value_); + EXPECT_FALSE(leftBaseNumber.signed_); + EXPECT_EQ(naja::verilog::BasedNumber::BINARY, leftBaseNumber.base_); + EXPECT_EQ(1, leftBaseNumber.size_); + EXPECT_EQ("0", leftBaseNumber.digits_); + } + + { + auto assign = mod->assigns_[2]; + EXPECT_EQ(2, assign.identifiers_.size()); + auto id0 = assign.identifiers_[0]; + EXPECT_EQ("n2", id0.name_); + EXPECT_TRUE(id0.range_.valid_); + EXPECT_EQ(3, id0.range_.msb_); + EXPECT_EQ(2, id0.range_.lsb_); + auto id1 = assign.identifiers_[1]; + EXPECT_EQ("n2", id1.name_); + EXPECT_TRUE(id1.range_.valid_); + EXPECT_EQ(1, id1.range_.msb_); + EXPECT_EQ(0, id1.range_.lsb_); + auto expression = assign.expression_; + EXPECT_TRUE(expression.valid_); + EXPECT_EQ(naja::verilog::Expression::Type::CONCATENATION, expression.value_.index()); + auto concatenation = std::get(expression.value_); + EXPECT_EQ(3, concatenation.expressions_.size()); + EXPECT_TRUE(concatenation.expressions_[2].valid_); + auto constant = concatenation.expressions_[2]; + EXPECT_EQ(naja::verilog::Expression::NUMBER, constant.value_.index()); + auto constantValue = std::get(constant.value_); + EXPECT_TRUE(constantValue.sign_); + EXPECT_EQ(naja::verilog::Number::BASED, constantValue.value_.index()); + auto constantNumber = std::get(constantValue.value_); + EXPECT_FALSE(constantNumber.signed_); + EXPECT_EQ(naja::verilog::BasedNumber::HEX, constantNumber.base_); + EXPECT_EQ(2, constantNumber.size_); + EXPECT_EQ("2", constantNumber.digits_); + } + + { + auto assign = mod->assigns_[3]; + EXPECT_EQ(1, assign.identifiers_.size()); + auto identifier = assign.identifiers_[0]; + EXPECT_EQ("n3", identifier.name_); + EXPECT_FALSE(identifier.range_.valid_); + auto expression = assign.expression_; + EXPECT_TRUE(expression.valid_); + EXPECT_EQ(naja::verilog::Expression::Type::NUMBER, expression.value_.index()); + auto leftId = std::get(expression.value_); + EXPECT_TRUE(leftId.sign_); + EXPECT_EQ(naja::verilog::Number::BASED, leftId.value_.index()); + auto leftBaseNumber = std::get(leftId.value_); + EXPECT_TRUE(leftBaseNumber.signed_); + EXPECT_EQ(naja::verilog::BasedNumber::HEX, leftBaseNumber.base_); + EXPECT_EQ(4, leftBaseNumber.size_); + EXPECT_EQ("F", leftBaseNumber.digits_); + } +} diff --git a/test/NajaVerilogTestErrors.cpp b/test/NajaVerilogTestErrors.cpp index 79ee6a4..aaeb99d 100644 --- a/test/NajaVerilogTestErrors.cpp +++ b/test/NajaVerilogTestErrors.cpp @@ -14,8 +14,38 @@ using namespace naja::verilog; #define NAJA_VERILOG_BENCHMARKS "Undefined" #endif -TEST(NajaVerilogTestErrors, test) { +TEST(NajaVerilogTestErrors, testErrorPath) { VerilogConstructorTest constructor; std::filesystem::path errorPath("does_not_exist.v"); EXPECT_THROW(constructor.parse(errorPath), VerilogException); +} + +TEST(NajaVerilogTestErrors, test0) { + std::filesystem::path error0Path( + std::filesystem::path(NAJA_VERILOG_BENCHMARKS) + / std::filesystem::path("benchmarks") + / std::filesystem::path("errors") + / std::filesystem::path("error0.v")); + VerilogConstructorTest constructor; + EXPECT_THROW(constructor.parse(error0Path), VerilogException); +} + +TEST(NajaVerilogTestErrors, test1) { + std::filesystem::path error1Path( + std::filesystem::path(NAJA_VERILOG_BENCHMARKS) + / std::filesystem::path("benchmarks") + / std::filesystem::path("errors") + / std::filesystem::path("error1.v")); + VerilogConstructorTest constructor; + EXPECT_THROW(constructor.parse(error1Path), VerilogException); +} + +TEST(NajaVerilogTestErrors, test2) { + std::filesystem::path error2Path( + std::filesystem::path(NAJA_VERILOG_BENCHMARKS) + / std::filesystem::path("benchmarks") + / std::filesystem::path("errors") + / std::filesystem::path("error2.v")); + VerilogConstructorTest constructor; + EXPECT_THROW(constructor.parse(error2Path), VerilogException); } \ No newline at end of file diff --git a/test/NajaVerilogTestMultipleFiles.cpp b/test/NajaVerilogTestMultipleFiles.cpp new file mode 100644 index 0000000..0a6128a --- /dev/null +++ b/test/NajaVerilogTestMultipleFiles.cpp @@ -0,0 +1,48 @@ +#include "gtest/gtest.h" + +#include +#include + +#include "VerilogConstructor.h" + +using namespace naja::verilog; + +#include "VerilogConstructorTest.h" + +#ifndef NAJA_VERILOG_BENCHMARKS +#define NAJA_VERILOG_BENCHMARKS "Undefined" +#endif + +TEST(NajaVerilogTestMultipleFiles, test) { + VerilogConstructorTest constructor; + std::filesystem::path multipleFilesPath( + std::filesystem::path(NAJA_VERILOG_BENCHMARKS) + / std::filesystem::path("benchmarks") + / std::filesystem::path("multifiles")); + VerilogConstructor::Paths paths; + paths.push_back(multipleFilesPath / std::filesystem::path("mod0.v")); + paths.push_back(multipleFilesPath / std::filesystem::path("mod1.v")); + paths.push_back(multipleFilesPath / std::filesystem::path("top.v")); + constructor.parse(paths); + ASSERT_EQ(3, constructor.modules_.size()); + EXPECT_EQ("mod0", constructor.modules_[0]->name_); + EXPECT_EQ("mod1", constructor.modules_[1]->name_); + EXPECT_EQ("top", constructor.modules_[2]->name_); + ASSERT_EQ(2, constructor.modules_[0]->ports_.size()); + ASSERT_EQ(2, constructor.modules_[1]->ports_.size()); + ASSERT_EQ(2, constructor.modules_[2]->ports_.size()); + + constructor.setFirstPass(false); + constructor.parse(paths); + + + EXPECT_TRUE(constructor.modules_[0]->instances_.empty()); + EXPECT_TRUE(constructor.modules_[1]->instances_.empty()); + ASSERT_EQ(2, constructor.modules_[2]->instances_.size()); + auto ins0 = constructor.modules_[2]->instances_[0]; + EXPECT_EQ("ins0", ins0.name_); + EXPECT_EQ("mod0", ins0.model_); + auto ins1 = constructor.modules_[2]->instances_[1]; + EXPECT_EQ("ins1", ins1.name_); + EXPECT_EQ("mod1", ins1.model_); +} diff --git a/test/VerilogConstructorTest.cpp b/test/VerilogConstructorTest.cpp index 9d491fe..7e0e471 100644 --- a/test/VerilogConstructorTest.cpp +++ b/test/VerilogConstructorTest.cpp @@ -104,12 +104,6 @@ void VerilogConstructorTest::addAssign( const naja::verilog::Identifiers& identifiers, const naja::verilog::Expression& expression) { if (not inFirstPass()) { - std::cerr << "Add assign: "; - for (auto identifier: identifiers) { - std::cerr << identifier.getDescription() << std::endl; - } - std::cerr << expression.getDescription() << std::endl; - //currentModule_->assigns_.push_back( - // Assign(naja::verilog::Identifier(parameterName), expression) + currentModule_->assigns_.push_back(Assign(identifiers, expression)); } } \ No newline at end of file diff --git a/test/VerilogConstructorTest.h b/test/VerilogConstructorTest.h index 6782381..3d567c2 100644 --- a/test/VerilogConstructorTest.h +++ b/test/VerilogConstructorTest.h @@ -72,7 +72,14 @@ class VerilogConstructorTest: public naja::verilog::VerilogConstructor { }; struct Assign { + Assign( + const naja::verilog::Identifiers& identifiers, + const naja::verilog::Expression& expression): + identifiers_(identifiers), + expression_(expression) + {} naja::verilog::Identifiers identifiers_ {}; + naja::verilog::Expression expression_ {}; }; struct Module { diff --git a/test/benchmarks/errors/error0.v b/test/benchmarks/errors/error0.v new file mode 100644 index 0000000..b3629fc --- /dev/null +++ b/test/benchmarks/errors/error0.v @@ -0,0 +1,9 @@ +/* + Unterminated comment +*/ + +module test(); +endmodule + +/* + This is not terminated \ No newline at end of file diff --git a/test/benchmarks/errors/error1.v b/test/benchmarks/errors/error1.v new file mode 100644 index 0000000..9b4c87a --- /dev/null +++ b/test/benchmarks/errors/error1.v @@ -0,0 +1,7 @@ +/* + Unterminated pragma +*/ + +(* src = "/home/source/test.v" +module test(); +endmodule \ No newline at end of file diff --git a/test/benchmarks/errors/error2.v b/test/benchmarks/errors/error2.v new file mode 100644 index 0000000..5d7c128 --- /dev/null +++ b/test/benchmarks/errors/error2.v @@ -0,0 +1,8 @@ +/* + Syntax error +*/ + +module test(); + //Missing ";" + model ins +endmodule \ No newline at end of file diff --git a/test/benchmarks/multifiles/mod0.v b/test/benchmarks/multifiles/mod0.v new file mode 100644 index 0000000..486ed9b --- /dev/null +++ b/test/benchmarks/multifiles/mod0.v @@ -0,0 +1,2 @@ +module mod0(input i, output o); +endmodule \ No newline at end of file diff --git a/test/benchmarks/multifiles/mod1.v b/test/benchmarks/multifiles/mod1.v new file mode 100644 index 0000000..54de858 --- /dev/null +++ b/test/benchmarks/multifiles/mod1.v @@ -0,0 +1,2 @@ +module mod1(input a, output b); +endmodule \ No newline at end of file diff --git a/test/benchmarks/multifiles/top.v b/test/benchmarks/multifiles/top.v new file mode 100644 index 0000000..61da2ca --- /dev/null +++ b/test/benchmarks/multifiles/top.v @@ -0,0 +1,5 @@ +module top(input in, output out); + wire n; + mod0 ins0(in, n); + mod1 ins1(n, out); +endmodule \ No newline at end of file diff --git a/test/benchmarks/test6.v b/test/benchmarks/test6.v index 01c2af4..52c25a4 100644 --- a/test/benchmarks/test6.v +++ b/test/benchmarks/test6.v @@ -4,8 +4,10 @@ module test(\asqrt[33] ); wire n0, n1; wire [3:0] n2; + wire [3:0] n3; assign n0 = n1; assign n1 = 1'b0; assign { n2[3:2], n2[1:0] } = { n0, n1, 2'h2 }; + assign n3 = 4'shF; endmodule \ No newline at end of file