diff --git a/modcc/expression.cpp b/modcc/expression.cpp index 51e8217b5147109af2dfff553a71889f25b11ef4..336acf91609bc385e2d34803dbd39218b9062241 100644 --- a/modcc/expression.cpp +++ b/modcc/expression.cpp @@ -79,6 +79,7 @@ std::string LocalVariable::to_string() const { *******************************************************************************/ void IdentifierExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; auto s = scope_->find(spelling_); @@ -142,6 +143,8 @@ expression_ptr DerivativeExpression::clone() const { } void DerivativeExpression::semantic(scope_ptr scp) { + error_ = false; + IdentifierExpression::semantic(scp); auto v = symbol_->is_variable(); if (!v || !v->is_state()) { @@ -198,6 +201,7 @@ bool LocalDeclaration::add_variable(Token tok) { } void LocalDeclaration::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; // loop over the variables declared in this LOCAL statement @@ -239,6 +243,7 @@ std::string ArgumentExpression::to_string() const { } void ArgumentExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; auto s = scope_->find(name_); @@ -303,12 +308,25 @@ expression_ptr ReactionExpression::clone() const { } void ReactionExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + lhs()->semantic(scp); rhs()->semantic(scp); fwd_rate()->semantic(scp); rev_rate()->semantic(scp); + + std::string msg = lhs_->has_error() ? lhs_->error_message() : + rhs_->has_error() ? rhs_->error_message() : + fwd_rate_->has_error() ? fwd_rate_->error_message() : + rev_rate_->has_error() ? rev_rate_->error_message() : ""; + + if (!msg.empty()) { + error(msg); + return; + } + if(fwd_rate_->is_procedure_call() || rev_rate_->is_procedure_call()) { error("procedure calls can't be made in an expression"); } @@ -324,8 +342,13 @@ expression_ptr StoichTermExpression::clone() const { } void StoichTermExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + ident()->semantic(scp); + if(ident()->has_error()) { + error(ident()->error_message()); + } } /******************************************************************************* @@ -353,9 +376,14 @@ std::string StoichExpression::to_string() const { } void StoichExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + for(auto& e: terms()) { e->semantic(scp); + if(e->has_error()) { + error(e->error_message()); + } } } @@ -387,8 +415,13 @@ std::string CompartmentExpression::to_string() const { } void CompartmentExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + scale_factor()->semantic(scp); + if(scale_factor()->has_error()) { + error(scale_factor()->error_message()); + } } /******************************************************************************* @@ -401,10 +434,19 @@ expression_ptr LinearExpression::clone() const { } void LinearExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + lhs_->semantic(scp); rhs_->semantic(scp); + std::string msg = lhs_->has_error() ? lhs_->error_message() : + rhs_->has_error() ? rhs_->error_message() : ""; + + if (!msg.empty()) { + error(msg); + return; + } if(rhs_->is_procedure_call()) { error("procedure calls can't be made in an expression"); } @@ -420,10 +462,19 @@ expression_ptr ConserveExpression::clone() const { } void ConserveExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + lhs_->semantic(scp); rhs_->semantic(scp); + std::string msg = lhs_->has_error() ? lhs_->error_message() : + rhs_->has_error() ? rhs_->error_message() : ""; + + if (!msg.empty()) { + error(msg); + return; + } if(rhs_->is_procedure_call()) { error("procedure calls can't be made in an expression"); } @@ -443,6 +494,7 @@ std::string CallExpression::to_string() const { } void CallExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; // look up to see if symbol is defined @@ -481,6 +533,9 @@ void CallExpression::semantic(scope_ptr scp) { // perform semantic analysis on the arguments for(auto& a : args_) { a->semantic(scp); + if(a->has_error()) { + error(a->error_message()); + } } } @@ -511,6 +566,7 @@ std::string ProcedureExpression::to_string() const { } void ProcedureExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; // assert that the symbol is already visible in the global_symbols @@ -525,6 +581,9 @@ void ProcedureExpression::semantic(scope_ptr scp) { // add the argumemts to the list of local variables for(auto& a : args_) { a->semantic(scope_); + if(a->has_error()) { + error(a->error_message()); + } } // this loop could be used to then check the types of statements in the body @@ -535,6 +594,9 @@ void ProcedureExpression::semantic(scope_ptr scp) { // perform semantic analysis for each expression in the body body_->semantic(scope_); + if(body_->has_error()) { + error(body_->error_message()); + } // the symbol for this expression is itself symbol_ = scope_->find_global(name()); @@ -543,6 +605,7 @@ void ProcedureExpression::semantic(scope_ptr scp) { void ProcedureExpression::semantic(scope_type::symbol_map &global_symbols) { // create the scope for this procedure and run semantic pass on it scope_ptr scp = std::make_shared<scope_type>(global_symbols); + error_ = false; switch (kind_) { case procedureKind::derivative: case procedureKind::kinetic: @@ -585,6 +648,8 @@ void APIMethod::semantic(scope_type::symbol_map &global_symbols) { // create the scope for this procedure, marking it as an API context, // and run semantic pass on it scope_ptr scp = std::make_shared<scope_type>(global_symbols); + error_ = false; + scp->in_api_context(true); semantic(scp); } @@ -618,14 +683,22 @@ void NetReceiveExpression::semantic(scope_type::symbol_map &global_symbols) { // create the scope for this procedure scope_ = std::make_shared<scope_type>(global_symbols); + error_ = false; // add the argumemts to the list of local variables for(auto& a : args_) { a->semantic(scope_); + if(a->has_error()) { + error(a->error_message()); + } } // perform semantic analysis for each expression in the body body_->semantic(scope_); + if(body_->has_error()) { + error(body_->error_message()); + } + // this loop could be used to then check the types of statements in the body for(auto& e : *(body_->is_block())) { if(e->is_initial_block()) { @@ -668,10 +741,14 @@ void FunctionExpression::semantic(scope_type::symbol_map &global_symbols) { // create the scope for this procedure scope_ = std::make_shared<scope_type>(global_symbols); + error_ = false; // add the argumemts to the list of local variables for(auto& a : args_) { a->semantic(scope_); + if(a->has_error()) { + error(a->error_message()); + } } // Add a variable that has the same name as the function, @@ -685,6 +762,9 @@ void FunctionExpression::semantic(scope_type::symbol_map &global_symbols) { // perform semantic analysis for each expression in the body body_->semantic(scope_); + if(body_->has_error()) { + error(body_->error_message()); + } // this loop could be used to then check the types of statements in the body for(auto& e : *(body())) { if(e->is_initial_block()) error("INITIAL block not allowed inside FUNCTION definition"); @@ -699,10 +779,14 @@ void FunctionExpression::semantic(scope_type::symbol_map &global_symbols) { UnaryExpression *******************************************************************************/ void UnaryExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; expression_->semantic(scp); - + if(expression_->has_error()) { + error(expression_->error_message()); + return; + } if(expression_->is_procedure_call()) { error("a procedure call can't be part of an expression"); } @@ -720,10 +804,19 @@ expression_ptr UnaryExpression::clone() const { BinaryExpression *******************************************************************************/ void BinaryExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + lhs_->semantic(scp); rhs_->semantic(scp); + std::string msg = lhs_->has_error() ? lhs_->error_message() : + rhs_->has_error() ? rhs_->error_message() : ""; + + if (!msg.empty()) { + error(msg); + return; + } if(rhs_->is_procedure_call() || lhs_->is_procedure_call()) { error("procedure calls can't be made in an expression"); } @@ -751,10 +844,20 @@ std::string BinaryExpression::to_string() const { *******************************************************************************/ void AssignmentExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; + lhs_->semantic(scp); rhs_->semantic(scp); + std::string msg = lhs_->has_error() ? lhs_->error_message() : + rhs_->has_error() ? rhs_->error_message() : ""; + + if (!msg.empty()) { + error(msg); + return; + } + // only flag an lvalue error if there was no error in the lhs expression // this ensures that we don't print redundant error messages when trying // to write to an undeclared variable @@ -771,6 +874,7 @@ void AssignmentExpression::semantic(scope_ptr scp) { *******************************************************************************/ void SolveExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; auto e = scp->find(name()); @@ -799,6 +903,7 @@ expression_ptr SolveExpression::clone() const { *******************************************************************************/ void ConductanceExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; // For now do nothing with the CONDUCTANCE statement, because it is not needed // to optimize conductance calculation. @@ -831,9 +936,13 @@ std::string BlockExpression::to_string() const { } void BlockExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; for(auto& e : statements_) { e->semantic(scope_); + if(e->has_error()) { + error(e->error_message()); + } } } @@ -862,18 +971,28 @@ std::string IfExpression::to_string() const { } void IfExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; condition_->semantic(scp); + if(condition_->has_error()) { + error(condition()->error_message()); + } if(!condition_->is_conditional()) { error("not a valid conditional expression"); } true_branch_->semantic(scp); + if(true_branch_->has_error()) { + error(true_branch_->error_message()); + } if(false_branch_) { false_branch_->semantic(scp); + if(false_branch_->has_error()) { + error(false_branch_->error_message()); + } } } @@ -899,6 +1018,7 @@ std::string PDiffExpression::to_string() const { } void PDiffExpression::semantic(scope_ptr scp) { + error_ = false; scope_ = scp; if (!var_->is_identifier()) { @@ -906,7 +1026,13 @@ void PDiffExpression::semantic(scope_ptr scp) { "an identifier, but instead %", yellow(var_->to_string()))); } var_->semantic(scp); + if(var_->has_error()) { + error(var_->error_message()); + } arg_->semantic(scp); + if(arg_->has_error()) { + error(arg_->error_message()); + } } expression_ptr PDiffExpression::clone() const { diff --git a/modcc/module.cpp b/modcc/module.cpp index 9938a8636448262e0d2dfc16669ea27362f3fcd2..a4d0f68b93afccb75b5404fc8b4bbf04b4948061 100644 --- a/modcc/module.cpp +++ b/modcc/module.cpp @@ -757,6 +757,22 @@ int Module::semantic_func_proc() { // - generate local variable table for each function/procedure // - inlining function calls //////////////////////////////////////////////////////////////////////////// + + // Before, make sure there are no errors + int errors = 0; + for(auto& e : symbols_) { + auto &s = e.second; + if(s->kind() == symbolKind::procedure || s->kind() == symbolKind::function) { + s->semantic(symbols_); + ErrorVisitor v(source_name()); + s->accept(&v); + errors += v.num_errors(); + } + } + if (errors > 0) { + return errors; + } + #ifdef LOGGING std::cout << white("===================================\n"); std::cout << cyan(" Function Inlining\n"); @@ -834,10 +850,11 @@ int Module::semantic_func_proc() { } } - int errors = 0; + errors = 0; for(auto& e : symbols_) { auto& s = e.second; if(s->kind() == symbolKind::procedure) { + s->semantic(symbols_); ErrorVisitor v(source_name()); s->accept(&v); errors += v.num_errors(); diff --git a/test/unit-modcc/test_printers.cpp b/test/unit-modcc/test_printers.cpp index 8e1635dcdc8e487666c628d4e219048f4dbf4ecb..3d8dcfa459bb15d934b3233016d149f3a4c98e1c 100644 --- a/test/unit-modcc/test_printers.cpp +++ b/test/unit-modcc/test_printers.cpp @@ -88,7 +88,10 @@ TEST(scalar_printer, statement) { ASSERT_TRUE(e); e->semantic(scope); - + if(e->has_error()) { + std::cerr << e->error_message() << std::endl; + FAIL(); + } { SCOPED_TRACE("CPrinter"); std::stringstream out;