1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 1996-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if ! defined (octave_ov_usr_fcn_h) 27 #define octave_ov_usr_fcn_h 1 28 29 #include "octave-config.h" 30 31 #include <ctime> 32 33 #include <string> 34 35 #include "comment-list.h" 36 #include "ovl.h" 37 #include "ov-fcn.h" 38 #include "ov-typeinfo.h" 39 #include "symscope.h" 40 #include "unwind-prot.h" 41 42 class string_vector; 43 44 class octave_value; 45 46 namespace octave 47 { 48 class file_info; 49 class stack_frame; 50 class tree_parameter_list; 51 class tree_statement_list; 52 class tree_evaluator; 53 class tree_expression; 54 class tree_walker; 55 #if defined (HAVE_LLVM) 56 class jit_function_info; 57 #endif 58 59 } 60 61 class 62 octave_user_code : public octave_function 63 { 64 protected: 65 66 octave_user_code (const std::string& fnm = "", const std::string& nm = "", 67 const octave::symbol_scope& scope = octave::symbol_scope (), 68 octave::tree_statement_list *cmds = nullptr, 69 const std::string& ds = "") octave_function(nm,ds)70 : octave_function (nm, ds), m_scope (scope), file_name (fnm), 71 t_parsed (static_cast<time_t> (0)), 72 t_checked (static_cast<time_t> (0)), 73 m_file_info (nullptr), cmd_list (cmds) 74 { 75 if (m_scope) 76 m_scope.set_user_code (this); 77 } 78 79 public: 80 81 // No copying! 82 83 octave_user_code (const octave_user_code& f) = delete; 84 85 octave_user_code& operator = (const octave_user_code& f) = delete; 86 87 ~octave_user_code (void); 88 is_user_code(void)89 bool is_user_code (void) const { return true; } 90 91 std::string get_code_line (std::size_t line); 92 93 std::deque<std::string> get_code_lines (std::size_t line, std::size_t num_lines); 94 95 void cache_function_text (const std::string& text, 96 const octave::sys::time& timestamp); 97 scope(void)98 octave::symbol_scope scope (void) { return m_scope; } 99 stash_fcn_file_name(const std::string & nm)100 void stash_fcn_file_name (const std::string& nm) { file_name = nm; } 101 mark_fcn_file_up_to_date(const octave::sys::time & t)102 void mark_fcn_file_up_to_date (const octave::sys::time& t) { t_checked = t; } 103 stash_fcn_file_time(const octave::sys::time & t)104 void stash_fcn_file_time (const octave::sys::time& t) 105 { 106 t_parsed = t; 107 mark_fcn_file_up_to_date (t); 108 } 109 fcn_file_name(void)110 std::string fcn_file_name (void) const { return file_name; } 111 time_parsed(void)112 octave::sys::time time_parsed (void) const { return t_parsed; } 113 time_checked(void)114 octave::sys::time time_checked (void) const { return t_checked; } 115 find_subfunction(const std::string &)116 virtual octave_value find_subfunction (const std::string&) const 117 { 118 return octave_value (); 119 } 120 121 virtual std::map<std::string, octave_value> subfunctions (void) const; 122 body(void)123 octave::tree_statement_list * body (void) { return cmd_list; } 124 125 octave_value dump (void) const; 126 127 protected: 128 129 void get_file_info (void); 130 131 // Our symbol table scope. 132 octave::symbol_scope m_scope; 133 134 // The name of the file we parsed. 135 std::string file_name; 136 137 // The time the file was parsed. 138 octave::sys::time t_parsed; 139 140 // The time the file was last checked to see if it needs to be 141 // parsed again. 142 octave::sys::time t_checked; 143 144 // Cached text of function or script code with line offsets 145 // calculated. 146 octave::file_info *m_file_info; 147 148 // The list of commands that make up the body of this function. 149 octave::tree_statement_list *cmd_list; 150 }; 151 152 // Scripts. 153 154 class 155 octave_user_script : public octave_user_code 156 { 157 public: 158 159 octave_user_script (void); 160 161 octave_user_script (const std::string& fnm, const std::string& nm, 162 const octave::symbol_scope& scope = octave::symbol_scope (), 163 octave::tree_statement_list *cmds = nullptr, 164 const std::string& ds = ""); 165 166 octave_user_script (const std::string& fnm, const std::string& nm, 167 const octave::symbol_scope& scope = octave::symbol_scope (), 168 const std::string& ds = ""); 169 170 // No copying! 171 172 octave_user_script (const octave_user_script& f) = delete; 173 174 octave_user_script& operator = (const octave_user_script& f) = delete; 175 176 ~octave_user_script (void) = default; 177 178 octave_function * function_value (bool = false) { return this; } 179 180 octave_user_script * user_script_value (bool = false) { return this; } 181 182 octave_user_code * user_code_value (bool = false) { return this; } 183 184 // Scripts and user functions are both considered "scripts" because 185 // they are written in Octave's scripting language. 186 is_user_script(void)187 bool is_user_script (void) const { return true; } 188 189 // We must overload the call method so that we call the proper 190 // push_stack_frame method, which is overloaded for pointers to 191 // octave_function, octave_user_function, and octave_user_script 192 // objects. 193 194 octave_value_list 195 call (octave::tree_evaluator& tw, int nargout = 0, 196 const octave_value_list& args = octave_value_list ()); 197 198 octave_value_list 199 execute (octave::tree_evaluator& tw, int nargout = 0, 200 const octave_value_list& args = octave_value_list ()); 201 202 void accept (octave::tree_walker& tw); 203 204 private: 205 206 DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA 207 }; 208 209 // User-defined functions. 210 211 class 212 octave_user_function : public octave_user_code 213 { 214 public: 215 216 octave_user_function (const octave::symbol_scope& scope = octave::symbol_scope (), 217 octave::tree_parameter_list *pl = nullptr, 218 octave::tree_parameter_list *rl = nullptr, 219 octave::tree_statement_list *cl = nullptr); 220 221 // No copying! 222 223 octave_user_function (const octave_user_function& fn) = delete; 224 225 octave_user_function& operator = (const octave_user_function& fn) = delete; 226 227 ~octave_user_function (void); 228 229 octave_function * function_value (bool = false) { return this; } 230 231 octave_user_function * user_function_value (bool = false) { return this; } 232 233 octave_user_code * user_code_value (bool = false) { return this; } 234 235 octave_user_function * define_param_list (octave::tree_parameter_list *t); 236 237 octave_user_function * define_ret_list (octave::tree_parameter_list *t); 238 stash_fcn_location(int line,int col)239 void stash_fcn_location (int line, int col) 240 { 241 location_line = line; 242 location_column = col; 243 } 244 beginning_line(void)245 int beginning_line (void) const { return location_line; } beginning_column(void)246 int beginning_column (void) const { return location_column; } 247 stash_fcn_end_location(int line,int col)248 void stash_fcn_end_location (int line, int col) 249 { 250 end_location_line = line; 251 end_location_column = col; 252 } 253 ending_line(void)254 int ending_line (void) const { return end_location_line; } ending_column(void)255 int ending_column (void) const { return end_location_column; } 256 257 void maybe_relocate_end (void); 258 stash_parent_fcn_name(const std::string & p)259 void stash_parent_fcn_name (const std::string& p) { parent_name = p; } 260 261 void stash_parent_fcn_scope (const octave::symbol_scope& ps); 262 stash_leading_comment(octave::comment_list * lc)263 void stash_leading_comment (octave::comment_list *lc) { lead_comm = lc; } 264 stash_trailing_comment(octave::comment_list * tc)265 void stash_trailing_comment (octave::comment_list *tc) { trail_comm = tc; } 266 267 std::string profiler_name (void) const; 268 parent_fcn_name(void)269 std::string parent_fcn_name (void) const { return parent_name; } 270 parent_fcn_scope(void)271 octave::symbol_scope parent_fcn_scope (void) const 272 { 273 return m_scope.parent_scope (); 274 } 275 parent_fcn_names(void)276 std::list<std::string> parent_fcn_names (void) const 277 { 278 return m_scope.parent_fcn_names (); 279 } 280 281 void mark_as_system_fcn_file (void); 282 is_system_fcn_file(void)283 bool is_system_fcn_file (void) const { return system_fcn_file; } 284 is_user_function(void)285 bool is_user_function (void) const { return true; } 286 287 void erase_subfunctions (void); 288 289 bool takes_varargs (void) const; 290 291 bool takes_var_return (void) const; 292 293 void mark_as_private_function (const std::string& cname = ""); 294 295 void lock_subfunctions (void); 296 297 void unlock_subfunctions (void); 298 299 std::map<std::string, octave_value> subfunctions (void) const; 300 301 octave_value find_subfunction (const std::string& subfuns) const; 302 303 bool has_subfunctions (void) const; 304 305 void stash_subfunction_names (const std::list<std::string>& names); 306 307 std::list<std::string> subfunction_names (void) const; 308 309 octave_value_list all_va_args (const octave_value_list& args); 310 stash_function_name(const std::string & s)311 void stash_function_name (const std::string& s) { my_name = s; } 312 mark_as_subfunction(void)313 void mark_as_subfunction (void) { subfunction = true; } 314 is_subfunction(void)315 bool is_subfunction (void) const { return subfunction; } 316 mark_as_inline_function(void)317 void mark_as_inline_function (void) { inline_function = true; } 318 is_inline_function(void)319 bool is_inline_function (void) const { return inline_function; } 320 mark_as_anonymous_function(void)321 void mark_as_anonymous_function (void) { anonymous_function = true; } 322 is_anonymous_function(void)323 bool is_anonymous_function (void) const { return anonymous_function; } 324 325 bool is_anonymous_function_of_class 326 (const std::string& cname = "") const 327 { 328 return anonymous_function 329 ? (cname.empty () 330 ? (! dispatch_class ().empty ()) 331 : cname == dispatch_class ()) 332 : false; 333 } 334 335 // If we are a special expression, then the function body consists of exactly 336 // one expression. The expression's result is the return value of the 337 // function. is_special_expr(void)338 bool is_special_expr (void) const 339 { 340 return is_inline_function () || is_anonymous_function (); 341 } 342 mark_as_nested_function(void)343 void mark_as_nested_function (void) { nested_function = true; } 344 is_nested_function(void)345 bool is_nested_function (void) const { return nested_function; } 346 is_parent_function(void)347 bool is_parent_function (void) const { return m_scope.is_parent (); } 348 mark_as_legacy_constructor(void)349 void mark_as_legacy_constructor (void) { class_constructor = legacy; } 350 351 bool is_legacy_constructor (const std::string& cname = "") const 352 { 353 return (class_constructor == legacy 354 ? (cname.empty () ? true : cname == dispatch_class ()) : false); 355 } 356 mark_as_classdef_constructor(void)357 void mark_as_classdef_constructor (void) { class_constructor = classdef; } 358 359 bool is_classdef_constructor (const std::string& cname = "") const 360 { 361 return (class_constructor == classdef 362 ? (cname.empty () ? true : cname == dispatch_class ()) : false); 363 } 364 mark_as_legacy_method(void)365 void mark_as_legacy_method (void) { class_method = legacy; } 366 367 bool is_legacy_method (const std::string& cname = "") const 368 { 369 return (class_method == legacy 370 ? (cname.empty () ? true : cname == dispatch_class ()) : false); 371 } 372 mark_as_classdef_method(void)373 void mark_as_classdef_method (void) { class_method = classdef; } 374 375 bool is_classdef_method (const std::string& cname = "") const 376 { 377 return (class_method == classdef 378 ? (cname.empty () ? true : cname == dispatch_class ()) : false); 379 } 380 381 // We must overload the call method so that we call the proper 382 // push_stack_frame method, which is overloaded for pointers to 383 // octave_function, octave_user_function, and octave_user_script 384 // objects. 385 386 octave_value_list 387 call (octave::tree_evaluator& tw, int nargout = 0, 388 const octave_value_list& args = octave_value_list ()); 389 390 octave_value_list 391 execute (octave::tree_evaluator& tw, int nargout = 0, 392 const octave_value_list& args = octave_value_list ()); 393 parameter_list(void)394 octave::tree_parameter_list * parameter_list (void) { return param_list; } 395 return_list(void)396 octave::tree_parameter_list * return_list (void) { return ret_list; } 397 leading_comment(void)398 octave::comment_list * leading_comment (void) { return lead_comm; } 399 trailing_comment(void)400 octave::comment_list * trailing_comment (void) { return trail_comm; } 401 402 // If is_special_expr is true, retrieve the sigular expression that forms the 403 // body. May be null (even if is_special_expr is true). 404 octave::tree_expression * special_expr (void); 405 406 bool subsasgn_optimization_ok (void); 407 408 void accept (octave::tree_walker& tw); 409 410 #if defined (HAVE_LLVM) get_info(void)411 octave::jit_function_info * get_info (void) { return jit_info; } 412 stash_info(octave::jit_function_info * info)413 void stash_info (octave::jit_function_info *info) { jit_info = info; } 414 #endif 415 416 octave_value dump (void) const; 417 418 private: 419 420 enum class_method_type 421 { 422 none, 423 legacy, 424 classdef 425 }; 426 427 std::string ctor_type_str (void) const; 428 std::string method_type_str (void) const; 429 430 // List of arguments for this function. These are local variables. 431 octave::tree_parameter_list *param_list; 432 433 // List of parameters we return. These are also local variables in 434 // this function. 435 octave::tree_parameter_list *ret_list; 436 437 // The comments preceding the FUNCTION token. 438 octave::comment_list *lead_comm; 439 440 // The comments preceding the ENDFUNCTION token. 441 octave::comment_list *trail_comm; 442 443 // Location where this function was defined. 444 int location_line; 445 int location_column; 446 int end_location_line; 447 int end_location_column; 448 449 // The name of the parent function, if any. 450 std::string parent_name; 451 452 // True if this function came from a file that is considered to be a 453 // system function. This affects whether we check the time stamp 454 // on the file to see if it has changed. 455 bool system_fcn_file; 456 457 // The number of arguments that have names. 458 int num_named_args; 459 460 // TRUE means this is a subfunction of a primary function. 461 bool subfunction; 462 463 // TRUE means this is an inline function. 464 bool inline_function; 465 466 // TRUE means this is an anonymous function. 467 bool anonymous_function; 468 469 // TRUE means this is a nested function. 470 bool nested_function; 471 472 // TRUE means this function contains a nested function. 473 bool parent_function; 474 475 // Enum describing whether this function is the constructor for class object. 476 class_method_type class_constructor; 477 478 // Enum describing whether this function is a method for a class. 479 class_method_type class_method; 480 481 #if defined (HAVE_LLVM) 482 octave::jit_function_info *jit_info; 483 #endif 484 485 void maybe_relocate_end_internal (void); 486 487 void print_code_function_header (const std::string& prefix); 488 489 void print_code_function_trailer (const std::string& prefix); 490 491 // XXX FIXME (public) 492 public: 493 494 void restore_warning_states (void); 495 496 DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA 497 }; 498 499 #endif 500