1 /*
2  * Copyright (C) 2019-2020 Dynare Team
3  *
4  * This file is part of Dynare.
5  *
6  * Dynare is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Dynare is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef _DIRECTIVES_HH
21 #define _DIRECTIVES_HH
22 
23 #include "Expressions.hh"
24 
25 #include <filesystem>
26 
27 namespace macro
28 {
29   class Directive : public Node
30   {
31     // A Parent class just for clarity
32   public:
Directive(Environment & env_arg,Tokenizer::location location_arg)33     Directive(Environment &env_arg, Tokenizer::location location_arg) :
34       Node(env_arg, move(location_arg)) { }
35     // Directives can be interpreted
36     virtual void interpret(ostream &output, vector<filesystem::path> &paths) = 0;
37   };
38 
39 
40   class TextNode : public Directive
41   {
42     // Class for text not interpreted by macroprocessor
43     // Not a real directive node
44     // Treated as such as the output is only to be interpreted
45   private:
46     const string text;
47   public:
TextNode(string text_arg,Environment & env_arg,Tokenizer::location location_arg)48     TextNode(string text_arg, Environment &env_arg, Tokenizer::location location_arg) :
49       Directive(env_arg, move(location_arg)), text{move(text_arg)} { }
interpret(ostream & output,vector<filesystem::path> & paths)50     inline void interpret(ostream &output, vector<filesystem::path> &paths) override { output << text; }
51   };
52 
53 
54   class Eval : public Directive
55   {
56     // Class for @{} statements
57     // Not a real directive node
58     // Treated as such as the output is only to be interpreted
59   private:
60     const ExpressionPtr expr;
61   public:
Eval(ExpressionPtr expr_arg,Environment & env_arg,Tokenizer::location location_arg)62     Eval(ExpressionPtr expr_arg, Environment &env_arg, Tokenizer::location location_arg) :
63       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
64     void interpret(ostream &output, vector<filesystem::path> &paths) override;
65   };
66 
67 
68   class Include : public Directive
69   {
70   private:
71     const ExpressionPtr expr;
72   public:
Include(ExpressionPtr expr_arg,Environment & env_arg,Tokenizer::location location_arg)73     Include(ExpressionPtr expr_arg, Environment &env_arg, Tokenizer::location location_arg) :
74       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
75     void interpret(ostream &output, vector<filesystem::path> &paths) override;
76   };
77 
78 
79   class IncludePath : public Directive
80   {
81   private:
82     const ExpressionPtr expr;
83   public:
IncludePath(ExpressionPtr expr_arg,Environment & env_arg,Tokenizer::location location_arg)84     IncludePath(ExpressionPtr expr_arg, Environment &env_arg, Tokenizer::location location_arg) :
85       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
86     void interpret(ostream &output, vector<filesystem::path> &paths) override;
87   };
88 
89 
90   class Define : public Directive
91   {
92   private:
93     const VariablePtr var;
94     const FunctionPtr func;
95     const ExpressionPtr value;
96   public:
Define(VariablePtr var_arg,ExpressionPtr value_arg,Environment & env_arg,Tokenizer::location location_arg)97     Define(VariablePtr var_arg,
98            ExpressionPtr value_arg,
99            Environment &env_arg, Tokenizer::location location_arg) :
100       Directive(env_arg, move(location_arg)), var{move(var_arg)}, value{move(value_arg)} { }
Define(FunctionPtr func_arg,ExpressionPtr value_arg,Environment & env_arg,Tokenizer::location location_arg)101     Define(FunctionPtr func_arg,
102            ExpressionPtr value_arg,
103            Environment &env_arg, Tokenizer::location location_arg) :
104       Directive(env_arg, move(location_arg)), func{move(func_arg)}, value{move(value_arg)} { }
105     void interpret(ostream &output, vector<filesystem::path> &paths) override;
106   };
107 
108 
109   class Echo : public Directive
110   {
111   private:
112     const ExpressionPtr expr;
113   public:
Echo(ExpressionPtr expr_arg,Environment & env_arg,Tokenizer::location location_arg)114     Echo(ExpressionPtr expr_arg,
115          Environment &env_arg, Tokenizer::location location_arg) :
116       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
117     void interpret(ostream &output, vector<filesystem::path> &paths) override;
118   };
119 
120 
121   class Error : public Directive
122   {
123   private:
124     const ExpressionPtr expr;
125   public:
Error(ExpressionPtr expr_arg,Environment & env_arg,Tokenizer::location location_arg)126     Error(ExpressionPtr expr_arg,
127           Environment &env_arg, Tokenizer::location location_arg) :
128       Directive(env_arg, move(location_arg)), expr{move(expr_arg)} { }
129     void interpret(ostream &output, vector<filesystem::path> &paths) override;
130   };
131 
132 
133   class EchoMacroVars : public Directive
134   {
135   private:
136     const bool save;
137     const vector<string> vars;
138   public:
EchoMacroVars(bool save_arg,Environment & env_arg,Tokenizer::location location_arg)139     EchoMacroVars(bool save_arg,
140                   Environment &env_arg, Tokenizer::location location_arg) :
141       Directive(env_arg, move(location_arg)), save{save_arg} { }
EchoMacroVars(bool save_arg,vector<string> vars_arg,Environment & env_arg,Tokenizer::location location_arg)142     EchoMacroVars(bool save_arg, vector<string> vars_arg,
143                   Environment &env_arg, Tokenizer::location location_arg) :
144       Directive(env_arg, move(location_arg)), save{save_arg}, vars{move(vars_arg)} { }
145     void interpret(ostream &output, vector<filesystem::path> &paths) override;
146   };
147 
148 
149   class For : public Directive
150   {
151   private:
152     const vector<VariablePtr> index_vec;
153     const ExpressionPtr index_vals;
154     const vector<DirectivePtr> statements;
155   public:
For(vector<VariablePtr> index_vec_arg,ExpressionPtr index_vals_arg,vector<DirectivePtr> statements_arg,Environment & env_arg,Tokenizer::location location_arg)156     For(vector<VariablePtr> index_vec_arg,
157         ExpressionPtr index_vals_arg,
158         vector<DirectivePtr> statements_arg,
159         Environment &env_arg, Tokenizer::location location_arg) :
160       Directive(env_arg, move(location_arg)), index_vec{move(index_vec_arg)},
161       index_vals{move(index_vals_arg)}, statements{move(statements_arg)} { }
162     void interpret(ostream &output, vector<filesystem::path> &paths) override;
163   };
164 
165 
166   class If : public Directive
167   {
168   protected:
169     /* Every if statement and the associated body to execute are stored in a
170      * pair<ExpressionPtr, vector<DirectivePtr>>, where the ExpressionPtr is the condition
171      * and vector<DirectivePtr> is the series of statements to execute if the condition evaluates
172      * to true.
173      * The `if` statement is the first element in the vector
174      * If there exist any `elseif` statements, they follow
175      * If there is an `else` statement it is the last element in the vector. Its condition is true.
176      */
177     const vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body;
178     const bool ifdef, ifndef;
179   public:
If(vector<pair<ExpressionPtr,vector<DirectivePtr>>> expr_and_body_arg,Environment & env_arg,Tokenizer::location location_arg,bool ifdef_arg=false,bool ifndef_arg=false)180     If(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
181        Environment &env_arg, Tokenizer::location location_arg,
182        bool ifdef_arg = false, bool ifndef_arg = false) :
183       Directive(env_arg, move(location_arg)), expr_and_body{move(expr_and_body_arg)},
184       ifdef{ifdef_arg}, ifndef{ifndef_arg} { }
185     void interpret(ostream &output, vector<filesystem::path> &paths) override;
186   protected:
187     void interpretBody(const vector<DirectivePtr> &body, ostream &output,
188                        vector<filesystem::path> &paths);
189   };
190 
191   class Ifdef : public If
192   {
193   public:
Ifdef(vector<pair<ExpressionPtr,vector<DirectivePtr>>> expr_and_body_arg,Environment & env_arg,Tokenizer::location location_arg)194     Ifdef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
195           Environment &env_arg, Tokenizer::location location_arg) :
196       If(move(expr_and_body_arg), env_arg, move(location_arg), true, false) { }
197   };
198 
199 
200   class Ifndef : public If
201   {
202   public:
Ifndef(vector<pair<ExpressionPtr,vector<DirectivePtr>>> expr_and_body_arg,Environment & env_arg,Tokenizer::location location_arg)203     Ifndef(vector<pair<ExpressionPtr, vector<DirectivePtr>>> expr_and_body_arg,
204            Environment &env_arg, Tokenizer::location location_arg) :
205       If(move(expr_and_body_arg), env_arg, move(location_arg), false, true) { }
206   };
207 }
208 #endif
209