Skip to content
Snippets Groups Projects
Unverified Commit 6e2be21b authored by Nora Abi Akar's avatar Nora Abi Akar Committed by GitHub
Browse files

Modcc: modify semantic passes (#932)

- Reset the error of the semantic pass of an expression at the start of the function call. 
- Check the errors of sub-expressions after applying to them their semantic passes, and report errors if found. If the error could disrupt the rest of the original semantic pass, return.
- Check errors in functions/procedures before and after inlining, but not during. 

Fixes #931 
parent ec1f7520
No related branches found
No related tags found
No related merge requests found
......@@ -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 {
......
......@@ -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();
......
......@@ -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;
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment