view src/pt-assign.cc @ 5794:1138ced03f14

[project @ 2006-05-08 20:23:04 by jwe]
author jwe
date Mon, 08 May 2006 20:23:07 +0000
parents ace8d8d26933
children fb4dea2184bf
line wrap: on
line source

/*

Copyright (C) 1996, 1997 John W. Eaton

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>

#include "defun.h"
#include "error.h"
#include "input.h"
#include "oct-obj.h"
#include "oct-lvalue.h"
#include "pager.h"
#include "ov.h"
#include "pt-arg-list.h"
#include "pt-bp.h"
#include "pt-assign.h"
#include "pt-walk.h"
#include "utils.h"
#include "variables.h"

// TRUE means print the right hand side of an assignment instead of
// the left.
static bool Vprint_rhs_assign_val = false;

// Simple assignment expressions.

tree_simple_assignment::~tree_simple_assignment (void)
{
  if (! preserve)
    delete lhs;

  delete rhs;
}

octave_value_list
tree_simple_assignment::rvalue (int nargout)
{
  octave_value_list retval;

  MAYBE_DO_BREAKPOINT;

  if (nargout > 1)
    error ("invalid number of output arguments for expression X = RHS");
  else
    retval = rvalue ();

  return retval;
}

// FIXME -- this works, but it would look a little better if
// it were broken up into a couple of separate functions.

octave_value
tree_simple_assignment::rvalue (void)
{
  octave_value retval;

  if (error_state)
    return retval;

  if (rhs)
    {
      octave_value_list tmp = rhs->rvalue ();

      if (! (error_state || tmp.empty ()))
	{
	  octave_value rhs_val = tmp(0);

	  if (rhs_val.is_undefined ())
	    {
	      error ("value on right hand side of assignment is undefined");
	      eval_error ();
	    }
	  else if (rhs_val.is_cs_list ())
	    {
	      error ("invalid assignment of comma-separated list");
	      eval_error ();
	    }
	  else
	    {
	      octave_lvalue ult = lhs->lvalue ();

	      if (error_state)
		eval_error ();
	      else
		{
		  ult.assign (etype, rhs_val);

		  if (! error_state)
		    {
		      if (etype == octave_value::op_asn_eq)
			retval = rhs_val;
		      else
			retval = ult.value ();

		      if (print_result ())
			{
			  if (Vprint_rhs_assign_val)
			    retval.print_with_name (octave_stdout,
						    lhs->str_print_code ());
			  else
			    {
			      // We clear any index here so that we can
			      // get the new value of the referenced
			      // object below, instead of the indexed
			      // value (which should be the same as the
			      // right hand side value).

			      ult.clear_index ();

			      octave_value lhs_val = ult.value ();

			      if (! error_state)
				lhs_val.print_with_name (octave_stdout,
							 lhs->name ());
			    }
			}
		    }
		  else
		    eval_error ();
		}
	    }
	}
      else
	eval_error ();
    }

  return retval;
}

void
tree_simple_assignment::eval_error (void)
{
  int l = line ();
  int c = column ();

  if (l != -1 && c != -1)
    ::error ("evaluating assignment expression near line %d, column %d",
	     l, c);
}

std::string
tree_simple_assignment::oper (void) const
{
  return octave_value::assign_op_as_string (etype);
}

void
tree_simple_assignment::accept (tree_walker& tw)
{
  tw.visit_simple_assignment (*this);
}

// Multi-valued assignment expressions.

tree_multi_assignment::~tree_multi_assignment (void)
{
  if (! preserve)
    delete lhs;

  delete rhs;
}

octave_value
tree_multi_assignment::rvalue (void)
{
  octave_value retval;

  octave_value_list tmp = rvalue (1);

  if (! tmp.empty ())
    retval = tmp(0);

  return retval;
}

// FIXME -- this works, but it would look a little better if
// it were broken up into a couple of separate functions.

octave_value_list
tree_multi_assignment::rvalue (int)
{
  octave_value_list retval;

  if (error_state)
    return retval;

  if (rhs)
    {
      int n_out = lhs->nargout_count ();

      if (error_state)
	return retval;

      octave_value_list rhs_val = rhs->rvalue (n_out);

      if (error_state)
	return retval;

      if (rhs_val.empty ())
	{
	  error ("value on right hand side of assignment is undefined");
	  eval_error ();
	  return retval;
	}
      else
	{
	  int k = 0;

	  int n = rhs_val.length ();

	  if (n == 1)
	    {
	      octave_value tmp = rhs_val(0);

	      if (tmp.is_cs_list ())
		{
		  error ("invalid assignment of comma-separated list");
		  eval_error ();
		  return retval;
		}
	    }

	  retval.resize (n, octave_value ());

	  for (tree_argument_list::iterator p = lhs->begin ();
	       p != lhs->end ();
	       p++)
	    {
	      tree_expression *lhs_elt = *p;

	      if (lhs_elt)
		{
		  octave_lvalue ult = lhs_elt->lvalue ();

		  if (error_state)
		    {
		      eval_error ();
		      break;
		    }
		  else if (k < n)
		    {
		      ult.assign (etype, rhs_val(k));

		      if (! error_state)
			{
			  if (etype == octave_value::op_asn_eq)
			    retval(k) = rhs_val(k);
			  else
			    retval(k) = ult.value ();
			}
		    }
		  else
		    error ("element number %d undefined in return list", k+1);

		  if (error_state)
		    {
		      eval_error ();
		      break;
		    }
		  else if (print_result ())
		    {
		      if (Vprint_rhs_assign_val)
			retval(k).print_with_name
			  (octave_stdout, lhs_elt->str_print_code ());
		      else
			{
			  // We clear any index here so that we can
			  // get the new value of the referenced
			  // object below, instead of the indexed
			  // value (which should be the same as the
			  // right hand side value).

			  ult.clear_index ();

			  octave_value lhs_val = ult.value ();

			  if (! error_state)
			    lhs_val.print_with_name (octave_stdout,
						     lhs_elt->name ());
			}
		    }
		}
	      else
		eval_error ();

	      if (error_state)
		break;

	      k++;
	    }
	}
    }
  else
    eval_error ();

  return retval;
}

void
tree_multi_assignment::eval_error (void)
{
  int l = line ();
  int c = column ();

  if (l != -1 && c != -1)
    ::error ("evaluating assignment expression near line %d, column %d",
	     l, c);
}

std::string
tree_multi_assignment::oper (void) const
{
  return octave_value::assign_op_as_string (etype);
}

void
tree_multi_assignment::accept (tree_walker& tw)
{
  tw.visit_multi_assignment (*this);
}

DEFUN (print_rhs_assign_val, args, nargout,
  "-*- texinfo -*-\n\
@deftypefn {Built-in Function} {@var{val} =} print_rhs_assign_val ()\n\
@deftypefnx {Built-in Function} {@var{old_val} =} print_rhs_assign_val (@var{new_val})\n\
Query or set the internal variable that controls whether Octave will\n\
print the value of the right hand side of assignment expressions\n\
instead of the value of the left hand side (after the assignment).\n\
@end deftypefn")
{
  return SET_INTERNAL_VARIABLE (print_rhs_assign_val);
}


/*
;;; Local Variables: ***
;;; mode: C++ ***
;;; End: ***
*/