Commit 11f6610d authored by Jonathan Wilkes's avatar Jonathan Wilkes
Browse files

Merge branch 'port-float-symbol-method'

parents 5a20d90f 4fc8e6cd
Pipeline #2186 passed with stage
in 296 minutes and 1 second
......@@ -44,7 +44,7 @@ t_blob *atom_getblob(t_atom *a) /* MP 20070108 */
else return (&st);
}
t_symbol *atom_gensym(t_atom *a) /* this works better for graph labels */
t_symbol *atom_gensym(t_atom *a) /* this works better for graph labels */
{
char buf[30];
if (a->a_type == A_SYMBOL) return (a->a_w.w_symbol);
......
......@@ -43,9 +43,108 @@ t_classtable *ct;
static t_symbol *class_extern_dir = &s_;
int symbol_can_float(t_symbol *s, t_float *f);
/* try to give the user some help with the uglier cases of unexpected
atom types in messages.
dostof flag controls whether we want to try to convert a symbol
to a float.
for [float]'s symbol conversion we even check if we received an
out of range error, but here for the general case we don't do that. */
char *type_hint(t_symbol *s, int argc, t_atom *argv, int dostof)
{
static char hint[MAXPDSTRING];
t_float f = 0;
/* Null selectors-- the user typically shouldn't encounter these,
especially one that triggers an unknown method error. But we
check for them anyway. */
if (!s)
{
sprintf(hint, " (Note: null selector detected)");
return hint;
}
/* Empty symbol selector is also rare. But a user can easily generate
one with [symbol( or [symbol] then send to [list trim]. */
if (s == &s_)
{
sprintf(hint, " (Note: empty symbol selector detected)");
return hint;
}
/* More commonly, the user may have a "symbol" message where the
payload is an empty symbol. This can cause confusion for debugging
since the empty symbol doesn't print out anything. */
if (s && s == &s_symbol && argc && argv->a_type == A_SYMBOL
&& argv->a_w.w_symbol == &s_)
{
sprintf(hint, " (Note: symbol message with empty payload detected)");
return hint;
}
/* Somewhat common edge case-- [makefilename] and other objects can
output a symbol message with a payload that looks numeric but is
indeed a symbol atom. In fact, Pd's text parser would interpret
such a string as a float if you sent it through the parser.
This can cause problems if the user tries to serialize the data
and read it back-- say, by saving the symbol message "symbol 123"
in a file. The next time they load it, "123" will be parsed as
a float atom, and any symbol methods will read from the wrong
union field and (probably) interpret it as an empty symbol. */
if (dostof)
{
if (symbol_can_float(atom_getsymbolarg(0, argc, argv), &f))
{
sprintf(hint, " (Note: this symbol message has a floatlike payload "
"which cannot be saved properly. Did you mean 'float %s'?)",
argv->a_w.w_symbol->s_name);
return hint;
}
else if (f == -1 || f == 1)
{
/* For values which would overflow, give a hint but don't
suggest float type */
sprintf(hint, " (Note: this symbol message has an %s floatlike "
"payload which cannot be saved properly.",
f == 1 ? "overflowing" : "underflowing");
return hint;
}
}
/* Rather uncommon case where the selector itself is a symbol atom
that would normally have been parsed as a float. */
if (dostof)
{
if (symbol_can_float(s, &f))
{
sprintf(hint, " (Note: %s looks like a float but is actually a "
"symbol atom which cannot be saved properly)", s->s_name);
return hint;
}
else if (f == -1 || f == 1)
{
/* For values which would overflow, give a hint but don't
suggest float type */
sprintf(hint, " (Note: this symbol atom has an %s floatlike "
"payload which cannot be saved properly.",
f == 1 ? "overflowing" : "underflowing");
return hint;
}
}
hint[0] = '\0';
return hint;
}
static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv)
{
pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name);
pd_error(x, "%s: no method for '%s'%s",
(*x)->c_name->s_name, s->s_name, type_hint(s, argc, argv,
*(*x)->c_floatmethod != pd_defaultfloat ? 1 : 0));
}
static void pd_defaultbang(t_pd *x)
......
......@@ -72,10 +72,12 @@ t_inlet *signalinlet_new(t_object *owner, t_float f)
return (x);
}
static void inlet_wrong(t_inlet *x, t_symbol *s)
char *type_hint(t_symbol *s, int argc, t_atom *argv, int dostof);
static void inlet_wrong(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
{
pd_error(x->i_owner, "inlet: expected '%s' but got '%s'",
x->i_symfrom->s_name, s->s_name);
pd_error(x->i_owner, "inlet: expected '%s' but got '%s'%s",
x->i_symfrom->s_name, s->s_name, type_hint(s, argc, argv, 1));
}
static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv);
......@@ -88,7 +90,7 @@ static void inlet_bang(t_inlet *x)
else if (!x->i_symfrom) pd_bang(x->i_dest);
else if (x->i_symfrom == &s_list)
inlet_list(x, &s_bang, 0, 0);
else inlet_wrong(x, &s_bang);
else inlet_wrong(x, &s_bang, 0, 0);
}
static void inlet_pointer(t_inlet *x, t_gpointer *gp)
......@@ -102,7 +104,7 @@ static void inlet_pointer(t_inlet *x, t_gpointer *gp)
SETPOINTER(&a, gp);
inlet_list(x, &s_pointer, 1, &a);
}
else inlet_wrong(x, &s_pointer);
else inlet_wrong(x, &s_pointer, 0, 0);
}
static void inlet_float(t_inlet *x, t_float f)
......@@ -119,7 +121,7 @@ static void inlet_float(t_inlet *x, t_float f)
SETFLOAT(&a, f);
inlet_list(x, &s_float, 1, &a);
}
else inlet_wrong(x, &s_float);
else inlet_wrong(x, &s_float, 0, 0);
}
static void inlet_symbol(t_inlet *x, t_symbol *s)
......@@ -127,13 +129,15 @@ static void inlet_symbol(t_inlet *x, t_symbol *s)
if (x->i_symfrom == &s_symbol)
pd_vmess(x->i_dest, x->i_symto, "s", s);
else if (!x->i_symfrom) pd_symbol(x->i_dest, s);
else if (x->i_symfrom == &s_list)
else
{
t_atom a;
SETSYMBOL(&a, s);
inlet_list(x, &s_symbol, 1, &a);
if (x->i_symfrom == &s_list)
inlet_list(x, &s_symbol, 1, &a);
else
inlet_wrong(x, &s_symbol, 1, &a);
}
else inlet_wrong(x, &s_symbol);
}
static void inlet_blob(t_inlet *x, t_blob *st) /* MP20061226 blob type */
......@@ -152,7 +156,7 @@ static void inlet_blob(t_inlet *x, t_blob *st) /* MP20061226 blob type */
else
{
/*post("inlet_blob calling inlet_wrong");*/
inlet_wrong(x, &s_blob);
inlet_wrong(x, &s_blob, 0, 0);
}
}
......@@ -168,7 +172,7 @@ static void inlet_list(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
inlet_float(x, atom_getfloat(argv));
else if (argc==1 && argv->a_type == A_SYMBOL)
inlet_symbol(x, atom_getsymbol(argv));
else inlet_wrong(x, &s_list);
else inlet_wrong(x, &s_list, 0, 0);
}
static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
......@@ -177,7 +181,7 @@ static void inlet_anything(t_inlet *x, t_symbol *s, int argc, t_atom *argv)
typedmess(x->i_dest, x->i_symto, argc, argv);
else if (!x->i_symfrom)
typedmess(x->i_dest, s, argc, argv);
else inlet_wrong(x, s);
else inlet_wrong(x, s, 0, 0);
}
void inlet_free(t_inlet *x)
......
......@@ -8,6 +8,9 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
extern t_pd *newest;
/* -------------------------- int ------------------------------ */
......@@ -95,6 +98,59 @@ static void pdfloat_float(t_pdfloat *x, t_float f)
outlet_float(x->x_obj.ob_outlet, x->x_f = f);
}
/* check if a symbol payload can be interpreted as a floating point number.
We get these cases sometimes from [makefilename], [keyname], and some
externals that shoot out data that would be parsed as a float if loaded
from a file.
return values are: 0 not a number
1 successfully parsed as float (stored in f)
if the number would underflow f is set to -1
if the number would overflow f is set to greater than zero
*/
int symbol_can_float(t_symbol *s, t_float *f)
{
int ret;
char c, *str_end;
c = s->s_name[0];
if (c != '-' && c != '+' && (c < 48 || c > 57)) return 0;
errno = 0;
*f = strtod(s->s_name, &str_end);
if (errno == ERANGE)
{
ret = 0;
if (*f == 0) *f = -1; /* underflow */
else *f = 1; /* assume overflow otherwise */
}
else if (*f == 0 && s->s_name == str_end)
{
ret = 0;
}
else
ret = 1;
return ret;
}
char *type_hint(t_symbol *s, int argc, t_atom *argv, int check_symforfloat);
static void pdfloat_symbol(t_pdfloat *x, t_symbol *s)
{
t_float f = 0;
if (symbol_can_float(s, &f))
outlet_float(x->x_obj.ob_outlet, x->x_f = f);
else
{
t_atom at;
SETSYMBOL(&at, s);
pd_error(x, "couldn't convert 'symbol %s' to float%s",
s->s_name,
f == -1 ? " (number too small)" :
f == 1 ? " (number too large)" :
type_hint(&s_symbol, 1, &at, 0));
}
}
static void pdfloat_send(t_pdfloat *x, t_symbol *s)
{
if (s->s_thing)
......@@ -111,6 +167,7 @@ void pdfloat_setup(void)
A_SYMBOL, 0);
class_addbang(pdfloat_class, pdfloat_bang);
class_addfloat(pdfloat_class, (t_method)pdfloat_float);
class_addsymbol(pdfloat_class, (t_method)pdfloat_symbol);
}
/* -------------------------- symbol ------------------------------ */
......
#N canvas 732 89 749 571 12;
#N canvas 340 105 749 571 12;
#X obj 465 281 r \$0-result;
#X obj 212 239 bng 31 250 50 0 empty empty Run_all 39 13 0 12 -262144
-1 -1;
......@@ -25,7 +25,7 @@ is handy for some binbuf tests.;
#X obj 198 659 rtest makefilename_double_percent;
#X obj 198 710 rtest makefilename_code_coverage;
#N canvas 461 242 450 323 (subpatch) 0;
#X restore 201 1995 pd;
#X restore 201 2175 pd;
#X obj 198 761 rtest makefilename_default;
#X obj 198 812 rtest makefilename_default_bang;
#X obj 198 863 rtest makefilename_float;
......@@ -55,6 +55,8 @@ is handy for some binbuf tests.;
#X obj 198 1811 rtest float_send_method;
#X obj 198 1866 rtest int_send_method;
#X obj 198 1921 rtest value_send_method;
#X obj 198 1976 rtest float_symbol_method;
#X obj 198 2031 rtest type_hint_coverage;
#X connect 0 0 27 0;
#X connect 1 0 4 0;
#X connect 2 0 42 0;
......@@ -95,3 +97,5 @@ is handy for some binbuf tests.;
#X connect 46 0 47 0;
#X connect 47 0 48 0;
#X connect 48 0 49 0;
#X connect 49 0 50 0;
#X connect 50 0 51 0;
#N canvas 43 89 962 524 12;
#X obj 94 24 inlet;
#X obj 355 123 unpost;
#X obj 424 227 float;
#X obj 280 93 trigger bang bang bang;
#X obj 330 188 list;
#X obj 94 53 trigger bang bang;
#X obj 330 217 list length;
#X obj 238 258 symbol;
#X obj 169 193 unpost;
#X obj 238 297 float;
#X obj 94 163 trigger bang bang bang;
#X obj 144 258 list;
#X obj 144 287 list length;
#X obj 424 188 makefilename %d;
#X msg 424 158 42;
#X obj 330 279 list append sending a symbol message with a numeric
payload to [float] should trigger a conversion to float;
#X obj 144 329 list append sending a symbol message with a non-numeric
payload to [float] should cause an error;
#X obj 144 444 outlet;
#X obj 330 246 == 0;
#X connect 0 0 5 0;
#X connect 1 0 4 1;
#X connect 1 1 14 0;
#X connect 3 0 4 0;
#X connect 3 1 1 0;
#X connect 3 2 4 1;
#X connect 4 0 6 0;
#X connect 5 0 10 0;
#X connect 5 1 3 0;
#X connect 6 0 18 0;
#X connect 7 0 9 0;
#X connect 8 0 11 1;
#X connect 8 1 7 0;
#X connect 10 0 11 0;
#X connect 10 1 8 0;
#X connect 10 2 11 1;
#X connect 11 0 12 0;
#X connect 12 0 16 0;
#X connect 13 0 2 0;
#X connect 14 0 13 0;
#X connect 15 0 17 0;
#X connect 16 0 17 0;
#X connect 18 0 15 0;
#N canvas 2 79 1230 587 12;
#X obj 128 68 inlet;
#X obj 244 127 unpost;
#X text 230 26 trigger as many branches as we can from the patch for
the type hints that come with certain errors. Just looking for crashers
here \, but we can later expand these if we wish.;
#X obj 128 486 list append triggered type hints and nothing crashed.
Hooray!;
#X obj 128 97 trigger bang bang;
#X obj 128 127 f 1;
#X obj 728 288 list trim;
#X msg 696 218 symbol;
#X obj 696 247 t a a;
#X text 755 219 empty symbol message;
#X text 805 289 empty symbol atom as selector;
#X msg 574 218 1;
#X obj 574 247 makefilename %d;
#X text 580 278 symbol message;
#X text 580 298 with "floatlike";
#X text 580 318 symbol atom;
#X text 580 338 payload;
#X obj 424 247 makefilename 1e+%d;
#X msg 424 218 2048;
#X msg 284 218 2048;
#X obj 284 247 makefilename 1e-%d;
#X obj 424 346 t a a;
#X obj 424 385 list trim;
#X obj 283 154 trigger bang bang bang bang;
#X text 283 286 symbol atoms with "floatlike" payload;
#X text 283 306 tht is out of range;
#X obj 128 531 outlet;
#X obj 696 430 trigger anything anything;
#X obj 696 499 int;
#X text 735 471 run through the inlet class \, too;
#X connect 0 0 4 0;
#X connect 1 1 23 0;
#X connect 3 0 26 0;
#X connect 4 0 5 0;
#X connect 4 1 1 0;
#X connect 5 0 3 0;
#X connect 6 0 27 0;
#X connect 7 0 8 0;
#X connect 8 0 27 0;
#X connect 8 1 6 0;
#X connect 11 0 12 0;
#X connect 12 0 27 0;
#X connect 17 0 21 0;
#X connect 18 0 17 0;
#X connect 19 0 20 0;
#X connect 20 0 21 0;
#X connect 21 0 22 0;
#X connect 21 1 27 0;
#X connect 22 0 27 0;
#X connect 23 0 19 0;
#X connect 23 1 18 0;
#X connect 23 2 11 0;
#X connect 23 3 7 0;
#X connect 27 0 28 0;
#X connect 27 1 28 1;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment