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 __USERFUNCTION_HH_DEFINED__
22 #define __USERFUNCTION_HH_DEFINED__
23 
24 #include <sys/types.h>
25 #include <vector>
26 
27 #include "Error.hh"
28 #include "Executable.hh"
29 #include "Function.hh"
30 #include "Symbol.hh"
31 #include "UserFunction_header.hh"
32 #include "UTF8_string.hh"
33 
34 //-----------------------------------------------------------------------------
35 /// One user-defined function
36 class UserFunction : public Function, public Executable
37 {
38 public:
39    /// constructor for a lambda
40    UserFunction(Fun_signature sig, int lambda_num,
41                 const UCS_string & text, Token_string & body);
42 
43    /// Destructor.
44    ~UserFunction();
45 
46    /// return true if this function is a lambda
is_lambda() const47    virtual bool is_lambda() const
48       { return header.get_name()[0] == UNI_LAMBDA; }
49 
50    /// return the macro number (if this function is one) or -1
get_macnum() const51    virtual int get_macnum() const
52       { return -1; }
53 
54    /// overloaded Executable::get_ufun()
get_ufun() const55    virtual const UserFunction * get_ufun() const
56    { return this; }
57 
58    /// overloaded Function::get_ufun1()
get_ufun1()59    virtual UserFunction * get_ufun1()
60    { return this; }
61 
62    /// overloaded Function::get_ufun1()
get_ufun1() const63    virtual const UserFunction * get_ufun1() const
64    { return this; }
65 
66    /// overloaded Executable::get_ufun()
get_ufun()67    virtual UserFunction * get_ufun()
68    { return this; }
69 
70    /// overloaded Function::get_fun_valence()
get_fun_valence() const71    virtual int get_fun_valence() const
72       { return header.get_fun_valence(); }
73 
74    /// overloaded Function::get_oper_valence()
get_oper_valence() const75    virtual int get_oper_valence() const
76       { return header.get_oper_valence(); }
77 
78    /// overloaded Function::has_result()
has_result() const79    virtual bool has_result() const
80       { return header.has_result(); }
81 
82    /// overloaded Function::has_axis()
has_axis() const83    virtual bool has_axis() const
84       { return header.has_axis(); }
85 
86    /// pop all
pop_local_vars() const87    void pop_local_vars() const
88       { header.pop_local_vars(); }
89 
90    /// print the local variables for command )SINL
print_local_vars(ostream & out) const91    void print_local_vars(ostream & out) const
92       { return header.print_local_vars(out); }
93 
94    /// return the number of local variables
local_var_count() const95    ShapeItem local_var_count() const
96       { return header.local_var_count(); }
97 
98 
99    /// return the idx'th local variable
get_local_var(ShapeItem idx) const100    const Symbol * get_local_var(ShapeItem idx) const
101       { return header.get_local_var(idx); }
102 
103 
104    /// Overloaded \b Function::is_operator.
is_operator() const105    virtual bool is_operator() const
106       { return header.is_operator(); }
107 
108    /// add a label
add_label(Symbol * sym,Function_Line line)109    void add_label(Symbol * sym, Function_Line line)
110       { header.add_label(sym, line); }
111 
112    /// return the execution properties (dyadic ⎕FX) of this defined function
get_exec_properties() const113    virtual const int * get_exec_properties() const
114       { return exec_properties; }
115 
116    /// ovewrloaded Executable::cannot_suspend
cannot_suspend() const117    virtual bool cannot_suspend() const
118       { return exec_properties[1] != 0; }
119 
120    /// set execution properties (as per A ⎕FX)
set_exec_properties(const int * props)121    void set_exec_properties(const int * props)
122       { loop(i, 4)   exec_properties[i] = props[i]; }
123 
124    /// overloaded Executable::print()
125    virtual ostream & print(ostream & out) const;
126 
127    /// return the name of this function
get_name() const128    virtual UCS_string get_name() const
129       { return header.get_name(); }
130 
131    /// return e.g. 'FOO[10]'
132    UCS_string get_name_and_line(Function_PC pc) const;
133 
134    /// Overloaded Function::print_properties()
135    virtual void print_properties(ostream & out, int indent) const;
136 
137    /// )SAVE this function in the workspace named \b workspace
138    /// (in the file system).
139    void save(const char * workspace, const char * function);
140 
141    /// )LOAD this function into the workspace named \b workspace.
142    /// Return a pounter to this newly created function (or 0 on error).
143    static UserFunction * load(const char * workspace, const char * function);
144 
145    /// overloaded Function::destroy()
146    virtual void destroy();
147 
148    /// overloaded Executable::pushes_sym() const
149    virtual bool pushes_sym(const Symbol * sym) const;
150 
151    /// print help for this function on out (for the )HELP command)
152    void help(ostream & out) const;
153 
154    /// Load this function into the workspace named \b workspace.
155    static void load(const char * workspace, const char * function,
156                     UserFunction * & fun);
157 
158    /// create a user defined function according to \b data of length \b len
159    /// in workspace \b w.
160    static UserFunction * fix(const UCS_string & text, int & err_line,
161                              bool keep_existing, const char * loc,
162                              const UTF8_string &  creator, bool tolerant);
163 
164    /// (re-)create a lambda
165    static UserFunction * fix_lambda(Symbol & var, const UCS_string & text);
166 
167    /// return the pc of the first token in line l (valid line), or
168    /// the pc of the last token in the function (invalid line)
169    Function_PC pc_for_line(Function_Line line) const;
170 
171    /// Overloaded Function::has_alpha()
has_alpha() const172    virtual bool has_alpha() const   { return true; }
173 
174    /// overloaded Executable::get_sym_Z()
get_sym_Z() const175    virtual Symbol * get_sym_Z() const   { return header.Z(); }
176 
177    /// overloaded Executable::get_line()
178    Function_Line get_line(Function_PC pc) const;
179 
180    /// Overloaded Function::eval_()
181    virtual Token eval_();
182 
183    /// Overloaded Function::eval_B()
184    virtual Token eval_B(Value_P B);
185 
186    /// Overloaded Function::eval_XB()
187    virtual Token eval_XB(Value_P X, Value_P B);
188 
189    /// Overloaded Function::eval_AB()
190    virtual Token eval_AB(Value_P A, Value_P B);
191 
192    /// Overloaded Function::eval_AXB()
193    virtual Token eval_AXB(Value_P A, Value_P X, Value_P B);
194 
195    /// Overloaded Function::eval_LB.
196    virtual Token eval_LB(Token & LO, Value_P B);
197 
198    /// Overloaded Function::eval_LXB()
199    virtual Token eval_LXB(Token & LO, Value_P X, Value_P B);
200 
201    /// Overloaded Function::eval_ALB.
202    virtual Token eval_ALB(Value_P A, Token & LO, Value_P B);
203 
204    /// Overloaded Function::eval_ALXB()
205    virtual Token eval_ALXB(Value_P A, Token & LO, Value_P X, Value_P B);
206 
207    /// Overloaded Function::eval_LRB()
208    virtual Token eval_LRB(Token & LO, Token & RO, Value_P B);
209 
210    /// Overloaded Function::eval_LRXB()
211    virtual Token eval_LRXB(Token & LO, Token & RO, Value_P X, Value_P B);
212 
213    /// Overloaded Function::eval_ALRB()
214    virtual Token eval_ALRB(Value_P A, Token & LO, Token & RO, Value_P B);
215 
216    /// Overloaded Function::eval_ALRXB()
217    virtual Token eval_ALRXB(Value_P A, Token & LO, Token & RO,
218                             Value_P X, Value_P B);
219 
220    /// Quad_CR of this function
221    virtual UCS_string canonical(bool with_lines) const;
222 
223    /// overloaded Executable::line_start()
224    virtual Function_PC line_start(Function_Line line) const;
225 
226    /// overloaded Executable::adjust_line_starts
227    virtual void adjust_line_starts();
228 
229    /// compute lines 2 and 3 in \b error
230    void set_locked_error_info(Error & error) const;
231 
232    /// return the entity that has created the function
get_creator() const233    const UTF8_string get_creator() const
234       { return creator; }
235 
236    /// set trace or stop vector
237    void set_trace_stop(std::vector<Function_Line> & lines, bool stop);
238 
239    /// transform a function body containing (old-style) multi-lines into a
240    /// standard function body
241    ErrorCode transform_multi_line_strings();
242 
243    /// transform a function body containing (new-style) multi-lines into a
244    /// standard function body
245    ErrorCode transform_multi_line_strings_3();
246 
247    /// recompile the body
248    void parse_body(const char * loc, bool tolerant, bool macro);
249 
250    /// return stop lines (from S∆fun ← lines)
get_stop_lines() const251    const std::vector<Function_Line> & get_stop_lines() const
252       { return stop_lines; }
253 
254    /// return trace lines (from S∆fun ← lines)
get_trace_lines() const255    const std::vector<Function_Line> & get_trace_lines() const
256       { return trace_lines; }
257 
258    /// return the header object (return value name, argument names, local vars,
259    /// and function name) for this function
get_header() const260    const UserFunction_header & get_header() const
261       { return header; }
262 
263 protected:
264    /// constructor for a normal (i.e. non-lambda) user defined function
265    UserFunction(const UCS_string txt, const char * loc,
266                 const UTF8_string &  _creator, bool tolerant, bool macro);
267 
268    /// overladed Function::may_push_SI()
may_push_SI() const269    virtual bool may_push_SI() const   { return true; }
270 
271    /// Overloaded Function::eval_fill_B()
272    virtual Token eval_fill_B(Value_P B);
273 
274    /// Overloaded Function::eval_fill_AB()
275    virtual Token eval_fill_AB(Value_P A, Value_P B);
276 
277    /// return the line number where an error has occurred (-1 if none)
get_error_line() const278    int get_error_line() const
279       { return error_line; }
280 
281    /// return information about an error (if any)
get_error_info() const282    const char * get_error_info() const
283       { return error_info; }
284 
285    /// helper function to print token with Function or Value content
286    static ostream & print_val_or_fun(ostream & out, Token & tok);
287 
288    /// "[nn] " prefix
289    UCS_string line_prefix(Function_Line l) const;
290 
291    /// the header (line [0]) of the user-defined function
292    UserFunction_header header;
293 
294    /** Offsets to the first token in every line (for jumps).
295        lines[0] points to the last line, which is automatically
296        added and is TOK_RETURN_VOID for void functions
297        and TOK_RETURN_VALUET for functions returning a value.
298 
299        An N line function:
300 
301        [0] R←A FOO B
302        [1] L1: xxx
303        ...
304        [N-1]   yyy
305 
306       will, for example, have a N+1 element jump vector:
307 
308       [0] goto end of function        --------------+
309       [1] L1: xxx                                   |
310       ...                                           |
311       [N-1]   yyy                                   |
312       [N] TOK_RETURN_SYMBOL or TOK_RETURN_VOID   <--+
313 
314    **/
315    std::vector<Function_PC> line_starts;
316 
317    /// stop lines (from S∆fun ← lines)
318    std::vector<Function_Line> stop_lines;
319 
320    /// trace lines (from S∆fun ← lines)
321    std::vector<Function_Line> trace_lines;
322 
323    /// execution properties as per 3⎕AT
324    int exec_properties[4];
325 
326    /// the entity (∇ editor, ⎕FX, or filename) that has created this function
327    const UTF8_string creator;
328 
329    /// the line number where an error has occurred (-1 if none)
330    int error_line;
331 
332    /// information about an error (if any)
333    const char * error_info;
334 };
335 //-----------------------------------------------------------------------------
336 
337 #endif // __USERFUNCTION_HH_DEFINED__
338