Mercurial > hg > octave-nkf
comparison libinterp/octave-value/ov-classdef.cc @ 16698:13b3b92ea99c classdef
Implement property accessors.
* libinterp/parse-tree/oct-parse.in.yy: Prepend "get." or "set." to
property accessor methods names.
* libinterp/octave-value/ov-classdef.h
(cdef_property_rep::is_recursive_set): Delete method.
* libinterp/octave-value/ov-classdef.cc
(cdef_property::cdef_property_rep::is_recursive_set): Delete method.
(is_method_executing): New static utility function.
(cdef_property::cdef_property_rep::get_value,
cdef_property::cdef_property_rep::set)value): Use it to check whether
the accessor method is already executing for the same object.
(cdef_class::make_meta_class): Associate property accessors to their
corresponding properties.
(make_fcn_handle(octave_value, string)): New static overload.
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Fri, 24 May 2013 15:41:52 -0400 |
parents | 665fa0f621cc |
children | c4f5c781c3ca |
comparison
equal
deleted
inserted
replaced
16696:665fa0f621cc | 16698:13b3b92ea99c |
---|---|
129 octave_value fcn_handle (new octave_fcn_handle (fcn, nm)); | 129 octave_value fcn_handle (new octave_fcn_handle (fcn, nm)); |
130 | 130 |
131 return fcn_handle; | 131 return fcn_handle; |
132 } | 132 } |
133 | 133 |
134 static octave_value | |
135 make_fcn_handle (const octave_value& fcn, const std::string& nm) | |
136 { | |
137 octave_value retval; | |
138 | |
139 if (fcn.is_defined ()) | |
140 retval = octave_value (new octave_fcn_handle (fcn, nm)); | |
141 | |
142 return retval; | |
143 } | |
144 | |
134 inline octave_value_list | 145 inline octave_value_list |
135 execute_ov (octave_value val, const octave_value_list& args, int nargout) | 146 execute_ov (octave_value val, const octave_value_list& args, int nargout) |
136 { | 147 { |
137 std::list<octave_value_list> idx (1, args); | 148 std::list<octave_value_list> idx (1, args); |
138 | 149 |
344 } | 355 } |
345 else | 356 else |
346 error ("invalid property/method access in class `%s'", | 357 error ("invalid property/method access in class `%s'", |
347 cls.get_name ().c_str ()); | 358 cls.get_name ().c_str ()); |
348 | 359 |
360 return false; | |
361 } | |
362 | |
363 bool | |
364 is_method_executing (const octave_value& ov, const cdef_object& obj) | |
365 { | |
366 octave_function* stack_fcn = octave_call_stack::current (); | |
367 | |
368 octave_function* method_fcn = ov.function_value (true); | |
369 | |
370 // Does the top of the call stack match our target function? | |
371 | |
372 if (stack_fcn && stack_fcn == method_fcn) | |
373 { | |
374 octave_user_function* uf = method_fcn->user_function_value (true); | |
375 | |
376 // We can only check the context object for user-function (not builtin), | |
377 // where we have access to the parameters (arguments and return values). | |
378 // That's ok as there's no need to call this function for builtin | |
379 // methods. | |
380 | |
381 if (uf) | |
382 { | |
383 // At this point, the method is executing, but we still need to | |
384 // check the context object for which the method is executing. For | |
385 // methods, it's the first argument of the function; for ctors, it | |
386 // is the first return value. | |
387 | |
388 tree_parameter_list* pl = uf->is_classdef_constructor () | |
389 ? uf->return_list () : uf->parameter_list (); | |
390 | |
391 if (pl && pl->size () > 0) | |
392 { | |
393 octave_value arg0 = pl->front ()->lvalue ().value (); | |
394 | |
395 if (arg0.is_defined () && arg0.type_name () == "object") | |
396 { | |
397 cdef_object arg0_obj = to_cdef (arg0); | |
398 | |
399 return obj.is (arg0_obj); | |
400 } | |
401 } | |
402 } | |
403 } | |
404 | |
349 return false; | 405 return false; |
350 } | 406 } |
351 | 407 |
352 static octave_value_list | 408 static octave_value_list |
353 class_get_methods (const octave_value_list& args, int /* nargout */) | 409 class_get_methods (const octave_value_list& args, int /* nargout */) |
2476 | 2532 |
2477 tree_classdef_body* b = t->body (); | 2533 tree_classdef_body* b = t->body (); |
2478 | 2534 |
2479 if (b) | 2535 if (b) |
2480 { | 2536 { |
2537 // Keep track of the get/set accessor methods. They will be used | |
2538 // later on when creating properties. | |
2539 | |
2540 std::map<std::string, octave_value> get_methods; | |
2541 std::map<std::string, octave_value> set_methods; | |
2542 | |
2481 // Method blocks | 2543 // Method blocks |
2482 | 2544 |
2483 std::list<tree_classdef_methods_block *> mb_list = b->methods_list (); | 2545 std::list<tree_classdef_methods_block *> mb_list = b->methods_list (); |
2484 | 2546 |
2485 for (tree_classdef_body::methods_list_iterator it = mb_list.begin (); | 2547 for (tree_classdef_body::methods_list_iterator it = mb_list.begin (); |
2497 { | 2559 { |
2498 std::string aname = (*ait)->ident ()->name (); | 2560 std::string aname = (*ait)->ident ()->name (); |
2499 octave_value avalue = compute_attribute_value (*ait); | 2561 octave_value avalue = compute_attribute_value (*ait); |
2500 | 2562 |
2501 gnulib::printf ("method attribute: %s = %s\n", aname.c_str (), | 2563 gnulib::printf ("method attribute: %s = %s\n", aname.c_str (), |
2502 attribute_value_to_string (*ait, avalue).c_str ()); | 2564 attribute_value_to_string (*ait, avalue).c_str ()); |
2503 amap[aname] = avalue; | 2565 amap[aname] = avalue; |
2504 } | 2566 } |
2505 } | 2567 } |
2506 | 2568 |
2507 // Methods | 2569 // Methods |
2510 { | 2572 { |
2511 for (tree_classdef_methods_list::iterator mit = (*it)->element_list ()->begin (); | 2573 for (tree_classdef_methods_list::iterator mit = (*it)->element_list ()->begin (); |
2512 mit != (*it)->element_list ()->end (); ++mit) | 2574 mit != (*it)->element_list ()->end (); ++mit) |
2513 { | 2575 { |
2514 std::string mname = mit->function_value ()->name (); | 2576 std::string mname = mit->function_value ()->name (); |
2515 cdef_method meth = make_method (retval, mname, *mit); | 2577 std::string mprefix = mname.substr (0, 4); |
2516 | 2578 |
2517 gnulib::printf ("%s: %s\n", (mname == class_name ? "constructor" : "method"), | 2579 if (mprefix == "get.") |
2518 mname.c_str ()); | 2580 get_methods[mname.substr (4)] = |
2519 for (std::map<std::string, octave_value>::iterator ait = amap.begin (); | 2581 make_fcn_handle (*mit, full_class_name + ">" + mname); |
2520 ait != amap.end (); ++ait) | 2582 else if (mprefix == "set.") |
2521 meth.put (ait->first, ait->second); | 2583 set_methods[mname.substr (4)] = |
2522 | 2584 make_fcn_handle (*mit, full_class_name + ">" + mname); |
2523 retval.install_method (meth); | 2585 else |
2586 { | |
2587 cdef_method meth = make_method (retval, mname, *mit); | |
2588 | |
2589 gnulib::printf ("%s: %s\n", (mname == class_name ? "constructor" : "method"), | |
2590 mname.c_str ()); | |
2591 for (std::map<std::string, octave_value>::iterator ait = amap.begin (); | |
2592 ait != amap.end (); ++ait) | |
2593 meth.put (ait->first, ait->second); | |
2594 | |
2595 retval.install_method (meth); | |
2596 } | |
2524 } | 2597 } |
2525 } | 2598 } |
2526 } | 2599 } |
2527 | 2600 |
2528 // Property blocks | 2601 // Property blocks |
2567 if ((*it)->element_list ()) | 2640 if ((*it)->element_list ()) |
2568 { | 2641 { |
2569 for (tree_classdef_property_list::iterator pit = (*it)->element_list ()->begin (); | 2642 for (tree_classdef_property_list::iterator pit = (*it)->element_list ()->begin (); |
2570 pit != (*it)->element_list ()->end (); ++pit) | 2643 pit != (*it)->element_list ()->end (); ++pit) |
2571 { | 2644 { |
2572 cdef_property prop = ::make_property (retval, (*pit)->ident ()->name ()); | 2645 std::string prop_name = (*pit)->ident ()->name (); |
2646 | |
2647 cdef_property prop = ::make_property (retval, prop_name); | |
2573 | 2648 |
2574 gnulib::printf ("property: %s\n", (*pit)->ident ()->name ().c_str ()); | 2649 gnulib::printf ("property: %s\n", (*pit)->ident ()->name ().c_str ()); |
2575 if ((*pit)->expression ()) | 2650 if ((*pit)->expression ()) |
2576 { | 2651 { |
2577 octave_value pvalue = (*pit)->expression ()->rvalue1 (); | 2652 octave_value pvalue = (*pit)->expression ()->rvalue1 (); |
2579 gnulib::printf ("property default: %s\n", | 2654 gnulib::printf ("property default: %s\n", |
2580 attribute_value_to_string (*pit, pvalue).c_str ()); | 2655 attribute_value_to_string (*pit, pvalue).c_str ()); |
2581 prop.put ("DefaultValue", pvalue); | 2656 prop.put ("DefaultValue", pvalue); |
2582 } | 2657 } |
2583 | 2658 |
2659 // Install property attributes. This is done before assigning the | |
2660 // property accessors so we can do validationby using cdef_property | |
2661 // methods. | |
2662 | |
2584 for (std::map<std::string, octave_value>::iterator ait = amap.begin (); | 2663 for (std::map<std::string, octave_value>::iterator ait = amap.begin (); |
2585 ait != amap.end (); ++ait) | 2664 ait != amap.end (); ++ait) |
2586 prop.put (ait->first, ait->second); | 2665 prop.put (ait->first, ait->second); |
2666 | |
2667 // Install property access methods, if any. Remove the accessor | |
2668 // methods from the temporary storage map, so we can detect which | |
2669 // ones are invalid and do not correspond to a defined property. | |
2670 | |
2671 std::map<std::string, octave_value>::iterator git = | |
2672 get_methods.find (prop_name); | |
2673 | |
2674 if (git != get_methods.end ()) | |
2675 { | |
2676 prop.put ("GetMethod", git->second); | |
2677 get_methods.erase (git); | |
2678 } | |
2679 | |
2680 std::map<std::string, octave_value>::iterator sit = | |
2681 set_methods.find (prop_name); | |
2682 | |
2683 if (sit != set_methods.end ()) | |
2684 { | |
2685 prop.put ("SetMethod", sit->second); | |
2686 set_methods.erase (sit); | |
2687 } | |
2587 | 2688 |
2588 retval.install_property (prop); | 2689 retval.install_property (prop); |
2589 } | 2690 } |
2590 } | 2691 } |
2591 } | 2692 } |
2630 | 2731 |
2631 octave_value get_fcn = get ("GetMethod"); | 2732 octave_value get_fcn = get ("GetMethod"); |
2632 | 2733 |
2633 // FIXME: should check whether we're already in get accessor method | 2734 // FIXME: should check whether we're already in get accessor method |
2634 | 2735 |
2635 if (get_fcn.is_empty ()) | 2736 if (get_fcn.is_empty () || is_method_executing (get_fcn, obj)) |
2636 retval = obj.get (get ("Name").string_value ()); | 2737 retval = obj.get (get ("Name").string_value ()); |
2637 else | 2738 else |
2638 { | 2739 { |
2639 octave_value_list args; | 2740 octave_value_list args; |
2640 | 2741 |
2695 } | 2796 } |
2696 } | 2797 } |
2697 | 2798 |
2698 octave_value set_fcn = get ("SetMethod"); | 2799 octave_value set_fcn = get ("SetMethod"); |
2699 | 2800 |
2700 if (set_fcn.is_empty () || is_recursive_set (obj)) | 2801 if (set_fcn.is_empty () || is_method_executing (set_fcn, obj)) |
2701 { | 2802 obj.put (get ("Name").string_value (), val); |
2702 obj.put (get ("Name").string_value (), val); | |
2703 } | |
2704 else | 2803 else |
2705 { | 2804 { |
2706 octave_value_list args; | 2805 octave_value_list args; |
2707 | 2806 |
2708 args(0) = to_ov (obj); | 2807 args(0) = to_ov (obj); |