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-2016  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 __WORKSPACE_HH_DEFINED__
22 #define __WORKSPACE_HH_DEFINED__
23 
24 #include <vector>
25 
26 #include "Command.hh"
27 #include "PrimitiveOperator.hh"
28 #include "PrintContext.hh"
29 #include "QuadFunction.hh"
30 #include "Quad_CR.hh"
31 #include "Quad_DLX.hh"
32 #include "Quad_FIO.hh"
33 #include "Quad_RE.hh"
34 #include "Quad_RL.hh"
35 #include "Quad_SVx.hh"
36 #include "Quad_WA.hh"
37 #include "ScalarFunction.hh"
38 #include "Symbol.hh"
39 #include "SymbolTable.hh"
40 #include "SystemVariable.hh"
41 #include "UTF8_string.hh"
42 
43 class Executable;
44 class StateIndicator;
45 
46 //-----------------------------------------------------------------------------
47 /**
48  The symbol tables of the Workspace. We put them into a base class for
49  Workspace, so that they are initialized before all the members of Workspace.
50  **/
51 /// The symbol tables of an APL workspace
52 class Workspace_0
53 {
54 protected:
55    /// the (user-defined) symbol table of this workspace.
56    SymbolTable symbol_table;
57 
58    /// the (system aka distinguished name) symbol table of this workspace.
59    SystemSymTab distinguished_names;
60 };
61 //-----------------------------------------------------------------------------
62 /**
63     An APL workspace. This structure contains everyting (variables, functions,
64     SI stack, etc.) belonging to a single APL workspace.
65  */
66 /// An APL workspace
67 class Workspace : public Workspace_0
68 {
69 public:
70    /// Construct an empty workspace.
71    Workspace();
72 
73    /// return the current ⎕CT
get_CT()74    static APL_Float get_CT()
75       { return the_workspace.v_Quad_CT.current(); }
76 
77    /// return element \b pos of the current ⎕FC (pos should be 0..5)
get_FC(int p)78    static APL_Char get_FC(int p)
79       { return the_workspace.v_Quad_FC.current()[p]; }
80 
81    /// return the current ⎕IO
get_IO()82    static APL_Integer get_IO()
83       { return the_workspace.v_Quad_IO.current(); }
84 
85    /// return the current ⎕LX
get_LX()86    static UCS_string get_LX()
87       { return UCS_string(*the_workspace.v_Quad_LX.get_apl_value()); }
88 
89    /// return style and the current ⎕PP, and ⎕PW
get_PrintContext(PrintStyle style)90    static PrintContext get_PrintContext(PrintStyle style)
91       {
92         return PrintContext(style, the_workspace.v_Quad_PP.current(),
93                                    the_workspace.v_Quad_PW.current());
94       }
95 
96    /// return the current ⎕PR
get_PR()97    static const UCS_string get_PR()
98       { return the_workspace.v_Quad_PR.current(); }
99 
100    /// return the current ⎕PW
get_PP()101    static int get_PP()
102       { return the_workspace.v_Quad_PP.current(); }
103 
104    /// return the current ⎕PW
get_PW()105    static int get_PW()
106       { return the_workspace.v_Quad_PW.current(); }
107 
108    /// set the current ⎕PW
set_PW(int PW,const char * loc)109    static void set_PW(int PW, const char * loc)
110       { the_workspace.v_Quad_PW.assign(IntScalar(PW, loc), false, loc); }
111 
112    /// the number of SI entries
SI_entry_count()113    static int SI_entry_count()
114       { return SI_top() ? (SI_top()->get_level() + 1) : 0; }
115 
116    /// the top of the SI stack (the SI pushed last)
SI_top()117    static StateIndicator * SI_top()
118       { return the_workspace.top_SI; }
119 
120    /// copy all allocated symbols into \b table of size \b table_size
get_all_symbols()121    static std::vector<const Symbol *> get_all_symbols()
122       { return the_workspace.symbol_table.get_all_symbols(); }
123 
124    /// lookup an existing user defined symbol. If not found, create one
125    /// (unless this would be a quad symbol)
lookup_symbol(const UCS_string & symbol_name)126    static Symbol * lookup_symbol(const UCS_string & symbol_name)
127       { return the_workspace.symbol_table.lookup_symbol(symbol_name);}
128 
129    /// increase the wait time for user input as reported in ⎕AI
add_wait(APL_time_us diff)130    static void add_wait(APL_time_us diff)
131       { the_workspace.v_Quad_AI.add_wait(diff); }
132 
133    /// return information in SI_top()
get_error()134    static Error * get_error()
135       { return &StateIndicator::get_error(SI_top()); }
136 
137    /// return reference to more info about last error
more_error()138    static UCS_string & more_error()
139       { return the_workspace.more_error_info; }
140 
141    /// erase the symbols in \b symbols from the symbol table
erase_symbols(ostream & out,const UCS_string_vector & symbols)142    static void erase_symbols(ostream & out, const UCS_string_vector & symbols)
143       { the_workspace.symbol_table.erase_symbols(CERR, symbols); }
144 
145    /// list all symbols (of category \b which) with names in \b from_to
list(ostream & out,ListCategory which,UCS_string from_to)146    static void list(ostream & out, ListCategory which, UCS_string from_to)
147       { the_workspace.symbol_table.list(out, which, from_to); }
148 
149    /// list all symbols with names in \b buf
list_symbol(ostream & out,const UCS_string & buf)150    static ostream & list_symbol(ostream & out, const UCS_string & buf)
151       { return the_workspace.symbol_table.list_symbol(out, buf); }
152 
153    /// add \b ufun to list of that were ⎕EX'ed while on the SI stack
add_expunged_function(const UserFunction * ufun)154    static void add_expunged_function(const UserFunction * ufun)
155       { the_workspace.expunged_functions.push_back(ufun); }
156 
157    /// return the symbol table of the current workspace.
get_symbol_table()158    static const SymbolTable & get_symbol_table()
159       { return the_workspace.symbol_table; }
160 
161    /// return the APL prompt
get_prompt()162    static const UCS_string & get_prompt()
163       { return the_workspace.prompt; }
164 
165    /// return the name of the current workspace.
get_WS_name()166    static const UCS_string & get_WS_name()
167       { return the_workspace.WS_name; }
168 
169    /// set the name of the current workspace.
set_WS_name(const UCS_string & new_name)170    static void set_WS_name(const UCS_string & new_name)
171       { the_workspace.WS_name = new_name; }
172 
173    /// Return all user-defined commands
get_user_commands()174    static vector<Command::user_command> & get_user_commands()
175       {  return the_workspace.user_commands; }
176 
177    /// Create a new SI-entry on the SI stack.
178    static void push_SI(Executable * fun, const char * loc);
179 
180    /// Remove the current SI-entry from the SI stack.
181    static void pop_SI(const char * loc);
182 
183    /// return the Quad-RL (to be taken % mod)
184    static uint64_t get_RL(uint64_t mod);
185 
186    /// clear ⎕EM and ⎕ET related errors (error entries on SI up to (including)
187    /// the next user-defined function
188    static void clear_error(const char * loc);
189 
190    /// create and execute one immediate execution context
191    // (leave with TOK_ESCAPE)
192    static Token immediate_execution(bool exit_on_error);
193 
194    /// clear the workspace
195    static void clear_WS(ostream & out, bool silent);
196 
197    /// clear the SI
198    static void clear_SI(ostream & out);
199 
200    /// print the SI on \b out
201    static void list_SI(ostream & out, SI_mode mode);
202 
203    /// the topmost SI with parse mode PM_FUNCTION
204    static StateIndicator * SI_top_fun();
205 
206    /// the topmost SI with an error
207    static StateIndicator * SI_top_error();
208 
209    /// lookup an existing name (user defined or ⎕xx, var or function).
210    /// return 0 if not found.
211    static NamedObject * lookup_existing_name(const UCS_string & name);
212 
213    /// lookup an existing symbol (user defined or ⎕xx).
214    static Symbol * lookup_existing_symbol(const UCS_string & symbol_name);
215 
216    /// return the name to which \b lambda ia assigned (empty if not found)
find_lambda_name(const UserFunction * lambda)217    static UCS_string find_lambda_name(const UserFunction * lambda)
218       { return the_workspace.symbol_table.find_lambda_name(lambda); }
219 
220    /// save this workspace
221    static void save_WS(ostream & out, LibRef lib, const UCS_string & wsname,
222                        bool name_from_WSID);
223 
224    /// backup an existing file \b filename, return true on error
225    static bool backup_existing_file(const char * filename);
226 
227    /// dump this workspace
228    static void dump_WS(ostream & out, LibRef lib, const UCS_string & wsname,
229                        bool html, bool silent);
230 
231    /// dump the commands in this workspace
232    static void dump_commands(ostream & out);
233 
234    /// set or inquire the workspace ID
235    static void wsid(ostream & out, UCS_string arg, LibRef lib, bool silent);
236 
237    /// load )DUMPed file from open file descriptor fd (closes fd)
238    static void load_DUMP(ostream & out, const UTF8_string & filename, int fd,
239                          LX_mode with_LX, bool silent,
240                          UCS_string_vector * object_filter);
241 
242    /// load \b lib_ws into the_workspace, maybe set ⎕LX of the new WS.
243    static void load_WS(ostream & out, LibRef lib, const UCS_string & wsname,
244                        UCS_string & quad_lx, bool silent);
245 
246    /// copy objects from another workspace
247    static void copy_WS(ostream & out, LibRef lib, const UCS_string & wsname,
248                        UCS_string_vector & objects, bool protection);
249 
250    /// return a token for system function or variable \b ucs
251    static Token get_quad(const UCS_string & ucs, int & len);
252 
253    /// return oldest SI entry that is running \b exex, or 0 if none
254    static StateIndicator * oldest_exec(const Executable * exec);
255 
256    /// return true iff function \b funname is on the current call stack
257    static bool is_called(const UCS_string & funname);
258 
259    /// write symbols for )OUT command
260    static void write_OUT(FILE * out, uint64_t & seq,
261                   const UCS_string_vector & objects);
262 
263    /// clear the marked flag in all values known in this workspace
264    static void unmark_all_values();
265 
266    /// print all owners of \b value
267    static int show_owners(ostream & out, const Value & value);
268 
269    /// maybe remove functions for which ⎕EX has failed
270    static int cleanup_expunged(ostream & out, bool & erased);
271 
272    // access to system variables.
273    //
274 #define ro_sv_def(x, _str, _txt) /** return x **/ static x & get_v_ ## x() \
275    { return the_workspace.v_ ## x; }
276 #define rw_sv_def(x, _str, _txt) /** return ## x **/ static x & get_v_ ## x() \
277    { return the_workspace.v_ ## x; }
278    rw_sv_def(Quad_Quad,  "", "⎕")
279    rw_sv_def(Quad_QUOTE, "", "⍞")
280 #include "SystemVariable.def"
281 
282    /// push a command. This is done when ⍎Command is performed and the command
283    /// would push the SI stack (i.e. )LOAD, )QLOAD, )CLEAR, or )SIC)
push_Command(const UCS_string & command)284    static void push_Command(const UCS_string & command)
285       { the_workspace.pushed_command = command; }
286 
287    /// return the pushed command
get_pushed_Command()288    static const UCS_string & get_pushed_Command()
289       { return the_workspace.pushed_command; }
290 
291 protected:
292    /// the name of the workspace
293    UCS_string WS_name;
294 
295    // system variables.
296    //
297 #define ro_sv_def(x, _str, _txt) /** x **/ x v_ ## x;
298 #define rw_sv_def(x, _str, _txt) /** x **/ x v_ ## x;
299    rw_sv_def(Quad_Quad,  "", "⎕")
300    rw_sv_def(Quad_QUOTE, "", "⍞")
301 #include "SystemVariable.def"
302 
303    /// the APL prompt (6 blanks by default)
304    UCS_string prompt;
305 
306    /// user defined functions that were ⎕EX'ed while on the SI stack
307    std::vector<const UserFunction *> expunged_functions;
308 
309    /// more info about last error
310    UCS_string more_error_info;
311 
312    /// the SI stack. Initially top_SI is 0 (empty stack)
313    StateIndicator * top_SI;
314 
315    /// )LOAD, )QLOAD, )CLEAR, or )SIC
316    UCS_string pushed_command;
317 
318    /// user defined commands
319    std::vector<Command::user_command> user_commands;
320 
321    /// the current workspace (for objects that need one but don't have one).
322    static Workspace the_workspace;
323 };
324 //-----------------------------------------------------------------------------
325 
326 #endif // __WORKSPACE_HH_DEFINED__
327