Mercurial > octave
comparison libinterp/octave-value/ov-fcn-handle.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 597f3ee61a48 |
comparison
equal
deleted
inserted
replaced
31605:e88a07dec498 | 31607:aac27ad79be6 |
---|---|
84 | 84 |
85 const std::string octave_fcn_handle::anonymous ("@<anonymous>"); | 85 const std::string octave_fcn_handle::anonymous ("@<anonymous>"); |
86 | 86 |
87 OCTAVE_BEGIN_NAMESPACE(octave) | 87 OCTAVE_BEGIN_NAMESPACE(octave) |
88 | 88 |
89 class invalid_fcn_handle : public base_fcn_handle | 89 class invalid_fcn_handle : public base_fcn_handle |
90 { | |
91 public: | |
92 | |
93 invalid_fcn_handle (void) : base_fcn_handle ("<invalid>") { } | |
94 | |
95 invalid_fcn_handle (const invalid_fcn_handle&) = default; | |
96 | |
97 ~invalid_fcn_handle (void) = default; | |
98 | |
99 invalid_fcn_handle * clone (void) const | |
90 { | 100 { |
91 public: | 101 return new invalid_fcn_handle (*this); |
92 | 102 } |
93 invalid_fcn_handle (void) : base_fcn_handle ("<invalid>") { } | 103 |
94 | 104 std::string type (void) const { return "<invalid>"; } |
95 invalid_fcn_handle (const invalid_fcn_handle&) = default; | 105 |
96 | 106 octave_value_list call (int nargout, const octave_value_list& args); |
97 ~invalid_fcn_handle (void) = default; | 107 }; |
98 | 108 |
99 invalid_fcn_handle * clone (void) const | 109 // Create a handle to an unnamed internal function. There will be no |
100 { | 110 // way to save and reload it. See, for example, the F__fltk_check__ |
101 return new invalid_fcn_handle (*this); | 111 // function in __init_fltk__.cc. |
102 } | 112 |
103 | 113 class internal_fcn_handle : public base_fcn_handle |
104 std::string type (void) const { return "<invalid>"; } | 114 { |
105 | 115 public: |
106 octave_value_list call (int nargout, const octave_value_list& args); | 116 |
107 }; | 117 internal_fcn_handle (const octave_value& fcn) |
108 | 118 : base_fcn_handle ("<internal>"), m_fcn (fcn) |
109 // Create a handle to an unnamed internal function. There will be no | 119 { } |
110 // way to save and reload it. See, for example, the F__fltk_check__ | 120 |
111 // function in __init_fltk__.cc. | 121 internal_fcn_handle (const internal_fcn_handle&) = default; |
112 | 122 |
113 class internal_fcn_handle : public base_fcn_handle | 123 ~internal_fcn_handle (void) = default; |
124 | |
125 internal_fcn_handle * clone (void) const | |
114 { | 126 { |
115 public: | 127 return new internal_fcn_handle (*this); |
116 | 128 } |
117 internal_fcn_handle (const octave_value& fcn) | 129 |
118 : base_fcn_handle ("<internal>"), m_fcn (fcn) | 130 std::string type (void) const { return "<internal>"; } |
119 { } | 131 |
120 | 132 bool is_internal (void) const { return true; } |
121 internal_fcn_handle (const internal_fcn_handle&) = default; | 133 |
122 | 134 octave_value_list call (int nargout, const octave_value_list& args); |
123 ~internal_fcn_handle (void) = default; | 135 |
124 | 136 // FIXME: These must go away. They don't do the right thing for |
125 internal_fcn_handle * clone (void) const | 137 // scoping or overloads. |
126 { | 138 octave_function * function_value (bool = false) |
127 return new internal_fcn_handle (*this); | |
128 } | |
129 | |
130 std::string type (void) const { return "<internal>"; } | |
131 | |
132 bool is_internal (void) const { return true; } | |
133 | |
134 octave_value_list call (int nargout, const octave_value_list& args); | |
135 | |
136 // FIXME: These must go away. They don't do the right thing for | |
137 // scoping or overloads. | |
138 octave_function * function_value (bool = false) | |
139 { | |
140 return m_fcn.function_value (); | |
141 } | |
142 | |
143 octave_user_function * user_function_value (bool = false) | |
144 { | |
145 return m_fcn.user_function_value (); | |
146 } | |
147 | |
148 octave_value fcn_val (void) { return m_fcn; } | |
149 | |
150 // Should be const. | |
151 octave_scalar_map info (void); | |
152 | |
153 friend bool is_equal_to (const internal_fcn_handle& fh1, | |
154 const internal_fcn_handle& fh2); | |
155 | |
156 private: | |
157 | |
158 octave_value m_fcn; | |
159 }; | |
160 | |
161 class simple_fcn_handle : public base_fcn_handle | |
162 { | 139 { |
163 public: | 140 return m_fcn.function_value (); |
164 | 141 } |
165 // FIXME: octaveroot is temporary information used when loading | 142 |
166 // handles. Can we avoid using it in the constructor? | 143 octave_user_function * user_function_value (bool = false) |
167 | |
168 simple_fcn_handle (const std::string& name = "", | |
169 const std::string& file = "", | |
170 const std::string& /*octaveroot*/ = "") | |
171 : base_fcn_handle (name, file), m_fcn () | |
172 { } | |
173 | |
174 simple_fcn_handle (const octave_value& fcn, const std::string& name) | |
175 : base_fcn_handle (name), m_fcn (fcn) | |
176 { | |
177 if (m_fcn.is_defined ()) | |
178 { | |
179 octave_function *oct_fcn = m_fcn.function_value (); | |
180 | |
181 if (oct_fcn) | |
182 m_file = oct_fcn->fcn_file_name (); | |
183 } | |
184 } | |
185 | |
186 simple_fcn_handle (const simple_fcn_handle&) = default; | |
187 | |
188 ~simple_fcn_handle (void) = default; | |
189 | |
190 simple_fcn_handle * clone (void) const | |
191 { | |
192 return new simple_fcn_handle (*this); | |
193 } | |
194 | |
195 std::string type (void) const { return "simple"; } | |
196 | |
197 bool is_simple (void) const { return true; } | |
198 | |
199 octave_value_list call (int nargout, const octave_value_list& args); | |
200 | |
201 // FIXME: These must go away. They don't do the right thing for | |
202 // scoping or overloads. | |
203 octave_function * function_value (bool); | |
204 | |
205 octave_user_function * user_function_value (bool); | |
206 | |
207 octave_value fcn_val (void); | |
208 | |
209 // Should be const. | |
210 octave_scalar_map info (void); | |
211 | |
212 bool save_ascii (std::ostream& os); | |
213 | |
214 bool load_ascii (std::istream& is); | |
215 | |
216 bool save_binary (std::ostream& os, bool save_as_floats); | |
217 | |
218 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
219 | |
220 bool save_hdf5 (octave_hdf5_id loc_hid, const char *name, | |
221 bool save_as_floats); | |
222 | |
223 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
224 octave_hdf5_id& type_hid); | |
225 | |
226 void print_raw (std::ostream& os, bool pr_as_read_syntax, | |
227 int current_print_indent_level) const; | |
228 | |
229 friend bool is_equal_to (const simple_fcn_handle& fh1, | |
230 const simple_fcn_handle& fh2); | |
231 | |
232 private: | |
233 | |
234 octave_value m_fcn; | |
235 }; | |
236 | |
237 class scoped_fcn_handle : public base_fcn_handle | |
238 { | 144 { |
239 public: | 145 return m_fcn.user_function_value (); |
240 | 146 } |
241 // FIXME: octaveroot is temporary information used when loading | 147 |
242 // handles. Can we avoid using it in the constructor? | 148 octave_value fcn_val (void) { return m_fcn; } |
243 | 149 |
244 scoped_fcn_handle (const std::string& name = "", | 150 // Should be const. |
245 const std::string& file = "", | 151 octave_scalar_map info (void); |
246 const std::string& /*octaveroot*/ = "") | 152 |
247 : base_fcn_handle (name, file) | 153 friend bool is_equal_to (const internal_fcn_handle& fh1, |
248 { } | 154 const internal_fcn_handle& fh2); |
249 | 155 |
250 scoped_fcn_handle (const octave_value& fcn, const std::string& name, | 156 private: |
251 const std::list<std::string>& parentage); | 157 |
252 | 158 octave_value m_fcn; |
253 scoped_fcn_handle (const scoped_fcn_handle&) = default; | 159 }; |
254 | 160 |
255 ~scoped_fcn_handle (void) = default; | 161 class simple_fcn_handle : public base_fcn_handle |
256 | 162 { |
257 scoped_fcn_handle * clone (void) const | 163 public: |
258 { | 164 |
259 return new scoped_fcn_handle (*this); | 165 // FIXME: octaveroot is temporary information used when loading |
260 } | 166 // handles. Can we avoid using it in the constructor? |
261 | 167 |
262 std::string type (void) const { return "scopedfunction"; } | 168 simple_fcn_handle (const std::string& name = "", |
263 | 169 const std::string& file = "", |
264 bool is_scoped (void) const { return true; } | 170 const std::string& /*octaveroot*/ = "") |
265 | 171 : base_fcn_handle (name, file), m_fcn () |
266 octave_value_list call (int nargout, const octave_value_list& args); | 172 { } |
267 | 173 |
268 // FIXME: These must go away. They don't do the right thing for | 174 simple_fcn_handle (const octave_value& fcn, const std::string& name) |
269 // scoping or overloads. | 175 : base_fcn_handle (name), m_fcn (fcn) |
270 octave_function * function_value (bool = false) | |
271 { | |
272 return m_fcn.function_value (); | |
273 } | |
274 | |
275 octave_user_function * user_function_value (bool = false) | |
276 { | |
277 return m_fcn.user_function_value (); | |
278 } | |
279 | |
280 octave_value fcn_val (void) { return m_fcn; } | |
281 | |
282 // Should be const. | |
283 octave_scalar_map info (void); | |
284 | |
285 bool save_ascii (std::ostream& os); | |
286 | |
287 bool load_ascii (std::istream& is); | |
288 | |
289 bool save_binary (std::ostream& os, bool save_as_floats); | |
290 | |
291 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
292 | |
293 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
294 bool save_as_floats); | |
295 | |
296 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
297 octave_hdf5_id& type_hid); | |
298 | |
299 void print_raw (std::ostream&, bool pr_as_read_syntax, | |
300 int current_print_indent_level) const; | |
301 | |
302 friend bool is_equal_to (const scoped_fcn_handle& fh1, | |
303 const scoped_fcn_handle& fh2); | |
304 | |
305 protected: | |
306 | |
307 void find_function (void); | |
308 | |
309 // The function we are handling. | |
310 octave_value m_fcn; | |
311 | |
312 // List of parent function names. The first element is the name of | |
313 // m_fcn. | |
314 std::list<std::string> m_parentage; | |
315 }; | |
316 | |
317 class base_nested_fcn_handle : public base_fcn_handle | |
318 { | 176 { |
319 public: | |
320 | |
321 // FIXME: octaveroot is temporary information used when loading | |
322 // handles. Can we avoid using it in the constructor? | |
323 | |
324 base_nested_fcn_handle (const std::string& name = "", | |
325 const std::string& file = "", | |
326 const std::string& /*octaveroot*/ = "") | |
327 : base_fcn_handle (name, file) | |
328 { } | |
329 | |
330 base_nested_fcn_handle (const octave_value& fcn, const std::string& name) | |
331 : base_fcn_handle (name), m_fcn (fcn) | |
332 { } | |
333 | |
334 std::string type (void) const { return "nested"; } | |
335 | |
336 using base_fcn_handle::is_nested; | |
337 | |
338 bool is_nested (void) const { return true; } | |
339 | |
340 // FIXME: These must go away. They don't do the right thing for | |
341 // scoping or overloads. | |
342 octave_function * function_value (bool = false) | |
343 { | |
344 return m_fcn.function_value (); | |
345 } | |
346 | |
347 octave_user_function * user_function_value (bool = false) | |
348 { | |
349 return m_fcn.user_function_value (); | |
350 } | |
351 | |
352 octave_value fcn_val (void) { return m_fcn; } | |
353 | |
354 virtual octave_value workspace (void) const = 0; | |
355 | |
356 // Should be const. | |
357 octave_scalar_map info (void); | |
358 | |
359 bool save_ascii (std::ostream& os); | |
360 | |
361 bool load_ascii (std::istream& is); | |
362 | |
363 bool save_binary (std::ostream& os, bool save_as_floats); | |
364 | |
365 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
366 | |
367 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
368 bool save_as_floats); | |
369 | |
370 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
371 octave_hdf5_id& type_hid); | |
372 | |
373 void print_raw (std::ostream&, bool pr_as_read_syntax, | |
374 int current_print_indent_level) const; | |
375 | |
376 protected: | |
377 | |
378 // The function we are handling. | |
379 octave_value m_fcn; | |
380 }; | |
381 | |
382 class nested_fcn_handle : public base_nested_fcn_handle | |
383 { | |
384 public: | |
385 | |
386 // FIXME: octaveroot is temporary information used when loading | |
387 // handles. Can we avoid using it in the constructor? | |
388 | |
389 nested_fcn_handle (const std::string& name = "", | |
390 const std::string& file = "", | |
391 const std::string& octaveroot = "") | |
392 : base_nested_fcn_handle (name, file, octaveroot) | |
393 { } | |
394 | |
395 nested_fcn_handle (const octave_value& fcn, const std::string& name, | |
396 const std::shared_ptr<stack_frame>& stack_context) | |
397 : base_nested_fcn_handle (fcn, name), m_stack_context (stack_context) | |
398 { | |
399 if (m_stack_context) | |
400 m_stack_context->mark_closure_context (); | |
401 } | |
402 | |
403 nested_fcn_handle (const nested_fcn_handle&) = default; | |
404 | |
405 ~nested_fcn_handle (void) = default; | |
406 | |
407 using base_nested_fcn_handle::is_nested; | |
408 | |
409 bool is_nested (const std::shared_ptr<stack_frame>& frame) const | |
410 { | |
411 return frame == m_stack_context; | |
412 } | |
413 | |
414 nested_fcn_handle * clone (void) const | |
415 { | |
416 return new nested_fcn_handle (*this); | |
417 } | |
418 | |
419 octave_value make_weak_nested_handle (void) const; | |
420 | |
421 octave_value_list call (int nargout, const octave_value_list& args); | |
422 | |
423 octave_value workspace (void) const; | |
424 | |
425 friend bool is_equal_to (const nested_fcn_handle& fh1, | |
426 const nested_fcn_handle& fh2); | |
427 | |
428 std::shared_ptr<stack_frame> stack_context (void) const | |
429 { | |
430 return m_stack_context; | |
431 } | |
432 | |
433 protected: | |
434 | |
435 // Pointer to closure stack frames. | |
436 std::shared_ptr<stack_frame> m_stack_context; | |
437 }; | |
438 | |
439 class weak_nested_fcn_handle : public base_nested_fcn_handle | |
440 { | |
441 public: | |
442 | |
443 weak_nested_fcn_handle (const nested_fcn_handle& nfh) | |
444 : base_nested_fcn_handle (nfh), m_stack_context (nfh.stack_context ()) | |
445 { } | |
446 | |
447 weak_nested_fcn_handle (const weak_nested_fcn_handle&) = default; | |
448 | |
449 ~weak_nested_fcn_handle (void) = default; | |
450 | |
451 weak_nested_fcn_handle * clone (void) const | |
452 { | |
453 return new weak_nested_fcn_handle (*this); | |
454 } | |
455 | |
456 bool is_weak_nested (void) const { return true; } | |
457 | |
458 octave_value_list call (int nargout, const octave_value_list& args); | |
459 | |
460 octave_value workspace (void) const; | |
461 | |
462 friend bool is_equal_to (const weak_nested_fcn_handle& fh1, | |
463 const weak_nested_fcn_handle& fh2); | |
464 | |
465 protected: | |
466 | |
467 // Pointer to closure stack frames. | |
468 std::weak_ptr<stack_frame> m_stack_context; | |
469 }; | |
470 | |
471 class class_simple_fcn_handle : public base_fcn_handle | |
472 { | |
473 public: | |
474 | |
475 // FIXME: octaveroot is temporary information used when loading | |
476 // handles. Can we avoid using it in the constructor? | |
477 | |
478 class_simple_fcn_handle (const std::string& name, | |
479 const std::string& file, | |
480 const std::string& /*octaveroot*/) | |
481 : base_fcn_handle (name, file) | |
482 { } | |
483 | |
484 // FIXME: is the method name supposed to be just the method name or | |
485 // also contain the object name? | |
486 | |
487 class_simple_fcn_handle (const std::string& class_nm, | |
488 const std::string& meth_nm); | |
489 | |
490 class_simple_fcn_handle (const octave_value& fcn, | |
491 const std::string& class_nm, | |
492 const std::string& meth_nm); | |
493 | |
494 class_simple_fcn_handle (const octave_value& obj, const octave_value& fcn, | |
495 const std::string& class_nm, | |
496 const std::string& meth_nm); | |
497 | |
498 class_simple_fcn_handle (const class_simple_fcn_handle&) = default; | |
499 | |
500 ~class_simple_fcn_handle (void) = default; | |
501 | |
502 class_simple_fcn_handle * clone (void) const | |
503 { | |
504 return new class_simple_fcn_handle (*this); | |
505 } | |
506 | |
507 std::string type (void) const { return "classsimple"; } | |
508 | |
509 bool is_class_simple (void) const { return true; } | |
510 | |
511 octave_value_list call (int nargout, const octave_value_list& args); | |
512 | |
513 // FIXME: These must go away. They don't do the right thing for | |
514 // scoping or overloads. | |
515 octave_function * function_value (bool = false) | |
516 { | |
517 // FIXME: Shouldn't the lookup rules here match those used in the | |
518 // call method? | |
519 | |
520 if (m_fcn.is_defined ()) | |
521 return m_fcn.function_value (); | |
522 | |
523 symbol_table& symtab = __get_symbol_table__ (); | |
524 | |
525 // FIXME: is caching the correct thing to do? | |
526 // Cache this value so that the pointer will be valid as long as the | |
527 // function handle object is valid. | |
528 | |
529 // FIXME: This should probably dispatch to the respective class method. | |
530 // But that breaks if a function handle is used in a class method with | |
531 // e.g. bsxfun with arguments of a different class (see bug #59661). | |
532 // m_fcn = symtab.find_method (m_name, m_dispatch_class); | |
533 m_fcn = symtab.find_function (m_name, octave_value_list ()); | |
534 | |
535 return m_fcn.is_defined () ? m_fcn.function_value () : nullptr; | |
536 } | |
537 | |
538 octave_user_function * user_function_value (bool = false) | |
539 { | |
540 return m_fcn.user_function_value (); | |
541 } | |
542 | |
543 octave_value fcn_val (void) { return m_fcn; } | |
544 | |
545 // Should be const. | |
546 octave_scalar_map info (void); | |
547 | |
548 std::string dispatch_class (void) const { return m_dispatch_class; } | |
549 | |
550 bool save_ascii (std::ostream& os); | |
551 | |
552 bool load_ascii (std::istream& is); | |
553 | |
554 bool save_binary (std::ostream& os, bool save_as_floats); | |
555 | |
556 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
557 | |
558 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
559 bool save_as_floats); | |
560 | |
561 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
562 octave_hdf5_id& type_hid); | |
563 | |
564 void print_raw (std::ostream&, bool pr_as_read_syntax, | |
565 int current_print_indent_level) const; | |
566 | |
567 friend bool is_equal_to (const class_simple_fcn_handle& fh1, | |
568 const class_simple_fcn_handle& fh2); | |
569 | |
570 protected: | |
571 | |
572 // The object containing the method we are handing. | |
573 octave_value m_obj; | |
574 | |
575 // The method we are handling. | |
576 octave_value m_fcn; | |
577 | |
578 // Name of the class that m_fcn belongs to. | |
579 std::string m_dispatch_class; | |
580 }; | |
581 | |
582 // Handles to anonymous functions are similar to handles to nested | |
583 // functions. If they are created in a context that contains nested | |
584 // functions, then they store a link to the parent call stack frames | |
585 // that are active when they are created. These call stack frames | |
586 // (closure frames) provide access to variables needed by any nested | |
587 // functions that are called from the anonymous function. Anonymous | |
588 // functions also store a list of values from their parent scope | |
589 // corresponding to the symbols in the anonymous function. This list | |
590 // of values captures the variable values that are visible in the | |
591 // scope where they are created. | |
592 // | |
593 // Note that because handles to anonymous and nested functions capture | |
594 // call stack frames when they are created, they will cause deletion | |
595 // of the values in those frames to be deferred until the handles to | |
596 // the anonymous or nested functions are deleted. | |
597 // | |
598 // Would it be possible to avoid storing the closure frames for | |
599 // handles to anonymous functions if we can determine that the | |
600 // anonymous function has no unbound variables (or parameters, which | |
601 // could be handles to nested functions?) or if it is not created in a | |
602 // context that contains nested functions? | |
603 // | |
604 // Would it be possible to define anonymous functions as a special | |
605 // type of nested function object that also has an variable | |
606 // initialization list associated with it? | |
607 | |
608 class base_anonymous_fcn_handle : public base_fcn_handle | |
609 { | |
610 public: | |
611 | |
612 static const std::string anonymous; | |
613 | |
614 // Setting NAME here is a bit of a kluge to cope with a bad choice | |
615 // made to append the number of local variables to the @<anonymous> | |
616 // tag in the binary file format. See also the save_binary and | |
617 // load_binary functions. | |
618 | |
619 base_anonymous_fcn_handle (const std::string& name = "") | |
620 : base_fcn_handle (name) | |
621 { } | |
622 | |
623 base_anonymous_fcn_handle (const octave_value& fcn, | |
624 const stack_frame::local_vars_map& local_vars) | |
625 : base_fcn_handle (anonymous), m_fcn (fcn), m_local_vars (local_vars) | |
626 { } | |
627 | |
628 base_anonymous_fcn_handle (const base_anonymous_fcn_handle&) = default; | |
629 | |
630 ~base_anonymous_fcn_handle (void) = default; | |
631 | |
632 std::string type (void) const { return "anonymous"; } | |
633 | |
634 bool is_anonymous (void) const { return true; } | |
635 | |
636 // FIXME: These must go away. They don't do the right thing for | |
637 // scoping or overloads. | |
638 octave_function * function_value (bool = false) | |
639 { | |
640 return m_fcn.function_value (); | |
641 } | |
642 | |
643 octave_user_function * user_function_value (bool = false) | |
644 { | |
645 return m_fcn.user_function_value (); | |
646 } | |
647 | |
648 octave_value fcn_val (void) { return m_fcn; } | |
649 | |
650 virtual octave_value workspace (void) const = 0; | |
651 | |
652 // Should be const. | |
653 octave_scalar_map info (void); | |
654 | |
655 bool save_ascii (std::ostream& os); | |
656 | |
657 bool load_ascii (std::istream& is); | |
658 | |
659 bool save_binary (std::ostream& os, bool save_as_floats); | |
660 | |
661 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
662 | |
663 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
664 bool save_as_floats); | |
665 | |
666 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
667 octave_hdf5_id& type_hid); | |
668 | |
669 void print_raw (std::ostream&, bool pr_as_read_syntax, | |
670 int current_print_indent_level) const; | |
671 | |
672 // Anonymous function handles are printed without a newline. | |
673 bool print_as_scalar (void) const { return false; } | |
674 | |
675 bool parse (const std::string& fcn_text); | |
676 | |
677 protected: | |
678 | |
679 // The function we are handling. | |
680 octave_value m_fcn; | |
681 | |
682 // List of captured variable values for anonymous fucntions. | |
683 stack_frame::local_vars_map m_local_vars; | |
684 }; | |
685 | |
686 class anonymous_fcn_handle : public base_anonymous_fcn_handle | |
687 { | |
688 public: | |
689 | |
690 using base_anonymous_fcn_handle::anonymous; | |
691 | |
692 // Setting NAME here is a bit of a kluge to cope with a bad choice | |
693 // made to append the number of local variables to the @<anonymous> | |
694 // tag in the binary file format. See also the save_binary and | |
695 // load_binary functions. | |
696 | |
697 anonymous_fcn_handle (const std::string& name = "") | |
698 : base_anonymous_fcn_handle (name), m_stack_context () | |
699 { } | |
700 | |
701 anonymous_fcn_handle (const octave_value& fcn, | |
702 const stack_frame::local_vars_map& local_vars, | |
703 const std::shared_ptr<stack_frame>& stack_context = std::shared_ptr<stack_frame> ()); | |
704 | |
705 anonymous_fcn_handle (const anonymous_fcn_handle&) = default; | |
706 | |
707 ~anonymous_fcn_handle (void) = default; | |
708 | |
709 anonymous_fcn_handle * clone (void) const | |
710 { | |
711 return new anonymous_fcn_handle (*this); | |
712 } | |
713 | |
714 octave_value make_weak_anonymous_handle (void) const; | |
715 | |
716 octave_value_list call (int nargout, const octave_value_list& args); | |
717 | |
718 octave_value workspace (void) const; | |
719 | |
720 friend bool is_equal_to (const anonymous_fcn_handle& fh1, | |
721 const anonymous_fcn_handle& fh2); | |
722 | |
723 std::shared_ptr<stack_frame> stack_context (void) const | |
724 { | |
725 return m_stack_context; | |
726 } | |
727 | |
728 protected: | |
729 | |
730 // Pointer to closure stack frames. | |
731 std::shared_ptr<stack_frame> m_stack_context; | |
732 }; | |
733 | |
734 class weak_anonymous_fcn_handle : public base_anonymous_fcn_handle | |
735 { | |
736 public: | |
737 | |
738 using base_anonymous_fcn_handle::anonymous; | |
739 | |
740 weak_anonymous_fcn_handle (const anonymous_fcn_handle& afh) | |
741 : base_anonymous_fcn_handle (afh), m_stack_context (afh.stack_context ()) | |
742 { } | |
743 | |
744 weak_anonymous_fcn_handle (const weak_anonymous_fcn_handle&) = default; | |
745 | |
746 ~weak_anonymous_fcn_handle (void) = default; | |
747 | |
748 weak_anonymous_fcn_handle * clone (void) const | |
749 { | |
750 return new weak_anonymous_fcn_handle (*this); | |
751 } | |
752 | |
753 bool is_weak_anonymous (void) const { return true; } | |
754 | |
755 octave_value_list call (int nargout, const octave_value_list& args); | |
756 | |
757 octave_value workspace (void) const; | |
758 | |
759 friend bool is_equal_to (const weak_anonymous_fcn_handle& fh1, | |
760 const weak_anonymous_fcn_handle& fh2); | |
761 | |
762 protected: | |
763 | |
764 // Pointer to closure stack frames. | |
765 std::weak_ptr<stack_frame> m_stack_context; | |
766 }; | |
767 | |
768 extern bool is_equal_to (const anonymous_fcn_handle& fh1, | |
769 const anonymous_fcn_handle& fh2); | |
770 | |
771 static void err_invalid_fcn_handle (const std::string& name) | |
772 { | |
773 error ("invalid function handle, unable to find function for @%s", | |
774 name.c_str ()); | |
775 } | |
776 | |
777 octave_value base_fcn_handle::make_weak_nested_handle (void) const | |
778 { | |
779 std::string type_str = type (); | |
780 error ("invalid conversion from %s handle to weak nestead handle", | |
781 type_str.c_str ()); | |
782 } | |
783 | |
784 octave_value base_fcn_handle::make_weak_anonymous_handle (void) const | |
785 { | |
786 std::string type_str = type (); | |
787 error ("invalid conversion from %s handle to weak anonymous handle", | |
788 type_str.c_str ()); | |
789 } | |
790 | |
791 octave_value_list | |
792 base_fcn_handle::subsref (const std::string& type, | |
793 const std::list<octave_value_list>& idx, | |
794 int nargout) | |
795 { | |
796 octave_value_list retval; | |
797 | |
798 switch (type[0]) | |
799 { | |
800 case '(': | |
801 { | |
802 int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout; | |
803 | |
804 retval = call (tmp_nargout, idx.front ()); | |
805 } | |
806 break; | |
807 | |
808 case '{': | |
809 case '.': | |
810 error ("function handle cannot be indexed with %c", type[0]); | |
811 | |
812 default: | |
813 panic_impossible (); | |
814 } | |
815 | |
816 // FIXME: perhaps there should be an | |
817 // octave_value_list::next_subsref member function? See also | |
818 // octave_builtin::subsref. | |
819 | |
820 if (idx.size () > 1) | |
821 retval = retval(0).next_subsref (nargout, type, idx); | |
822 | |
823 return retval; | |
824 } | |
825 | |
826 octave_value | |
827 base_fcn_handle::convert_to_str_internal (bool, bool, char type) const | |
828 { | |
829 std::ostringstream buf; | |
830 print_raw (buf, true, 0); | |
831 return octave_value (buf.str (), type); | |
832 } | |
833 | |
834 bool | |
835 base_fcn_handle::save_ascii (std::ostream&) | |
836 { | |
837 unimplemented ("save", "text"); | |
838 | |
839 return true; | |
840 } | |
841 | |
842 bool | |
843 base_fcn_handle::load_ascii (std::istream&) | |
844 { | |
845 unimplemented ("load", "text"); | |
846 | |
847 return true; | |
848 } | |
849 | |
850 bool | |
851 base_fcn_handle::save_binary (std::ostream&, bool) | |
852 { | |
853 unimplemented ("save", "binary"); | |
854 | |
855 return true; | |
856 } | |
857 | |
858 bool | |
859 base_fcn_handle::load_binary (std::istream&, bool, mach_info::float_format) | |
860 { | |
861 unimplemented ("load", "binary"); | |
862 | |
863 return true; | |
864 } | |
865 | |
866 bool | |
867 base_fcn_handle::save_hdf5 (octave_hdf5_id, const char *, bool) | |
868 { | |
869 unimplemented ("save", "hdf5"); | |
870 | |
871 return true; | |
872 } | |
873 | |
874 bool | |
875 base_fcn_handle::load_hdf5 (octave_hdf5_id&, octave_hdf5_id&, octave_hdf5_id&) | |
876 { | |
877 unimplemented ("load", "hdf5"); | |
878 | |
879 return true; | |
880 } | |
881 | |
882 void base_fcn_handle::warn_load (const char *file_type) const | |
883 { | |
884 std::string obj_type = type (); | |
885 | |
886 warning_with_id | |
887 ("Octave:load-save-unavailable", | |
888 "%s: loading %s files not available in this version of Octave", | |
889 obj_type.c_str (), file_type); | |
890 } | |
891 | |
892 void base_fcn_handle::warn_save (const char *file_type) const | |
893 { | |
894 std::string obj_type = type (); | |
895 | |
896 warning_with_id | |
897 ("Octave:load-save-unavailable", | |
898 "%s: saving %s files not available in this version of Octave", | |
899 obj_type.c_str (), file_type); | |
900 } | |
901 | |
902 void base_fcn_handle::unimplemented (const char *op, const char *fmt) const | |
903 { | |
904 std::string htype = type (); | |
905 | |
906 warning ("%s for %s handles with %s format is not implemented", | |
907 op, htype.c_str (), fmt); | |
908 } | |
909 | |
910 octave_value_list | |
911 invalid_fcn_handle::call (int, const octave_value_list&) | |
912 { | |
913 error ("invalid call to invalid function handle"); | |
914 } | |
915 | |
916 octave_value_list | |
917 internal_fcn_handle::call (int nargout, const octave_value_list& args) | |
918 { | |
919 interpreter& interp = __get_interpreter__ (); | |
920 | |
921 return interp.feval (m_fcn, args, nargout); | |
922 } | |
923 | |
924 octave_scalar_map internal_fcn_handle::info (void) | |
925 { | |
926 octave_scalar_map m; | |
927 | |
928 m.setfield ("function", fcn_name ()); | |
929 m.setfield ("type", type ()); | |
930 m.setfield ("file", ""); | |
931 | |
932 return m; | |
933 } | |
934 | |
935 bool is_equal_to (const internal_fcn_handle& fh1, | |
936 const internal_fcn_handle& fh2) | |
937 { | |
938 if (fh1.m_name == fh2.m_name | |
939 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
940 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
941 else | |
942 return false; | |
943 } | |
944 | |
945 octave_value_list | |
946 simple_fcn_handle::call (int nargout, const octave_value_list& args) | |
947 { | |
948 // FIXME: if m_name has a '.' in the name, lookup first component. If | |
949 // it is a classdef meta object, then build TYPE and IDX arguments and | |
950 // make a subsref call using them. | |
951 | |
952 interpreter& interp = __get_interpreter__ (); | |
953 | |
954 octave_value fcn_to_call; | |
955 | |
956 // The following code is similar to part of | |
957 // tree_evaluator::visit_index_expression but simpler because it | |
958 // handles a more restricted case. | |
959 | |
960 symbol_table& symtab = interp.get_symbol_table (); | |
961 | |
962 std::size_t pos = m_name.find ('.'); | |
963 | |
964 if (pos != std::string::npos) | |
965 { | |
966 // FIXME: check to see which of these cases actually work in | |
967 // Octave and Matlab. For the last two, assume handle is | |
968 // created before object is defined as an object. | |
969 // | |
970 // We can have one of | |
971 // | |
972 // pkg-list . fcn (args) | |
973 // pkg-list . cls . meth (args) | |
974 // class-name . method (args) | |
975 // class-name . static-method (args) | |
976 // object . method (args) | |
977 // object . static-method (args) | |
978 | |
979 // Evaluate package elements until we find a function, | |
980 // classdef object, or classdef_meta object that is not a | |
981 // package. An object may only appear as the first element, | |
982 // then it must be followed directly by a function name. | |
983 | |
984 std::size_t beg = 0; | |
985 std::size_t end = pos; | |
986 | |
987 std::vector<std::string> idx_elts; | |
988 | |
989 while (true) | |
990 { | |
991 end = m_name.find ('.', beg); | |
992 | |
993 idx_elts.push_back (m_name.substr (beg, end-beg)); | |
994 | |
995 if (end == std::string::npos) | |
996 break; | |
997 | |
998 beg = end+1; | |
999 } | |
1000 | |
1001 std::size_t n_elts = idx_elts.size (); | |
1002 | |
1003 bool have_object = false; | |
1004 octave_value partial_expr_val; | |
1005 | |
1006 // Lazy evaluation. The first element was not known to be defined | |
1007 // as an object in the scope where the handle was created. See if | |
1008 // there is a definition in the current scope. | |
1009 | |
1010 partial_expr_val = interp.varval (idx_elts[0]); | |
1011 | |
1012 if (partial_expr_val.is_defined ()) | |
1013 { | |
1014 if (! partial_expr_val.is_classdef_object () || n_elts != 2) | |
1015 err_invalid_fcn_handle (m_name); | |
1016 | |
1017 have_object = true; | |
1018 } | |
1019 else | |
1020 partial_expr_val = symtab.find_function (idx_elts[0], ovl ()); | |
1021 | |
1022 std::string type; | |
1023 std::list<octave_value_list> arg_list; | |
1024 | |
1025 for (std::size_t i = 1; i < n_elts; i++) | |
1026 { | |
1027 if (partial_expr_val.is_package ()) | |
1028 { | |
1029 if (have_object) | |
1030 err_invalid_fcn_handle (m_name); | |
1031 | |
1032 type = "."; | |
1033 arg_list.push_back (ovl (idx_elts[i])); | |
1034 | |
1035 try | |
1036 { | |
1037 // Silently ignore extra output values. | |
1038 | |
1039 octave_value_list tmp_list | |
1040 = partial_expr_val.subsref (type, arg_list, 0); | |
1041 | |
1042 partial_expr_val | |
1043 = tmp_list.length () ? tmp_list(0) : octave_value (); | |
1044 | |
1045 if (partial_expr_val.is_cs_list ()) | |
1046 err_invalid_fcn_handle (m_name); | |
1047 | |
1048 arg_list.clear (); | |
1049 } | |
1050 catch (const index_exception&) | |
1051 { | |
1052 err_invalid_fcn_handle (m_name); | |
1053 } | |
1054 } | |
1055 else if (have_object || partial_expr_val.is_classdef_meta ()) | |
1056 { | |
1057 // Object or class name must be the next to the last | |
1058 // element (it was the previous one, so if this is the | |
1059 // final element, it should be a classdef method, | |
1060 // but we'll let the classdef or classdef_meta subsref | |
1061 // function sort that out. | |
1062 | |
1063 if (i != n_elts-1) | |
1064 err_invalid_fcn_handle (m_name); | |
1065 | |
1066 type = ".("; | |
1067 arg_list.push_back (ovl (idx_elts[i])); | |
1068 arg_list.push_back (args); | |
1069 | |
1070 return partial_expr_val.subsref (type, arg_list, nargout); | |
1071 } | |
1072 else | |
1073 err_invalid_fcn_handle (m_name); | |
1074 } | |
1075 | |
1076 // If we get here, we must have a function to call. | |
1077 | |
1078 if (! partial_expr_val.is_function ()) | |
1079 err_invalid_fcn_handle (m_name); | |
1080 | |
1081 fcn_to_call = partial_expr_val; | |
1082 } | |
1083 else | |
1084 { | |
1085 // No "." in the name. | |
1086 | |
1087 // Perform function lookup given current arguments. We'll need | |
1088 // to do this regardless of whether a function was found when | |
1089 // the handle was created. | |
1090 | |
1091 octave_value ov_fcn = symtab.find_function (m_name, args); | |
1092 | |
1093 if (m_fcn.is_defined ()) | |
1094 { | |
1095 // A simple function was found when the handle was created. | |
1096 // Use that unless we find a class method to override it. | |
1097 | |
1098 fcn_to_call = m_fcn; | |
1099 | |
1100 if (ov_fcn.is_defined ()) | |
1101 { | |
1102 octave_function *fcn = ov_fcn.function_value (); | |
1103 | |
1104 std::string dispatch_class = fcn->dispatch_class (); | |
1105 | |
1106 if (fcn->is_class_method ()) | |
1107 { | |
1108 // Function found through lookup is a class method | |
1109 // so use it instead of the simple one found when | |
1110 // the handle was created. | |
1111 | |
1112 fcn_to_call = ov_fcn; | |
1113 } | |
1114 } | |
1115 } | |
1116 else | |
1117 { | |
1118 // There was no simple function found when the handle was | |
1119 // created so use the one found here (if any). | |
1120 | |
1121 fcn_to_call = ov_fcn; | |
1122 } | |
1123 } | |
1124 | |
1125 if (! fcn_to_call.is_defined ()) | |
1126 err_invalid_fcn_handle (m_name); | |
1127 | |
1128 return interp.feval (fcn_to_call, args, nargout); | |
1129 } | |
1130 | |
1131 octave_function * simple_fcn_handle::function_value (bool) | |
1132 { | |
1133 // FIXME: Shouldn't the lookup rules here match those used in the | |
1134 // call method? | |
1135 | |
1136 if (m_fcn.is_defined ()) | |
1137 return m_fcn.function_value (); | |
1138 | |
1139 symbol_table& symtab = __get_symbol_table__ (); | |
1140 | |
1141 // FIXME: is caching the correct thing to do? | |
1142 // Cache this value so that the pointer will be valid as long as the | |
1143 // function handle object is valid. | |
1144 | |
1145 m_fcn = symtab.find_function (m_name, octave_value_list ()); | |
1146 | |
1147 return m_fcn.is_defined () ? m_fcn.function_value () : nullptr; | |
1148 } | |
1149 | |
1150 octave_user_function * simple_fcn_handle::user_function_value (bool) | |
1151 { | |
1152 // FIXME: Shouldn't the lookup rules here match those used in the | |
1153 // call method? | |
1154 | |
1155 if (m_fcn.is_defined ()) | |
1156 return m_fcn.user_function_value (); | |
1157 | |
1158 symbol_table& symtab = __get_symbol_table__ (); | |
1159 | |
1160 // FIXME: is caching the correct thing to do? | |
1161 // Cache this value so that the pointer will be valid as long as the | |
1162 // function handle object is valid. | |
1163 | |
1164 m_fcn = symtab.find_user_function (m_name); | |
1165 | |
1166 return m_fcn.is_defined () ? m_fcn.user_function_value () : nullptr; | |
1167 } | |
1168 | |
1169 octave_value simple_fcn_handle::fcn_val (void) | |
1170 { | |
1171 if (m_fcn.is_defined ()) | |
1172 return m_fcn; | |
1173 | |
1174 symbol_table& symtab = __get_symbol_table__ (); | |
1175 | |
1176 // FIXME: is caching the correct thing to do? | |
1177 // Cache this value so that the pointer will be valid as long as the | |
1178 // function handle object is valid. | |
1179 | |
1180 m_fcn = symtab.find_user_function (m_name); | |
1181 | |
1182 return m_fcn; | |
1183 } | |
1184 | |
1185 octave_scalar_map simple_fcn_handle::info (void) | |
1186 { | |
1187 octave_scalar_map m; | |
1188 | |
1189 m.setfield ("function", fcn_name ()); | |
1190 m.setfield ("type", type ()); | |
1191 // When is FILE defined for simple function handles? | |
1192 m.setfield ("file", file ()); | |
1193 | |
1194 return m; | |
1195 } | |
1196 | |
1197 bool simple_fcn_handle::save_ascii (std::ostream& os) | |
1198 { | |
1199 os << "# octaveroot: " << config::octave_exec_home () << "\n"; | |
1200 | |
1201 std::string fnm = file (); | |
1202 if (! fnm.empty ()) | |
1203 os << "# path: " << fnm << "\n"; | |
1204 | |
1205 os << "# subtype: " << type () << "\n"; | |
1206 | |
1207 os << m_name << "\n"; | |
1208 | |
1209 return true; | |
1210 } | |
1211 | |
1212 bool simple_fcn_handle::load_ascii (std::istream& is) | |
1213 { | |
1214 // FIXME: If m_file is not empty, try to load the file and define | |
1215 // the function? Is it an error if that fails? Or should this job | |
1216 // always be deferred until the handle is used? | |
1217 | |
1218 return is.good (); | |
1219 } | |
1220 | |
1221 bool simple_fcn_handle::save_binary (std::ostream& os, bool) | |
1222 { | |
1223 std::ostringstream nmbuf; | |
1224 | |
1225 // When is FILE defined for simple function handles? | |
1226 std::string fnm; | |
1227 | |
1228 nmbuf << m_name << "@<simple>\n" << config::octave_exec_home () | |
1229 << "\n" << fnm; | |
1230 | |
1231 std::string buf_str = nmbuf.str (); | |
1232 int32_t tmp = buf_str.length (); | |
1233 os.write (reinterpret_cast<char *> (&tmp), 4); | |
1234 os.write (buf_str.c_str (), buf_str.length ()); | |
1235 | |
1236 return true; | |
1237 } | |
1238 | |
1239 bool simple_fcn_handle::load_binary (std::istream& is, bool, | |
1240 mach_info::float_format) | |
1241 { | |
1242 return is.good (); | |
1243 } | |
1244 | |
1245 bool simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
1246 bool) | |
1247 { | |
1248 #if defined (HAVE_HDF5) | |
1249 | |
1250 bool retval = true; | |
1251 | |
1252 octave_hdf5_id group_hid = -1; | |
1253 #if defined (HAVE_HDF5_18) | |
1254 group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
1255 octave_H5P_DEFAULT); | |
1256 #else | |
1257 group_hid = H5Gcreate (loc_id, name, 0); | |
1258 #endif | |
1259 if (group_hid < 0) | |
1260 return false; | |
1261 | |
1262 octave_hdf5_id space_hid, data_hid, type_hid; | |
1263 space_hid = data_hid = type_hid = -1; | |
1264 | |
1265 // attach the type of the variable | |
1266 type_hid = H5Tcopy (H5T_C_S1); | |
1267 H5Tset_size (type_hid, m_name.length () + 1); | |
1268 if (type_hid < 0) | |
1269 { | |
1270 H5Gclose (group_hid); | |
1271 return false; | |
1272 } | |
1273 | |
1274 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2); | |
1275 hdims[0] = 0; | |
1276 hdims[1] = 0; | |
1277 space_hid = H5Screate_simple (0, hdims, nullptr); | |
1278 if (space_hid < 0) | |
1279 { | |
1280 H5Tclose (type_hid); | |
1281 H5Gclose (group_hid); | |
1282 return false; | |
1283 } | |
1284 #if defined (HAVE_HDF5_18) | |
1285 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
1286 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
1287 octave_H5P_DEFAULT); | |
1288 #else | |
1289 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
1290 octave_H5P_DEFAULT); | |
1291 #endif | |
1292 if (data_hid < 0 | |
1293 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, | |
1294 octave_H5P_DEFAULT, m_name.c_str ()) < 0) | |
1295 { | |
1296 H5Sclose (space_hid); | |
1297 H5Tclose (type_hid); | |
1298 H5Gclose (group_hid); | |
1299 return false; | |
1300 } | |
1301 H5Dclose (data_hid); | |
1302 | |
1303 std::string octaveroot = config::octave_exec_home (); | |
1304 | |
1305 // When is FILE defined for simple fucntion handles? | |
1306 std::string fpath; | |
1307 | |
1308 H5Sclose (space_hid); | |
1309 hdims[0] = 1; | |
1310 hdims[1] = octaveroot.length (); | |
1311 space_hid = H5Screate_simple (0, hdims, nullptr); | |
1312 if (space_hid < 0) | |
1313 { | |
1314 H5Tclose (type_hid); | |
1315 H5Gclose (group_hid); | |
1316 return false; | |
1317 } | |
1318 | |
1319 H5Tclose (type_hid); | |
1320 type_hid = H5Tcopy (H5T_C_S1); | |
1321 H5Tset_size (type_hid, octaveroot.length () + 1); | |
1322 octave_hdf5_id a_id; | |
1323 #if defined (HAVE_HDF5_18) | |
1324 a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid, | |
1325 octave_H5P_DEFAULT, octave_H5P_DEFAULT); | |
1326 #else | |
1327 a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid, | |
1328 octave_H5P_DEFAULT); | |
1329 #endif | |
1330 | |
1331 if (a_id >= 0) | |
1332 { | |
1333 retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0); | |
1334 | |
1335 H5Aclose (a_id); | |
1336 } | |
1337 else | |
1338 { | |
1339 H5Sclose (space_hid); | |
1340 H5Tclose (type_hid); | |
1341 H5Gclose (group_hid); | |
1342 return false; | |
1343 } | |
1344 | |
1345 H5Sclose (space_hid); | |
1346 hdims[0] = 1; | |
1347 hdims[1] = fpath.length (); | |
1348 space_hid = H5Screate_simple (0, hdims, nullptr); | |
1349 if (space_hid < 0) | |
1350 { | |
1351 H5Tclose (type_hid); | |
1352 H5Gclose (group_hid); | |
1353 return false; | |
1354 } | |
1355 | |
1356 H5Tclose (type_hid); | |
1357 type_hid = H5Tcopy (H5T_C_S1); | |
1358 H5Tset_size (type_hid, fpath.length () + 1); | |
1359 | |
1360 #if defined (HAVE_HDF5_18) | |
1361 a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid, | |
1362 octave_H5P_DEFAULT, octave_H5P_DEFAULT); | |
1363 #else | |
1364 a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid, | |
1365 octave_H5P_DEFAULT); | |
1366 #endif | |
1367 | |
1368 if (a_id >= 0) | |
1369 { | |
1370 retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0); | |
1371 | |
1372 H5Aclose (a_id); | |
1373 } | |
1374 else | |
1375 retval = false; | |
1376 | |
1377 H5Sclose (space_hid); | |
1378 H5Tclose (type_hid); | |
1379 H5Gclose (group_hid); | |
1380 | |
1381 return retval; | |
1382 | |
1383 #else | |
1384 | |
1385 octave_unused_parameter (loc_id); | |
1386 octave_unused_parameter (name); | |
1387 | |
1388 warn_save ("hdf5"); | |
1389 | |
1390 return false; | |
1391 | |
1392 #endif | |
1393 } | |
1394 | |
1395 bool simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
1396 octave_hdf5_id& space_hid, | |
1397 octave_hdf5_id& type_hid) | |
1398 { | |
1399 #if defined (HAVE_HDF5) | |
1400 | |
1401 unimplemented ("load", "hdf5"); | |
1402 | |
1403 octave_unused_parameter (group_hid); | |
1404 octave_unused_parameter (space_hid); | |
1405 octave_unused_parameter (type_hid); | |
1406 | |
1407 return true; | |
1408 | |
1409 #else | |
1410 | |
1411 octave_unused_parameter (group_hid); | |
1412 octave_unused_parameter (space_hid); | |
1413 octave_unused_parameter (type_hid); | |
1414 | |
1415 return false; | |
1416 | |
1417 #endif | |
1418 } | |
1419 | |
1420 void simple_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax, | |
1421 int current_print_indent_level) const | |
1422 { | |
1423 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
1424 current_print_indent_level); | |
1425 } | |
1426 | |
1427 bool is_equal_to (const simple_fcn_handle& fh1, const simple_fcn_handle& fh2) | |
1428 { | |
1429 if (fh1.m_name == fh2.m_name) | |
1430 { | |
1431 if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1432 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1433 | |
1434 if (fh1.m_fcn.is_undefined () && fh2.m_fcn.is_undefined ()) | |
1435 return true; | |
1436 } | |
1437 | |
1438 return false; | |
1439 } | |
1440 | |
1441 scoped_fcn_handle::scoped_fcn_handle (const octave_value& fcn, | |
1442 const std::string& name, | |
1443 const std::list<std::string>& parentage) | |
1444 : base_fcn_handle (name), m_fcn (fcn), m_parentage (parentage) | |
1445 { | |
1446 // FIXME: should it be an error if FCN is undefined? | |
1447 | |
1448 if (m_fcn.is_defined ()) | 177 if (m_fcn.is_defined ()) |
1449 { | 178 { |
1450 octave_function *oct_fcn = m_fcn.function_value (); | 179 octave_function *oct_fcn = m_fcn.function_value (); |
1451 | 180 |
1452 if (oct_fcn) | 181 if (oct_fcn) |
1453 m_file = oct_fcn->fcn_file_name (); | 182 m_file = oct_fcn->fcn_file_name (); |
1454 } | 183 } |
1455 | |
1456 m_parentage.push_front (name); | |
1457 } | 184 } |
1458 | 185 |
1459 octave_value_list | 186 simple_fcn_handle (const simple_fcn_handle&) = default; |
1460 scoped_fcn_handle::call (int nargout, const octave_value_list& args) | 187 |
188 ~simple_fcn_handle (void) = default; | |
189 | |
190 simple_fcn_handle * clone (void) const | |
1461 { | 191 { |
1462 // FIXME: we aren't really using the scope yet. Hmm. | 192 return new simple_fcn_handle (*this); |
1463 | |
1464 interpreter& interp = __get_interpreter__ (); | |
1465 | |
1466 if (! m_fcn.is_defined ()) | |
1467 { | |
1468 // Try to find it? | |
1469 | |
1470 find_function (); | |
1471 } | |
1472 | |
1473 if (! m_fcn.is_defined ()) | |
1474 err_invalid_fcn_handle (m_name); | |
1475 | |
1476 return interp.feval (m_fcn, args, nargout); | |
1477 } | 193 } |
1478 | 194 |
1479 octave_scalar_map scoped_fcn_handle::info (void) | 195 std::string type (void) const { return "simple"; } |
196 | |
197 bool is_simple (void) const { return true; } | |
198 | |
199 octave_value_list call (int nargout, const octave_value_list& args); | |
200 | |
201 // FIXME: These must go away. They don't do the right thing for | |
202 // scoping or overloads. | |
203 octave_function * function_value (bool); | |
204 | |
205 octave_user_function * user_function_value (bool); | |
206 | |
207 octave_value fcn_val (void); | |
208 | |
209 // Should be const. | |
210 octave_scalar_map info (void); | |
211 | |
212 bool save_ascii (std::ostream& os); | |
213 | |
214 bool load_ascii (std::istream& is); | |
215 | |
216 bool save_binary (std::ostream& os, bool save_as_floats); | |
217 | |
218 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
219 | |
220 bool save_hdf5 (octave_hdf5_id loc_hid, const char *name, | |
221 bool save_as_floats); | |
222 | |
223 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
224 octave_hdf5_id& type_hid); | |
225 | |
226 void print_raw (std::ostream& os, bool pr_as_read_syntax, | |
227 int current_print_indent_level) const; | |
228 | |
229 friend bool is_equal_to (const simple_fcn_handle& fh1, | |
230 const simple_fcn_handle& fh2); | |
231 | |
232 private: | |
233 | |
234 octave_value m_fcn; | |
235 }; | |
236 | |
237 class scoped_fcn_handle : public base_fcn_handle | |
238 { | |
239 public: | |
240 | |
241 // FIXME: octaveroot is temporary information used when loading | |
242 // handles. Can we avoid using it in the constructor? | |
243 | |
244 scoped_fcn_handle (const std::string& name = "", | |
245 const std::string& file = "", | |
246 const std::string& /*octaveroot*/ = "") | |
247 : base_fcn_handle (name, file) | |
248 { } | |
249 | |
250 scoped_fcn_handle (const octave_value& fcn, const std::string& name, | |
251 const std::list<std::string>& parentage); | |
252 | |
253 scoped_fcn_handle (const scoped_fcn_handle&) = default; | |
254 | |
255 ~scoped_fcn_handle (void) = default; | |
256 | |
257 scoped_fcn_handle * clone (void) const | |
1480 { | 258 { |
1481 octave_scalar_map m; | 259 return new scoped_fcn_handle (*this); |
1482 | |
1483 m.setfield ("function", fcn_name ()); | |
1484 m.setfield ("type", type ()); | |
1485 m.setfield ("file", file ()); | |
1486 | |
1487 m.setfield ("parentage", Cell (m_parentage)); | |
1488 | |
1489 return m; | |
1490 } | 260 } |
1491 | 261 |
1492 bool scoped_fcn_handle::save_ascii (std::ostream& os) | 262 std::string type (void) const { return "scopedfunction"; } |
263 | |
264 bool is_scoped (void) const { return true; } | |
265 | |
266 octave_value_list call (int nargout, const octave_value_list& args); | |
267 | |
268 // FIXME: These must go away. They don't do the right thing for | |
269 // scoping or overloads. | |
270 octave_function * function_value (bool = false) | |
1493 { | 271 { |
1494 os << "# octaveroot: " << config::octave_exec_home () << "\n"; | 272 return m_fcn.function_value (); |
1495 | |
1496 std::string fnm = file (); | |
1497 if (! fnm.empty ()) | |
1498 os << "# path: " << fnm << "\n"; | |
1499 | |
1500 os << "# subtype: " << type () << "\n"; | |
1501 | |
1502 os << m_name << "\n"; | |
1503 | |
1504 octave_value tmp = Cell (m_parentage); | |
1505 tmp.save_ascii (os); | |
1506 | |
1507 return os.good (); | |
1508 } | 273 } |
1509 | 274 |
1510 bool scoped_fcn_handle::load_ascii (std::istream& is) | 275 octave_user_function * user_function_value (bool = false) |
1511 { | 276 { |
1512 octave_cell ov_cell; | 277 return m_fcn.user_function_value (); |
1513 ov_cell.load_ascii (is); | |
1514 | |
1515 if (ov_cell.iscellstr ()) | |
1516 { | |
1517 Array<std::string> cellstr_val = ov_cell.cellstr_value (); | |
1518 | |
1519 for (octave_idx_type i = 0; i < cellstr_val.numel (); i++) | |
1520 m_parentage.push_back (cellstr_val(i)); | |
1521 } | |
1522 | |
1523 return is.good (); | |
1524 } | 278 } |
1525 | 279 |
1526 bool scoped_fcn_handle::save_binary (std::ostream& os, bool save_as_floats) | 280 octave_value fcn_val (void) { return m_fcn; } |
281 | |
282 // Should be const. | |
283 octave_scalar_map info (void); | |
284 | |
285 bool save_ascii (std::ostream& os); | |
286 | |
287 bool load_ascii (std::istream& is); | |
288 | |
289 bool save_binary (std::ostream& os, bool save_as_floats); | |
290 | |
291 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
292 | |
293 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
294 bool save_as_floats); | |
295 | |
296 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
297 octave_hdf5_id& type_hid); | |
298 | |
299 void print_raw (std::ostream&, bool pr_as_read_syntax, | |
300 int current_print_indent_level) const; | |
301 | |
302 friend bool is_equal_to (const scoped_fcn_handle& fh1, | |
303 const scoped_fcn_handle& fh2); | |
304 | |
305 protected: | |
306 | |
307 void find_function (void); | |
308 | |
309 // The function we are handling. | |
310 octave_value m_fcn; | |
311 | |
312 // List of parent function names. The first element is the name of | |
313 // m_fcn. | |
314 std::list<std::string> m_parentage; | |
315 }; | |
316 | |
317 class base_nested_fcn_handle : public base_fcn_handle | |
318 { | |
319 public: | |
320 | |
321 // FIXME: octaveroot is temporary information used when loading | |
322 // handles. Can we avoid using it in the constructor? | |
323 | |
324 base_nested_fcn_handle (const std::string& name = "", | |
325 const std::string& file = "", | |
326 const std::string& /*octaveroot*/ = "") | |
327 : base_fcn_handle (name, file) | |
328 { } | |
329 | |
330 base_nested_fcn_handle (const octave_value& fcn, const std::string& name) | |
331 : base_fcn_handle (name), m_fcn (fcn) | |
332 { } | |
333 | |
334 std::string type (void) const { return "nested"; } | |
335 | |
336 using base_fcn_handle::is_nested; | |
337 | |
338 bool is_nested (void) const { return true; } | |
339 | |
340 // FIXME: These must go away. They don't do the right thing for | |
341 // scoping or overloads. | |
342 octave_function * function_value (bool = false) | |
1527 { | 343 { |
1528 std::ostringstream nmbuf; | 344 return m_fcn.function_value (); |
1529 | |
1530 std::string fnm = file (); | |
1531 | |
1532 nmbuf << m_name << "@<scopedfunction>\n" << config::octave_exec_home () | |
1533 << "\n" << fnm; | |
1534 | |
1535 std::string buf_str = nmbuf.str (); | |
1536 int32_t len = buf_str.length (); | |
1537 os.write (reinterpret_cast<char *> (&len), 4); | |
1538 os.write (buf_str.c_str (), buf_str.length ()); | |
1539 | |
1540 octave_value tmp = Cell (m_parentage); | |
1541 tmp.save_binary (os, save_as_floats); | |
1542 | |
1543 return os.good (); | |
1544 } | 345 } |
1545 | 346 |
1546 bool scoped_fcn_handle::load_binary (std::istream& is, bool swap, | 347 octave_user_function * user_function_value (bool = false) |
1547 mach_info::float_format fmt) | |
1548 { | 348 { |
1549 octave_cell ov_cell; | 349 return m_fcn.user_function_value (); |
1550 ov_cell.load_binary (is, swap, fmt); | |
1551 | |
1552 if (ov_cell.iscellstr ()) | |
1553 { | |
1554 Array<std::string> cellstr_val = ov_cell.cellstr_value (); | |
1555 | |
1556 for (octave_idx_type i = 0; i < cellstr_val.numel (); i++) | |
1557 m_parentage.push_back (cellstr_val(i)); | |
1558 } | |
1559 | |
1560 return is.good (); | |
1561 } | 350 } |
1562 | 351 |
1563 bool scoped_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name, | 352 octave_value fcn_val (void) { return m_fcn; } |
1564 bool) | 353 |
1565 { | 354 virtual octave_value workspace (void) const = 0; |
1566 #if defined (HAVE_HDF5) | 355 |
1567 | 356 // Should be const. |
1568 unimplemented ("save", "hdf5"); | 357 octave_scalar_map info (void); |
1569 | 358 |
1570 // FIXME: save parentage. | 359 bool save_ascii (std::ostream& os); |
1571 | 360 |
1572 octave_unused_parameter (loc_id); | 361 bool load_ascii (std::istream& is); |
1573 octave_unused_parameter (name); | 362 |
1574 | 363 bool save_binary (std::ostream& os, bool save_as_floats); |
1575 return true; | 364 |
1576 | 365 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); |
1577 #else | 366 |
1578 | 367 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, |
1579 octave_unused_parameter (loc_id); | 368 bool save_as_floats); |
1580 octave_unused_parameter (name); | 369 |
1581 | 370 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, |
1582 warn_save ("hdf5"); | 371 octave_hdf5_id& type_hid); |
1583 | 372 |
1584 return false; | 373 void print_raw (std::ostream&, bool pr_as_read_syntax, |
1585 | 374 int current_print_indent_level) const; |
1586 #endif | 375 |
1587 } | 376 protected: |
1588 | 377 |
1589 bool scoped_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | 378 // The function we are handling. |
1590 octave_hdf5_id& space_hid, | 379 octave_value m_fcn; |
1591 octave_hdf5_id& type_hid) | 380 }; |
1592 { | 381 |
1593 #if defined (HAVE_HDF5) | 382 class nested_fcn_handle : public base_nested_fcn_handle |
1594 | 383 { |
1595 unimplemented ("load", "hdf5"); | 384 public: |
1596 | 385 |
1597 // FIXME: load parentage. | 386 // FIXME: octaveroot is temporary information used when loading |
1598 | 387 // handles. Can we avoid using it in the constructor? |
1599 octave_unused_parameter (group_hid); | 388 |
1600 octave_unused_parameter (space_hid); | 389 nested_fcn_handle (const std::string& name = "", |
1601 octave_unused_parameter (type_hid); | 390 const std::string& file = "", |
1602 | 391 const std::string& octaveroot = "") |
1603 return true; | 392 : base_nested_fcn_handle (name, file, octaveroot) |
1604 | |
1605 #else | |
1606 | |
1607 octave_unused_parameter (group_hid); | |
1608 octave_unused_parameter (space_hid); | |
1609 octave_unused_parameter (type_hid); | |
1610 | |
1611 return false; | |
1612 | |
1613 #endif | |
1614 } | |
1615 | |
1616 void scoped_fcn_handle::print_raw (std::ostream& os, | |
1617 bool pr_as_read_syntax, | |
1618 int current_print_indent_level) const | |
1619 { | |
1620 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
1621 current_print_indent_level); | |
1622 } | |
1623 | |
1624 bool is_equal_to (const scoped_fcn_handle& fh1, const scoped_fcn_handle& fh2) | |
1625 { | |
1626 if (fh1.m_name == fh2.m_name | |
1627 && fh2.m_parentage == fh2.m_parentage | |
1628 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1629 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1630 else | |
1631 return false; | |
1632 } | |
1633 | |
1634 void scoped_fcn_handle::find_function (void) | |
1635 { | |
1636 // Since a scoped function is not visible by itself, try to load the | |
1637 // file named in m_file then find and define the scoped function. | |
1638 // It is not an error if this fails. We can report later that the | |
1639 // handle is invalid. | |
1640 | |
1641 symbol_table& symtab = __get_symbol_table__ (); | |
1642 | |
1643 if (m_parentage.size () == 1) | |
1644 { | |
1645 std::string dir_name = sys::file_ops::dirname (m_file); | |
1646 | |
1647 std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ()); | |
1648 | |
1649 if (pos != std::string::npos) | |
1650 dir_name = dir_name.substr (0, pos); | |
1651 else if (dir_name == "private") | |
1652 dir_name = "."; | |
1653 | |
1654 std::string fcn_name = m_parentage.front (); | |
1655 | |
1656 // FIXME: Does dir_name need to be in the load path for this to work? | |
1657 | |
1658 m_fcn = symtab.find_private_function (dir_name, m_name); | |
1659 | |
1660 // FIXME: Verify that it is a private function? | |
1661 } | |
1662 else | |
1663 { | |
1664 std::string primary_parent_name = m_parentage.back (); | |
1665 | |
1666 octave_value ov_parent_fcn | |
1667 = symtab.find_user_function (primary_parent_name); | |
1668 | |
1669 if (ov_parent_fcn.is_defined ()) | |
1670 { | |
1671 octave_user_function *fcn = ov_parent_fcn.user_function_value (); | |
1672 | |
1673 if (fcn) | |
1674 { | |
1675 std::string file_name = fcn->fcn_file_name (); | |
1676 | |
1677 std::string oct_home = config::octave_exec_home (); | |
1678 | |
1679 if (file_name.substr (0, oct_home.size ()) == oct_home) | |
1680 file_name = file_name.substr (oct_home.size ()); | |
1681 | |
1682 octave_value subfcn = fcn->find_subfunction (m_name); | |
1683 | |
1684 if (subfcn.is_defined ()) | |
1685 m_fcn = subfcn; | |
1686 } | |
1687 } | |
1688 } | |
1689 } | |
1690 | |
1691 octave_scalar_map base_nested_fcn_handle::info (void) | |
1692 { | |
1693 octave_scalar_map m; | |
1694 | |
1695 m.setfield ("function", fcn_name ()); | |
1696 m.setfield ("type", type ()); | |
1697 m.setfield ("file", ""); | |
1698 m.setfield ("workspace", workspace ()); | |
1699 | |
1700 return m; | |
1701 } | |
1702 | |
1703 // FIXME: For save, we need a way to save the (possibly shared) | |
1704 // workspace. For load, we need a way to load and link to the | |
1705 // (possibly shared) workspace that was saved. | |
1706 // | |
1707 // Since a nested function is not visible by itself, do we need to try | |
1708 // to load the file named in m_file then find and define the function? | |
1709 // Is it an error if that fails? Or should this job always be | |
1710 // deferred until the handle is used? | |
1711 | |
1712 bool base_nested_fcn_handle::save_ascii (std::ostream& os) | |
1713 { | |
1714 unimplemented ("save", "text"); | |
1715 | |
1716 octave_unused_parameter (os); | |
1717 | |
1718 return true; | |
1719 } | |
1720 | |
1721 bool base_nested_fcn_handle::load_ascii (std::istream& is) | |
1722 { | |
1723 unimplemented ("load", "text"); | |
1724 | |
1725 octave_unused_parameter (is); | |
1726 | |
1727 return true; | |
1728 } | |
1729 | |
1730 bool base_nested_fcn_handle::save_binary (std::ostream& os, | |
1731 bool save_as_floats) | |
1732 { | |
1733 unimplemented ("save", "binary"); | |
1734 | |
1735 octave_unused_parameter (os); | |
1736 octave_unused_parameter (save_as_floats); | |
1737 | |
1738 return true; | |
1739 } | |
1740 | |
1741 bool base_nested_fcn_handle::load_binary (std::istream& is, bool swap, | |
1742 mach_info::float_format fmt) | |
1743 { | |
1744 unimplemented ("load", "binary"); | |
1745 | |
1746 octave_unused_parameter (is); | |
1747 octave_unused_parameter (swap); | |
1748 octave_unused_parameter (fmt); | |
1749 | |
1750 return true; | |
1751 } | |
1752 | |
1753 bool base_nested_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, | |
1754 const char *name, bool) | |
1755 { | |
1756 #if defined (HAVE_HDF5) | |
1757 | |
1758 unimplemented ("save", "hdf5"); | |
1759 | |
1760 octave_unused_parameter (loc_id); | |
1761 octave_unused_parameter (name); | |
1762 | |
1763 return true; | |
1764 | |
1765 #else | |
1766 | |
1767 octave_unused_parameter (loc_id); | |
1768 octave_unused_parameter (name); | |
1769 | |
1770 warn_save ("hdf5"); | |
1771 | |
1772 return false; | |
1773 | |
1774 #endif | |
1775 } | |
1776 | |
1777 bool base_nested_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
1778 octave_hdf5_id& space_hid, | |
1779 octave_hdf5_id& type_hid) | |
1780 { | |
1781 #if defined (HAVE_HDF5) | |
1782 | |
1783 unimplemented ("load", "hdf5"); | |
1784 | |
1785 octave_unused_parameter (group_hid); | |
1786 octave_unused_parameter (space_hid); | |
1787 octave_unused_parameter (type_hid); | |
1788 | |
1789 return true; | |
1790 | |
1791 #else | |
1792 | |
1793 octave_unused_parameter (group_hid); | |
1794 octave_unused_parameter (space_hid); | |
1795 octave_unused_parameter (type_hid); | |
1796 | |
1797 return false; | |
1798 | |
1799 #endif | |
1800 } | |
1801 | |
1802 void base_nested_fcn_handle::print_raw (std::ostream& os, | |
1803 bool pr_as_read_syntax, | |
1804 int current_print_indent_level) const | |
1805 { | |
1806 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
1807 current_print_indent_level); | |
1808 } | |
1809 | |
1810 octave_value nested_fcn_handle::make_weak_nested_handle (void) const | |
1811 { | |
1812 return octave_value (new octave_fcn_handle | |
1813 (new weak_nested_fcn_handle (*this))); | |
1814 } | |
1815 | |
1816 octave_value_list | |
1817 nested_fcn_handle::call (int nargout, const octave_value_list& args) | |
1818 { | |
1819 tree_evaluator& tw = __get_evaluator__ (); | |
1820 | |
1821 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | |
1822 | |
1823 tw.push_stack_frame (oct_usr_fcn, m_stack_context); | |
1824 | |
1825 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
1826 | |
1827 return oct_usr_fcn->execute (tw, nargout, args); | |
1828 } | |
1829 | |
1830 octave_value nested_fcn_handle::workspace (void) const | |
1831 { | |
1832 return m_stack_context->workspace (); | |
1833 } | |
1834 | |
1835 bool is_equal_to (const nested_fcn_handle& fh1, const nested_fcn_handle& fh2) | |
1836 { | |
1837 if (fh1.m_name == fh2.m_name | |
1838 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1839 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1840 else | |
1841 return false; | |
1842 } | |
1843 | |
1844 octave_value_list | |
1845 weak_nested_fcn_handle::call (int nargout, const octave_value_list& args) | |
1846 { | |
1847 tree_evaluator& tw = __get_evaluator__ (); | |
1848 | |
1849 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | |
1850 | |
1851 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | |
1852 | |
1853 tw.push_stack_frame (oct_usr_fcn, frames); | |
1854 | |
1855 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
1856 | |
1857 return oct_usr_fcn->execute (tw, nargout, args); | |
1858 } | |
1859 | |
1860 octave_value weak_nested_fcn_handle::workspace (void) const | |
1861 { | |
1862 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | |
1863 | |
1864 return frames ? frames->workspace () : octave_value (); | |
1865 } | |
1866 | |
1867 bool is_equal_to (const weak_nested_fcn_handle& fh1, | |
1868 const weak_nested_fcn_handle& fh2) | |
1869 { | |
1870 if (fh1.m_name == fh2.m_name | |
1871 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1872 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1873 else | |
1874 return false; | |
1875 } | |
1876 | |
1877 class_simple_fcn_handle::class_simple_fcn_handle (const std::string& class_nm, | |
1878 const std::string& meth_nm) | |
1879 : base_fcn_handle (meth_nm), m_obj (), m_fcn (), | |
1880 m_dispatch_class (class_nm) | |
1881 { } | 393 { } |
1882 | 394 |
1883 class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& fcn, | 395 nested_fcn_handle (const octave_value& fcn, const std::string& name, |
1884 const std::string& class_nm, | 396 const std::shared_ptr<stack_frame>& stack_context) |
1885 const std::string& meth_nm) | 397 : base_nested_fcn_handle (fcn, name), m_stack_context (stack_context) |
1886 : base_fcn_handle (meth_nm), m_obj (), m_fcn (fcn), | |
1887 m_dispatch_class (class_nm) | |
1888 { } | |
1889 | |
1890 class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& obj, | |
1891 const octave_value& fcn, | |
1892 const std::string& class_nm, | |
1893 const std::string& meth_nm) | |
1894 : base_fcn_handle (meth_nm), m_obj (obj), m_fcn (fcn), | |
1895 m_dispatch_class (class_nm) | |
1896 { } | |
1897 | |
1898 octave_value_list | |
1899 class_simple_fcn_handle::call (int nargout, const octave_value_list& args) | |
1900 { | |
1901 interpreter& interp = __get_interpreter__ (); | |
1902 | |
1903 if (m_obj.is_defined ()) | |
1904 { | |
1905 octave_value_list tmp_args = args; | |
1906 tmp_args.prepend (m_obj); | |
1907 | |
1908 return interp.feval (m_fcn, tmp_args, nargout); | |
1909 } | |
1910 | |
1911 // FIXME: is this the best approach? Should we be saving current | |
1912 // dispatch class and restoring that value instead of | |
1913 // unconditionally setting it to "" when we return from this | |
1914 // function? | |
1915 | |
1916 tree_evaluator& tw = interp.get_evaluator (); | |
1917 | |
1918 unwind_action act ([&tw] () { tw.set_dispatch_class (""); }); | |
1919 | |
1920 tw.set_dispatch_class (m_dispatch_class); | |
1921 | |
1922 if (m_fcn.is_defined ()) | |
1923 return interp.feval (m_fcn, args, nargout); | |
1924 | |
1925 return interp.feval (fcn_name (), args, nargout); | |
1926 } | |
1927 | |
1928 octave_scalar_map class_simple_fcn_handle::info (void) | |
1929 { | |
1930 octave_scalar_map m; | |
1931 | |
1932 m.setfield ("function", fcn_name ()); | |
1933 m.setfield ("type", type ()); | |
1934 m.setfield ("file", ""); | |
1935 m.setfield ("class", dispatch_class ()); | |
1936 | |
1937 return m; | |
1938 } | |
1939 | |
1940 // FIXME: Since a class method is not visible by itself, do we need to | |
1941 // try to load the file named in m_file then find and define the | |
1942 // function? Is it an error if that fails? Or should this job always | |
1943 // be deferred until the handle is used? | |
1944 | |
1945 bool class_simple_fcn_handle::save_ascii (std::ostream& os) | |
1946 { | |
1947 unimplemented ("save", "text"); | |
1948 | |
1949 octave_unused_parameter (os); | |
1950 | |
1951 return true; | |
1952 } | |
1953 | |
1954 bool class_simple_fcn_handle::load_ascii (std::istream& is) | |
1955 { | |
1956 unimplemented ("load", "text"); | |
1957 | |
1958 octave_unused_parameter (is); | |
1959 | |
1960 return true; | |
1961 } | |
1962 | |
1963 bool class_simple_fcn_handle::save_binary (std::ostream& os, | |
1964 bool save_as_floats) | |
1965 { | |
1966 unimplemented ("save", "binary"); | |
1967 | |
1968 octave_unused_parameter (os); | |
1969 octave_unused_parameter (save_as_floats); | |
1970 | |
1971 return true; | |
1972 } | |
1973 | |
1974 bool class_simple_fcn_handle::load_binary (std::istream& is, bool swap, | |
1975 mach_info::float_format fmt) | |
1976 { | |
1977 unimplemented ("load", "binary"); | |
1978 | |
1979 octave_unused_parameter (is); | |
1980 octave_unused_parameter (swap); | |
1981 octave_unused_parameter (fmt); | |
1982 | |
1983 return true; | |
1984 } | |
1985 | |
1986 bool class_simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, | |
1987 const char *name, bool) | |
1988 { | |
1989 #if defined (HAVE_HDF5) | |
1990 | |
1991 unimplemented ("save", "hdf5"); | |
1992 | |
1993 octave_unused_parameter (loc_id); | |
1994 octave_unused_parameter (name); | |
1995 | |
1996 return true; | |
1997 | |
1998 #else | |
1999 | |
2000 octave_unused_parameter (loc_id); | |
2001 octave_unused_parameter (name); | |
2002 | |
2003 warn_save ("hdf5"); | |
2004 | |
2005 return false; | |
2006 | |
2007 #endif | |
2008 } | |
2009 | |
2010 bool class_simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
2011 octave_hdf5_id& space_hid, | |
2012 octave_hdf5_id& type_hid) | |
2013 { | |
2014 #if defined (HAVE_HDF5) | |
2015 | |
2016 unimplemented ("load", "hdf5"); | |
2017 | |
2018 octave_unused_parameter (group_hid); | |
2019 octave_unused_parameter (space_hid); | |
2020 octave_unused_parameter (type_hid); | |
2021 | |
2022 return true; | |
2023 | |
2024 #else | |
2025 | |
2026 octave_unused_parameter (group_hid); | |
2027 octave_unused_parameter (space_hid); | |
2028 octave_unused_parameter (type_hid); | |
2029 | |
2030 return false; | |
2031 | |
2032 #endif | |
2033 } | |
2034 | |
2035 void class_simple_fcn_handle::print_raw (std::ostream& os, | |
2036 bool pr_as_read_syntax, | |
2037 int current_print_indent_level) const | |
2038 { | |
2039 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
2040 current_print_indent_level); | |
2041 } | |
2042 | |
2043 bool is_equal_to (const class_simple_fcn_handle& fh1, | |
2044 const class_simple_fcn_handle& fh2) | |
2045 { | |
2046 // FIXME: Also need to check object values are equivalent? | |
2047 | |
2048 if (fh1.m_name == fh2.m_name | |
2049 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
2050 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
2051 else | |
2052 return false; | |
2053 } | |
2054 | |
2055 const std::string base_anonymous_fcn_handle::anonymous ("@<anonymous>"); | |
2056 | |
2057 octave_scalar_map base_anonymous_fcn_handle::info (void) | |
2058 { | |
2059 octave_scalar_map m; | |
2060 | |
2061 std::ostringstream buf; | |
2062 print_raw (buf, true, 0); | |
2063 m.setfield ("function", buf.str ()); | |
2064 | |
2065 m.setfield ("type", type ()); | |
2066 m.setfield ("file", ""); | |
2067 m.setfield ("workspace", workspace ()); | |
2068 m.setfield ("within_file_path", ""); | |
2069 | |
2070 return m; | |
2071 } | |
2072 | |
2073 bool base_anonymous_fcn_handle::save_ascii (std::ostream& os) | |
2074 { | |
2075 // FIXME: can we ensure that m_fcn is always defined? | |
2076 | |
2077 if (m_fcn.is_undefined ()) | |
2078 return false; | |
2079 | |
2080 os << m_name << "\n"; | |
2081 | |
2082 print_raw (os, true, 0); | |
2083 os << "\n"; | |
2084 | |
2085 std::size_t varlen = m_local_vars.size (); | |
2086 | |
2087 if (varlen > 0) | |
2088 { | |
2089 os << "# length: " << varlen << "\n"; | |
2090 | |
2091 for (const auto& nm_val : m_local_vars) | |
2092 { | |
2093 if (! save_text_data (os, nm_val.second, nm_val.first, false, 0)) | |
2094 return ! os.fail (); | |
2095 } | |
2096 } | |
2097 | |
2098 return true; | |
2099 } | |
2100 | |
2101 bool base_anonymous_fcn_handle::load_ascii (std::istream& is) | |
2102 { | |
2103 octave::skip_preceeding_newline (is); | |
2104 | |
2105 std::string buf; | |
2106 | |
2107 if (is) | |
2108 { | |
2109 // Get a line of text whitespace characters included, leaving | |
2110 // newline in the stream. | |
2111 | |
2112 buf = octave::read_until_newline (is, true); | |
2113 } | |
2114 | |
2115 std::streampos pos = is.tellg (); | |
2116 | |
2117 // Set up temporary scope to use for evaluating the text that | |
2118 // defines the anonymous function. | |
2119 | |
2120 interpreter& interp = __get_interpreter__ (); | |
2121 | |
2122 tree_evaluator& tw = interp.get_evaluator (); | |
2123 | |
2124 tw.push_dummy_scope (buf); | |
2125 unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw); | |
2126 | |
2127 octave_idx_type len = 0; | |
2128 | |
2129 if (extract_keyword (is, "length", len, true) && len >= 0) | |
2130 { | |
2131 if (len > 0) | |
2132 { | |
2133 for (octave_idx_type i = 0; i < len; i++) | |
2134 { | |
2135 octave_value t2; | |
2136 bool dummy; | |
2137 | |
2138 std::string name = read_text_data (is, "", dummy, t2, i); | |
2139 | |
2140 if (! is) | |
2141 error ("load: failed to load anonymous function handle"); | |
2142 | |
2143 m_local_vars[name] = t2; | |
2144 } | |
2145 } | |
2146 } | |
2147 else | |
2148 { | |
2149 is.seekg (pos); | |
2150 is.clear (); | |
2151 } | |
2152 | |
2153 if (is) | |
2154 return parse (buf); | |
2155 | |
2156 return false; | |
2157 } | |
2158 | |
2159 bool base_anonymous_fcn_handle::save_binary (std::ostream& os, | |
2160 bool save_as_floats) | |
2161 { | |
2162 // FIXME: can we ensure that m_fcn is always defined? | |
2163 | |
2164 if (m_fcn.is_undefined ()) | |
2165 return false; | |
2166 | |
2167 std::ostringstream nmbuf; | |
2168 | |
2169 std::size_t varlen = m_local_vars.size (); | |
2170 | |
2171 nmbuf << anonymous; | |
2172 if (varlen > 0) | |
2173 nmbuf << ' ' << varlen; | |
2174 | |
2175 std::string buf_str = nmbuf.str (); | |
2176 int32_t tmp = buf_str.length (); | |
2177 os.write (reinterpret_cast<char *> (&tmp), 4); | |
2178 os.write (buf_str.c_str (), buf_str.length ()); | |
2179 | |
2180 std::ostringstream buf; | |
2181 print_raw (buf, true, 0); | |
2182 std::string stmp = buf.str (); | |
2183 tmp = stmp.length (); | |
2184 os.write (reinterpret_cast<char *> (&tmp), 4); | |
2185 os.write (stmp.c_str (), stmp.length ()); | |
2186 | |
2187 if (varlen > 0) | |
2188 { | |
2189 for (const auto& nm_val : m_local_vars) | |
2190 { | |
2191 if (! save_binary_data (os, nm_val.second, nm_val.first, | |
2192 "", 0, save_as_floats)) | |
2193 return ! os.fail (); | |
2194 } | |
2195 } | |
2196 | |
2197 return true; | |
2198 } | |
2199 | |
2200 bool base_anonymous_fcn_handle::load_binary (std::istream& is, bool swap, | |
2201 mach_info::float_format fmt) | |
2202 { | |
2203 // Read extra characters in m_name as the number of local variable | |
2204 // values in this anonymous function. | |
2205 | |
2206 octave_idx_type len = 0; | |
2207 std::size_t anl = anonymous.length (); | |
2208 if (m_name.length () > anl) | |
2209 { | |
2210 std::istringstream nm_is (m_name.substr (anl)); | |
2211 nm_is >> len; | |
2212 | |
2213 // Anonymous functions don't have names. We just used this | |
2214 // string as temporary storage to pass the number of local | |
2215 // variable values. | |
2216 | |
2217 m_name = ""; | |
2218 } | |
2219 | |
2220 int32_t tmp; | |
2221 | |
2222 if (! is.read (reinterpret_cast<char *> (&tmp), 4)) | |
2223 return false; | |
2224 if (swap) | |
2225 swap_bytes<4> (&tmp); | |
2226 | |
2227 OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1); | |
2228 // is.get (ctmp2, tmp+1, 0); caused is.eof () to be true though | |
2229 // effectively not reading over file end | |
2230 is.read (ctmp2, tmp); | |
2231 ctmp2[tmp] = 0; | |
2232 | |
2233 // Set up temporary scope to use for evaluating the text that | |
2234 // defines the anonymous function. | |
2235 | |
2236 interpreter& interp = __get_interpreter__ (); | |
2237 | |
2238 tree_evaluator& tw = interp.get_evaluator (); | |
2239 | |
2240 tw.push_dummy_scope (ctmp2); | |
2241 unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw); | |
2242 | |
2243 if (len > 0) | |
2244 { | |
2245 for (octave_idx_type i = 0; i < len; i++) | |
2246 { | |
2247 octave_value t2; | |
2248 bool dummy; | |
2249 std::string doc; | |
2250 | |
2251 std::string name | |
2252 = read_binary_data (is, swap, fmt, "", dummy, t2, doc); | |
2253 | |
2254 if (! is) | |
2255 error ("load: failed to load anonymous function handle"); | |
2256 | |
2257 m_local_vars[name] = t2; | |
2258 } | |
2259 } | |
2260 | |
2261 if (is) | |
2262 return parse (ctmp2); | |
2263 | |
2264 return false; | |
2265 } | |
2266 | |
2267 bool base_anonymous_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, | |
2268 const char *name, | |
2269 bool save_as_floats) | |
2270 { | |
2271 #if defined (HAVE_HDF5) | |
2272 | |
2273 bool retval = true; | |
2274 | |
2275 octave_hdf5_id group_hid = -1; | |
2276 #if defined (HAVE_HDF5_18) | |
2277 group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2278 octave_H5P_DEFAULT); | |
2279 #else | |
2280 group_hid = H5Gcreate (loc_id, name, 0); | |
2281 #endif | |
2282 if (group_hid < 0) | |
2283 return false; | |
2284 | |
2285 octave_hdf5_id space_hid, data_hid, type_hid; | |
2286 space_hid = data_hid = type_hid = -1; | |
2287 | |
2288 // attach the type of the variable | |
2289 type_hid = H5Tcopy (H5T_C_S1); | |
2290 H5Tset_size (type_hid, m_name.length () + 1); | |
2291 if (type_hid < 0) | |
2292 { | |
2293 H5Gclose (group_hid); | |
2294 return false; | |
2295 } | |
2296 | |
2297 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2); | |
2298 hdims[0] = 0; | |
2299 hdims[1] = 0; | |
2300 space_hid = H5Screate_simple (0, hdims, nullptr); | |
2301 if (space_hid < 0) | |
2302 { | |
2303 H5Tclose (type_hid); | |
2304 H5Gclose (group_hid); | |
2305 return false; | |
2306 } | |
2307 #if defined (HAVE_HDF5_18) | |
2308 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
2309 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2310 octave_H5P_DEFAULT); | |
2311 #else | |
2312 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
2313 octave_H5P_DEFAULT); | |
2314 #endif | |
2315 if (data_hid < 0 | |
2316 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, | |
2317 octave_H5P_DEFAULT, m_name.c_str ()) < 0) | |
2318 { | |
2319 H5Sclose (space_hid); | |
2320 H5Tclose (type_hid); | |
2321 H5Gclose (group_hid); | |
2322 return false; | |
2323 } | |
2324 H5Dclose (data_hid); | |
2325 | |
2326 std::ostringstream buf; | |
2327 print_raw (buf, true, 0); | |
2328 std::string stmp = buf.str (); | |
2329 | |
2330 // attach the type of the variable | |
2331 H5Tset_size (type_hid, stmp.length () + 1); | |
2332 if (type_hid < 0) | |
2333 { | |
2334 H5Sclose (space_hid); | |
2335 H5Gclose (group_hid); | |
2336 return false; | |
2337 } | |
2338 | |
2339 #if defined (HAVE_HDF5_18) | |
2340 data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid, | |
2341 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2342 octave_H5P_DEFAULT); | |
2343 #else | |
2344 data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid, | |
2345 octave_H5P_DEFAULT); | |
2346 #endif | |
2347 if (data_hid < 0 | |
2348 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, | |
2349 octave_H5P_DEFAULT, stmp.c_str ()) < 0) | |
2350 { | |
2351 H5Sclose (space_hid); | |
2352 H5Tclose (type_hid); | |
2353 H5Gclose (group_hid); | |
2354 return false; | |
2355 } | |
2356 | |
2357 H5Dclose (data_hid); | |
2358 | |
2359 std::size_t varlen = m_local_vars.size (); | |
2360 | |
2361 if (varlen > 0) | |
2362 { | |
2363 octave_hdf5_id as_id = H5Screate (H5S_SCALAR); | |
2364 | |
2365 if (as_id >= 0) | |
2366 { | |
2367 octave_hdf5_id a_id; | |
2368 #if defined (HAVE_HDF5_18) | |
2369 a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id, | |
2370 octave_H5P_DEFAULT, octave_H5P_DEFAULT); | |
2371 | |
2372 #else | |
2373 a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id, | |
2374 octave_H5P_DEFAULT); | |
2375 #endif | |
2376 | |
2377 if (a_id >= 0) | |
2378 { | |
2379 retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0); | |
2380 | |
2381 H5Aclose (a_id); | |
2382 } | |
2383 else | |
2384 retval = false; | |
2385 | |
2386 H5Sclose (as_id); | |
2387 } | |
2388 else | |
2389 retval = false; | |
2390 #if defined (HAVE_HDF5_18) | |
2391 data_hid = H5Gcreate (group_hid, "symbol table", | |
2392 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2393 octave_H5P_DEFAULT); | |
2394 #else | |
2395 data_hid = H5Gcreate (group_hid, "symbol table", 0); | |
2396 #endif | |
2397 if (data_hid < 0) | |
2398 { | |
2399 H5Sclose (space_hid); | |
2400 H5Tclose (type_hid); | |
2401 H5Gclose (group_hid); | |
2402 return false; | |
2403 } | |
2404 | |
2405 for (const auto& nm_val : m_local_vars) | |
2406 { | |
2407 if (! add_hdf5_data (data_hid, nm_val.second, nm_val.first, | |
2408 "", false, save_as_floats)) | |
2409 break; | |
2410 } | |
2411 | |
2412 H5Gclose (data_hid); | |
2413 } | |
2414 | |
2415 H5Sclose (space_hid); | |
2416 H5Tclose (type_hid); | |
2417 H5Gclose (group_hid); | |
2418 | |
2419 return retval; | |
2420 | |
2421 #else | |
2422 | |
2423 octave_unused_parameter (loc_id); | |
2424 octave_unused_parameter (name); | |
2425 octave_unused_parameter (save_as_floats); | |
2426 | |
2427 warn_save ("hdf5"); | |
2428 | |
2429 return false; | |
2430 | |
2431 #endif | |
2432 } | |
2433 | |
2434 bool base_anonymous_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
2435 octave_hdf5_id& space_hid, | |
2436 octave_hdf5_id& type_hid) | |
2437 { | |
2438 #if defined (HAVE_HDF5) | |
2439 | |
2440 bool success = true; | |
2441 | |
2442 #if defined (HAVE_HDF5_18) | |
2443 octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn", octave_H5P_DEFAULT); | |
2444 #else | |
2445 octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn"); | |
2446 #endif | |
2447 | |
2448 if (data_hid < 0) | |
2449 { | |
2450 H5Sclose (space_hid); | |
2451 H5Tclose (type_hid); | |
2452 H5Gclose (group_hid); | |
2453 return false; | |
2454 } | |
2455 | |
2456 H5Tclose (type_hid); | |
2457 type_hid = H5Dget_type (data_hid); | |
2458 octave_hdf5_id type_class_hid = H5Tget_class (type_hid); | |
2459 | |
2460 if (type_class_hid != H5T_STRING) | |
2461 { | |
2462 H5Sclose (space_hid); | |
2463 H5Tclose (type_hid); | |
2464 H5Dclose (data_hid); | |
2465 H5Gclose (group_hid); | |
2466 return false; | |
2467 } | |
2468 | |
2469 H5Sclose (space_hid); | |
2470 space_hid = H5Dget_space (data_hid); | |
2471 hsize_t rank = H5Sget_simple_extent_ndims (space_hid); | |
2472 | |
2473 if (rank != 0) | |
2474 { | |
2475 H5Sclose (space_hid); | |
2476 H5Tclose (type_hid); | |
2477 H5Dclose (data_hid); | |
2478 H5Gclose (group_hid); | |
2479 return false; | |
2480 } | |
2481 | |
2482 int slen = H5Tget_size (type_hid); | |
2483 if (slen < 0) | |
2484 { | |
2485 H5Sclose (space_hid); | |
2486 H5Tclose (type_hid); | |
2487 H5Dclose (data_hid); | |
2488 H5Gclose (group_hid); | |
2489 return false; | |
2490 } | |
2491 | |
2492 OCTAVE_LOCAL_BUFFER (char, fcn_tmp, slen); | |
2493 | |
2494 // create datatype for (null-terminated) string to read into: | |
2495 octave_hdf5_id st_id = H5Tcopy (H5T_C_S1); | |
2496 H5Tset_size (st_id, slen); | |
2497 | |
2498 if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL, | |
2499 octave_H5P_DEFAULT, fcn_tmp) | |
2500 < 0) | |
2501 { | |
2502 H5Tclose (st_id); | |
2503 H5Sclose (space_hid); | |
2504 H5Tclose (type_hid); | |
2505 H5Dclose (data_hid); | |
2506 H5Gclose (group_hid); | |
2507 return false; | |
2508 } | |
2509 H5Tclose (st_id); | |
2510 H5Dclose (data_hid); | |
2511 | |
2512 octave_idx_type len = 0; | |
2513 | |
2514 // we have to pull some shenanigans here to make sure | |
2515 // HDF5 doesn't print out all sorts of error messages if we | |
2516 // call H5Aopen for a non-existing attribute | |
2517 | |
2518 H5E_auto_t err_fcn; | |
2519 void *err_fcn_data; | |
2520 | |
2521 // turn off error reporting temporarily, but save the error | |
2522 // reporting function: | |
2523 #if defined (HAVE_HDF5_18) | |
2524 H5Eget_auto (octave_H5E_DEFAULT, &err_fcn, &err_fcn_data); | |
2525 H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr); | |
2526 #else | |
2527 H5Eget_auto (&err_fcn, &err_fcn_data); | |
2528 H5Eset_auto (nullptr, nullptr); | |
2529 #endif | |
2530 | |
2531 octave_hdf5_id attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE"); | |
2532 | |
2533 if (attr_id >= 0) | |
2534 { | |
2535 if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0) | |
2536 success = false; | |
2537 | |
2538 H5Aclose (attr_id); | |
2539 } | |
2540 | |
2541 // restore error reporting: | |
2542 #if defined (HAVE_HDF5_18) | |
2543 H5Eset_auto (octave_H5E_DEFAULT, err_fcn, err_fcn_data); | |
2544 #else | |
2545 H5Eset_auto (err_fcn, err_fcn_data); | |
2546 #endif | |
2547 | |
2548 // Set up temporary scope to use for evaluating the text that | |
2549 // defines the anonymous function. | |
2550 | |
2551 interpreter& interp = __get_interpreter__ (); | |
2552 | |
2553 tree_evaluator& tw = interp.get_evaluator (); | |
2554 | |
2555 tw.push_dummy_scope (fcn_tmp); | |
2556 unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw); | |
2557 | |
2558 if (len > 0 && success) | |
2559 { | |
2560 hsize_t num_obj = 0; | |
2561 #if defined (HAVE_HDF5_18) | |
2562 data_hid = H5Gopen (group_hid, "symbol table", octave_H5P_DEFAULT); | |
2563 #else | |
2564 data_hid = H5Gopen (group_hid, "symbol table"); | |
2565 #endif | |
2566 H5Gget_num_objs (data_hid, &num_obj); | |
2567 H5Gclose (data_hid); | |
2568 | |
2569 if (num_obj != static_cast<hsize_t> (len)) | |
2570 error ("load: failed to load anonymous function handle"); | |
2571 | |
2572 hdf5_callback_data dsub; | |
2573 int current_item = 0; | |
2574 for (octave_idx_type i = 0; i < len; i++) | |
2575 { | |
2576 if (hdf5_h5g_iterate (group_hid, "symbol table", ¤t_item, | |
2577 &dsub) <= 0) | |
2578 error ("load: failed to load anonymous function handle"); | |
2579 | |
2580 m_local_vars[dsub.name] = dsub.tc; | |
2581 } | |
2582 } | |
2583 | |
2584 if (success) | |
2585 return parse (fcn_tmp); | |
2586 | |
2587 return false; | |
2588 | |
2589 #else | |
2590 | |
2591 octave_unused_parameter (group_hid); | |
2592 octave_unused_parameter (space_hid); | |
2593 octave_unused_parameter (type_hid); | |
2594 | |
2595 return false; | |
2596 | |
2597 #endif | |
2598 } | |
2599 | |
2600 void base_anonymous_fcn_handle::print_raw (std::ostream& os, bool, int) const | |
2601 { | |
2602 tree_print_code tpc (os); | |
2603 | |
2604 octave_user_function *f = m_fcn.user_function_value (); | |
2605 | |
2606 if (! f) | |
2607 error ("invalid anonymous function handle"); | |
2608 | |
2609 os << "@"; | |
2610 | |
2611 // The parameter list should always be valid for anonymous | |
2612 // functions, so we should always call accept for it, and it will | |
2613 // print the parens for us. | |
2614 | |
2615 tree_parameter_list *p = f->parameter_list (); | |
2616 | |
2617 if (p) | |
2618 p->accept (tpc); | |
2619 | |
2620 os << " "; | |
2621 | |
2622 tree_statement_list *b = f->body (); | |
2623 | |
2624 panic_if (b->length () != 1); | |
2625 | |
2626 tree_statement *s = b->front (); | |
2627 | |
2628 if (! s) | |
2629 error ("invalid anonymous function handle"); | |
2630 | |
2631 panic_unless (s->is_expression ()); | |
2632 | |
2633 tree_expression *e = s->expression (); | |
2634 | |
2635 if (! e) | |
2636 error ("invalid anonymous function handle"); | |
2637 | |
2638 tpc.print_fcn_handle_body (e); | |
2639 } | |
2640 | |
2641 bool base_anonymous_fcn_handle::parse (const std::string& fcn_text) | |
2642 { | |
2643 // FIXME: If evaluation of the string gives us an anonymous function | |
2644 // handle object, then why extract the function and create a new | |
2645 // anonymous function object? Why not just attach the workspace | |
2646 // values to the object returned by eval_string? This code is also is | |
2647 // duplicated in read_mat5_binary_element in ls-mat5.cc. | |
2648 | |
2649 interpreter& interp = __get_interpreter__ (); | |
2650 | |
2651 // Set up temporary scope to use for evaluating the text that defines | |
2652 // the anonymous function so that we don't pick up values of random | |
2653 // variables that might be in the current scope. | |
2654 | |
2655 tree_evaluator& tw = interp.get_evaluator (); | |
2656 tw.push_dummy_scope ("read_mat5_binary_element"); | |
2657 | |
2658 unwind_action act ([&tw] () { tw.pop_scope (); }); | |
2659 | |
2660 int parse_status; | |
2661 octave_value anonymous_fcn_hdl | |
2662 = interp.eval_string (fcn_text, true, parse_status); | |
2663 | |
2664 if (parse_status != 0) | |
2665 return false; | |
2666 | |
2667 octave_fcn_handle *fh = anonymous_fcn_hdl.fcn_handle_value (); | |
2668 | |
2669 if (! fh) | |
2670 return false; | |
2671 | |
2672 m_fcn = fh->fcn_val (); | |
2673 | |
2674 octave_user_function *uf = m_fcn.user_function_value (true); | |
2675 | |
2676 if (uf) | |
2677 { | |
2678 symbol_scope uf_scope = uf->scope (); | |
2679 | |
2680 if (uf_scope) | |
2681 uf_scope.cache_name (m_name); | |
2682 } | |
2683 | |
2684 return true; | |
2685 } | |
2686 | |
2687 anonymous_fcn_handle::anonymous_fcn_handle (const octave_value& fcn, | |
2688 const stack_frame::local_vars_map& local_vars, | |
2689 const std::shared_ptr<stack_frame>& stack_context) | |
2690 : base_anonymous_fcn_handle (fcn, local_vars), | |
2691 m_stack_context (stack_context) | |
2692 { | 398 { |
2693 if (m_stack_context) | 399 if (m_stack_context) |
2694 m_stack_context->mark_closure_context (); | 400 m_stack_context->mark_closure_context (); |
2695 } | 401 } |
2696 | 402 |
2697 octave_value anonymous_fcn_handle::make_weak_anonymous_handle (void) const | 403 nested_fcn_handle (const nested_fcn_handle&) = default; |
404 | |
405 ~nested_fcn_handle (void) = default; | |
406 | |
407 using base_nested_fcn_handle::is_nested; | |
408 | |
409 bool is_nested (const std::shared_ptr<stack_frame>& frame) const | |
2698 { | 410 { |
2699 return octave_value (new octave_fcn_handle | 411 return frame == m_stack_context; |
2700 (new weak_anonymous_fcn_handle (*this))); | |
2701 } | 412 } |
2702 | 413 |
2703 octave_value_list | 414 nested_fcn_handle * clone (void) const |
2704 anonymous_fcn_handle::call (int nargout, const octave_value_list& args) | |
2705 { | 415 { |
2706 tree_evaluator& tw = __get_evaluator__ (); | 416 return new nested_fcn_handle (*this); |
2707 | |
2708 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | |
2709 | |
2710 tw.push_stack_frame (oct_usr_fcn, m_local_vars, m_stack_context); | |
2711 | |
2712 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
2713 | |
2714 return oct_usr_fcn->execute (tw, nargout, args); | |
2715 } | 417 } |
2716 | 418 |
2717 octave_value anonymous_fcn_handle::workspace (void) const | 419 octave_value make_weak_nested_handle (void) const; |
420 | |
421 octave_value_list call (int nargout, const octave_value_list& args); | |
422 | |
423 octave_value workspace (void) const; | |
424 | |
425 friend bool is_equal_to (const nested_fcn_handle& fh1, | |
426 const nested_fcn_handle& fh2); | |
427 | |
428 std::shared_ptr<stack_frame> stack_context (void) const | |
2718 { | 429 { |
2719 octave_scalar_map local_vars_map; | 430 return m_stack_context; |
2720 | 431 } |
2721 for (const auto& nm_val : m_local_vars) | 432 |
2722 local_vars_map.assign (nm_val.first, nm_val.second); | 433 protected: |
2723 | 434 |
2724 // FIXME: it would be more convenient if stack_frame::workspace | 435 // Pointer to closure stack frames. |
2725 // returned a Cell object directly instead of a Cell in an | 436 std::shared_ptr<stack_frame> m_stack_context; |
2726 // octave_value object. | 437 }; |
2727 | 438 |
2728 Cell cell_frames; | 439 class weak_nested_fcn_handle : public base_nested_fcn_handle |
2729 | 440 { |
2730 if (m_stack_context) | 441 public: |
442 | |
443 weak_nested_fcn_handle (const nested_fcn_handle& nfh) | |
444 : base_nested_fcn_handle (nfh), m_stack_context (nfh.stack_context ()) | |
445 { } | |
446 | |
447 weak_nested_fcn_handle (const weak_nested_fcn_handle&) = default; | |
448 | |
449 ~weak_nested_fcn_handle (void) = default; | |
450 | |
451 weak_nested_fcn_handle * clone (void) const | |
452 { | |
453 return new weak_nested_fcn_handle (*this); | |
454 } | |
455 | |
456 bool is_weak_nested (void) const { return true; } | |
457 | |
458 octave_value_list call (int nargout, const octave_value_list& args); | |
459 | |
460 octave_value workspace (void) const; | |
461 | |
462 friend bool is_equal_to (const weak_nested_fcn_handle& fh1, | |
463 const weak_nested_fcn_handle& fh2); | |
464 | |
465 protected: | |
466 | |
467 // Pointer to closure stack frames. | |
468 std::weak_ptr<stack_frame> m_stack_context; | |
469 }; | |
470 | |
471 class class_simple_fcn_handle : public base_fcn_handle | |
472 { | |
473 public: | |
474 | |
475 // FIXME: octaveroot is temporary information used when loading | |
476 // handles. Can we avoid using it in the constructor? | |
477 | |
478 class_simple_fcn_handle (const std::string& name, | |
479 const std::string& file, | |
480 const std::string& /*octaveroot*/) | |
481 : base_fcn_handle (name, file) | |
482 { } | |
483 | |
484 // FIXME: is the method name supposed to be just the method name or | |
485 // also contain the object name? | |
486 | |
487 class_simple_fcn_handle (const std::string& class_nm, | |
488 const std::string& meth_nm); | |
489 | |
490 class_simple_fcn_handle (const octave_value& fcn, | |
491 const std::string& class_nm, | |
492 const std::string& meth_nm); | |
493 | |
494 class_simple_fcn_handle (const octave_value& obj, const octave_value& fcn, | |
495 const std::string& class_nm, | |
496 const std::string& meth_nm); | |
497 | |
498 class_simple_fcn_handle (const class_simple_fcn_handle&) = default; | |
499 | |
500 ~class_simple_fcn_handle (void) = default; | |
501 | |
502 class_simple_fcn_handle * clone (void) const | |
503 { | |
504 return new class_simple_fcn_handle (*this); | |
505 } | |
506 | |
507 std::string type (void) const { return "classsimple"; } | |
508 | |
509 bool is_class_simple (void) const { return true; } | |
510 | |
511 octave_value_list call (int nargout, const octave_value_list& args); | |
512 | |
513 // FIXME: These must go away. They don't do the right thing for | |
514 // scoping or overloads. | |
515 octave_function * function_value (bool = false) | |
516 { | |
517 // FIXME: Shouldn't the lookup rules here match those used in the | |
518 // call method? | |
519 | |
520 if (m_fcn.is_defined ()) | |
521 return m_fcn.function_value (); | |
522 | |
523 symbol_table& symtab = __get_symbol_table__ (); | |
524 | |
525 // FIXME: is caching the correct thing to do? | |
526 // Cache this value so that the pointer will be valid as long as the | |
527 // function handle object is valid. | |
528 | |
529 // FIXME: This should probably dispatch to the respective class method. | |
530 // But that breaks if a function handle is used in a class method with | |
531 // e.g. bsxfun with arguments of a different class (see bug #59661). | |
532 // m_fcn = symtab.find_method (m_name, m_dispatch_class); | |
533 m_fcn = symtab.find_function (m_name, octave_value_list ()); | |
534 | |
535 return m_fcn.is_defined () ? m_fcn.function_value () : nullptr; | |
536 } | |
537 | |
538 octave_user_function * user_function_value (bool = false) | |
539 { | |
540 return m_fcn.user_function_value (); | |
541 } | |
542 | |
543 octave_value fcn_val (void) { return m_fcn; } | |
544 | |
545 // Should be const. | |
546 octave_scalar_map info (void); | |
547 | |
548 std::string dispatch_class (void) const { return m_dispatch_class; } | |
549 | |
550 bool save_ascii (std::ostream& os); | |
551 | |
552 bool load_ascii (std::istream& is); | |
553 | |
554 bool save_binary (std::ostream& os, bool save_as_floats); | |
555 | |
556 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
557 | |
558 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
559 bool save_as_floats); | |
560 | |
561 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
562 octave_hdf5_id& type_hid); | |
563 | |
564 void print_raw (std::ostream&, bool pr_as_read_syntax, | |
565 int current_print_indent_level) const; | |
566 | |
567 friend bool is_equal_to (const class_simple_fcn_handle& fh1, | |
568 const class_simple_fcn_handle& fh2); | |
569 | |
570 protected: | |
571 | |
572 // The object containing the method we are handing. | |
573 octave_value m_obj; | |
574 | |
575 // The method we are handling. | |
576 octave_value m_fcn; | |
577 | |
578 // Name of the class that m_fcn belongs to. | |
579 std::string m_dispatch_class; | |
580 }; | |
581 | |
582 // Handles to anonymous functions are similar to handles to nested | |
583 // functions. If they are created in a context that contains nested | |
584 // functions, then they store a link to the parent call stack frames | |
585 // that are active when they are created. These call stack frames | |
586 // (closure frames) provide access to variables needed by any nested | |
587 // functions that are called from the anonymous function. Anonymous | |
588 // functions also store a list of values from their parent scope | |
589 // corresponding to the symbols in the anonymous function. This list | |
590 // of values captures the variable values that are visible in the | |
591 // scope where they are created. | |
592 // | |
593 // Note that because handles to anonymous and nested functions capture | |
594 // call stack frames when they are created, they will cause deletion | |
595 // of the values in those frames to be deferred until the handles to | |
596 // the anonymous or nested functions are deleted. | |
597 // | |
598 // Would it be possible to avoid storing the closure frames for | |
599 // handles to anonymous functions if we can determine that the | |
600 // anonymous function has no unbound variables (or parameters, which | |
601 // could be handles to nested functions?) or if it is not created in a | |
602 // context that contains nested functions? | |
603 // | |
604 // Would it be possible to define anonymous functions as a special | |
605 // type of nested function object that also has an variable | |
606 // initialization list associated with it? | |
607 | |
608 class base_anonymous_fcn_handle : public base_fcn_handle | |
609 { | |
610 public: | |
611 | |
612 static const std::string anonymous; | |
613 | |
614 // Setting NAME here is a bit of a kluge to cope with a bad choice | |
615 // made to append the number of local variables to the @<anonymous> | |
616 // tag in the binary file format. See also the save_binary and | |
617 // load_binary functions. | |
618 | |
619 base_anonymous_fcn_handle (const std::string& name = "") | |
620 : base_fcn_handle (name) | |
621 { } | |
622 | |
623 base_anonymous_fcn_handle (const octave_value& fcn, | |
624 const stack_frame::local_vars_map& local_vars) | |
625 : base_fcn_handle (anonymous), m_fcn (fcn), m_local_vars (local_vars) | |
626 { } | |
627 | |
628 base_anonymous_fcn_handle (const base_anonymous_fcn_handle&) = default; | |
629 | |
630 ~base_anonymous_fcn_handle (void) = default; | |
631 | |
632 std::string type (void) const { return "anonymous"; } | |
633 | |
634 bool is_anonymous (void) const { return true; } | |
635 | |
636 // FIXME: These must go away. They don't do the right thing for | |
637 // scoping or overloads. | |
638 octave_function * function_value (bool = false) | |
639 { | |
640 return m_fcn.function_value (); | |
641 } | |
642 | |
643 octave_user_function * user_function_value (bool = false) | |
644 { | |
645 return m_fcn.user_function_value (); | |
646 } | |
647 | |
648 octave_value fcn_val (void) { return m_fcn; } | |
649 | |
650 virtual octave_value workspace (void) const = 0; | |
651 | |
652 // Should be const. | |
653 octave_scalar_map info (void); | |
654 | |
655 bool save_ascii (std::ostream& os); | |
656 | |
657 bool load_ascii (std::istream& is); | |
658 | |
659 bool save_binary (std::ostream& os, bool save_as_floats); | |
660 | |
661 bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt); | |
662 | |
663 bool save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
664 bool save_as_floats); | |
665 | |
666 bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid, | |
667 octave_hdf5_id& type_hid); | |
668 | |
669 void print_raw (std::ostream&, bool pr_as_read_syntax, | |
670 int current_print_indent_level) const; | |
671 | |
672 // Anonymous function handles are printed without a newline. | |
673 bool print_as_scalar (void) const { return false; } | |
674 | |
675 bool parse (const std::string& fcn_text); | |
676 | |
677 protected: | |
678 | |
679 // The function we are handling. | |
680 octave_value m_fcn; | |
681 | |
682 // List of captured variable values for anonymous fucntions. | |
683 stack_frame::local_vars_map m_local_vars; | |
684 }; | |
685 | |
686 class anonymous_fcn_handle : public base_anonymous_fcn_handle | |
687 { | |
688 public: | |
689 | |
690 using base_anonymous_fcn_handle::anonymous; | |
691 | |
692 // Setting NAME here is a bit of a kluge to cope with a bad choice | |
693 // made to append the number of local variables to the @<anonymous> | |
694 // tag in the binary file format. See also the save_binary and | |
695 // load_binary functions. | |
696 | |
697 anonymous_fcn_handle (const std::string& name = "") | |
698 : base_anonymous_fcn_handle (name), m_stack_context () | |
699 { } | |
700 | |
701 anonymous_fcn_handle (const octave_value& fcn, | |
702 const stack_frame::local_vars_map& local_vars, | |
703 const std::shared_ptr<stack_frame>& stack_context = std::shared_ptr<stack_frame> ()); | |
704 | |
705 anonymous_fcn_handle (const anonymous_fcn_handle&) = default; | |
706 | |
707 ~anonymous_fcn_handle (void) = default; | |
708 | |
709 anonymous_fcn_handle * clone (void) const | |
710 { | |
711 return new anonymous_fcn_handle (*this); | |
712 } | |
713 | |
714 octave_value make_weak_anonymous_handle (void) const; | |
715 | |
716 octave_value_list call (int nargout, const octave_value_list& args); | |
717 | |
718 octave_value workspace (void) const; | |
719 | |
720 friend bool is_equal_to (const anonymous_fcn_handle& fh1, | |
721 const anonymous_fcn_handle& fh2); | |
722 | |
723 std::shared_ptr<stack_frame> stack_context (void) const | |
724 { | |
725 return m_stack_context; | |
726 } | |
727 | |
728 protected: | |
729 | |
730 // Pointer to closure stack frames. | |
731 std::shared_ptr<stack_frame> m_stack_context; | |
732 }; | |
733 | |
734 class weak_anonymous_fcn_handle : public base_anonymous_fcn_handle | |
735 { | |
736 public: | |
737 | |
738 using base_anonymous_fcn_handle::anonymous; | |
739 | |
740 weak_anonymous_fcn_handle (const anonymous_fcn_handle& afh) | |
741 : base_anonymous_fcn_handle (afh), m_stack_context (afh.stack_context ()) | |
742 { } | |
743 | |
744 weak_anonymous_fcn_handle (const weak_anonymous_fcn_handle&) = default; | |
745 | |
746 ~weak_anonymous_fcn_handle (void) = default; | |
747 | |
748 weak_anonymous_fcn_handle * clone (void) const | |
749 { | |
750 return new weak_anonymous_fcn_handle (*this); | |
751 } | |
752 | |
753 bool is_weak_anonymous (void) const { return true; } | |
754 | |
755 octave_value_list call (int nargout, const octave_value_list& args); | |
756 | |
757 octave_value workspace (void) const; | |
758 | |
759 friend bool is_equal_to (const weak_anonymous_fcn_handle& fh1, | |
760 const weak_anonymous_fcn_handle& fh2); | |
761 | |
762 protected: | |
763 | |
764 // Pointer to closure stack frames. | |
765 std::weak_ptr<stack_frame> m_stack_context; | |
766 }; | |
767 | |
768 extern bool is_equal_to (const anonymous_fcn_handle& fh1, | |
769 const anonymous_fcn_handle& fh2); | |
770 | |
771 static void err_invalid_fcn_handle (const std::string& name) | |
772 { | |
773 error ("invalid function handle, unable to find function for @%s", | |
774 name.c_str ()); | |
775 } | |
776 | |
777 octave_value base_fcn_handle::make_weak_nested_handle (void) const | |
778 { | |
779 std::string type_str = type (); | |
780 error ("invalid conversion from %s handle to weak nestead handle", | |
781 type_str.c_str ()); | |
782 } | |
783 | |
784 octave_value base_fcn_handle::make_weak_anonymous_handle (void) const | |
785 { | |
786 std::string type_str = type (); | |
787 error ("invalid conversion from %s handle to weak anonymous handle", | |
788 type_str.c_str ()); | |
789 } | |
790 | |
791 octave_value_list | |
792 base_fcn_handle::subsref (const std::string& type, | |
793 const std::list<octave_value_list>& idx, | |
794 int nargout) | |
795 { | |
796 octave_value_list retval; | |
797 | |
798 switch (type[0]) | |
799 { | |
800 case '(': | |
2731 { | 801 { |
2732 octave_value ov_frames = m_stack_context->workspace (); | 802 int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout; |
2733 cell_frames = ov_frames.cell_value (); | 803 |
804 retval = call (tmp_nargout, idx.front ()); | |
2734 } | 805 } |
2735 | 806 break; |
2736 octave_idx_type num_frames = cell_frames.numel (); | 807 |
2737 // FIXME: It seems there should be a simple way to concatenate cells... | 808 case '{': |
2738 Cell retval = Cell (num_frames+1, 1); | 809 case '.': |
2739 retval(0) = m_local_vars; | 810 error ("function handle cannot be indexed with %c", type[0]); |
2740 for (octave_idx_type i = 0; i < num_frames; i++) | 811 |
2741 retval(i+1) = cell_frames(i); | 812 default: |
2742 | 813 panic_impossible (); |
2743 return retval; | 814 } |
2744 } | 815 |
2745 | 816 // FIXME: perhaps there should be an |
2746 bool is_equal_to (const anonymous_fcn_handle& fh1, | 817 // octave_value_list::next_subsref member function? See also |
2747 const anonymous_fcn_handle& fh2) | 818 // octave_builtin::subsref. |
2748 { | 819 |
2749 if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | 820 if (idx.size () > 1) |
2750 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | 821 retval = retval(0).next_subsref (nargout, type, idx); |
2751 else | 822 |
823 return retval; | |
824 } | |
825 | |
826 octave_value | |
827 base_fcn_handle::convert_to_str_internal (bool, bool, char type) const | |
828 { | |
829 std::ostringstream buf; | |
830 print_raw (buf, true, 0); | |
831 return octave_value (buf.str (), type); | |
832 } | |
833 | |
834 bool | |
835 base_fcn_handle::save_ascii (std::ostream&) | |
836 { | |
837 unimplemented ("save", "text"); | |
838 | |
839 return true; | |
840 } | |
841 | |
842 bool | |
843 base_fcn_handle::load_ascii (std::istream&) | |
844 { | |
845 unimplemented ("load", "text"); | |
846 | |
847 return true; | |
848 } | |
849 | |
850 bool | |
851 base_fcn_handle::save_binary (std::ostream&, bool) | |
852 { | |
853 unimplemented ("save", "binary"); | |
854 | |
855 return true; | |
856 } | |
857 | |
858 bool | |
859 base_fcn_handle::load_binary (std::istream&, bool, mach_info::float_format) | |
860 { | |
861 unimplemented ("load", "binary"); | |
862 | |
863 return true; | |
864 } | |
865 | |
866 bool | |
867 base_fcn_handle::save_hdf5 (octave_hdf5_id, const char *, bool) | |
868 { | |
869 unimplemented ("save", "hdf5"); | |
870 | |
871 return true; | |
872 } | |
873 | |
874 bool | |
875 base_fcn_handle::load_hdf5 (octave_hdf5_id&, octave_hdf5_id&, octave_hdf5_id&) | |
876 { | |
877 unimplemented ("load", "hdf5"); | |
878 | |
879 return true; | |
880 } | |
881 | |
882 void base_fcn_handle::warn_load (const char *file_type) const | |
883 { | |
884 std::string obj_type = type (); | |
885 | |
886 warning_with_id | |
887 ("Octave:load-save-unavailable", | |
888 "%s: loading %s files not available in this version of Octave", | |
889 obj_type.c_str (), file_type); | |
890 } | |
891 | |
892 void base_fcn_handle::warn_save (const char *file_type) const | |
893 { | |
894 std::string obj_type = type (); | |
895 | |
896 warning_with_id | |
897 ("Octave:load-save-unavailable", | |
898 "%s: saving %s files not available in this version of Octave", | |
899 obj_type.c_str (), file_type); | |
900 } | |
901 | |
902 void base_fcn_handle::unimplemented (const char *op, const char *fmt) const | |
903 { | |
904 std::string htype = type (); | |
905 | |
906 warning ("%s for %s handles with %s format is not implemented", | |
907 op, htype.c_str (), fmt); | |
908 } | |
909 | |
910 octave_value_list | |
911 invalid_fcn_handle::call (int, const octave_value_list&) | |
912 { | |
913 error ("invalid call to invalid function handle"); | |
914 } | |
915 | |
916 octave_value_list | |
917 internal_fcn_handle::call (int nargout, const octave_value_list& args) | |
918 { | |
919 interpreter& interp = __get_interpreter__ (); | |
920 | |
921 return interp.feval (m_fcn, args, nargout); | |
922 } | |
923 | |
924 octave_scalar_map internal_fcn_handle::info (void) | |
925 { | |
926 octave_scalar_map m; | |
927 | |
928 m.setfield ("function", fcn_name ()); | |
929 m.setfield ("type", type ()); | |
930 m.setfield ("file", ""); | |
931 | |
932 return m; | |
933 } | |
934 | |
935 bool is_equal_to (const internal_fcn_handle& fh1, | |
936 const internal_fcn_handle& fh2) | |
937 { | |
938 if (fh1.m_name == fh2.m_name | |
939 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
940 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
941 else | |
942 return false; | |
943 } | |
944 | |
945 octave_value_list | |
946 simple_fcn_handle::call (int nargout, const octave_value_list& args) | |
947 { | |
948 // FIXME: if m_name has a '.' in the name, lookup first component. If | |
949 // it is a classdef meta object, then build TYPE and IDX arguments and | |
950 // make a subsref call using them. | |
951 | |
952 interpreter& interp = __get_interpreter__ (); | |
953 | |
954 octave_value fcn_to_call; | |
955 | |
956 // The following code is similar to part of | |
957 // tree_evaluator::visit_index_expression but simpler because it | |
958 // handles a more restricted case. | |
959 | |
960 symbol_table& symtab = interp.get_symbol_table (); | |
961 | |
962 std::size_t pos = m_name.find ('.'); | |
963 | |
964 if (pos != std::string::npos) | |
965 { | |
966 // FIXME: check to see which of these cases actually work in | |
967 // Octave and Matlab. For the last two, assume handle is | |
968 // created before object is defined as an object. | |
969 // | |
970 // We can have one of | |
971 // | |
972 // pkg-list . fcn (args) | |
973 // pkg-list . cls . meth (args) | |
974 // class-name . method (args) | |
975 // class-name . static-method (args) | |
976 // object . method (args) | |
977 // object . static-method (args) | |
978 | |
979 // Evaluate package elements until we find a function, | |
980 // classdef object, or classdef_meta object that is not a | |
981 // package. An object may only appear as the first element, | |
982 // then it must be followed directly by a function name. | |
983 | |
984 std::size_t beg = 0; | |
985 std::size_t end = pos; | |
986 | |
987 std::vector<std::string> idx_elts; | |
988 | |
989 while (true) | |
990 { | |
991 end = m_name.find ('.', beg); | |
992 | |
993 idx_elts.push_back (m_name.substr (beg, end-beg)); | |
994 | |
995 if (end == std::string::npos) | |
996 break; | |
997 | |
998 beg = end+1; | |
999 } | |
1000 | |
1001 std::size_t n_elts = idx_elts.size (); | |
1002 | |
1003 bool have_object = false; | |
1004 octave_value partial_expr_val; | |
1005 | |
1006 // Lazy evaluation. The first element was not known to be defined | |
1007 // as an object in the scope where the handle was created. See if | |
1008 // there is a definition in the current scope. | |
1009 | |
1010 partial_expr_val = interp.varval (idx_elts[0]); | |
1011 | |
1012 if (partial_expr_val.is_defined ()) | |
1013 { | |
1014 if (! partial_expr_val.is_classdef_object () || n_elts != 2) | |
1015 err_invalid_fcn_handle (m_name); | |
1016 | |
1017 have_object = true; | |
1018 } | |
1019 else | |
1020 partial_expr_val = symtab.find_function (idx_elts[0], ovl ()); | |
1021 | |
1022 std::string type; | |
1023 std::list<octave_value_list> arg_list; | |
1024 | |
1025 for (std::size_t i = 1; i < n_elts; i++) | |
1026 { | |
1027 if (partial_expr_val.is_package ()) | |
1028 { | |
1029 if (have_object) | |
1030 err_invalid_fcn_handle (m_name); | |
1031 | |
1032 type = "."; | |
1033 arg_list.push_back (ovl (idx_elts[i])); | |
1034 | |
1035 try | |
1036 { | |
1037 // Silently ignore extra output values. | |
1038 | |
1039 octave_value_list tmp_list | |
1040 = partial_expr_val.subsref (type, arg_list, 0); | |
1041 | |
1042 partial_expr_val | |
1043 = tmp_list.length () ? tmp_list(0) : octave_value (); | |
1044 | |
1045 if (partial_expr_val.is_cs_list ()) | |
1046 err_invalid_fcn_handle (m_name); | |
1047 | |
1048 arg_list.clear (); | |
1049 } | |
1050 catch (const index_exception&) | |
1051 { | |
1052 err_invalid_fcn_handle (m_name); | |
1053 } | |
1054 } | |
1055 else if (have_object || partial_expr_val.is_classdef_meta ()) | |
1056 { | |
1057 // Object or class name must be the next to the last | |
1058 // element (it was the previous one, so if this is the | |
1059 // final element, it should be a classdef method, | |
1060 // but we'll let the classdef or classdef_meta subsref | |
1061 // function sort that out. | |
1062 | |
1063 if (i != n_elts-1) | |
1064 err_invalid_fcn_handle (m_name); | |
1065 | |
1066 type = ".("; | |
1067 arg_list.push_back (ovl (idx_elts[i])); | |
1068 arg_list.push_back (args); | |
1069 | |
1070 return partial_expr_val.subsref (type, arg_list, nargout); | |
1071 } | |
1072 else | |
1073 err_invalid_fcn_handle (m_name); | |
1074 } | |
1075 | |
1076 // If we get here, we must have a function to call. | |
1077 | |
1078 if (! partial_expr_val.is_function ()) | |
1079 err_invalid_fcn_handle (m_name); | |
1080 | |
1081 fcn_to_call = partial_expr_val; | |
1082 } | |
1083 else | |
1084 { | |
1085 // No "." in the name. | |
1086 | |
1087 // Perform function lookup given current arguments. We'll need | |
1088 // to do this regardless of whether a function was found when | |
1089 // the handle was created. | |
1090 | |
1091 octave_value ov_fcn = symtab.find_function (m_name, args); | |
1092 | |
1093 if (m_fcn.is_defined ()) | |
1094 { | |
1095 // A simple function was found when the handle was created. | |
1096 // Use that unless we find a class method to override it. | |
1097 | |
1098 fcn_to_call = m_fcn; | |
1099 | |
1100 if (ov_fcn.is_defined ()) | |
1101 { | |
1102 octave_function *fcn = ov_fcn.function_value (); | |
1103 | |
1104 std::string dispatch_class = fcn->dispatch_class (); | |
1105 | |
1106 if (fcn->is_class_method ()) | |
1107 { | |
1108 // Function found through lookup is a class method | |
1109 // so use it instead of the simple one found when | |
1110 // the handle was created. | |
1111 | |
1112 fcn_to_call = ov_fcn; | |
1113 } | |
1114 } | |
1115 } | |
1116 else | |
1117 { | |
1118 // There was no simple function found when the handle was | |
1119 // created so use the one found here (if any). | |
1120 | |
1121 fcn_to_call = ov_fcn; | |
1122 } | |
1123 } | |
1124 | |
1125 if (! fcn_to_call.is_defined ()) | |
1126 err_invalid_fcn_handle (m_name); | |
1127 | |
1128 return interp.feval (fcn_to_call, args, nargout); | |
1129 } | |
1130 | |
1131 octave_function *simple_fcn_handle::function_value (bool) | |
1132 { | |
1133 // FIXME: Shouldn't the lookup rules here match those used in the | |
1134 // call method? | |
1135 | |
1136 if (m_fcn.is_defined ()) | |
1137 return m_fcn.function_value (); | |
1138 | |
1139 symbol_table& symtab = __get_symbol_table__ (); | |
1140 | |
1141 // FIXME: is caching the correct thing to do? | |
1142 // Cache this value so that the pointer will be valid as long as the | |
1143 // function handle object is valid. | |
1144 | |
1145 m_fcn = symtab.find_function (m_name, octave_value_list ()); | |
1146 | |
1147 return m_fcn.is_defined () ? m_fcn.function_value () : nullptr; | |
1148 } | |
1149 | |
1150 octave_user_function *simple_fcn_handle::user_function_value (bool) | |
1151 { | |
1152 // FIXME: Shouldn't the lookup rules here match those used in the | |
1153 // call method? | |
1154 | |
1155 if (m_fcn.is_defined ()) | |
1156 return m_fcn.user_function_value (); | |
1157 | |
1158 symbol_table& symtab = __get_symbol_table__ (); | |
1159 | |
1160 // FIXME: is caching the correct thing to do? | |
1161 // Cache this value so that the pointer will be valid as long as the | |
1162 // function handle object is valid. | |
1163 | |
1164 m_fcn = symtab.find_user_function (m_name); | |
1165 | |
1166 return m_fcn.is_defined () ? m_fcn.user_function_value () : nullptr; | |
1167 } | |
1168 | |
1169 octave_value simple_fcn_handle::fcn_val (void) | |
1170 { | |
1171 if (m_fcn.is_defined ()) | |
1172 return m_fcn; | |
1173 | |
1174 symbol_table& symtab = __get_symbol_table__ (); | |
1175 | |
1176 // FIXME: is caching the correct thing to do? | |
1177 // Cache this value so that the pointer will be valid as long as the | |
1178 // function handle object is valid. | |
1179 | |
1180 m_fcn = symtab.find_user_function (m_name); | |
1181 | |
1182 return m_fcn; | |
1183 } | |
1184 | |
1185 octave_scalar_map simple_fcn_handle::info (void) | |
1186 { | |
1187 octave_scalar_map m; | |
1188 | |
1189 m.setfield ("function", fcn_name ()); | |
1190 m.setfield ("type", type ()); | |
1191 // When is FILE defined for simple function handles? | |
1192 m.setfield ("file", file ()); | |
1193 | |
1194 return m; | |
1195 } | |
1196 | |
1197 bool simple_fcn_handle::save_ascii (std::ostream& os) | |
1198 { | |
1199 os << "# octaveroot: " << config::octave_exec_home () << "\n"; | |
1200 | |
1201 std::string fnm = file (); | |
1202 if (! fnm.empty ()) | |
1203 os << "# path: " << fnm << "\n"; | |
1204 | |
1205 os << "# subtype: " << type () << "\n"; | |
1206 | |
1207 os << m_name << "\n"; | |
1208 | |
1209 return true; | |
1210 } | |
1211 | |
1212 bool simple_fcn_handle::load_ascii (std::istream& is) | |
1213 { | |
1214 // FIXME: If m_file is not empty, try to load the file and define | |
1215 // the function? Is it an error if that fails? Or should this job | |
1216 // always be deferred until the handle is used? | |
1217 | |
1218 return is.good (); | |
1219 } | |
1220 | |
1221 bool simple_fcn_handle::save_binary (std::ostream& os, bool) | |
1222 { | |
1223 std::ostringstream nmbuf; | |
1224 | |
1225 // When is FILE defined for simple function handles? | |
1226 std::string fnm; | |
1227 | |
1228 nmbuf << m_name << "@<simple>\n" << config::octave_exec_home () | |
1229 << "\n" << fnm; | |
1230 | |
1231 std::string buf_str = nmbuf.str (); | |
1232 int32_t tmp = buf_str.length (); | |
1233 os.write (reinterpret_cast<char *> (&tmp), 4); | |
1234 os.write (buf_str.c_str (), buf_str.length ()); | |
1235 | |
1236 return true; | |
1237 } | |
1238 | |
1239 bool simple_fcn_handle::load_binary (std::istream& is, bool, | |
1240 mach_info::float_format) | |
1241 { | |
1242 return is.good (); | |
1243 } | |
1244 | |
1245 bool simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
1246 bool) | |
1247 { | |
1248 #if defined (HAVE_HDF5) | |
1249 | |
1250 bool retval = true; | |
1251 | |
1252 octave_hdf5_id group_hid = -1; | |
1253 #if defined (HAVE_HDF5_18) | |
1254 group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
1255 octave_H5P_DEFAULT); | |
1256 #else | |
1257 group_hid = H5Gcreate (loc_id, name, 0); | |
1258 #endif | |
1259 if (group_hid < 0) | |
1260 return false; | |
1261 | |
1262 octave_hdf5_id space_hid, data_hid, type_hid; | |
1263 space_hid = data_hid = type_hid = -1; | |
1264 | |
1265 // attach the type of the variable | |
1266 type_hid = H5Tcopy (H5T_C_S1); | |
1267 H5Tset_size (type_hid, m_name.length () + 1); | |
1268 if (type_hid < 0) | |
1269 { | |
1270 H5Gclose (group_hid); | |
2752 return false; | 1271 return false; |
2753 } | 1272 } |
2754 | 1273 |
2755 octave_value_list | 1274 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2); |
2756 weak_anonymous_fcn_handle::call (int nargout, const octave_value_list& args) | 1275 hdims[0] = 0; |
2757 { | 1276 hdims[1] = 0; |
2758 tree_evaluator& tw = __get_evaluator__ (); | 1277 space_hid = H5Screate_simple (0, hdims, nullptr); |
2759 | 1278 if (space_hid < 0) |
2760 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | 1279 { |
2761 | 1280 H5Tclose (type_hid); |
2762 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | 1281 H5Gclose (group_hid); |
2763 | |
2764 tw.push_stack_frame (oct_usr_fcn, m_local_vars, frames); | |
2765 | |
2766 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
2767 | |
2768 return oct_usr_fcn->execute (tw, nargout, args); | |
2769 } | |
2770 | |
2771 octave_value weak_anonymous_fcn_handle::workspace (void) const | |
2772 { | |
2773 octave_scalar_map local_vars_map; | |
2774 | |
2775 for (const auto& nm_val : m_local_vars) | |
2776 local_vars_map.assign (nm_val.first, nm_val.second); | |
2777 | |
2778 // FIXME: it would be more convenient if stack_frame::workspace | |
2779 // returned a Cell object directly instead of a Cell in an | |
2780 // octave_value object. | |
2781 | |
2782 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | |
2783 | |
2784 Cell cell_frames; | |
2785 | |
2786 if (frames) | |
2787 { | |
2788 octave_value ov_frames = frames->workspace (); | |
2789 cell_frames = ov_frames.cell_value (); | |
2790 } | |
2791 | |
2792 octave_idx_type num_frames = cell_frames.numel (); | |
2793 | |
2794 // FIXME: It seems there should be a simple way to concatenate | |
2795 // cells... | |
2796 Cell retval = Cell (num_frames+1, 1); | |
2797 retval(0) = m_local_vars; | |
2798 for (octave_idx_type i = 0; i < num_frames; i++) | |
2799 retval(i+1) = cell_frames(i); | |
2800 | |
2801 return retval; | |
2802 } | |
2803 | |
2804 bool is_equal_to (const weak_anonymous_fcn_handle& fh1, | |
2805 const weak_anonymous_fcn_handle& fh2) | |
2806 { | |
2807 if (fh1.m_name == fh2.m_name | |
2808 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
2809 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
2810 else | |
2811 return false; | 1282 return false; |
2812 } | 1283 } |
1284 #if defined (HAVE_HDF5_18) | |
1285 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
1286 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
1287 octave_H5P_DEFAULT); | |
1288 #else | |
1289 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
1290 octave_H5P_DEFAULT); | |
1291 #endif | |
1292 if (data_hid < 0 | |
1293 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, | |
1294 octave_H5P_DEFAULT, m_name.c_str ()) < 0) | |
1295 { | |
1296 H5Sclose (space_hid); | |
1297 H5Tclose (type_hid); | |
1298 H5Gclose (group_hid); | |
1299 return false; | |
1300 } | |
1301 H5Dclose (data_hid); | |
1302 | |
1303 std::string octaveroot = config::octave_exec_home (); | |
1304 | |
1305 // When is FILE defined for simple fucntion handles? | |
1306 std::string fpath; | |
1307 | |
1308 H5Sclose (space_hid); | |
1309 hdims[0] = 1; | |
1310 hdims[1] = octaveroot.length (); | |
1311 space_hid = H5Screate_simple (0, hdims, nullptr); | |
1312 if (space_hid < 0) | |
1313 { | |
1314 H5Tclose (type_hid); | |
1315 H5Gclose (group_hid); | |
1316 return false; | |
1317 } | |
1318 | |
1319 H5Tclose (type_hid); | |
1320 type_hid = H5Tcopy (H5T_C_S1); | |
1321 H5Tset_size (type_hid, octaveroot.length () + 1); | |
1322 octave_hdf5_id a_id; | |
1323 #if defined (HAVE_HDF5_18) | |
1324 a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid, | |
1325 octave_H5P_DEFAULT, octave_H5P_DEFAULT); | |
1326 #else | |
1327 a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid, | |
1328 octave_H5P_DEFAULT); | |
1329 #endif | |
1330 | |
1331 if (a_id >= 0) | |
1332 { | |
1333 retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0); | |
1334 | |
1335 H5Aclose (a_id); | |
1336 } | |
1337 else | |
1338 { | |
1339 H5Sclose (space_hid); | |
1340 H5Tclose (type_hid); | |
1341 H5Gclose (group_hid); | |
1342 return false; | |
1343 } | |
1344 | |
1345 H5Sclose (space_hid); | |
1346 hdims[0] = 1; | |
1347 hdims[1] = fpath.length (); | |
1348 space_hid = H5Screate_simple (0, hdims, nullptr); | |
1349 if (space_hid < 0) | |
1350 { | |
1351 H5Tclose (type_hid); | |
1352 H5Gclose (group_hid); | |
1353 return false; | |
1354 } | |
1355 | |
1356 H5Tclose (type_hid); | |
1357 type_hid = H5Tcopy (H5T_C_S1); | |
1358 H5Tset_size (type_hid, fpath.length () + 1); | |
1359 | |
1360 #if defined (HAVE_HDF5_18) | |
1361 a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid, | |
1362 octave_H5P_DEFAULT, octave_H5P_DEFAULT); | |
1363 #else | |
1364 a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid, | |
1365 octave_H5P_DEFAULT); | |
1366 #endif | |
1367 | |
1368 if (a_id >= 0) | |
1369 { | |
1370 retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0); | |
1371 | |
1372 H5Aclose (a_id); | |
1373 } | |
1374 else | |
1375 retval = false; | |
1376 | |
1377 H5Sclose (space_hid); | |
1378 H5Tclose (type_hid); | |
1379 H5Gclose (group_hid); | |
1380 | |
1381 return retval; | |
1382 | |
1383 #else | |
1384 | |
1385 octave_unused_parameter (loc_id); | |
1386 octave_unused_parameter (name); | |
1387 | |
1388 warn_save ("hdf5"); | |
1389 | |
1390 return false; | |
1391 | |
1392 #endif | |
1393 } | |
1394 | |
1395 bool simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
1396 octave_hdf5_id& space_hid, | |
1397 octave_hdf5_id& type_hid) | |
1398 { | |
1399 #if defined (HAVE_HDF5) | |
1400 | |
1401 unimplemented ("load", "hdf5"); | |
1402 | |
1403 octave_unused_parameter (group_hid); | |
1404 octave_unused_parameter (space_hid); | |
1405 octave_unused_parameter (type_hid); | |
1406 | |
1407 return true; | |
1408 | |
1409 #else | |
1410 | |
1411 octave_unused_parameter (group_hid); | |
1412 octave_unused_parameter (space_hid); | |
1413 octave_unused_parameter (type_hid); | |
1414 | |
1415 return false; | |
1416 | |
1417 #endif | |
1418 } | |
1419 | |
1420 void simple_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax, | |
1421 int current_print_indent_level) const | |
1422 { | |
1423 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
1424 current_print_indent_level); | |
1425 } | |
1426 | |
1427 bool is_equal_to (const simple_fcn_handle& fh1, const simple_fcn_handle& fh2) | |
1428 { | |
1429 if (fh1.m_name == fh2.m_name) | |
1430 { | |
1431 if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1432 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1433 | |
1434 if (fh1.m_fcn.is_undefined () && fh2.m_fcn.is_undefined ()) | |
1435 return true; | |
1436 } | |
1437 | |
1438 return false; | |
1439 } | |
1440 | |
1441 scoped_fcn_handle::scoped_fcn_handle (const octave_value& fcn, | |
1442 const std::string& name, | |
1443 const std::list<std::string>& parentage) | |
1444 : base_fcn_handle (name), m_fcn (fcn), m_parentage (parentage) | |
1445 { | |
1446 // FIXME: should it be an error if FCN is undefined? | |
1447 | |
1448 if (m_fcn.is_defined ()) | |
1449 { | |
1450 octave_function *oct_fcn = m_fcn.function_value (); | |
1451 | |
1452 if (oct_fcn) | |
1453 m_file = oct_fcn->fcn_file_name (); | |
1454 } | |
1455 | |
1456 m_parentage.push_front (name); | |
1457 } | |
1458 | |
1459 octave_value_list | |
1460 scoped_fcn_handle::call (int nargout, const octave_value_list& args) | |
1461 { | |
1462 // FIXME: we aren't really using the scope yet. Hmm. | |
1463 | |
1464 interpreter& interp = __get_interpreter__ (); | |
1465 | |
1466 if (! m_fcn.is_defined ()) | |
1467 { | |
1468 // Try to find it? | |
1469 | |
1470 find_function (); | |
1471 } | |
1472 | |
1473 if (! m_fcn.is_defined ()) | |
1474 err_invalid_fcn_handle (m_name); | |
1475 | |
1476 return interp.feval (m_fcn, args, nargout); | |
1477 } | |
1478 | |
1479 octave_scalar_map scoped_fcn_handle::info (void) | |
1480 { | |
1481 octave_scalar_map m; | |
1482 | |
1483 m.setfield ("function", fcn_name ()); | |
1484 m.setfield ("type", type ()); | |
1485 m.setfield ("file", file ()); | |
1486 | |
1487 m.setfield ("parentage", Cell (m_parentage)); | |
1488 | |
1489 return m; | |
1490 } | |
1491 | |
1492 bool scoped_fcn_handle::save_ascii (std::ostream& os) | |
1493 { | |
1494 os << "# octaveroot: " << config::octave_exec_home () << "\n"; | |
1495 | |
1496 std::string fnm = file (); | |
1497 if (! fnm.empty ()) | |
1498 os << "# path: " << fnm << "\n"; | |
1499 | |
1500 os << "# subtype: " << type () << "\n"; | |
1501 | |
1502 os << m_name << "\n"; | |
1503 | |
1504 octave_value tmp = Cell (m_parentage); | |
1505 tmp.save_ascii (os); | |
1506 | |
1507 return os.good (); | |
1508 } | |
1509 | |
1510 bool scoped_fcn_handle::load_ascii (std::istream& is) | |
1511 { | |
1512 octave_cell ov_cell; | |
1513 ov_cell.load_ascii (is); | |
1514 | |
1515 if (ov_cell.iscellstr ()) | |
1516 { | |
1517 Array<std::string> cellstr_val = ov_cell.cellstr_value (); | |
1518 | |
1519 for (octave_idx_type i = 0; i < cellstr_val.numel (); i++) | |
1520 m_parentage.push_back (cellstr_val(i)); | |
1521 } | |
1522 | |
1523 return is.good (); | |
1524 } | |
1525 | |
1526 bool scoped_fcn_handle::save_binary (std::ostream& os, bool save_as_floats) | |
1527 { | |
1528 std::ostringstream nmbuf; | |
1529 | |
1530 std::string fnm = file (); | |
1531 | |
1532 nmbuf << m_name << "@<scopedfunction>\n" << config::octave_exec_home () | |
1533 << "\n" << fnm; | |
1534 | |
1535 std::string buf_str = nmbuf.str (); | |
1536 int32_t len = buf_str.length (); | |
1537 os.write (reinterpret_cast<char *> (&len), 4); | |
1538 os.write (buf_str.c_str (), buf_str.length ()); | |
1539 | |
1540 octave_value tmp = Cell (m_parentage); | |
1541 tmp.save_binary (os, save_as_floats); | |
1542 | |
1543 return os.good (); | |
1544 } | |
1545 | |
1546 bool scoped_fcn_handle::load_binary (std::istream& is, bool swap, | |
1547 mach_info::float_format fmt) | |
1548 { | |
1549 octave_cell ov_cell; | |
1550 ov_cell.load_binary (is, swap, fmt); | |
1551 | |
1552 if (ov_cell.iscellstr ()) | |
1553 { | |
1554 Array<std::string> cellstr_val = ov_cell.cellstr_value (); | |
1555 | |
1556 for (octave_idx_type i = 0; i < cellstr_val.numel (); i++) | |
1557 m_parentage.push_back (cellstr_val(i)); | |
1558 } | |
1559 | |
1560 return is.good (); | |
1561 } | |
1562 | |
1563 bool scoped_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name, | |
1564 bool) | |
1565 { | |
1566 #if defined (HAVE_HDF5) | |
1567 | |
1568 unimplemented ("save", "hdf5"); | |
1569 | |
1570 // FIXME: save parentage. | |
1571 | |
1572 octave_unused_parameter (loc_id); | |
1573 octave_unused_parameter (name); | |
1574 | |
1575 return true; | |
1576 | |
1577 #else | |
1578 | |
1579 octave_unused_parameter (loc_id); | |
1580 octave_unused_parameter (name); | |
1581 | |
1582 warn_save ("hdf5"); | |
1583 | |
1584 return false; | |
1585 | |
1586 #endif | |
1587 } | |
1588 | |
1589 bool scoped_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
1590 octave_hdf5_id& space_hid, | |
1591 octave_hdf5_id& type_hid) | |
1592 { | |
1593 #if defined (HAVE_HDF5) | |
1594 | |
1595 unimplemented ("load", "hdf5"); | |
1596 | |
1597 // FIXME: load parentage. | |
1598 | |
1599 octave_unused_parameter (group_hid); | |
1600 octave_unused_parameter (space_hid); | |
1601 octave_unused_parameter (type_hid); | |
1602 | |
1603 return true; | |
1604 | |
1605 #else | |
1606 | |
1607 octave_unused_parameter (group_hid); | |
1608 octave_unused_parameter (space_hid); | |
1609 octave_unused_parameter (type_hid); | |
1610 | |
1611 return false; | |
1612 | |
1613 #endif | |
1614 } | |
1615 | |
1616 void scoped_fcn_handle::print_raw (std::ostream& os, | |
1617 bool pr_as_read_syntax, | |
1618 int current_print_indent_level) const | |
1619 { | |
1620 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
1621 current_print_indent_level); | |
1622 } | |
1623 | |
1624 bool is_equal_to (const scoped_fcn_handle& fh1, const scoped_fcn_handle& fh2) | |
1625 { | |
1626 if (fh1.m_name == fh2.m_name | |
1627 && fh2.m_parentage == fh2.m_parentage | |
1628 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1629 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1630 else | |
1631 return false; | |
1632 } | |
1633 | |
1634 void scoped_fcn_handle::find_function (void) | |
1635 { | |
1636 // Since a scoped function is not visible by itself, try to load the | |
1637 // file named in m_file then find and define the scoped function. | |
1638 // It is not an error if this fails. We can report later that the | |
1639 // handle is invalid. | |
1640 | |
1641 symbol_table& symtab = __get_symbol_table__ (); | |
1642 | |
1643 if (m_parentage.size () == 1) | |
1644 { | |
1645 std::string dir_name = sys::file_ops::dirname (m_file); | |
1646 | |
1647 std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ()); | |
1648 | |
1649 if (pos != std::string::npos) | |
1650 dir_name = dir_name.substr (0, pos); | |
1651 else if (dir_name == "private") | |
1652 dir_name = "."; | |
1653 | |
1654 std::string fcn_name = m_parentage.front (); | |
1655 | |
1656 // FIXME: Does dir_name need to be in the load path for this to work? | |
1657 | |
1658 m_fcn = symtab.find_private_function (dir_name, m_name); | |
1659 | |
1660 // FIXME: Verify that it is a private function? | |
1661 } | |
1662 else | |
1663 { | |
1664 std::string primary_parent_name = m_parentage.back (); | |
1665 | |
1666 octave_value ov_parent_fcn | |
1667 = symtab.find_user_function (primary_parent_name); | |
1668 | |
1669 if (ov_parent_fcn.is_defined ()) | |
1670 { | |
1671 octave_user_function *fcn = ov_parent_fcn.user_function_value (); | |
1672 | |
1673 if (fcn) | |
1674 { | |
1675 std::string file_name = fcn->fcn_file_name (); | |
1676 | |
1677 std::string oct_home = config::octave_exec_home (); | |
1678 | |
1679 if (file_name.substr (0, oct_home.size ()) == oct_home) | |
1680 file_name = file_name.substr (oct_home.size ()); | |
1681 | |
1682 octave_value subfcn = fcn->find_subfunction (m_name); | |
1683 | |
1684 if (subfcn.is_defined ()) | |
1685 m_fcn = subfcn; | |
1686 } | |
1687 } | |
1688 } | |
1689 } | |
1690 | |
1691 octave_scalar_map base_nested_fcn_handle::info (void) | |
1692 { | |
1693 octave_scalar_map m; | |
1694 | |
1695 m.setfield ("function", fcn_name ()); | |
1696 m.setfield ("type", type ()); | |
1697 m.setfield ("file", ""); | |
1698 m.setfield ("workspace", workspace ()); | |
1699 | |
1700 return m; | |
1701 } | |
1702 | |
1703 // FIXME: For save, we need a way to save the (possibly shared) | |
1704 // workspace. For load, we need a way to load and link to the | |
1705 // (possibly shared) workspace that was saved. | |
1706 // | |
1707 // Since a nested function is not visible by itself, do we need to try | |
1708 // to load the file named in m_file then find and define the function? | |
1709 // Is it an error if that fails? Or should this job always be | |
1710 // deferred until the handle is used? | |
1711 | |
1712 bool base_nested_fcn_handle::save_ascii (std::ostream& os) | |
1713 { | |
1714 unimplemented ("save", "text"); | |
1715 | |
1716 octave_unused_parameter (os); | |
1717 | |
1718 return true; | |
1719 } | |
1720 | |
1721 bool base_nested_fcn_handle::load_ascii (std::istream& is) | |
1722 { | |
1723 unimplemented ("load", "text"); | |
1724 | |
1725 octave_unused_parameter (is); | |
1726 | |
1727 return true; | |
1728 } | |
1729 | |
1730 bool base_nested_fcn_handle::save_binary (std::ostream& os, | |
1731 bool save_as_floats) | |
1732 { | |
1733 unimplemented ("save", "binary"); | |
1734 | |
1735 octave_unused_parameter (os); | |
1736 octave_unused_parameter (save_as_floats); | |
1737 | |
1738 return true; | |
1739 } | |
1740 | |
1741 bool base_nested_fcn_handle::load_binary (std::istream& is, bool swap, | |
1742 mach_info::float_format fmt) | |
1743 { | |
1744 unimplemented ("load", "binary"); | |
1745 | |
1746 octave_unused_parameter (is); | |
1747 octave_unused_parameter (swap); | |
1748 octave_unused_parameter (fmt); | |
1749 | |
1750 return true; | |
1751 } | |
1752 | |
1753 bool base_nested_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, | |
1754 const char *name, bool) | |
1755 { | |
1756 #if defined (HAVE_HDF5) | |
1757 | |
1758 unimplemented ("save", "hdf5"); | |
1759 | |
1760 octave_unused_parameter (loc_id); | |
1761 octave_unused_parameter (name); | |
1762 | |
1763 return true; | |
1764 | |
1765 #else | |
1766 | |
1767 octave_unused_parameter (loc_id); | |
1768 octave_unused_parameter (name); | |
1769 | |
1770 warn_save ("hdf5"); | |
1771 | |
1772 return false; | |
1773 | |
1774 #endif | |
1775 } | |
1776 | |
1777 bool base_nested_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
1778 octave_hdf5_id& space_hid, | |
1779 octave_hdf5_id& type_hid) | |
1780 { | |
1781 #if defined (HAVE_HDF5) | |
1782 | |
1783 unimplemented ("load", "hdf5"); | |
1784 | |
1785 octave_unused_parameter (group_hid); | |
1786 octave_unused_parameter (space_hid); | |
1787 octave_unused_parameter (type_hid); | |
1788 | |
1789 return true; | |
1790 | |
1791 #else | |
1792 | |
1793 octave_unused_parameter (group_hid); | |
1794 octave_unused_parameter (space_hid); | |
1795 octave_unused_parameter (type_hid); | |
1796 | |
1797 return false; | |
1798 | |
1799 #endif | |
1800 } | |
1801 | |
1802 void base_nested_fcn_handle::print_raw (std::ostream& os, | |
1803 bool pr_as_read_syntax, | |
1804 int current_print_indent_level) const | |
1805 { | |
1806 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
1807 current_print_indent_level); | |
1808 } | |
1809 | |
1810 octave_value nested_fcn_handle::make_weak_nested_handle (void) const | |
1811 { | |
1812 return octave_value (new octave_fcn_handle | |
1813 (new weak_nested_fcn_handle (*this))); | |
1814 } | |
1815 | |
1816 octave_value_list | |
1817 nested_fcn_handle::call (int nargout, const octave_value_list& args) | |
1818 { | |
1819 tree_evaluator& tw = __get_evaluator__ (); | |
1820 | |
1821 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | |
1822 | |
1823 tw.push_stack_frame (oct_usr_fcn, m_stack_context); | |
1824 | |
1825 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
1826 | |
1827 return oct_usr_fcn->execute (tw, nargout, args); | |
1828 } | |
1829 | |
1830 octave_value nested_fcn_handle::workspace (void) const | |
1831 { | |
1832 return m_stack_context->workspace (); | |
1833 } | |
1834 | |
1835 bool is_equal_to (const nested_fcn_handle& fh1, const nested_fcn_handle& fh2) | |
1836 { | |
1837 if (fh1.m_name == fh2.m_name | |
1838 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1839 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1840 else | |
1841 return false; | |
1842 } | |
1843 | |
1844 octave_value_list | |
1845 weak_nested_fcn_handle::call (int nargout, const octave_value_list& args) | |
1846 { | |
1847 tree_evaluator& tw = __get_evaluator__ (); | |
1848 | |
1849 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | |
1850 | |
1851 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | |
1852 | |
1853 tw.push_stack_frame (oct_usr_fcn, frames); | |
1854 | |
1855 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
1856 | |
1857 return oct_usr_fcn->execute (tw, nargout, args); | |
1858 } | |
1859 | |
1860 octave_value weak_nested_fcn_handle::workspace (void) const | |
1861 { | |
1862 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | |
1863 | |
1864 return frames ? frames->workspace () : octave_value (); | |
1865 } | |
1866 | |
1867 bool is_equal_to (const weak_nested_fcn_handle& fh1, | |
1868 const weak_nested_fcn_handle& fh2) | |
1869 { | |
1870 if (fh1.m_name == fh2.m_name | |
1871 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
1872 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
1873 else | |
1874 return false; | |
1875 } | |
1876 | |
1877 class_simple_fcn_handle::class_simple_fcn_handle (const std::string& class_nm, | |
1878 const std::string& meth_nm) | |
1879 : base_fcn_handle (meth_nm), m_obj (), m_fcn (), | |
1880 m_dispatch_class (class_nm) | |
1881 { } | |
1882 | |
1883 class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& fcn, | |
1884 const std::string& class_nm, | |
1885 const std::string& meth_nm) | |
1886 : base_fcn_handle (meth_nm), m_obj (), m_fcn (fcn), | |
1887 m_dispatch_class (class_nm) | |
1888 { } | |
1889 | |
1890 class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& obj, | |
1891 const octave_value& fcn, | |
1892 const std::string& class_nm, | |
1893 const std::string& meth_nm) | |
1894 : base_fcn_handle (meth_nm), m_obj (obj), m_fcn (fcn), | |
1895 m_dispatch_class (class_nm) | |
1896 { } | |
1897 | |
1898 octave_value_list | |
1899 class_simple_fcn_handle::call (int nargout, const octave_value_list& args) | |
1900 { | |
1901 interpreter& interp = __get_interpreter__ (); | |
1902 | |
1903 if (m_obj.is_defined ()) | |
1904 { | |
1905 octave_value_list tmp_args = args; | |
1906 tmp_args.prepend (m_obj); | |
1907 | |
1908 return interp.feval (m_fcn, tmp_args, nargout); | |
1909 } | |
1910 | |
1911 // FIXME: is this the best approach? Should we be saving current | |
1912 // dispatch class and restoring that value instead of | |
1913 // unconditionally setting it to "" when we return from this | |
1914 // function? | |
1915 | |
1916 tree_evaluator& tw = interp.get_evaluator (); | |
1917 | |
1918 unwind_action act ([&tw] () { tw.set_dispatch_class (""); }); | |
1919 | |
1920 tw.set_dispatch_class (m_dispatch_class); | |
1921 | |
1922 if (m_fcn.is_defined ()) | |
1923 return interp.feval (m_fcn, args, nargout); | |
1924 | |
1925 return interp.feval (fcn_name (), args, nargout); | |
1926 } | |
1927 | |
1928 octave_scalar_map class_simple_fcn_handle::info (void) | |
1929 { | |
1930 octave_scalar_map m; | |
1931 | |
1932 m.setfield ("function", fcn_name ()); | |
1933 m.setfield ("type", type ()); | |
1934 m.setfield ("file", ""); | |
1935 m.setfield ("class", dispatch_class ()); | |
1936 | |
1937 return m; | |
1938 } | |
1939 | |
1940 // FIXME: Since a class method is not visible by itself, do we need to | |
1941 // try to load the file named in m_file then find and define the | |
1942 // function? Is it an error if that fails? Or should this job always | |
1943 // be deferred until the handle is used? | |
1944 | |
1945 bool class_simple_fcn_handle::save_ascii (std::ostream& os) | |
1946 { | |
1947 unimplemented ("save", "text"); | |
1948 | |
1949 octave_unused_parameter (os); | |
1950 | |
1951 return true; | |
1952 } | |
1953 | |
1954 bool class_simple_fcn_handle::load_ascii (std::istream& is) | |
1955 { | |
1956 unimplemented ("load", "text"); | |
1957 | |
1958 octave_unused_parameter (is); | |
1959 | |
1960 return true; | |
1961 } | |
1962 | |
1963 bool class_simple_fcn_handle::save_binary (std::ostream& os, | |
1964 bool save_as_floats) | |
1965 { | |
1966 unimplemented ("save", "binary"); | |
1967 | |
1968 octave_unused_parameter (os); | |
1969 octave_unused_parameter (save_as_floats); | |
1970 | |
1971 return true; | |
1972 } | |
1973 | |
1974 bool class_simple_fcn_handle::load_binary (std::istream& is, bool swap, | |
1975 mach_info::float_format fmt) | |
1976 { | |
1977 unimplemented ("load", "binary"); | |
1978 | |
1979 octave_unused_parameter (is); | |
1980 octave_unused_parameter (swap); | |
1981 octave_unused_parameter (fmt); | |
1982 | |
1983 return true; | |
1984 } | |
1985 | |
1986 bool class_simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, | |
1987 const char *name, bool) | |
1988 { | |
1989 #if defined (HAVE_HDF5) | |
1990 | |
1991 unimplemented ("save", "hdf5"); | |
1992 | |
1993 octave_unused_parameter (loc_id); | |
1994 octave_unused_parameter (name); | |
1995 | |
1996 return true; | |
1997 | |
1998 #else | |
1999 | |
2000 octave_unused_parameter (loc_id); | |
2001 octave_unused_parameter (name); | |
2002 | |
2003 warn_save ("hdf5"); | |
2004 | |
2005 return false; | |
2006 | |
2007 #endif | |
2008 } | |
2009 | |
2010 bool class_simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
2011 octave_hdf5_id& space_hid, | |
2012 octave_hdf5_id& type_hid) | |
2013 { | |
2014 #if defined (HAVE_HDF5) | |
2015 | |
2016 unimplemented ("load", "hdf5"); | |
2017 | |
2018 octave_unused_parameter (group_hid); | |
2019 octave_unused_parameter (space_hid); | |
2020 octave_unused_parameter (type_hid); | |
2021 | |
2022 return true; | |
2023 | |
2024 #else | |
2025 | |
2026 octave_unused_parameter (group_hid); | |
2027 octave_unused_parameter (space_hid); | |
2028 octave_unused_parameter (type_hid); | |
2029 | |
2030 return false; | |
2031 | |
2032 #endif | |
2033 } | |
2034 | |
2035 void class_simple_fcn_handle::print_raw (std::ostream& os, | |
2036 bool pr_as_read_syntax, | |
2037 int current_print_indent_level) const | |
2038 { | |
2039 octave_print_internal (os, '@' + m_name, pr_as_read_syntax, | |
2040 current_print_indent_level); | |
2041 } | |
2042 | |
2043 bool is_equal_to (const class_simple_fcn_handle& fh1, | |
2044 const class_simple_fcn_handle& fh2) | |
2045 { | |
2046 // FIXME: Also need to check object values are equivalent? | |
2047 | |
2048 if (fh1.m_name == fh2.m_name | |
2049 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
2050 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
2051 else | |
2052 return false; | |
2053 } | |
2054 | |
2055 const std::string base_anonymous_fcn_handle::anonymous ("@<anonymous>"); | |
2056 | |
2057 octave_scalar_map base_anonymous_fcn_handle::info (void) | |
2058 { | |
2059 octave_scalar_map m; | |
2060 | |
2061 std::ostringstream buf; | |
2062 print_raw (buf, true, 0); | |
2063 m.setfield ("function", buf.str ()); | |
2064 | |
2065 m.setfield ("type", type ()); | |
2066 m.setfield ("file", ""); | |
2067 m.setfield ("workspace", workspace ()); | |
2068 m.setfield ("within_file_path", ""); | |
2069 | |
2070 return m; | |
2071 } | |
2072 | |
2073 bool base_anonymous_fcn_handle::save_ascii (std::ostream& os) | |
2074 { | |
2075 // FIXME: can we ensure that m_fcn is always defined? | |
2076 | |
2077 if (m_fcn.is_undefined ()) | |
2078 return false; | |
2079 | |
2080 os << m_name << "\n"; | |
2081 | |
2082 print_raw (os, true, 0); | |
2083 os << "\n"; | |
2084 | |
2085 std::size_t varlen = m_local_vars.size (); | |
2086 | |
2087 if (varlen > 0) | |
2088 { | |
2089 os << "# length: " << varlen << "\n"; | |
2090 | |
2091 for (const auto& nm_val : m_local_vars) | |
2092 { | |
2093 if (! save_text_data (os, nm_val.second, nm_val.first, false, 0)) | |
2094 return ! os.fail (); | |
2095 } | |
2096 } | |
2097 | |
2098 return true; | |
2099 } | |
2100 | |
2101 bool base_anonymous_fcn_handle::load_ascii (std::istream& is) | |
2102 { | |
2103 octave::skip_preceeding_newline (is); | |
2104 | |
2105 std::string buf; | |
2106 | |
2107 if (is) | |
2108 { | |
2109 // Get a line of text whitespace characters included, leaving | |
2110 // newline in the stream. | |
2111 | |
2112 buf = octave::read_until_newline (is, true); | |
2113 } | |
2114 | |
2115 std::streampos pos = is.tellg (); | |
2116 | |
2117 // Set up temporary scope to use for evaluating the text that | |
2118 // defines the anonymous function. | |
2119 | |
2120 interpreter& interp = __get_interpreter__ (); | |
2121 | |
2122 tree_evaluator& tw = interp.get_evaluator (); | |
2123 | |
2124 tw.push_dummy_scope (buf); | |
2125 unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw); | |
2126 | |
2127 octave_idx_type len = 0; | |
2128 | |
2129 if (extract_keyword (is, "length", len, true) && len >= 0) | |
2130 { | |
2131 if (len > 0) | |
2132 { | |
2133 for (octave_idx_type i = 0; i < len; i++) | |
2134 { | |
2135 octave_value t2; | |
2136 bool dummy; | |
2137 | |
2138 std::string name = read_text_data (is, "", dummy, t2, i); | |
2139 | |
2140 if (! is) | |
2141 error ("load: failed to load anonymous function handle"); | |
2142 | |
2143 m_local_vars[name] = t2; | |
2144 } | |
2145 } | |
2146 } | |
2147 else | |
2148 { | |
2149 is.seekg (pos); | |
2150 is.clear (); | |
2151 } | |
2152 | |
2153 if (is) | |
2154 return parse (buf); | |
2155 | |
2156 return false; | |
2157 } | |
2158 | |
2159 bool base_anonymous_fcn_handle::save_binary (std::ostream& os, | |
2160 bool save_as_floats) | |
2161 { | |
2162 // FIXME: can we ensure that m_fcn is always defined? | |
2163 | |
2164 if (m_fcn.is_undefined ()) | |
2165 return false; | |
2166 | |
2167 std::ostringstream nmbuf; | |
2168 | |
2169 std::size_t varlen = m_local_vars.size (); | |
2170 | |
2171 nmbuf << anonymous; | |
2172 if (varlen > 0) | |
2173 nmbuf << ' ' << varlen; | |
2174 | |
2175 std::string buf_str = nmbuf.str (); | |
2176 int32_t tmp = buf_str.length (); | |
2177 os.write (reinterpret_cast<char *> (&tmp), 4); | |
2178 os.write (buf_str.c_str (), buf_str.length ()); | |
2179 | |
2180 std::ostringstream buf; | |
2181 print_raw (buf, true, 0); | |
2182 std::string stmp = buf.str (); | |
2183 tmp = stmp.length (); | |
2184 os.write (reinterpret_cast<char *> (&tmp), 4); | |
2185 os.write (stmp.c_str (), stmp.length ()); | |
2186 | |
2187 if (varlen > 0) | |
2188 { | |
2189 for (const auto& nm_val : m_local_vars) | |
2190 { | |
2191 if (! save_binary_data (os, nm_val.second, nm_val.first, | |
2192 "", 0, save_as_floats)) | |
2193 return ! os.fail (); | |
2194 } | |
2195 } | |
2196 | |
2197 return true; | |
2198 } | |
2199 | |
2200 bool base_anonymous_fcn_handle::load_binary (std::istream& is, bool swap, | |
2201 mach_info::float_format fmt) | |
2202 { | |
2203 // Read extra characters in m_name as the number of local variable | |
2204 // values in this anonymous function. | |
2205 | |
2206 octave_idx_type len = 0; | |
2207 std::size_t anl = anonymous.length (); | |
2208 if (m_name.length () > anl) | |
2209 { | |
2210 std::istringstream nm_is (m_name.substr (anl)); | |
2211 nm_is >> len; | |
2212 | |
2213 // Anonymous functions don't have names. We just used this | |
2214 // string as temporary storage to pass the number of local | |
2215 // variable values. | |
2216 | |
2217 m_name = ""; | |
2218 } | |
2219 | |
2220 int32_t tmp; | |
2221 | |
2222 if (! is.read (reinterpret_cast<char *> (&tmp), 4)) | |
2223 return false; | |
2224 if (swap) | |
2225 swap_bytes<4> (&tmp); | |
2226 | |
2227 OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1); | |
2228 // is.get (ctmp2, tmp+1, 0); caused is.eof () to be true though | |
2229 // effectively not reading over file end | |
2230 is.read (ctmp2, tmp); | |
2231 ctmp2[tmp] = 0; | |
2232 | |
2233 // Set up temporary scope to use for evaluating the text that | |
2234 // defines the anonymous function. | |
2235 | |
2236 interpreter& interp = __get_interpreter__ (); | |
2237 | |
2238 tree_evaluator& tw = interp.get_evaluator (); | |
2239 | |
2240 tw.push_dummy_scope (ctmp2); | |
2241 unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw); | |
2242 | |
2243 if (len > 0) | |
2244 { | |
2245 for (octave_idx_type i = 0; i < len; i++) | |
2246 { | |
2247 octave_value t2; | |
2248 bool dummy; | |
2249 std::string doc; | |
2250 | |
2251 std::string name | |
2252 = read_binary_data (is, swap, fmt, "", dummy, t2, doc); | |
2253 | |
2254 if (! is) | |
2255 error ("load: failed to load anonymous function handle"); | |
2256 | |
2257 m_local_vars[name] = t2; | |
2258 } | |
2259 } | |
2260 | |
2261 if (is) | |
2262 return parse (ctmp2); | |
2263 | |
2264 return false; | |
2265 } | |
2266 | |
2267 bool base_anonymous_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, | |
2268 const char *name, | |
2269 bool save_as_floats) | |
2270 { | |
2271 #if defined (HAVE_HDF5) | |
2272 | |
2273 bool retval = true; | |
2274 | |
2275 octave_hdf5_id group_hid = -1; | |
2276 #if defined (HAVE_HDF5_18) | |
2277 group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2278 octave_H5P_DEFAULT); | |
2279 #else | |
2280 group_hid = H5Gcreate (loc_id, name, 0); | |
2281 #endif | |
2282 if (group_hid < 0) | |
2283 return false; | |
2284 | |
2285 octave_hdf5_id space_hid, data_hid, type_hid; | |
2286 space_hid = data_hid = type_hid = -1; | |
2287 | |
2288 // attach the type of the variable | |
2289 type_hid = H5Tcopy (H5T_C_S1); | |
2290 H5Tset_size (type_hid, m_name.length () + 1); | |
2291 if (type_hid < 0) | |
2292 { | |
2293 H5Gclose (group_hid); | |
2294 return false; | |
2295 } | |
2296 | |
2297 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2); | |
2298 hdims[0] = 0; | |
2299 hdims[1] = 0; | |
2300 space_hid = H5Screate_simple (0, hdims, nullptr); | |
2301 if (space_hid < 0) | |
2302 { | |
2303 H5Tclose (type_hid); | |
2304 H5Gclose (group_hid); | |
2305 return false; | |
2306 } | |
2307 #if defined (HAVE_HDF5_18) | |
2308 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
2309 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2310 octave_H5P_DEFAULT); | |
2311 #else | |
2312 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, | |
2313 octave_H5P_DEFAULT); | |
2314 #endif | |
2315 if (data_hid < 0 | |
2316 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, | |
2317 octave_H5P_DEFAULT, m_name.c_str ()) < 0) | |
2318 { | |
2319 H5Sclose (space_hid); | |
2320 H5Tclose (type_hid); | |
2321 H5Gclose (group_hid); | |
2322 return false; | |
2323 } | |
2324 H5Dclose (data_hid); | |
2325 | |
2326 std::ostringstream buf; | |
2327 print_raw (buf, true, 0); | |
2328 std::string stmp = buf.str (); | |
2329 | |
2330 // attach the type of the variable | |
2331 H5Tset_size (type_hid, stmp.length () + 1); | |
2332 if (type_hid < 0) | |
2333 { | |
2334 H5Sclose (space_hid); | |
2335 H5Gclose (group_hid); | |
2336 return false; | |
2337 } | |
2338 | |
2339 #if defined (HAVE_HDF5_18) | |
2340 data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid, | |
2341 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2342 octave_H5P_DEFAULT); | |
2343 #else | |
2344 data_hid = H5Dcreate (group_hid, "fcn", type_hid, space_hid, | |
2345 octave_H5P_DEFAULT); | |
2346 #endif | |
2347 if (data_hid < 0 | |
2348 || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL, | |
2349 octave_H5P_DEFAULT, stmp.c_str ()) < 0) | |
2350 { | |
2351 H5Sclose (space_hid); | |
2352 H5Tclose (type_hid); | |
2353 H5Gclose (group_hid); | |
2354 return false; | |
2355 } | |
2356 | |
2357 H5Dclose (data_hid); | |
2358 | |
2359 std::size_t varlen = m_local_vars.size (); | |
2360 | |
2361 if (varlen > 0) | |
2362 { | |
2363 octave_hdf5_id as_id = H5Screate (H5S_SCALAR); | |
2364 | |
2365 if (as_id >= 0) | |
2366 { | |
2367 octave_hdf5_id a_id; | |
2368 #if defined (HAVE_HDF5_18) | |
2369 a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id, | |
2370 octave_H5P_DEFAULT, octave_H5P_DEFAULT); | |
2371 | |
2372 #else | |
2373 a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id, | |
2374 octave_H5P_DEFAULT); | |
2375 #endif | |
2376 | |
2377 if (a_id >= 0) | |
2378 { | |
2379 retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0); | |
2380 | |
2381 H5Aclose (a_id); | |
2382 } | |
2383 else | |
2384 retval = false; | |
2385 | |
2386 H5Sclose (as_id); | |
2387 } | |
2388 else | |
2389 retval = false; | |
2390 #if defined (HAVE_HDF5_18) | |
2391 data_hid = H5Gcreate (group_hid, "symbol table", | |
2392 octave_H5P_DEFAULT, octave_H5P_DEFAULT, | |
2393 octave_H5P_DEFAULT); | |
2394 #else | |
2395 data_hid = H5Gcreate (group_hid, "symbol table", 0); | |
2396 #endif | |
2397 if (data_hid < 0) | |
2398 { | |
2399 H5Sclose (space_hid); | |
2400 H5Tclose (type_hid); | |
2401 H5Gclose (group_hid); | |
2402 return false; | |
2403 } | |
2404 | |
2405 for (const auto& nm_val : m_local_vars) | |
2406 { | |
2407 if (! add_hdf5_data (data_hid, nm_val.second, nm_val.first, | |
2408 "", false, save_as_floats)) | |
2409 break; | |
2410 } | |
2411 | |
2412 H5Gclose (data_hid); | |
2413 } | |
2414 | |
2415 H5Sclose (space_hid); | |
2416 H5Tclose (type_hid); | |
2417 H5Gclose (group_hid); | |
2418 | |
2419 return retval; | |
2420 | |
2421 #else | |
2422 | |
2423 octave_unused_parameter (loc_id); | |
2424 octave_unused_parameter (name); | |
2425 octave_unused_parameter (save_as_floats); | |
2426 | |
2427 warn_save ("hdf5"); | |
2428 | |
2429 return false; | |
2430 | |
2431 #endif | |
2432 } | |
2433 | |
2434 bool base_anonymous_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid, | |
2435 octave_hdf5_id& space_hid, | |
2436 octave_hdf5_id& type_hid) | |
2437 { | |
2438 #if defined (HAVE_HDF5) | |
2439 | |
2440 bool success = true; | |
2441 | |
2442 #if defined (HAVE_HDF5_18) | |
2443 octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn", octave_H5P_DEFAULT); | |
2444 #else | |
2445 octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn"); | |
2446 #endif | |
2447 | |
2448 if (data_hid < 0) | |
2449 { | |
2450 H5Sclose (space_hid); | |
2451 H5Tclose (type_hid); | |
2452 H5Gclose (group_hid); | |
2453 return false; | |
2454 } | |
2455 | |
2456 H5Tclose (type_hid); | |
2457 type_hid = H5Dget_type (data_hid); | |
2458 octave_hdf5_id type_class_hid = H5Tget_class (type_hid); | |
2459 | |
2460 if (type_class_hid != H5T_STRING) | |
2461 { | |
2462 H5Sclose (space_hid); | |
2463 H5Tclose (type_hid); | |
2464 H5Dclose (data_hid); | |
2465 H5Gclose (group_hid); | |
2466 return false; | |
2467 } | |
2468 | |
2469 H5Sclose (space_hid); | |
2470 space_hid = H5Dget_space (data_hid); | |
2471 hsize_t rank = H5Sget_simple_extent_ndims (space_hid); | |
2472 | |
2473 if (rank != 0) | |
2474 { | |
2475 H5Sclose (space_hid); | |
2476 H5Tclose (type_hid); | |
2477 H5Dclose (data_hid); | |
2478 H5Gclose (group_hid); | |
2479 return false; | |
2480 } | |
2481 | |
2482 int slen = H5Tget_size (type_hid); | |
2483 if (slen < 0) | |
2484 { | |
2485 H5Sclose (space_hid); | |
2486 H5Tclose (type_hid); | |
2487 H5Dclose (data_hid); | |
2488 H5Gclose (group_hid); | |
2489 return false; | |
2490 } | |
2491 | |
2492 OCTAVE_LOCAL_BUFFER (char, fcn_tmp, slen); | |
2493 | |
2494 // create datatype for (null-terminated) string to read into: | |
2495 octave_hdf5_id st_id = H5Tcopy (H5T_C_S1); | |
2496 H5Tset_size (st_id, slen); | |
2497 | |
2498 if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL, | |
2499 octave_H5P_DEFAULT, fcn_tmp) | |
2500 < 0) | |
2501 { | |
2502 H5Tclose (st_id); | |
2503 H5Sclose (space_hid); | |
2504 H5Tclose (type_hid); | |
2505 H5Dclose (data_hid); | |
2506 H5Gclose (group_hid); | |
2507 return false; | |
2508 } | |
2509 H5Tclose (st_id); | |
2510 H5Dclose (data_hid); | |
2511 | |
2512 octave_idx_type len = 0; | |
2513 | |
2514 // we have to pull some shenanigans here to make sure | |
2515 // HDF5 doesn't print out all sorts of error messages if we | |
2516 // call H5Aopen for a non-existing attribute | |
2517 | |
2518 H5E_auto_t err_fcn; | |
2519 void *err_fcn_data; | |
2520 | |
2521 // turn off error reporting temporarily, but save the error | |
2522 // reporting function: | |
2523 #if defined (HAVE_HDF5_18) | |
2524 H5Eget_auto (octave_H5E_DEFAULT, &err_fcn, &err_fcn_data); | |
2525 H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr); | |
2526 #else | |
2527 H5Eget_auto (&err_fcn, &err_fcn_data); | |
2528 H5Eset_auto (nullptr, nullptr); | |
2529 #endif | |
2530 | |
2531 octave_hdf5_id attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE"); | |
2532 | |
2533 if (attr_id >= 0) | |
2534 { | |
2535 if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0) | |
2536 success = false; | |
2537 | |
2538 H5Aclose (attr_id); | |
2539 } | |
2540 | |
2541 // restore error reporting: | |
2542 #if defined (HAVE_HDF5_18) | |
2543 H5Eset_auto (octave_H5E_DEFAULT, err_fcn, err_fcn_data); | |
2544 #else | |
2545 H5Eset_auto (err_fcn, err_fcn_data); | |
2546 #endif | |
2547 | |
2548 // Set up temporary scope to use for evaluating the text that | |
2549 // defines the anonymous function. | |
2550 | |
2551 interpreter& interp = __get_interpreter__ (); | |
2552 | |
2553 tree_evaluator& tw = interp.get_evaluator (); | |
2554 | |
2555 tw.push_dummy_scope (fcn_tmp); | |
2556 unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw); | |
2557 | |
2558 if (len > 0 && success) | |
2559 { | |
2560 hsize_t num_obj = 0; | |
2561 #if defined (HAVE_HDF5_18) | |
2562 data_hid = H5Gopen (group_hid, "symbol table", octave_H5P_DEFAULT); | |
2563 #else | |
2564 data_hid = H5Gopen (group_hid, "symbol table"); | |
2565 #endif | |
2566 H5Gget_num_objs (data_hid, &num_obj); | |
2567 H5Gclose (data_hid); | |
2568 | |
2569 if (num_obj != static_cast<hsize_t> (len)) | |
2570 error ("load: failed to load anonymous function handle"); | |
2571 | |
2572 hdf5_callback_data dsub; | |
2573 int current_item = 0; | |
2574 for (octave_idx_type i = 0; i < len; i++) | |
2575 { | |
2576 if (hdf5_h5g_iterate (group_hid, "symbol table", ¤t_item, | |
2577 &dsub) <= 0) | |
2578 error ("load: failed to load anonymous function handle"); | |
2579 | |
2580 m_local_vars[dsub.name] = dsub.tc; | |
2581 } | |
2582 } | |
2583 | |
2584 if (success) | |
2585 return parse (fcn_tmp); | |
2586 | |
2587 return false; | |
2588 | |
2589 #else | |
2590 | |
2591 octave_unused_parameter (group_hid); | |
2592 octave_unused_parameter (space_hid); | |
2593 octave_unused_parameter (type_hid); | |
2594 | |
2595 return false; | |
2596 | |
2597 #endif | |
2598 } | |
2599 | |
2600 void base_anonymous_fcn_handle::print_raw (std::ostream& os, bool, int) const | |
2601 { | |
2602 tree_print_code tpc (os); | |
2603 | |
2604 octave_user_function *f = m_fcn.user_function_value (); | |
2605 | |
2606 if (! f) | |
2607 error ("invalid anonymous function handle"); | |
2608 | |
2609 os << "@"; | |
2610 | |
2611 // The parameter list should always be valid for anonymous | |
2612 // functions, so we should always call accept for it, and it will | |
2613 // print the parens for us. | |
2614 | |
2615 tree_parameter_list *p = f->parameter_list (); | |
2616 | |
2617 if (p) | |
2618 p->accept (tpc); | |
2619 | |
2620 os << " "; | |
2621 | |
2622 tree_statement_list *b = f->body (); | |
2623 | |
2624 panic_if (b->length () != 1); | |
2625 | |
2626 tree_statement *s = b->front (); | |
2627 | |
2628 if (! s) | |
2629 error ("invalid anonymous function handle"); | |
2630 | |
2631 panic_unless (s->is_expression ()); | |
2632 | |
2633 tree_expression *e = s->expression (); | |
2634 | |
2635 if (! e) | |
2636 error ("invalid anonymous function handle"); | |
2637 | |
2638 tpc.print_fcn_handle_body (e); | |
2639 } | |
2640 | |
2641 bool base_anonymous_fcn_handle::parse (const std::string& fcn_text) | |
2642 { | |
2643 // FIXME: If evaluation of the string gives us an anonymous function | |
2644 // handle object, then why extract the function and create a new | |
2645 // anonymous function object? Why not just attach the workspace | |
2646 // values to the object returned by eval_string? This code is also is | |
2647 // duplicated in read_mat5_binary_element in ls-mat5.cc. | |
2648 | |
2649 interpreter& interp = __get_interpreter__ (); | |
2650 | |
2651 // Set up temporary scope to use for evaluating the text that defines | |
2652 // the anonymous function so that we don't pick up values of random | |
2653 // variables that might be in the current scope. | |
2654 | |
2655 tree_evaluator& tw = interp.get_evaluator (); | |
2656 tw.push_dummy_scope ("read_mat5_binary_element"); | |
2657 | |
2658 unwind_action act ([&tw] () { tw.pop_scope (); }); | |
2659 | |
2660 int parse_status; | |
2661 octave_value anonymous_fcn_hdl | |
2662 = interp.eval_string (fcn_text, true, parse_status); | |
2663 | |
2664 if (parse_status != 0) | |
2665 return false; | |
2666 | |
2667 octave_fcn_handle *fh = anonymous_fcn_hdl.fcn_handle_value (); | |
2668 | |
2669 if (! fh) | |
2670 return false; | |
2671 | |
2672 m_fcn = fh->fcn_val (); | |
2673 | |
2674 octave_user_function *uf = m_fcn.user_function_value (true); | |
2675 | |
2676 if (uf) | |
2677 { | |
2678 symbol_scope uf_scope = uf->scope (); | |
2679 | |
2680 if (uf_scope) | |
2681 uf_scope.cache_name (m_name); | |
2682 } | |
2683 | |
2684 return true; | |
2685 } | |
2686 | |
2687 anonymous_fcn_handle::anonymous_fcn_handle (const octave_value& fcn, | |
2688 const stack_frame::local_vars_map& local_vars, | |
2689 const std::shared_ptr<stack_frame>& stack_context) | |
2690 : base_anonymous_fcn_handle (fcn, local_vars), | |
2691 m_stack_context (stack_context) | |
2692 { | |
2693 if (m_stack_context) | |
2694 m_stack_context->mark_closure_context (); | |
2695 } | |
2696 | |
2697 octave_value anonymous_fcn_handle::make_weak_anonymous_handle (void) const | |
2698 { | |
2699 return octave_value (new octave_fcn_handle | |
2700 (new weak_anonymous_fcn_handle (*this))); | |
2701 } | |
2702 | |
2703 octave_value_list | |
2704 anonymous_fcn_handle::call (int nargout, const octave_value_list& args) | |
2705 { | |
2706 tree_evaluator& tw = __get_evaluator__ (); | |
2707 | |
2708 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | |
2709 | |
2710 tw.push_stack_frame (oct_usr_fcn, m_local_vars, m_stack_context); | |
2711 | |
2712 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
2713 | |
2714 return oct_usr_fcn->execute (tw, nargout, args); | |
2715 } | |
2716 | |
2717 octave_value anonymous_fcn_handle::workspace (void) const | |
2718 { | |
2719 octave_scalar_map local_vars_map; | |
2720 | |
2721 for (const auto& nm_val : m_local_vars) | |
2722 local_vars_map.assign (nm_val.first, nm_val.second); | |
2723 | |
2724 // FIXME: it would be more convenient if stack_frame::workspace | |
2725 // returned a Cell object directly instead of a Cell in an | |
2726 // octave_value object. | |
2727 | |
2728 Cell cell_frames; | |
2729 | |
2730 if (m_stack_context) | |
2731 { | |
2732 octave_value ov_frames = m_stack_context->workspace (); | |
2733 cell_frames = ov_frames.cell_value (); | |
2734 } | |
2735 | |
2736 octave_idx_type num_frames = cell_frames.numel (); | |
2737 // FIXME: It seems there should be a simple way to concatenate cells... | |
2738 Cell retval = Cell (num_frames+1, 1); | |
2739 retval(0) = m_local_vars; | |
2740 for (octave_idx_type i = 0; i < num_frames; i++) | |
2741 retval(i+1) = cell_frames(i); | |
2742 | |
2743 return retval; | |
2744 } | |
2745 | |
2746 bool is_equal_to (const anonymous_fcn_handle& fh1, | |
2747 const anonymous_fcn_handle& fh2) | |
2748 { | |
2749 if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
2750 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
2751 else | |
2752 return false; | |
2753 } | |
2754 | |
2755 octave_value_list | |
2756 weak_anonymous_fcn_handle::call (int nargout, const octave_value_list& args) | |
2757 { | |
2758 tree_evaluator& tw = __get_evaluator__ (); | |
2759 | |
2760 octave_user_function *oct_usr_fcn = m_fcn.user_function_value (); | |
2761 | |
2762 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | |
2763 | |
2764 tw.push_stack_frame (oct_usr_fcn, m_local_vars, frames); | |
2765 | |
2766 unwind_action act ([&tw] () { tw.pop_stack_frame (); }); | |
2767 | |
2768 return oct_usr_fcn->execute (tw, nargout, args); | |
2769 } | |
2770 | |
2771 octave_value weak_anonymous_fcn_handle::workspace (void) const | |
2772 { | |
2773 octave_scalar_map local_vars_map; | |
2774 | |
2775 for (const auto& nm_val : m_local_vars) | |
2776 local_vars_map.assign (nm_val.first, nm_val.second); | |
2777 | |
2778 // FIXME: it would be more convenient if stack_frame::workspace | |
2779 // returned a Cell object directly instead of a Cell in an | |
2780 // octave_value object. | |
2781 | |
2782 std::shared_ptr<stack_frame> frames = m_stack_context.lock (); | |
2783 | |
2784 Cell cell_frames; | |
2785 | |
2786 if (frames) | |
2787 { | |
2788 octave_value ov_frames = frames->workspace (); | |
2789 cell_frames = ov_frames.cell_value (); | |
2790 } | |
2791 | |
2792 octave_idx_type num_frames = cell_frames.numel (); | |
2793 | |
2794 // FIXME: It seems there should be a simple way to concatenate | |
2795 // cells... | |
2796 Cell retval = Cell (num_frames+1, 1); | |
2797 retval(0) = m_local_vars; | |
2798 for (octave_idx_type i = 0; i < num_frames; i++) | |
2799 retval(i+1) = cell_frames(i); | |
2800 | |
2801 return retval; | |
2802 } | |
2803 | |
2804 bool is_equal_to (const weak_anonymous_fcn_handle& fh1, | |
2805 const weak_anonymous_fcn_handle& fh2) | |
2806 { | |
2807 if (fh1.m_name == fh2.m_name | |
2808 && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ()) | |
2809 return fh1.m_fcn.is_copy_of (fh2.m_fcn); | |
2810 else | |
2811 return false; | |
2812 } | |
2813 | 2813 |
2814 OCTAVE_END_NAMESPACE(octave) | 2814 OCTAVE_END_NAMESPACE(octave) |
2815 | 2815 |
2816 octave_fcn_handle::octave_fcn_handle (void) | 2816 octave_fcn_handle::octave_fcn_handle (void) |
2817 : octave_base_value (), m_rep (new octave::invalid_fcn_handle ()) | 2817 : octave_base_value (), m_rep (new octave::invalid_fcn_handle ()) |
2955 { | 2955 { |
2956 std::string name; | 2956 std::string name; |
2957 is >> name; | 2957 is >> name; |
2958 | 2958 |
2959 new_rep.reset (new octave::simple_fcn_handle (name, fpath, | 2959 new_rep.reset (new octave::simple_fcn_handle (name, fpath, |
2960 octaveroot)); | 2960 octaveroot)); |
2961 } | 2961 } |
2962 else if (subtype == "scopedfunction") | 2962 else if (subtype == "scopedfunction") |
2963 { | 2963 { |
2964 std::string name; | 2964 std::string name; |
2965 is >> name; | 2965 is >> name; |
2966 | 2966 |
2967 new_rep.reset (new octave::scoped_fcn_handle (name, fpath, | 2967 new_rep.reset (new octave::scoped_fcn_handle (name, fpath, |
2968 octaveroot)); | 2968 octaveroot)); |
2969 } | 2969 } |
2970 else if (subtype == "anonymous") | 2970 else if (subtype == "anonymous") |
2971 new_rep.reset (new octave::anonymous_fcn_handle ()); | 2971 new_rep.reset (new octave::anonymous_fcn_handle ()); |
2972 else if (subtype == "nested") | 2972 else if (subtype == "nested") |
2973 { | 2973 { |
2974 std::string name; | 2974 std::string name; |
2975 is >> name; | 2975 is >> name; |
2976 | 2976 |
2977 new_rep.reset (new octave::nested_fcn_handle (name, fpath, | 2977 new_rep.reset (new octave::nested_fcn_handle (name, fpath, |
2978 octaveroot)); | 2978 octaveroot)); |
2979 } | 2979 } |
2980 else if (subtype == "classsimple") | 2980 else if (subtype == "classsimple") |
2981 { | 2981 { |
2982 std::string name; | 2982 std::string name; |
2983 is >> name; | 2983 is >> name; |
2984 | 2984 |
2985 new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, | 2985 new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, |
2986 octaveroot)); | 2986 octaveroot)); |
2987 } | 2987 } |
2988 } | 2988 } |
2989 | 2989 |
2990 if (! new_rep) | 2990 if (! new_rep) |
2991 return false; | 2991 return false; |
3082 new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot)); | 3082 new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot)); |
3083 else if (subtype == "nested") | 3083 else if (subtype == "nested") |
3084 new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot)); | 3084 new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot)); |
3085 else if (subtype == "classsimple") | 3085 else if (subtype == "classsimple") |
3086 new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, | 3086 new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, |
3087 octaveroot)); | 3087 octaveroot)); |
3088 } | 3088 } |
3089 | 3089 |
3090 if (! new_rep) | 3090 if (! new_rep) |
3091 return false; | 3091 return false; |
3092 | 3092 |
3236 new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot)); | 3236 new_rep.reset (new octave::scoped_fcn_handle (name, fpath, octaveroot)); |
3237 else if (subtype == "nested") | 3237 else if (subtype == "nested") |
3238 new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot)); | 3238 new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot)); |
3239 else if (subtype == "classsimple") | 3239 else if (subtype == "classsimple") |
3240 new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, | 3240 new_rep.reset (new octave::class_simple_fcn_handle (name, fpath, |
3241 octaveroot)); | 3241 octaveroot)); |
3242 } | 3242 } |
3243 | 3243 |
3244 bool status = false; | 3244 bool status = false; |
3245 | 3245 |
3246 if (new_rep && new_rep->load_hdf5 (group_hid, space_hid, type_hid)) | 3246 if (new_rep && new_rep->load_hdf5 (group_hid, space_hid, type_hid)) |
3457 @end deftypefn */) | 3457 @end deftypefn */) |
3458 { | 3458 { |
3459 if (args.length () != 1) | 3459 if (args.length () != 1) |
3460 print_usage (); | 3460 print_usage (); |
3461 | 3461 |
3462 octave_fcn_handle *fh = args(0).xfcn_handle_value ("functions: FCN_HANDLE argument must be a function handle object"); | 3462 octave_fcn_handle *fh = args( |
3463 0).xfcn_handle_value ("functions: FCN_HANDLE argument must be a function handle object"); | |
3463 | 3464 |
3464 return ovl (fh->info ()); | 3465 return ovl (fh->info ()); |
3465 } | 3466 } |
3466 | 3467 |
3467 DEFUN (func2str, args, , | 3468 DEFUN (func2str, args, , |
3473 @end deftypefn */) | 3474 @end deftypefn */) |
3474 { | 3475 { |
3475 if (args.length () != 1) | 3476 if (args.length () != 1) |
3476 print_usage (); | 3477 print_usage (); |
3477 | 3478 |
3478 octave_fcn_handle *fh = args(0).xfcn_handle_value ("func2str: FCN_HANDLE argument must be a function handle object"); | 3479 octave_fcn_handle *fh = args( |
3480 0).xfcn_handle_value ("func2str: FCN_HANDLE argument must be a function handle object"); | |
3479 | 3481 |
3480 if (! fh) | 3482 if (! fh) |
3481 error ("func2str: FCN_HANDLE must be a valid function handle"); | 3483 error ("func2str: FCN_HANDLE must be a valid function handle"); |
3482 | 3484 |
3483 octave_value retval; | 3485 octave_value retval; |