diff options
Diffstat (limited to 'gdb/guile/scm-math.c')
-rw-r--r-- | gdb/guile/scm-math.c | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/gdb/guile/scm-math.c b/gdb/guile/scm-math.c new file mode 100644 index 0000000..80e1673 --- /dev/null +++ b/gdb/guile/scm-math.c @@ -0,0 +1,998 @@ +/* GDB/Scheme support for math operations on values. + + Copyright (C) 2008-2014 Free Software Foundation, Inc. + + This file is part of GDB. + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* See README file in this directory for implementation notes, coding + conventions, et.al. */ + +#include "defs.h" +#include "arch-utils.h" +#include "charset.h" +#include "cp-abi.h" +#include "doublest.h" /* Needed by dfp.h. */ +#include "expression.h" /* Needed by dfp.h. */ +#include "dfp.h" +#include "gdb_assert.h" +#include "symtab.h" /* Needed by language.h. */ +#include "language.h" +#include "valprint.h" +#include "value.h" +#include "guile-internal.h" + +/* Note: Use target types here to remain consistent with the values system in + GDB (which uses target arithmetic). */ + +enum valscm_unary_opcode +{ + VALSCM_NOT, + VALSCM_NEG, + VALSCM_NOP, + VALSCM_ABS, + /* Note: This is Scheme's "logical not", not GDB's. + GDB calls this UNOP_COMPLEMENT. */ + VALSCM_LOGNOT +}; + +enum valscm_binary_opcode +{ + VALSCM_ADD, + VALSCM_SUB, + VALSCM_MUL, + VALSCM_DIV, + VALSCM_REM, + VALSCM_MOD, + VALSCM_POW, + VALSCM_LSH, + VALSCM_RSH, + VALSCM_MIN, + VALSCM_MAX, + VALSCM_BITAND, + VALSCM_BITOR, + VALSCM_BITXOR +}; + +/* If TYPE is a reference, return the target; otherwise return TYPE. */ +#define STRIP_REFERENCE(TYPE) \ + ((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (TYPE)) + +/* Returns a value object which is the result of applying the operation + specified by OPCODE to the given argument. + If there's an error a Scheme exception is thrown. */ + +static SCM +vlscm_unop (enum valscm_unary_opcode opcode, SCM x, const char *func_name) +{ + struct gdbarch *gdbarch = get_current_arch (); + const struct language_defn *language = current_language; + struct value *arg1; + SCM result = SCM_BOOL_F; + struct value *res_val = NULL; + SCM except_scm; + struct cleanup *cleanups; + volatile struct gdb_exception except; + + cleanups = make_cleanup_value_free_to_mark (value_mark ()); + + arg1 = vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x, + &except_scm, gdbarch, language); + if (arg1 == NULL) + { + do_cleanups (cleanups); + gdbscm_throw (except_scm); + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + switch (opcode) + { + case VALSCM_NOT: + /* Alas gdb and guile use the opposite meaning for "logical not". */ + { + struct type *type = language_bool_type (language, gdbarch); + res_val + = value_from_longest (type, (LONGEST) value_logical_not (arg1)); + } + break; + case VALSCM_NEG: + res_val = value_neg (arg1); + break; + case VALSCM_NOP: + /* Seemingly a no-op, but if X was a Scheme value it is now + a <gdb:value> object. */ + res_val = arg1; + break; + case VALSCM_ABS: + if (value_less (arg1, value_zero (value_type (arg1), not_lval))) + res_val = value_neg (arg1); + else + res_val = arg1; + break; + case VALSCM_LOGNOT: + res_val = value_complement (arg1); + break; + default: + gdb_assert_not_reached ("unsupported operation"); + } + } + GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups); + + gdb_assert (res_val != NULL); + result = vlscm_scm_from_value (res_val); + + do_cleanups (cleanups); + + if (gdbscm_is_exception (result)) + gdbscm_throw (result); + + return result; +} + +/* Returns a value object which is the result of applying the operation + specified by OPCODE to the given arguments. + If there's an error a Scheme exception is thrown. */ + +static SCM +vlscm_binop (enum valscm_binary_opcode opcode, SCM x, SCM y, + const char *func_name) +{ + struct gdbarch *gdbarch = get_current_arch (); + const struct language_defn *language = current_language; + struct value *arg1, *arg2; + SCM result = SCM_BOOL_F; + struct value *res_val = NULL; + SCM except_scm; + struct cleanup *cleanups; + volatile struct gdb_exception except; + + cleanups = make_cleanup_value_free_to_mark (value_mark ()); + + arg1 = vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x, + &except_scm, gdbarch, language); + if (arg1 == NULL) + { + do_cleanups (cleanups); + gdbscm_throw (except_scm); + } + arg2 = vlscm_convert_value_from_scheme (func_name, SCM_ARG2, y, + &except_scm, gdbarch, language); + if (arg2 == NULL) + { + do_cleanups (cleanups); + gdbscm_throw (except_scm); + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + switch (opcode) + { + case VALSCM_ADD: + { + struct type *ltype = value_type (arg1); + struct type *rtype = value_type (arg2); + + CHECK_TYPEDEF (ltype); + ltype = STRIP_REFERENCE (ltype); + CHECK_TYPEDEF (rtype); + rtype = STRIP_REFERENCE (rtype); + + if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && is_integral_type (rtype)) + res_val = value_ptradd (arg1, value_as_long (arg2)); + else if (TYPE_CODE (rtype) == TYPE_CODE_PTR + && is_integral_type (ltype)) + res_val = value_ptradd (arg2, value_as_long (arg1)); + else + res_val = value_binop (arg1, arg2, BINOP_ADD); + } + break; + case VALSCM_SUB: + { + struct type *ltype = value_type (arg1); + struct type *rtype = value_type (arg2); + + CHECK_TYPEDEF (ltype); + ltype = STRIP_REFERENCE (ltype); + CHECK_TYPEDEF (rtype); + rtype = STRIP_REFERENCE (rtype); + + if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && TYPE_CODE (rtype) == TYPE_CODE_PTR) + { + /* A ptrdiff_t for the target would be preferable here. */ + res_val + = value_from_longest (builtin_type (gdbarch)->builtin_long, + value_ptrdiff (arg1, arg2)); + } + else if (TYPE_CODE (ltype) == TYPE_CODE_PTR + && is_integral_type (rtype)) + res_val = value_ptradd (arg1, - value_as_long (arg2)); + else + res_val = value_binop (arg1, arg2, BINOP_SUB); + } + break; + case VALSCM_MUL: + res_val = value_binop (arg1, arg2, BINOP_MUL); + break; + case VALSCM_DIV: + res_val = value_binop (arg1, arg2, BINOP_DIV); + break; + case VALSCM_REM: + res_val = value_binop (arg1, arg2, BINOP_REM); + break; + case VALSCM_MOD: + res_val = value_binop (arg1, arg2, BINOP_MOD); + break; + case VALSCM_POW: + res_val = value_binop (arg1, arg2, BINOP_EXP); + break; + case VALSCM_LSH: + res_val = value_binop (arg1, arg2, BINOP_LSH); + break; + case VALSCM_RSH: + res_val = value_binop (arg1, arg2, BINOP_RSH); + break; + case VALSCM_MIN: + res_val = value_binop (arg1, arg2, BINOP_MIN); + break; + case VALSCM_MAX: + res_val = value_binop (arg1, arg2, BINOP_MAX); + break; + case VALSCM_BITAND: + res_val = value_binop (arg1, arg2, BINOP_BITWISE_AND); + break; + case VALSCM_BITOR: + res_val = value_binop (arg1, arg2, BINOP_BITWISE_IOR); + break; + case VALSCM_BITXOR: + res_val = value_binop (arg1, arg2, BINOP_BITWISE_XOR); + break; + default: + gdb_assert_not_reached ("unsupported operation"); + } + } + GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups); + + gdb_assert (res_val != NULL); + result = vlscm_scm_from_value (res_val); + + do_cleanups (cleanups); + + if (gdbscm_is_exception (result)) + gdbscm_throw (result); + + return result; +} + +/* (value-add x y) -> <gdb:value> */ + +static SCM +gdbscm_value_add (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_ADD, x, y, FUNC_NAME); +} + +/* (value-sub x y) -> <gdb:value> */ + +static SCM +gdbscm_value_sub (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_SUB, x, y, FUNC_NAME); +} + +/* (value-mul x y) -> <gdb:value> */ + +static SCM +gdbscm_value_mul (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_MUL, x, y, FUNC_NAME); +} + +/* (value-div x y) -> <gdb:value> */ + +static SCM +gdbscm_value_div (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_DIV, x, y, FUNC_NAME); +} + +/* (value-rem x y) -> <gdb:value> */ + +static SCM +gdbscm_value_rem (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_REM, x, y, FUNC_NAME); +} + +/* (value-mod x y) -> <gdb:value> */ + +static SCM +gdbscm_value_mod (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_MOD, x, y, FUNC_NAME); +} + +/* (value-pow x y) -> <gdb:value> */ + +static SCM +gdbscm_value_pow (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_POW, x, y, FUNC_NAME); +} + +/* (value-neg x) -> <gdb:value> */ + +static SCM +gdbscm_value_neg (SCM x) +{ + return vlscm_unop (VALSCM_NEG, x, FUNC_NAME); +} + +/* (value-pos x) -> <gdb:value> */ + +static SCM +gdbscm_value_pos (SCM x) +{ + return vlscm_unop (VALSCM_NOP, x, FUNC_NAME); +} + +/* (value-abs x) -> <gdb:value> */ + +static SCM +gdbscm_value_abs (SCM x) +{ + return vlscm_unop (VALSCM_ABS, x, FUNC_NAME); +} + +/* (value-lsh x y) -> <gdb:value> */ + +static SCM +gdbscm_value_lsh (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_LSH, x, y, FUNC_NAME); +} + +/* (value-rsh x y) -> <gdb:value> */ + +static SCM +gdbscm_value_rsh (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_RSH, x, y, FUNC_NAME); +} + +/* (value-min x y) -> <gdb:value> */ + +static SCM +gdbscm_value_min (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_MIN, x, y, FUNC_NAME); +} + +/* (value-max x y) -> <gdb:value> */ + +static SCM +gdbscm_value_max (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_MAX, x, y, FUNC_NAME); +} + +/* (value-not x) -> <gdb:value> */ + +static SCM +gdbscm_value_not (SCM x) +{ + return vlscm_unop (VALSCM_NOT, x, FUNC_NAME); +} + +/* (value-lognot x) -> <gdb:value> */ + +static SCM +gdbscm_value_lognot (SCM x) +{ + return vlscm_unop (VALSCM_LOGNOT, x, FUNC_NAME); +} + +/* (value-logand x y) -> <gdb:value> */ + +static SCM +gdbscm_value_logand (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_BITAND, x, y, FUNC_NAME); +} + +/* (value-logior x y) -> <gdb:value> */ + +static SCM +gdbscm_value_logior (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_BITOR, x, y, FUNC_NAME); +} + +/* (value-logxor x y) -> <gdb:value> */ + +static SCM +gdbscm_value_logxor (SCM x, SCM y) +{ + return vlscm_binop (VALSCM_BITXOR, x, y, FUNC_NAME); +} + +/* Utility to perform all value comparisons. + If there's an error a Scheme exception is thrown. */ + +static SCM +vlscm_rich_compare (int op, SCM x, SCM y, const char *func_name) +{ + struct gdbarch *gdbarch = get_current_arch (); + const struct language_defn *language = current_language; + struct value *v1, *v2; + int result = 0; + SCM except_scm; + struct cleanup *cleanups; + volatile struct gdb_exception except; + + cleanups = make_cleanup_value_free_to_mark (value_mark ()); + + v1 = vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x, + &except_scm, gdbarch, language); + if (v1 == NULL) + { + do_cleanups (cleanups); + gdbscm_throw (except_scm); + } + v2 = vlscm_convert_value_from_scheme (func_name, SCM_ARG2, y, + &except_scm, gdbarch, language); + if (v2 == NULL) + { + do_cleanups (cleanups); + gdbscm_throw (except_scm); + } + + TRY_CATCH (except, RETURN_MASK_ALL) + { + switch (op) + { + case BINOP_LESS: + result = value_less (v1, v2); + break; + case BINOP_LEQ: + result = (value_less (v1, v2) + || value_equal (v1, v2)); + break; + case BINOP_EQUAL: + result = value_equal (v1, v2); + break; + case BINOP_NOTEQUAL: + gdb_assert_not_reached ("not-equal not implemented"); + case BINOP_GTR: + result = value_less (v2, v1); + break; + case BINOP_GEQ: + result = (value_less (v2, v1) + || value_equal (v1, v2)); + break; + default: + gdb_assert_not_reached ("invalid <gdb:value> comparison"); + } + } + do_cleanups (cleanups); + GDBSCM_HANDLE_GDB_EXCEPTION (except); + + return scm_from_bool (result); +} + +/* (value=? x y) -> boolean + There is no "not-equal?" function (value!= ?) on purpose. + We're following string=?, etc. as our Guide here. */ + +static SCM +gdbscm_value_eq_p (SCM x, SCM y) +{ + return vlscm_rich_compare (BINOP_EQUAL, x, y, FUNC_NAME); +} + +/* (value<? x y) -> boolean */ + +static SCM +gdbscm_value_lt_p (SCM x, SCM y) +{ + return vlscm_rich_compare (BINOP_LESS, x, y, FUNC_NAME); +} + +/* (value<=? x y) -> boolean */ + +static SCM +gdbscm_value_le_p (SCM x, SCM y) +{ + return vlscm_rich_compare (BINOP_LEQ, x, y, FUNC_NAME); +} + +/* (value>? x y) -> boolean */ + +static SCM +gdbscm_value_gt_p (SCM x, SCM y) +{ + return vlscm_rich_compare (BINOP_GTR, x, y, FUNC_NAME); +} + +/* (value>=? x y) -> boolean */ + +static SCM +gdbscm_value_ge_p (SCM x, SCM y) +{ + return vlscm_rich_compare (BINOP_GEQ, x, y, FUNC_NAME); +} + +/* Subroutine of vlscm_convert_typed_value_from_scheme to simplify it. + Convert OBJ, a Scheme number, to a <gdb:value> object. + OBJ_ARG_POS is its position in the argument list, used in exception text. + + TYPE is the result type. TYPE_ARG_POS is its position in + the argument list, used in exception text. + TYPE_SCM is Scheme object wrapping TYPE, used in exception text. + + If the number isn't representable, e.g. it's too big, a <gdb:exception> + object is stored in *EXCEPT_SCMP and NULL is returned. + The conversion may throw a gdb error, e.g., if TYPE is invalid. */ + +static struct value * +vlscm_convert_typed_number (const char *func_name, int obj_arg_pos, SCM obj, + int type_arg_pos, SCM type_scm, struct type *type, + struct gdbarch *gdbarch, SCM *except_scmp) +{ + if (is_integral_type (type) + || TYPE_CODE (type) == TYPE_CODE_PTR) + { + if (TYPE_UNSIGNED (type)) + { + ULONGEST max; + + get_unsigned_type_max (type, &max); + if (!scm_is_unsigned_integer (obj, 0, max)) + { + *except_scmp + = gdbscm_make_out_of_range_error (func_name, + obj_arg_pos, obj, + _("value out of range for type")); + return NULL; + } + return value_from_longest (type, gdbscm_scm_to_ulongest (obj)); + } + else + { + LONGEST min, max; + + get_signed_type_minmax (type, &min, &max); + if (!scm_is_signed_integer (obj, min, max)) + { + *except_scmp + = gdbscm_make_out_of_range_error (func_name, + obj_arg_pos, obj, + _("value out of range for type")); + return NULL; + } + return value_from_longest (type, gdbscm_scm_to_longest (obj)); + } + } + else if (TYPE_CODE (type) == TYPE_CODE_FLT) + return value_from_double (type, scm_to_double (obj)); + else + { + *except_scmp = gdbscm_make_type_error (func_name, obj_arg_pos, obj, + NULL); + return NULL; + } +} + +/* Return non-zero if OBJ, an integer, fits in TYPE. */ + +static int +vlscm_integer_fits_p (SCM obj, struct type *type) +{ + if (TYPE_UNSIGNED (type)) + { + ULONGEST max; + + /* If scm_is_unsigned_integer can't work with this type, just punt. */ + if (TYPE_LENGTH (type) > sizeof (scm_t_uintmax)) + return 0; + get_unsigned_type_max (type, &max); + return scm_is_unsigned_integer (obj, 0, max); + } + else + { + LONGEST min, max; + + /* If scm_is_signed_integer can't work with this type, just punt. */ + if (TYPE_LENGTH (type) > sizeof (scm_t_intmax)) + return 0; + get_signed_type_minmax (type, &min, &max); + return scm_is_signed_integer (obj, min, max); + } +} + +/* Subroutine of vlscm_convert_typed_value_from_scheme to simplify it. + Convert OBJ, a Scheme number, to a <gdb:value> object. + OBJ_ARG_POS is its position in the argument list, used in exception text. + + If OBJ is an integer, then the smallest int that will hold the value in + the following progression is chosen: + int, unsigned int, long, unsigned long, long long, unsigned long long. + Otherwise, if OBJ is a real number, then it is converted to a double. + Otherwise an exception is thrown. + + If the number isn't representable, e.g. it's too big, a <gdb:exception> + object is stored in *EXCEPT_SCMP and NULL is returned. */ + +static struct value * +vlscm_convert_number (const char *func_name, int obj_arg_pos, SCM obj, + struct gdbarch *gdbarch, SCM *except_scmp) +{ + const struct builtin_type *bt = builtin_type (gdbarch); + + /* One thing to keep in mind here is that we are interested in the + target's representation of OBJ, not the host's. */ + + if (scm_is_exact (obj) && scm_is_integer (obj)) + { + if (vlscm_integer_fits_p (obj, bt->builtin_int)) + return value_from_longest (bt->builtin_int, + gdbscm_scm_to_longest (obj)); + if (vlscm_integer_fits_p (obj, bt->builtin_unsigned_int)) + return value_from_longest (bt->builtin_unsigned_int, + gdbscm_scm_to_ulongest (obj)); + if (vlscm_integer_fits_p (obj, bt->builtin_long)) + return value_from_longest (bt->builtin_long, + gdbscm_scm_to_longest (obj)); + if (vlscm_integer_fits_p (obj, bt->builtin_unsigned_long)) + return value_from_longest (bt->builtin_unsigned_long, + gdbscm_scm_to_ulongest (obj)); + if (vlscm_integer_fits_p (obj, bt->builtin_long_long)) + return value_from_longest (bt->builtin_long_long, + gdbscm_scm_to_longest (obj)); + if (vlscm_integer_fits_p (obj, bt->builtin_unsigned_long_long)) + return value_from_longest (bt->builtin_unsigned_long_long, + gdbscm_scm_to_ulongest (obj)); + } + else if (scm_is_real (obj)) + return value_from_double (bt->builtin_double, scm_to_double (obj)); + + *except_scmp = gdbscm_make_out_of_range_error (func_name, obj_arg_pos, obj, + _("value not a number representable on the target")); + return NULL; +} + +/* Subroutine of vlscm_convert_typed_value_from_scheme to simplify it. + Convert BV, a Scheme bytevector, to a <gdb:value> object. + + TYPE, if non-NULL, is the result type. Otherwise, a vector of type + uint8_t is used. + TYPE_SCM is Scheme object wrapping TYPE, used in exception text, + or #f if TYPE is NULL. + + If the bytevector isn't the same size as the type, then a <gdb:exception> + object is stored in *EXCEPT_SCMP, and NULL is returned. */ + +static struct value * +vlscm_convert_bytevector (SCM bv, struct type *type, SCM type_scm, + int arg_pos, const char *func_name, + SCM *except_scmp, struct gdbarch *gdbarch) +{ + LONGEST length = SCM_BYTEVECTOR_LENGTH (bv); + struct value *value; + + if (type == NULL) + { + type = builtin_type (gdbarch)->builtin_uint8; + type = lookup_array_range_type (type, 0, length); + make_vector_type (type); + } + type = check_typedef (type); + if (TYPE_LENGTH (type) != length) + { + *except_scmp = gdbscm_make_out_of_range_error (func_name, arg_pos, + type_scm, + _("size of type does not match size of bytevector")); + return NULL; + } + + value = value_from_contents (type, + (gdb_byte *) SCM_BYTEVECTOR_CONTENTS (bv)); + return value; +} + +/* Convert OBJ, a Scheme value, to a <gdb:value> object. + OBJ_ARG_POS is its position in the argument list, used in exception text. + + TYPE, if non-NULL, is the result type which must be compatible with + the value being converted. + If TYPE is NULL then a suitable default type is chosen. + TYPE_SCM is Scheme object wrapping TYPE, used in exception text, + or SCM_UNDEFINED if TYPE is NULL. + TYPE_ARG_POS is its position in the argument list, used in exception text, + or -1 if TYPE is NULL. + + OBJ may also be a <gdb:value> object, in which case a copy is returned + and TYPE must be NULL. + + If the value cannot be converted, NULL is returned and a gdb:exception + object is stored in *EXCEPT_SCMP. + Otherwise the new value is returned, added to the all_values chain. */ + +struct value * +vlscm_convert_typed_value_from_scheme (const char *func_name, + int obj_arg_pos, SCM obj, + int type_arg_pos, SCM type_scm, + struct type *type, + SCM *except_scmp, + struct gdbarch *gdbarch, + const struct language_defn *language) +{ + struct value *value = NULL; + SCM except_scm = SCM_BOOL_F; + volatile struct gdb_exception except; + + if (type == NULL) + { + gdb_assert (type_arg_pos == -1); + gdb_assert (SCM_UNBNDP (type_scm)); + } + + *except_scmp = SCM_BOOL_F; + + TRY_CATCH (except, RETURN_MASK_ALL) + { + if (vlscm_is_value (obj)) + { + if (type != NULL) + { + except_scm = gdbscm_make_misc_error (func_name, type_arg_pos, + type_scm, + _("No type allowed")); + value = NULL; + } + else + value = value_copy (vlscm_scm_to_value (obj)); + } + else if (gdbscm_is_true (scm_bytevector_p (obj))) + { + value = vlscm_convert_bytevector (obj, type, type_scm, + obj_arg_pos, func_name, + &except_scm, gdbarch); + } + else if (gdbscm_is_bool (obj)) + { + if (type != NULL + && !is_integral_type (type)) + { + except_scm = gdbscm_make_type_error (func_name, type_arg_pos, + type_scm, NULL); + } + else + { + value = value_from_longest (type + ? type + : language_bool_type (language, + gdbarch), + gdbscm_is_true (obj)); + } + } + else if (scm_is_number (obj)) + { + if (type != NULL) + { + value = vlscm_convert_typed_number (func_name, obj_arg_pos, obj, + type_arg_pos, type_scm, type, + gdbarch, &except_scm); + } + else + { + value = vlscm_convert_number (func_name, obj_arg_pos, obj, + gdbarch, &except_scm); + } + } + else if (scm_is_string (obj)) + { + char *s; + size_t len; + struct cleanup *cleanup; + + if (type != NULL) + { + except_scm = gdbscm_make_misc_error (func_name, type_arg_pos, + type_scm, + _("No type allowed")); + value = NULL; + } + else + { + /* TODO: Provide option to specify conversion strategy. */ + s = gdbscm_scm_to_string (obj, &len, + target_charset (gdbarch), + 0 /*non-strict*/, + &except_scm); + if (s != NULL) + { + cleanup = make_cleanup (xfree, s); + value + = value_cstring (s, len, + language_string_char_type (language, + gdbarch)); + do_cleanups (cleanup); + } + else + value = NULL; + } + } + else if (lsscm_is_lazy_string (obj)) + { + if (type != NULL) + { + except_scm = gdbscm_make_misc_error (func_name, type_arg_pos, + type_scm, + _("No type allowed")); + value = NULL; + } + else + { + value = lsscm_safe_lazy_string_to_value (obj, obj_arg_pos, + func_name, + &except_scm); + } + } + else /* OBJ isn't anything we support. */ + { + except_scm = gdbscm_make_type_error (func_name, obj_arg_pos, obj, + NULL); + value = NULL; + } + } + if (except.reason < 0) + except_scm = gdbscm_scm_from_gdb_exception (except); + + if (gdbscm_is_true (except_scm)) + { + gdb_assert (value == NULL); + *except_scmp = except_scm; + } + + return value; +} + +/* Wrapper around vlscm_convert_typed_value_from_scheme for cases where there + is no supplied type. See vlscm_convert_typed_value_from_scheme for + details. */ + +struct value * +vlscm_convert_value_from_scheme (const char *func_name, + int obj_arg_pos, SCM obj, + SCM *except_scmp, struct gdbarch *gdbarch, + const struct language_defn *language) +{ + return vlscm_convert_typed_value_from_scheme (func_name, obj_arg_pos, obj, + -1, SCM_UNDEFINED, NULL, + except_scmp, + gdbarch, language); +} + +/* Initialize value math support. */ + +static const scheme_function math_functions[] = +{ + { "value-add", 2, 0, 0, gdbscm_value_add, + "\ +Return a + b." }, + + { "value-sub", 2, 0, 0, gdbscm_value_sub, + "\ +Return a - b." }, + + { "value-mul", 2, 0, 0, gdbscm_value_mul, + "\ +Return a * b." }, + + { "value-div", 2, 0, 0, gdbscm_value_div, + "\ +Return a / b." }, + + { "value-rem", 2, 0, 0, gdbscm_value_rem, + "\ +Return a % b." }, + + { "value-mod", 2, 0, 0, gdbscm_value_mod, + "\ +Return a mod b. See Knuth 1.2.4." }, + + { "value-pow", 2, 0, 0, gdbscm_value_pow, + "\ +Return pow (x, y)." }, + + { "value-not", 1, 0, 0, gdbscm_value_not, + "\ +Return !a." }, + + { "value-neg", 1, 0, 0, gdbscm_value_neg, + "\ +Return -a." }, + + { "value-pos", 1, 0, 0, gdbscm_value_pos, + "\ +Return a." }, + + { "value-abs", 1, 0, 0, gdbscm_value_abs, + "\ +Return abs (a)." }, + + { "value-lsh", 2, 0, 0, gdbscm_value_lsh, + "\ +Return a << b." }, + + { "value-rsh", 2, 0, 0, gdbscm_value_rsh, + "\ +Return a >> b." }, + + { "value-min", 2, 0, 0, gdbscm_value_min, + "\ +Return min (a, b)." }, + + { "value-max", 2, 0, 0, gdbscm_value_max, + "\ +Return max (a, b)." }, + + { "value-lognot", 1, 0, 0, gdbscm_value_lognot, + "\ +Return ~a." }, + + { "value-logand", 2, 0, 0, gdbscm_value_logand, + "\ +Return a & b." }, + + { "value-logior", 2, 0, 0, gdbscm_value_logior, + "\ +Return a | b." }, + + { "value-logxor", 2, 0, 0, gdbscm_value_logxor, + "\ +Return a ^ b." }, + + { "value=?", 2, 0, 0, gdbscm_value_eq_p, + "\ +Return a == b." }, + + { "value<?", 2, 0, 0, gdbscm_value_lt_p, + "\ +Return a < b." }, + + { "value<=?", 2, 0, 0, gdbscm_value_le_p, + "\ +Return a <= b." }, + + { "value>?", 2, 0, 0, gdbscm_value_gt_p, + "\ +Return a > b." }, + + { "value>=?", 2, 0, 0, gdbscm_value_ge_p, + "\ +Return a >= b." }, + + END_FUNCTIONS +}; + +void +gdbscm_initialize_math (void) +{ + gdbscm_define_functions (math_functions, 1); +} |