From e84a0e36ba4b2e9f22ee3c6c6f779620783ae7c4 Mon Sep 17 00:00:00 2001
From: Nora Abi Akar <nora.abiakar@gmail.com>
Date: Fri, 17 May 2019 12:51:59 +0200
Subject: [PATCH] modcc fixes (#745)

* Fixes segmentation faults; output compiler errors instead.
* Consume units if provided in function/procedure prototypes or after function prototype.
* Consume UNITSON/UNITSOFF.
* Consume and store VALENCE as an ion property.
---
 modcc/blocks.hpp          |  1 +
 modcc/functioninliner.cpp |  7 +++++++
 modcc/module.cpp          |  6 +++++-
 modcc/parser.cpp          | 26 ++++++++++++++++++++++++++
 modcc/parser.hpp          |  1 +
 modcc/token.cpp           |  2 ++
 modcc/token.hpp           |  2 +-
 7 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/modcc/blocks.hpp b/modcc/blocks.hpp
index 9ba8c657..868f60bd 100644
--- a/modcc/blocks.hpp
+++ b/modcc/blocks.hpp
@@ -17,6 +17,7 @@ struct IonDep {
     std::string name;         // name of ion channel
     std::vector<Token> read;  // name of channels parameters to write
     std::vector<Token> write; // name of channels parameters to read
+    std::string valence;
 
     bool has_variable(std::string const& name) const {
         return writes_variable(name) || reads_variable(name);
diff --git a/modcc/functioninliner.cpp b/modcc/functioninliner.cpp
index da5dd5eb..20c0c2ed 100644
--- a/modcc/functioninliner.cpp
+++ b/modcc/functioninliner.cpp
@@ -18,6 +18,13 @@ expression_ptr inline_function_call(Expression* e)
                 "can only inline functions with one statement", func->location()
             );
         }
+
+        if(body.front()->is_if()) {
+            throw compiler_exception(
+                    "can not inline functions with if statements", func->location()
+            );
+        }
+
         // assume that the function body is correctly formed, with the last
         // statement being an assignment expression
         auto last = body.front()->is_assignment();
diff --git a/modcc/module.cpp b/modcc/module.cpp
index c78d9c72..97debcad 100644
--- a/modcc/module.cpp
+++ b/modcc/module.cpp
@@ -590,7 +590,11 @@ void Module::add_variables_to_symbols() {
         VariableExpression* state = nullptr;
         if (has_symbol(name)) {
             state = symbols_[name].get()->is_variable();
-            if (!state || !state->is_state()) {
+            if (!state) {
+                error(pprintf("the symbol defined % can't be redeclared", yellow(name)), tkn.location);
+                return;
+            }
+            if (!state->is_state()) {
                 error(pprintf("the symbol defined % at % can't be redeclared",
                     state->location(), yellow(name)), tkn.location);
                 return;
diff --git a/modcc/parser.cpp b/modcc/parser.cpp
index 6ce9258b..1598711a 100644
--- a/modcc/parser.cpp
+++ b/modcc/parser.cpp
@@ -35,6 +35,15 @@ bool Parser::expect(tok tok, std::string const& str) {
     return false;
 }
 
+void Parser::parse_unit() {
+    if(token_.type == tok::lparen) {
+        while (token_.type != tok::rparen) {
+            get_token();
+        }
+        get_token(); // consume ')'
+    }
+}
+
 void Parser::error(std::string msg) {
     std::string location_info = pprintf(
             "%:% ", module_ ? module_->source_name() : "", token_.location);
@@ -125,6 +134,12 @@ bool Parser::parse() {
                 module_->add_callable(std::move(f));
                 }
                 break;
+            case tok::unitson :
+                get_token();
+                break;
+            case tok::unitsoff :
+                get_token();
+                break;
             default :
                 error(pprintf("expected block type, found '%'", token_.spelling));
                 break;
@@ -317,6 +332,13 @@ void Parser::parse_neuron_block() {
                             target.push_back(id);
                         }
                     }
+
+                    if(token_.type == tok::valence) {
+                        //Consume "Valence"
+                        get_token();
+                        ion.valence == value_literal();
+                    }
+
                     // add the ion dependency to the NEURON block
                     neuron_block.ions.push_back(std::move(ion));
                 }
@@ -715,6 +737,8 @@ expression_ptr Parser::parse_prototype(std::string name=std::string()) {
 
         get_token(); // consume the identifier
 
+        parse_unit(); // consume the unit if provided
+
         // look for a comma
         if(!(token_.type == tok::comma || token_.type==tok::rparen)) {
             error(  "expected a comma or closing parenthesis, found '"
@@ -839,6 +863,8 @@ symbol_ptr Parser::parse_function() {
     auto p = parse_prototype();
     if(p==nullptr) return nullptr;
 
+    parse_unit();
+
     // check for opening left brace {
     if(!expect(tok::lbrace)) return nullptr;
 
diff --git a/modcc/parser.hpp b/modcc/parser.hpp
index 43fb323b..8b941423 100644
--- a/modcc/parser.hpp
+++ b/modcc/parser.hpp
@@ -75,6 +75,7 @@ private:
     Parser();
     Parser(Parser const &);
 
+    void parse_unit();
     bool expect(tok, const char *str="");
     bool expect(tok, std::string const& str);
 };
diff --git a/modcc/token.cpp b/modcc/token.cpp
index 1ea8d27a..ba89e2ce 100644
--- a/modcc/token.cpp
+++ b/modcc/token.cpp
@@ -41,6 +41,7 @@ static Keyword keywords[] = {
     {"USEION",      tok::useion},
     {"READ",        tok::read},
     {"WRITE",       tok::write},
+    {"VALENCE",     tok::valence},
     {"RANGE",       tok::range},
     {"LOCAL",       tok::local},
     {"CONSERVE",    tok::conserve},
@@ -110,6 +111,7 @@ static TokenString token_strings[] = {
     {"USEION",      tok::useion},
     {"READ",        tok::read},
     {"WRITE",       tok::write},
+    {"VALENCE",     tok::valence},
     {"RANGE",       tok::range},
     {"LOCAL",       tok::local},
     {"SOLVE",       tok::solve},
diff --git a/modcc/token.hpp b/modcc/token.hpp
index 97667c2e..149ee743 100644
--- a/modcc/token.hpp
+++ b/modcc/token.hpp
@@ -59,7 +59,7 @@ enum class tok {
     // keywoards inside blocks
     unitsoff, unitson,
     suffix, nonspecific_current, useion,
-    read, write,
+    read, write, valence,
     range, local, conserve,
     solve, method,
     threadsafe, global,
-- 
GitLab