1 /*
2     This file is part of GNU APL, a free implementation of the
3     ISO/IEC Standard 13751, "Programming Language APL, Extended"
4 
5     Copyright (C) 2008-2015  Dr. Jürgen Sauermann
6 
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef __STATE_INDICATOR_HH_DEFINED__
22 #define __STATE_INDICATOR_HH_DEFINED__
23 
24 #include "Common.hh"
25 #include "DerivedFunction.hh"
26 #include "Executable.hh"
27 #include "Error.hh"
28 #include "Function.hh"
29 #include "Parser.hh"
30 #include "Prefix.hh"
31 #include "PrintOperator.hh"
32 
33 //-----------------------------------------------------------------------------
34 /**
35     One entry of the state indicator (SI) of the APL interpreter.
36     Compared to e.g.  C++, the state indicator is (one element of) the
37     function call stack of the interpreter.
38  */
39 /// One entry of the state indicator (SI) of the APL interpreter
40 class StateIndicator
41 {
42    friend class XML_Loading_Archive;
43    friend class XML_Saving_Archive;
44 
45 public:
46    /// constructor
47    StateIndicator(Executable * exec, StateIndicator * _par);
48 
49    /// destructor
50    ~StateIndicator();
51 
52    /// continue this StateIndicator (to line N after →N back into it)
53    void goon(Function_Line N, const char * loc);
54 
55    /// retry this StateIndicator (after →'')
56    void retry(const char * loc);
57 
58    /// return true iff
59    ///  (1) this SI entry is executing \b funname, or
60    ///  (2) has resolved \b funname on its prefix parser stack
61    bool uses_function(const UserFunction * ufun) const;
62 
63    /// Return the function name, or "*" for an immediate execution context
64    UCS_string function_name() const;
65 
66    /// list the stack entry (for commands ]SI, )SI, and )SIS)
67    void list(ostream & out, SI_mode mode) const;
68 
69    /// list the stack entry (for command ]SI)
70    void print(ostream & out) const;
71 
72    /// print spaces according to level
73    ostream & indent(ostream & out) const;
74 
75    /// return pointer to the current user function, statements, or execute
get_executable()76    Executable * get_executable()
77       { return executable; }
78 
79    /// return pointer to the current user function, statements, or execute
get_executable() const80    const Executable * get_executable() const
81       { return executable; }
82 
83    /// return the name of the parse mode
84    Unicode get_parse_mode_name() const;
85 
86    /// return the current PC
get_PC() const87    Function_PC get_PC() const
88       { return current_stack.get_PC(); }
89 
90    /// set the current PC
set_PC(Function_PC new_pc)91    void set_PC(Function_PC new_pc)
92       { current_stack.set_PC(new_pc); }
93 
94    /// return the mode of this entry
get_parse_mode() const95    ParseMode get_parse_mode() const
96       { return executable->get_parse_mode(); }
97 
98    /// evaluate a →N statement. Update pc, return true iff context has changed
99    Token jump(Value_P val);
100 
101    /// return the nesting level (oldest SI has level 0, next has level 1, ...)
get_level() const102    SI_level get_level() const   { return level; };
103 
104    /// return the current line number
105    Function_Line get_line() const;
106 
107    /// Maybe print B (according to tag) and erase B
108    void statement_result(Token & result, bool trace);
109 
110    /// Escape from \b user function (exit from each invocation until
111    /// immediate execution is reached)
112    void escape();
113 
114    /// execute token in body...
115    Token run();
116 
117    /// clear the marked bit in all parsers
118    void unmark_all_values() const;
119 
120    /// print all owners of \b value
121    int show_owners(ostream & out, const Value & value) const;
122 
123    /// print a short debug info
124    void info(ostream & out, const char * loc) const;
125 
126    /// return the error related info in this context
get_error(StateIndicator * si)127    static Error & get_error(StateIndicator * si)
128        { return si ? si->error : top_level_error; }
129 
130    /// return the error related info in this context
get_error(const StateIndicator * si)131    static const Error & get_error(const StateIndicator * si)
132        { return si ? si->error : top_level_error; }
133 
134    /// return left arg
135    Value_P get_L();
136 
137    /// change left arg
138    void set_L(Value_P value);
139 
140    /// return right arg
141    Value_P get_R();
142 
143    /// change right arg
144    void set_R(Value_P value);
145 
146    /// return axis arg
147    Value_P get_X();
148 
149    /// change axis arg
150    void set_X(Value_P value);
151 
152    /// return true if this SI entry has entered safe execution mode (via ⎕EC)
is_safe_execution_start() const153    bool is_safe_execution_start() const
154       { if (!parent)   return safe_execution_count > 0;
155         return safe_execution_count > parent->safe_execution_count;
156       }
157 
158    /// return the number of pending ⎕ECs (or other safe execution contexts)
get_safe_execution() const159    int get_safe_execution() const
160       { return safe_execution_count; }
161 
162    /// set safe_execution mode
set_safe_execution()163    void set_safe_execution()
164       {
165         if (parent)  safe_execution_count = parent->safe_execution_count + 1;
166         else         safe_execution_count = 1;
167       }
168 
169    /// clear safe_execution mode
clear_safe_execution()170    void clear_safe_execution()
171       {
172         if (parent)  safe_execution_count = parent->safe_execution_count;
173         else         safe_execution_count = 0;
174       }
175 
176    /// get the current prefix parser
get_prefix()177    Prefix & get_prefix()
178       { return current_stack; }
179 
180    /// get the current prefix parser
get_prefix() const181    const Prefix & get_prefix() const
182       { return current_stack; }
183 
184    /// return the SI that has called this one
get_parent() const185    StateIndicator * get_parent() const
186       { return parent; }
187 
188    /// return the level at which sym is pushed for the nth. time
189    SI_level nth_push(const Symbol * sym, int from_tos) const;
190 
191    /// a small storage for DerivedFunction objects.
192    DerivedFunctionCache fun_oper_cache;
193 
194    /// error when )SI is empty
195    static Error top_level_error;
196 
197 protected:
198    /// the user function that is being executed
199    Executable * executable;
200 
201    /// the number of pending ⎕EC calles
202    int safe_execution_count;
203 
204    /// The nesting level (of sub-executions)
205    const SI_level level;
206 
207    /// details of the last error in this context.
208    Error error;
209 
210    /// the current-stack of this context.
211    Prefix current_stack;
212 
213    /// the StateIndicator that has called this one
214    StateIndicator * parent;
215 };
216 //-----------------------------------------------------------------------------
217 
218 #endif // __STATE_INDICATOR_HH_DEFINED__
219