summaryrefslogtreecommitdiff
path: root/rational.c
diff options
context:
space:
mode:
authortadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-17 15:19:55 +0000
committertadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-11-17 15:19:55 +0000
commit47fe9b79a3039f3fdd74847feb3570e368a7ac35 (patch)
tree434171417169b0df7ca1dba4f68ebca941875fc7 /rational.c
parent20039668ddf425ab3430e06b1021bc86f2f30b4f (diff)
* complex.c (string_to_c_strict, string_to_c): rewrote without regexp.
* rational.c (string_to_r_strict, string_to_r): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37702 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'rational.c')
-rw-r--r--rational.c292
1 files changed, 167 insertions, 125 deletions
diff --git a/rational.c b/rational.c
index 845b4d80b4..88f4083341 100644
--- a/rational.c
+++ b/rational.c
@@ -1956,145 +1956,185 @@ float_rationalize(int argc, VALUE *argv, VALUE self)
return rb_rational_new2(p, q);
}
-static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore;
-
-#define WS "\\s*"
-#define DIGITS "(?:[0-9](?:_[0-9]|[0-9])*)"
-#define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
-#define DENOMINATOR DIGITS
-#define PATTERN "\\A" WS "([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?" WS
+#include <ctype.h>
-static void
-make_patterns(void)
+static int
+read_sign(const char **s)
{
- static const char rat_pat_source[] = PATTERN;
- static const char an_e_pat_source[] = "[eE]";
- static const char a_dot_pat_source[] = "\\.";
- static const char underscores_pat_source[] = "_+";
+ int sign = '?';
- if (rat_pat) return;
-
- rat_pat = rb_reg_new(rat_pat_source, sizeof rat_pat_source - 1, 0);
- rb_gc_register_mark_object(rat_pat);
+ if (**s == '-' || **s == '+') {
+ sign = **s;
+ (*s)++;
+ }
+ return sign;
+}
- an_e_pat = rb_reg_new(an_e_pat_source, sizeof an_e_pat_source - 1, 0);
- rb_gc_register_mark_object(an_e_pat);
+static int
+read_digits(const char **s, int strict,
+ VALUE *num, int *count)
+{
+ int us = 1;
- a_dot_pat = rb_reg_new(a_dot_pat_source, sizeof a_dot_pat_source - 1, 0);
- rb_gc_register_mark_object(a_dot_pat);
+ if (!isdigit((unsigned char)**s))
+ return 0;
- underscores_pat = rb_reg_new(underscores_pat_source,
- sizeof underscores_pat_source - 1, 0);
- rb_gc_register_mark_object(underscores_pat);
+ *num = ZERO;
- an_underscore = rb_usascii_str_new2("_");
- rb_gc_register_mark_object(an_underscore);
+ while (isdigit((unsigned char)**s) || **s == '_') {
+ if (**s == '_') {
+ if (strict) {
+ if (us)
+ return 0;
+ }
+ us = 1;
+ }
+ else {
+ *num = f_mul(*num, INT2FIX(10));
+ *num = f_add(*num, INT2FIX(**s - '0'));
+ if (count)
+ (*count)++;
+ us = 0;
+ }
+ (*s)++;
+ }
+ if (us)
+ do {
+ (*s)--;
+ } while (**s == '_');
+ return 1;
}
-#define id_match rb_intern("match")
-#define f_match(x,y) rb_funcall((x), id_match, 1, (y))
+static int
+read_num(const char **s, int numsign, int strict,
+ VALUE *num)
+{
+ VALUE ip, fp, exp;
-#define id_split rb_intern("split")
-#define f_split(x,y) rb_funcall((x), id_split, 1, (y))
+ *num = rb_rational_raw2(ZERO, ONE);
+ exp = Qnil;
-#include <ctype.h>
+ if (**s != '.') {
+ if (!read_digits(s, strict, &ip, NULL))
+ return 0;
+ *num = rb_rational_raw2(ip, ONE);
+ }
-static VALUE
-string_to_r_internal(VALUE self)
-{
- VALUE s, m;
+ if (**s == '.') {
+ int count = 0;
- s = self;
+ (*s)++;
+ if (!read_digits(s, strict, &fp, &count))
+ return 0;
+ {
+ VALUE l = f_expt10(INT2NUM(count));
+ *num = f_mul(*num, l);
+ *num = f_add(*num, fp);
+ *num = f_div(*num, l);
+ }
+ }
- if (RSTRING_LEN(s) == 0)
- return rb_assoc_new(Qnil, self);
+ if (**s == 'e' || **s == 'E') {
+ int expsign;
- m = f_match(rat_pat, s);
+ (*s)++;
+ expsign = read_sign(s);
+ if (!read_digits(s, strict, &exp, NULL))
+ return 0;
+ if (expsign == '-')
+ exp = f_negate(exp);
+ }
- if (!NIL_P(m)) {
- VALUE v, ifp, exp, ip, fp;
- VALUE si = rb_reg_nth_match(1, m);
- VALUE nu = rb_reg_nth_match(2, m);
- VALUE de = rb_reg_nth_match(3, m);
- VALUE re = rb_reg_match_post(m);
+ if (numsign == '-')
+ *num = f_negate(*num);
+ if (!NIL_P(exp)) {
+ VALUE l = f_expt10(exp);
+ *num = f_mul(*num, l);
+ }
+ return 1;
+}
- {
- VALUE a;
+static int
+read_den(const char **s, int strict,
+ VALUE *num)
+{
+ if (!read_digits(s, strict, num, NULL))
+ return 0;
+ return 1;
+}
- if (!strpbrk(RSTRING_PTR(nu), "eE")) {
- ifp = nu; /* not a copy */
- exp = Qnil;
- }
- else {
- a = f_split(nu, an_e_pat);
- ifp = RARRAY_PTR(a)[0];
- if (RARRAY_LEN(a) != 2)
- exp = Qnil;
- else
- exp = RARRAY_PTR(a)[1];
- }
+static int
+read_rat_nos(const char **s, int sign, int strict,
+ VALUE *num)
+{
+ VALUE den;
- if (!strchr(RSTRING_PTR(ifp), '.')) {
- ip = ifp; /* not a copy */
- fp = Qnil;
- }
- else {
- a = f_split(ifp, a_dot_pat);
- ip = RARRAY_PTR(a)[0];
- if (RARRAY_LEN(a) != 2)
- fp = Qnil;
- else
- fp = RARRAY_PTR(a)[1];
- }
- }
+ if (!read_num(s, sign, strict, num))
+ return 0;
+ if (**s == '/') {
+ (*s)++;
+ if (!read_den(s, strict, &den))
+ return 0;
+ if (!(FIXNUM_P(den) && FIX2LONG(den) == 1))
+ *num = f_div(*num, den);
+ }
+ return 1;
+}
- v = rb_rational_new1(f_to_i(ip));
+static int
+read_rat(const char **s, int strict,
+ VALUE *num)
+{
+ int sign;
- if (!NIL_P(fp)) {
- char *p = RSTRING_PTR(fp);
- long count = 0;
- VALUE l;
+ sign = read_sign(s);
+ if (!read_rat_nos(s, sign, strict, num))
+ return 0;
+ return 1;
+}
- while (*p) {
- if (rb_isdigit(*p))
- count++;
- p++;
- }
- l = f_expt10(LONG2NUM(count));
- v = f_mul(v, l);
- v = f_add(v, f_to_i(fp));
- v = f_div(v, l);
- }
- if (!NIL_P(si) && *RSTRING_PTR(si) == '-')
- v = f_negate(v);
- if (!NIL_P(exp))
- v = f_mul(v, f_expt10(f_to_i(exp)));
-#if 0
- if (!NIL_P(de) && (!NIL_P(fp) || !NIL_P(exp)))
- return rb_assoc_new(v, rb_usascii_str_new2("dummy"));
-#endif
- if (!NIL_P(de))
- v = f_div(v, f_to_i(de));
+static int
+parse_rat(const char *s, int strict,
+ VALUE *num)
+{
+ while (isspace((unsigned char)*s))
+ s++;
- return rb_assoc_new(v, re);
- }
- return rb_assoc_new(Qnil, self);
+ if (!read_rat(&s, strict, num))
+ return 0;
+
+ while (isspace((unsigned char)*s))
+ s++;
+
+ if (strict)
+ if (*s != '\0')
+ return 0;
+ return 1;
}
static VALUE
string_to_r_strict(VALUE self)
{
- VALUE a = string_to_r_internal(self);
- if (NIL_P(RARRAY_PTR(a)[0]) || RSTRING_LEN(RARRAY_PTR(a)[1]) > 0) {
- VALUE s = f_inspect(self);
+ const char *s;
+ VALUE num;
+
+ rb_must_asciicompat(self);
+
+ s = RSTRING_PTR(self);
+
+ if (memchr(s, 0, RSTRING_LEN(self)))
+ rb_raise(rb_eArgError, "string contains null byte");
+
+ if (!parse_rat(s, 1, &num)) {
+ VALUE ins = f_inspect(self);
rb_raise(rb_eArgError, "invalid value for convert(): %s",
- StringValuePtr(s));
+ StringValuePtr(ins));
}
- return RARRAY_PTR(a)[0];
-}
-#define id_gsub rb_intern("gsub")
-#define f_gsub(x,y,z) rb_funcall((x), id_gsub, 2, (y), (z))
+ if (RB_TYPE_P(num, T_FLOAT))
+ rb_raise(rb_eFloatDomainError, "Infinity");
+ return num;
+}
/*
* call-seq:
@@ -2120,27 +2160,31 @@ string_to_r_strict(VALUE self)
static VALUE
string_to_r(VALUE self)
{
- VALUE s, a, a1, backref;
+ const char *s;
+ VALUE num;
- backref = rb_backref_get();
- rb_match_busy(backref);
+ rb_must_asciicompat(self);
- s = f_gsub(self, underscores_pat, an_underscore);
- a = string_to_r_internal(s);
+ s = RSTRING_PTR(self);
- rb_backref_set(backref);
+ (void)parse_rat(s, 0, &num);
- a1 = RARRAY_PTR(a)[0];
- if (!NIL_P(a1)) {
- if (RB_TYPE_P(a1, T_FLOAT))
- rb_raise(rb_eFloatDomainError, "Infinity");
- return a1;
- }
- return rb_rational_new1(INT2FIX(0));
+ if (RB_TYPE_P(num, T_FLOAT))
+ rb_raise(rb_eFloatDomainError, "Infinity");
+ return num;
}
-#define id_to_r rb_intern("to_r")
-#define f_to_r(x) rb_funcall((x), id_to_r, 0)
+VALUE
+rb_cstr_to_rat(const char *s, int strict) /* for complex's internal */
+{
+ VALUE num;
+
+ (void)parse_rat(s, strict, &num);
+
+ if (RB_TYPE_P(num, T_FLOAT))
+ rb_raise(rb_eFloatDomainError, "Infinity");
+ return num;
+}
static VALUE
nurat_s_convert(int argc, VALUE *argv, VALUE klass)
@@ -2369,8 +2413,6 @@ Init_Rational(void)
rb_define_method(rb_cFloat, "to_r", float_to_r, 0);
rb_define_method(rb_cFloat, "rationalize", float_rationalize, -1);
- make_patterns();
-
rb_define_method(rb_cString, "to_r", string_to_r, 0);
rb_define_private_method(CLASS_OF(rb_cRational), "convert", nurat_s_convert, -1);