00001 /* 00002 00003 Copyright (C) 1996-2012 John W. Eaton 00004 00005 This file is part of Octave. 00006 00007 Octave is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU General Public License as published by the 00009 Free Software Foundation; either version 3 of the License, or (at your 00010 option) any later version. 00011 00012 Octave is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 00015 for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with Octave; see the file COPYING. If not, see 00019 <http://www.gnu.org/licenses/>. 00020 00021 */ 00022 00023 #ifdef HAVE_CONFIG_H 00024 #include <config.h> 00025 #endif 00026 00027 #include <iostream> 00028 #include <string> 00029 00030 #include "str-vec.h" 00031 00032 #include "defun.h" 00033 #include "error.h" 00034 #include "oct-lvalue.h" 00035 #include "oct-obj.h" 00036 #include "ov.h" 00037 #include "ov-usr-fcn.h" 00038 #include "parse.h" 00039 #include "pt-arg-list.h" 00040 #include "pt-exp.h" 00041 #include "pt-id.h" 00042 #include "pt-pr-code.h" 00043 #include "pt-walk.h" 00044 #include "toplev.h" 00045 #include "unwind-prot.h" 00046 00047 // Argument lists. 00048 00049 tree_argument_list::~tree_argument_list (void) 00050 { 00051 while (! empty ()) 00052 { 00053 iterator p = begin (); 00054 delete *p; 00055 erase (p); 00056 } 00057 } 00058 00059 bool 00060 tree_argument_list::has_magic_end (void) const 00061 { 00062 for (const_iterator p = begin (); p != end (); p++) 00063 { 00064 tree_expression *elt = *p; 00065 00066 if (elt && elt->has_magic_end ()) 00067 return true; 00068 } 00069 00070 return false; 00071 } 00072 00073 void 00074 tree_argument_list::append (const element_type& s) 00075 { 00076 octave_base_list<tree_expression *>::append (s); 00077 00078 if (! list_includes_magic_end && s && s->has_magic_end ()) 00079 list_includes_magic_end = true; 00080 00081 if (! list_includes_magic_tilde && s && s->is_identifier ()) 00082 { 00083 tree_identifier *id = dynamic_cast<tree_identifier *> (s); 00084 list_includes_magic_tilde = id && id->is_black_hole (); 00085 } 00086 } 00087 00088 bool 00089 tree_argument_list::all_elements_are_constant (void) const 00090 { 00091 for (const_iterator p = begin (); p != end (); p++) 00092 { 00093 tree_expression *elt = *p; 00094 00095 if (! elt->is_constant ()) 00096 return false; 00097 } 00098 00099 return true; 00100 } 00101 00102 static const octave_value *indexed_object = 0; 00103 static int index_position = 0; 00104 static int num_indices = 0; 00105 00106 DEFCONSTFUN (__end__, , , 00107 "internal function") 00108 { 00109 octave_value retval; 00110 00111 if (indexed_object) 00112 { 00113 if (indexed_object->is_object ()) 00114 { 00115 octave_value_list args; 00116 00117 args(2) = num_indices; 00118 args(1) = index_position + 1; 00119 args(0) = *indexed_object; 00120 00121 std::string class_name = indexed_object->class_name (); 00122 00123 octave_value meth = symbol_table::find_method ("end", class_name); 00124 00125 if (meth.is_defined ()) 00126 return feval (meth.function_value (), args, 1); 00127 } 00128 00129 dim_vector dv = indexed_object->dims (); 00130 int ndims = dv.length (); 00131 00132 if (num_indices < ndims) 00133 { 00134 for (int i = num_indices; i < ndims; i++) 00135 dv(num_indices-1) *= dv(i); 00136 00137 if (num_indices == 1) 00138 { 00139 ndims = 2; 00140 dv.resize (ndims); 00141 dv(1) = 1; 00142 } 00143 else 00144 { 00145 ndims = num_indices; 00146 dv.resize (ndims); 00147 } 00148 } 00149 00150 if (index_position < ndims) 00151 retval = dv(index_position); 00152 else 00153 retval = 1; 00154 } 00155 else 00156 ::error ("invalid use of end"); 00157 00158 return retval; 00159 } 00160 00161 octave_value_list 00162 tree_argument_list::convert_to_const_vector (const octave_value *object) 00163 { 00164 // END doesn't make sense for functions. Maybe we need a different 00165 // way of asking an octave_value object this question? 00166 00167 bool stash_object = (list_includes_magic_end 00168 && object 00169 && ! (object->is_function () 00170 || object->is_function_handle ())); 00171 00172 unwind_protect frame; 00173 00174 if (stash_object) 00175 { 00176 frame.protect_var (indexed_object); 00177 00178 indexed_object = object; 00179 } 00180 00181 int len = length (); 00182 00183 std::list<octave_value_list> args; 00184 00185 iterator p = begin (); 00186 for (int k = 0; k < len; k++) 00187 { 00188 if (stash_object) 00189 { 00190 frame.protect_var (index_position); 00191 frame.protect_var (num_indices); 00192 00193 index_position = k; 00194 num_indices = len; 00195 } 00196 00197 tree_expression *elt = *p++; 00198 00199 if (elt) 00200 { 00201 octave_value tmp = elt->rvalue1 (); 00202 00203 if (error_state) 00204 { 00205 ::error ("evaluating argument list element number %d", k+1); 00206 args.clear (); 00207 break; 00208 } 00209 else 00210 { 00211 if (tmp.is_cs_list ()) 00212 args.push_back (tmp.list_value ()); 00213 else if (tmp.is_defined ()) 00214 args.push_back (tmp); 00215 } 00216 } 00217 else 00218 { 00219 args.push_back (octave_value ()); 00220 break; 00221 } 00222 } 00223 00224 return args; 00225 } 00226 00227 std::list<octave_lvalue> 00228 tree_argument_list::lvalue_list (void) 00229 { 00230 std::list<octave_lvalue> retval; 00231 00232 for (tree_argument_list::iterator p = begin (); 00233 p != end (); 00234 p++) 00235 { 00236 tree_expression *elt = *p; 00237 00238 retval.push_back (elt->lvalue ()); 00239 } 00240 00241 return retval; 00242 } 00243 00244 string_vector 00245 tree_argument_list::get_arg_names (void) const 00246 { 00247 int len = length (); 00248 00249 string_vector retval (len); 00250 00251 int k = 0; 00252 00253 for (const_iterator p = begin (); p != end (); p++) 00254 { 00255 tree_expression *elt = *p; 00256 00257 retval(k++) = elt->str_print_code (); 00258 } 00259 00260 return retval; 00261 } 00262 00263 tree_argument_list * 00264 tree_argument_list::dup (symbol_table::scope_id scope, 00265 symbol_table::context_id context) const 00266 { 00267 tree_argument_list *new_list = new tree_argument_list (); 00268 00269 new_list->list_includes_magic_end = list_includes_magic_end; 00270 new_list->simple_assign_lhs = simple_assign_lhs; 00271 00272 for (const_iterator p = begin (); p != end (); p++) 00273 { 00274 const tree_expression *elt = *p; 00275 00276 new_list->append (elt ? elt->dup (scope, context) : 0); 00277 } 00278 00279 return new_list; 00280 } 00281 00282 void 00283 tree_argument_list::accept (tree_walker& tw) 00284 { 00285 tw.visit_argument_list (*this); 00286 }