changeset 18262:69990d5edcc2

Allow to parse external methods declaration in classdef files. * libinterp/parse-tree/parser.h (octave_base_parser::start_classdef_external_method, octave_base_parser::finish_classdef_external_method): New methods. * libinterp/parse-tree/oct-parse.in.yy (octave_base_parser::start_classdef_external_method, octave_base_parser::finish_classdef_external_method): Likewise. (%destructor): Add missing directives for classdef-related types. (method, method_decl, method_decl1): New nonterminal rules. (methods_list): Use "method" on terminal. * libinterp/octave-value/ov-classdef.cc (cdef_package::cdef_package_rep::meta_subsref): When searching for package methods, only issue an error when error_state is not set.
author Michael Goffioul <michael.goffioul@gmail.com>
date Sun, 12 Jan 2014 15:54:43 -0500
parents bffa6c8255a9
children b5be1a2aa5ab
files libinterp/octave-value/ov-classdef.cc libinterp/parse-tree/oct-parse.in.yy libinterp/parse-tree/parse.h
diffstat 3 files changed, 123 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-classdef.cc	Sat Jan 11 22:50:11 2014 -0800
+++ b/libinterp/octave-value/ov-classdef.cc	Sun Jan 12 15:54:43 2014 -0500
@@ -3176,7 +3176,7 @@
                   else
                     retval(0) = o;
                 }
-              else
+              else if (! error_state)
                 error ("member `%s' in package `%s' does not exist",
                        nm.c_str (), get_name ().c_str ());
             }
--- a/libinterp/parse-tree/oct-parse.in.yy	Sat Jan 11 22:50:11 2014 -0800
+++ b/libinterp/parse-tree/oct-parse.in.yy	Sun Jan 12 15:54:43 2014 -0500
@@ -298,6 +298,8 @@
 %type <tree_classdef_enum_type> class_enum
 %type <tree_classdef_enum_list_type> enum_list
 %type <tree_classdef_enum_block_type> enum_block
+%type <tree_function_def_type> method_decl method
+%type <octave_user_function_type> method_decl1
 
 // Precedence and associativity.
 %right '=' ADD_EQ SUB_EQ MUL_EQ DIV_EQ LEFTDIV_EQ POW_EQ EMUL_EQ EDIV_EQ ELEFTDIV_EQ EPOW_EQ OR_EQ AND_EQ LSHIFT_EQ RSHIFT_EQ
@@ -334,6 +336,8 @@
 %destructor { delete $$; } <tree_expression_type> 
 %destructor { delete $$; } <tree_constant_type> 
 %destructor { delete $$; } <tree_fcn_handle_type> 
+%destructor { delete $$; } <tree_funcall>
+%destructor { delete $$; } <tree_function_def>
 %destructor { delete $$; } <tree_anon_fcn_handle_type> 
 %destructor { delete $$; } <tree_identifier_type> 
 %destructor { delete $$; } <tree_index_expression_type> 
@@ -354,6 +358,24 @@
 %destructor { delete $$; } <tree_statement_list_type> 
 %destructor { delete $$; } <octave_user_function_type> 
 
