From 9e454debb5eb7cbabcf29e844e16f2463d8d7eb6 Mon Sep 17 00:00:00 2001
From: Houtan Bastani <houtan@dynare.org>
Date: Tue, 8 Oct 2019 16:06:01 +0200
Subject: [PATCH] support external functions in MATLAB namespace. closes
 dynare#1639

---
 src/DynareBison.yy   | 26 ++++++++++++++++++--------
 src/DynareFlex.ll    |  2 +-
 src/ParsingDriver.cc |  6 ++++++
 3 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/src/DynareBison.yy b/src/DynareBison.yy
index 5453d10a..8839deeb 100644
--- a/src/DynareBison.yy
+++ b/src/DynareBison.yy
@@ -174,7 +174,8 @@ class ParsingDriver;
 %type <expr_t> expression expression_or_empty
 %type <expr_t> equation hand_side
 %type <string> non_negative_number signed_number signed_integer date_str
-%type <string> filename symbol vec_of_vec_value vec_value_list date_expr number
+%type <string> filename symbol namespace_qualified_filename namespace_qualified_symbol
+%type <string> vec_of_vec_value vec_value_list date_expr number
 %type <string> vec_value_1 vec_value signed_inf signed_number_w_inf
 %type <string> range vec_value_w_inf vec_value_1_w_inf
 %type <string> integer_range signed_integer_range
@@ -747,7 +748,7 @@ init_param : symbol EQUAL expression ';' { driver.init_param($1, $3); };
 
 expression : '(' expression ')'
              { $$ = $2;}
-           | symbol
+           | namespace_qualified_symbol
              { $$ = driver.add_expression_variable($1); }
            | non_negative_number
              { $$ = driver.add_non_negative_constant($1); }
@@ -809,7 +810,7 @@ expression : '(' expression ')'
              { $$ = driver.add_max($3, $5); }
            | MIN '(' expression COMMA expression ')'
              { $$ = driver.add_min($3, $5); }
-           | symbol { driver.push_external_function_arg_vector_onto_stack(); } '(' comma_expression ')'
+           | namespace_qualified_symbol { driver.push_external_function_arg_vector_onto_stack(); } '(' comma_expression ')'
              { $$ = driver.add_model_var_or_external_function($1, false); }
            | NORMCDF '(' expression COMMA expression COMMA expression ')'
              { $$ = driver.add_normcdf($3, $5, $7); }
@@ -939,7 +940,7 @@ tag_pair : NAME EQUAL QUOTED_STRING
 
 hand_side : '(' hand_side ')'
             { $$ = $2;}
-          | symbol
+          | namespace_qualified_symbol
             { $$ = driver.add_model_variable($1); }
           | symbol PIPE_E
             { $$ = driver.declare_or_change_type(SymbolType::endogenous, $1); }
@@ -1019,7 +1020,7 @@ hand_side : '(' hand_side ')'
             { $$ = driver.add_max($3, $5); }
           | MIN '(' hand_side COMMA hand_side ')'
             { $$ = driver.add_min($3, $5); }
-          | symbol { driver.push_external_function_arg_vector_onto_stack(); } '(' comma_hand_side ')'
+          | namespace_qualified_symbol { driver.push_external_function_arg_vector_onto_stack(); } '(' comma_hand_side ')'
             { $$ = driver.add_model_var_or_external_function($1, true); }
           | NORMCDF '(' hand_side COMMA hand_side COMMA hand_side ')'
             { $$ = driver.add_normcdf($3, $5, $7); }
@@ -2253,6 +2254,15 @@ filename : symbol
          | QUOTED_STRING
          ;
 
+namespace_qualified_symbol : symbol
+                           | namespace_qualified_symbol '.' symbol
+                             { $$ = $1 + "." + $3; }
+                           ;
+
+namespace_qualified_filename : namespace_qualified_symbol
+                             | QUOTED_STRING
+                             ;
+
 parallel_local_filename_list : filename
                                { driver.add_parallel_local_file($1); }
                              | parallel_local_filename_list COMMA filename
@@ -3559,14 +3569,14 @@ o_equations : EQUATIONS EQUAL vec_int
 o_silent_optimizer : SILENT_OPTIMIZER { driver.option_num("silent_optimizer", "true"); };
 o_instruments : INSTRUMENTS EQUAL '(' symbol_list ')' {driver.option_symbol_list("instruments"); };
 
-o_ext_func_name : EXT_FUNC_NAME EQUAL filename { driver.external_function_option("name", $3); };
+o_ext_func_name : EXT_FUNC_NAME EQUAL namespace_qualified_filename { driver.external_function_option("name", $3); };
 o_ext_func_nargs : EXT_FUNC_NARGS EQUAL INT_NUMBER { driver.external_function_option("nargs",$3); };
-o_first_deriv_provided : FIRST_DERIV_PROVIDED EQUAL filename
+o_first_deriv_provided : FIRST_DERIV_PROVIDED EQUAL namespace_qualified_filename
                          { driver.external_function_option("first_deriv_provided", $3); }
                        | FIRST_DERIV_PROVIDED
                          { driver.external_function_option("first_deriv_provided", ""); }
                        ;
-o_second_deriv_provided : SECOND_DERIV_PROVIDED EQUAL filename
+o_second_deriv_provided : SECOND_DERIV_PROVIDED EQUAL namespace_qualified_filename
                           { driver.external_function_option("second_deriv_provided", $3); }
                         | SECOND_DERIV_PROVIDED
                           { driver.external_function_option("second_deriv_provided", ""); }
diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll
index 75307f2d..111d07cb 100644
--- a/src/DynareFlex.ll
+++ b/src/DynareFlex.ll
@@ -781,7 +781,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4]|w([1-9]{1}|[1-4][0-9]|5[0-2]))
 <DYNARE_STATEMENT>variances {return token::VARIANCES;}
 <DYNARE_STATEMENT>equations {return token::EQUATIONS;}
 
-<DYNARE_STATEMENT>\. {return Dynare::parser::token_type (yytext[0]);}
+<DYNARE_STATEMENT,DYNARE_BLOCK>\. {return Dynare::parser::token_type (yytext[0]);}
 <DYNARE_STATEMENT>\\ {return Dynare::parser::token_type (yytext[0]);}
 <DYNARE_STATEMENT>\' {return Dynare::parser::token_type (yytext[0]);}
 
diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc
index 4efbe0cf..2ecac4d6 100644
--- a/src/ParsingDriver.cc
+++ b/src/ParsingDriver.cc
@@ -319,6 +319,9 @@ ParsingDriver::add_inf_constant()
 expr_t
 ParsingDriver::add_model_variable(const string &name)
 {
+  if (name.find(".") != string::npos)
+    error(name + " treated as a variable, but it contains a '.'");
+
   check_symbol_existence_in_model_block(name);
   int symb_id;
   try
@@ -406,6 +409,9 @@ ParsingDriver::add_model_variable(int symb_id, int lag)
 expr_t
 ParsingDriver::add_expression_variable(const string &name)
 {
+  if (name.find(".") != string::npos)
+    error(name + " treated as a variable, but it contains a '.'");
+
   if (parsing_epilogue && !mod_file->symbol_table.exists(name))
     error("Variable " + name + " used in the epilogue block but was not declared.");
 
-- 
GitLab