+%destructor { delete $$; } <tree_classdef_type>
+%destructor { delete $$; } <tree_classdef_attribute_type>
+%destructor { delete $$; } <tree_classdef_attribute_list_type>
+%destructor { delete $$; } <tree_classdef_superclass_type>
+%destructor { delete $$; } <tree_classdef_superclass_list_type>
+%destructor { delete $$; } <tree_classdef_body_type>
+%destructor { delete $$; } <tree_classdef_property_type>
+%destructor { delete $$; } <tree_classdef_property_list_type>
+%destructor { delete $$; } <tree_classdef_properties_block_type>
+%destructor { delete $$; } <tree_classdef_methods_list_type>
+%destructor { delete $$; } <tree_classdef_methods_block_type>
+%destructor { delete $$; } <tree_classdef_event_type>
+%destructor { delete $$; } <tree_classdef_events_list_type>
+%destructor { delete $$; } <tree_classdef_events_block_type>
+%destructor { delete $$; } <tree_classdef_enum_type>
+%destructor { delete $$; } <tree_classdef_enum_list_type>
+%destructor { delete $$; } <tree_classdef_enum_block_type>
+
 %destructor {
     warning_with_id
       ("Octave:parser-destructor",
@@ -1605,7 +1627,30 @@
                   }
                 ;
 
-methods_list    : function
+method_decl1    : identifier
+		  {
+                    if (! ($$ = parser.start_classdef_external_method ($1, 0)))
+                      ABORT_PARSE;
+                  }
+		| identifier param_list
+		  { if (! ($$ = parser.start_classdef_external_method ($1, $2)))
+                      ABORT_PARSE;
+                  }
+                ;
+
+method_decl     : stash_comment method_decl1
+		  { $$ = parser.finish_classdef_external_method ($2, 0, $1); }
+                | stash_comment return_list '=' method_decl1
+		  { $$ = parser.finish_classdef_external_method ($4, $2, $1); }
+                ;
+
+method          : method_decl
+		  { $$ = $1; }
+		| function
+                  { $$ = $1; }
+                ;
+
+methods_list    : method
                   {
                     octave_value fcn;
                     if ($1)
@@ -1613,7 +1658,7 @@
                     delete $1;
                     $$ = new tree_classdef_methods_list (fcn);
                   }
-                | methods_list opt_sep function
+                | methods_list opt_sep method
                   {
                     octave_value fcn;
                     if ($3)
@@ -3199,6 +3244,72 @@
   return retval;
 }
 
+octave_user_function*
+octave_base_parser::start_classdef_external_method (tree_identifier *id,
+		                                    tree_parameter_list *pl)
+{
+  octave_user_function* retval = 0;
+
+  // External methods are only allowed within @-folders. In this case,
+  // curr_class_name will be non-empty.
+
+  if (! curr_class_name.empty ())
+    {
+
+      std::string mname = id->name ();
+
+      // Methods that cannot be declared outside the classdef file:
+      // - methods with '.' character (e.g. property accessors)
+      // - class constructor
+      // - `delete'
+
+      if (mname.find_first_of (".") == std::string::npos
+          && mname != "delete"
+          && mname != curr_class_name)
+        {
+          // Create a dummy function that is used until the real method
+          // is loaded.
+
+          retval = new octave_user_function (-1, pl);
+
+          retval->stash_function_name (mname);
+
+          int l = id->line ();
+          int c = id->column ();
+
+          retval->stash_fcn_location (l, c);
+        }
+      else
+        bison_error ("invalid external method declaration, an external "
+                     "method cannot be the class constructor, `delete' "
+                     "or have a dot (.) character in its name");
+    }
+  else
+    bison_error ("external methods are only allowed in @-folders");
+
+  if (! retval)
+    delete id;
+
+  return retval;
+}
+
+tree_function_def *
+octave_base_parser::finish_classdef_external_method (octave_user_function *fcn,
+		                                     tree_parameter_list *ret_list,
+                                                     octave_comment_list *cl)
+{
+  if (ret_list)
+    fcn->define_ret_list (ret_list);
+
+  if (cl)
+    fcn->stash_leading_comment (cl);
+
+  int l = fcn->beginning_line ();
+  int c = fcn->beginning_column ();
+
+  return new tree_function_def (fcn, l, c);
+}
+
 // Make an index expression.
 
 tree_index_expression *
--- a/libinterp/parse-tree/parse.h	Sat Jan 11 22:50:11 2014 -0800
+++ b/libinterp/parse-tree/parse.h	Sun Jan 12 15:54:43 2014 -0500
@@ -339,6 +339,15 @@
                             tree_classdef_enum_list *elist,
                             token *end_tok, octave_comment_list *lc);
 
+  octave_user_function *
+  start_classdef_external_method (tree_identifier *id,
+                                  tree_parameter_list *pl);
+
+  tree_function_def *
+  finish_classdef_external_method (octave_user_function *fcn,
+                                   tree_parameter_list *ret_list,
+                                   octave_comment_list *cl);
+
   // Make an index expression.
   tree_index_expression *
   make_index_expression (tree_expression *expr,