[前][次][番号順一覧][スレッド一覧]

ruby-changes:30259

From: mrkn <ko1@a...>
Date: Thu, 1 Aug 2013 23:59:10 +0900 (JST)
Subject: [ruby-changes:30259] mrkn:r42311 (trunk): * rational.c (rb_flt_rationalize_with_prec): new public C function

mrkn	2013-08-01 23:58:54 +0900 (Thu, 01 Aug 2013)

  New Revision: 42311

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42311

  Log:
    * rational.c (rb_flt_rationalize_with_prec): new public C function
      to rationalize a Float instance with a precision.
    
    * rational.c (rb_flt_rationalize): new public C function to
     rationalize a Float instance.  A precision is calculated from
     the given float number.
    
    * include/ruby/intern.h: Add rb_flt_rationalize_with_prec and
      rb_flt_rationalize.
    
    * parse.y: implement number literal suffixes, 'r' and 'i'.
      [ruby-core:55096] [Feature #8430]
    
    * bootstraptest/test_literal_suffix.rb: add tests for parser to scan
      number literals with the above tsuffixes.

  Added files:
    trunk/bootstraptest/test_literal_suffix.rb
  Modified files:
    trunk/ChangeLog
    trunk/include/ruby/intern.h
    trunk/parse.y
    trunk/rational.c

Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 42310)
+++ include/ruby/intern.h	(revision 42311)
@@ -171,6 +171,8 @@ VALUE rb_rational_new(VALUE, VALUE); https://github.com/ruby/ruby/blob/trunk/include/ruby/intern.h#L171
 VALUE rb_Rational(VALUE, VALUE);
 #define rb_Rational1(x) rb_Rational((x), INT2FIX(1))
 #define rb_Rational2(x,y) rb_Rational((x), (y))
+VALUE rb_flt_rationalize_with_prec(VALUE, VALUE);
+VALUE rb_flt_rationalize(VALUE);
 /* complex.c */
 VALUE rb_complex_raw(VALUE, VALUE);
 #define rb_complex_raw1(x) rb_complex_raw((x), INT2FIX(0))
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 42310)
+++ ChangeLog	(revision 42311)
@@ -1,3 +1,21 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Aug  1 23:45:00 2013  Kenta Murata  <mrkn@m...>
+
+	* rational.c (rb_flt_rationalize_with_prec): new public C function
+	  to rationalize a Float instance with a precision.
+
+	* rational.c (rb_flt_rationalize): new public C function to
+	 rationalize a Float instance.  A precision is calculated from
+	 the given float number.
+
+	* include/ruby/intern.h: Add rb_flt_rationalize_with_prec and
+	  rb_flt_rationalize.
+
+	* parse.y: implement number literal suffixes, 'r' and 'i'.
+	  [ruby-core:55096] [Feature #8430]
+
+	* bootstraptest/test_literal_suffix.rb: add tests for parser to scan
+	  number literals with the above tsuffixes.
+
 Thu Aug  1 23:55:08 2013  Tanaka Akira  <akr@f...>
 
 	* bignum.c (rb_big2str1): Remove a local variable.
Index: bootstraptest/test_literal_suffix.rb
===================================================================
--- bootstraptest/test_literal_suffix.rb	(revision 0)
+++ bootstraptest/test_literal_suffix.rb	(revision 42311)
@@ -0,0 +1,46 @@ https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_literal_suffix.rb#L1
+# numbers with suffix
+assert_equal '0/1',             '0r'
+assert_equal 'Rational',        '0r.class'
+assert_equal '1/1',             '1r'
+assert_equal 'Rational',        '1r.class'
+assert_equal '1/1',             '0x1r'
+assert_equal 'Rational',        '0x1r.class'
+assert_equal '1/1',             '0b1r'
+assert_equal 'Rational',        '0b1r.class'
+assert_equal '1/1',             '0d1r'
+assert_equal 'Rational',        '0d1r.class'
+assert_equal '1/1',             '0o1r'
+assert_equal 'Rational',        '0o1r.class'
+assert_equal '1/1',             '01r'
+assert_equal 'Rational',        '01r.class'
+assert_equal '6/5',             '1.2r'
+assert_equal 'Rational',        '1.2r.class'
+assert_equal '0+0i',            '0i'
+assert_equal 'Complex',         '0i.class'
+assert_equal '0+1i',            '1i'
+assert_equal 'Complex',         '1i.class'
+assert_equal '0+1i',            '0x1i'
+assert_equal 'Complex',         '0x1i.class'
+assert_equal '0+1i',            '0b1i'
+assert_equal 'Complex',         '0b1i.class'
+assert_equal '0+1i',            '0d1i'
+assert_equal 'Complex',         '0d1i.class'
+assert_equal '0+1i',            '0o1i'
+assert_equal 'Complex',         '0o1i.class'
+assert_equal '0+1i',            '01i'
+assert_equal 'Complex',         '01i.class'
+assert_equal '0+1.2i',          '1.2i'
+assert_equal 'Complex',         '1.2i.class'
+assert_equal '0+1/1i',          '1ri'
+assert_equal 'Complex',         '1ri.class'
+assert_equal '0+6/5i',          '1.2ri'
+assert_equal 'Complex',         '1.2ri.class'
+assert_equal '0+10.0i',         '1e1i'
+assert_equal 'Complex',         '1e1i.class'
+
+assert_equal 'syntax error, unexpected tIDENTIFIER, expecting end-of-input',
+             %q{begin eval('1ir', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
+assert_equal 'syntax error, unexpected tIDENTIFIER, expecting end-of-input',
+             %q{begin eval('1.2ir', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
+assert_equal 'syntax error, unexpected tIDENTIFIER, expecting end-of-input',
+             %q{begin eval('1e1r', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
Index: parse.y
===================================================================
--- parse.y	(revision 42310)
+++ parse.y	(revision 42311)
@@ -754,7 +754,7 @@ static void token_info_pop(struct parser https://github.com/ruby/ruby/blob/trunk/parse.y#L754
 	keyword__ENCODING__
 
 %token <id>   tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
-%token <node> tINTEGER tFLOAT tSTRING_CONTENT tCHAR
+%token <node> tINTEGER tFLOAT tRATIONAL tIMAGINARY tSTRING_CONTENT tCHAR
 %token <node> tNTH_REF tBACK_REF
 %token <num>  tREGEXP_END
 
@@ -2128,6 +2128,24 @@ arg		: lhs '=' arg https://github.com/ruby/ruby/blob/trunk/parse.y#L2128
 			$$ = dispatch2(unary, ripper_intern("-@"), $$);
 		    %*/
 		    }
+                | tUMINUS_NUM tRATIONAL tPOW arg
+                    {
+                    /*%%%*/
+                        $$ = NEW_CALL(call_bin_op($2, tPOW, $4), tUMINUS, 0);
+                    /*%
+                        $$ = dispatch3(binary, $2, ripper_intern("**"), $4);
+                        $$ = dispatch2(unary, ripper_intern("-@"), $$);
+                    %*/
+                    }
+                | tUMINUS_NUM tIMAGINARY tPOW arg
+                    {
+                    /*%%%*/
+                        $$ = NEW_CALL(call_bin_op($2, tPOW, $4), tUMINUS, 0);
+                    /*%
+                        $$ = dispatch3(binary, $2, ripper_intern("**"), $4);
+                        $$ = dispatch2(unary, ripper_intern("-@"), $$);
+                    %*/
+                    }
 		| tUPLUS arg
 		    {
 		    /*%%%*/
@@ -4294,6 +4312,8 @@ dsym		: tSYMBEG xstring_contents tSTRING https://github.com/ruby/ruby/blob/trunk/parse.y#L4312
 
 numeric 	: tINTEGER
 		| tFLOAT
+                | tRATIONAL
+                | tIMAGINARY
 		| tUMINUS_NUM tINTEGER	       %prec tLOWEST
 		    {
 		    /*%%%*/
@@ -4310,6 +4330,22 @@ numeric 	: tINTEGER https://github.com/ruby/ruby/blob/trunk/parse.y#L4330
 			$$ = dispatch2(unary, ripper_intern("-@"), $2);
 		    %*/
 		    }
+                | tUMINUS_NUM tRATIONAL	       %prec tLOWEST
+                    {
+                    /*%%%*/
+                        $$ = negate_lit($2);
+                    /*%
+                        $$ = dispatch2(unary, ripper_intern("-@"), $2);
+                    %*/
+                    }
+                | tUMINUS_NUM tIMAGINARY       %prec tLOWEST
+                    {
+                    /*%%%*/
+                        $$ = negate_lit($2);
+                    /*%
+                        $$ = dispatch2(unary, ripper_intern("-@"), $2);
+                    %*/
+                    }
 		;
 
 user_variable	: tIDENTIFIER
@@ -5020,22 +5056,23 @@ static int parser_parse_string(struct pa https://github.com/ruby/ruby/blob/trunk/parse.y#L5056
 static int parser_here_document(struct parser_params*,NODE*);
 
 
-# define nextc()                   parser_nextc(parser)
-# define pushback(c)               parser_pushback(parser, (c))
-# define newtok()                  parser_newtok(parser)
-# define tokspace(n)               parser_tokspace(parser, (n))
-# define tokadd(c)                 parser_tokadd(parser, (c))
-# define tok_hex(numlen)           parser_tok_hex(parser, (numlen))
-# define read_escape(flags,e)      parser_read_escape(parser, (flags), (e))
-# define tokadd_escape(e)          parser_tokadd_escape(parser, (e))
-# define regx_options()            parser_regx_options(parser)
-# define tokadd_string(f,t,p,n,e)  parser_tokadd_string(parser,(f),(t),(p),(n),(e))
-# define parse_string(n)           parser_parse_string(parser,(n))
-# define tokaddmbc(c, enc)         parser_tokaddmbc(parser, (c), (enc))
-# define here_document(n)          parser_here_document(parser,(n))
-# define heredoc_identifier()      parser_heredoc_identifier(parser)
-# define heredoc_restore(n)        parser_heredoc_restore(parser,(n))
-# define whole_match_p(e,l,i)      parser_whole_match_p(parser,(e),(l),(i))
+# define nextc()                      parser_nextc(parser)
+# define pushback(c)                  parser_pushback(parser, (c))
+# define newtok()                     parser_newtok(parser)
+# define tokspace(n)                  parser_tokspace(parser, (n))
+# define tokadd(c)                    parser_tokadd(parser, (c))
+# define tok_hex(numlen)              parser_tok_hex(parser, (numlen))
+# define read_escape(flags,e)         parser_read_escape(parser, (flags), (e))
+# define tokadd_escape(e)             parser_tokadd_escape(parser, (e))
+# define regx_options()               parser_regx_options(parser)
+# define tokadd_string(f,t,p,n,e)     parser_tokadd_string(parser,(f),(t),(p),(n),(e))
+# define parse_string(n)              parser_parse_string(parser,(n))
+# define tokaddmbc(c, enc)            parser_tokaddmbc(parser, (c), (enc))
+# define here_document(n)             parser_here_document(parser,(n))
+# define heredoc_identifier()         parser_heredoc_identifier(parser)
+# define heredoc_restore(n)           parser_heredoc_restore(parser,(n))
+# define whole_match_p(e,l,i)         parser_whole_match_p(parser,(e),(l),(i))
+# define number_literal_suffix(v, f)  parser_number_literal_suffix(parser, (v), (f))
 
 #ifndef RIPPER
 # define set_yylval_str(x) (yylval.node = NEW_STR(x))
@@ -6388,6 +6425,58 @@ parser_whole_match_p(struct parser_param https://github.com/ruby/ruby/blob/trunk/parse.y#L6425
     return strncmp(eos, p, len) == 0;
 }
 
+#define NUM_SUFFIX_R   (1<<0)
+#define NUM_SUFFIX_I   (1<<1)
+#define NUM_SUFFIX_ALL 3
+
+static int
+parser_number_literal_suffix(struct parser_params *parser, VALUE v, int const flag)
+{
+    int c = nextc();
+    if ((flag & NUM_SUFFIX_R) > 0 && c == 'r') {
+        c = nextc();
+        if (c != 'i' && (ISALNUM(c) || c == '_')) {
+            pushback(c);
+            pushback('r');
+            goto finish;
+        }
+
+        if (RB_TYPE_P(v, T_FLOAT)) {
+            v = rb_flt_rationalize(v);
+        }
+        else {
+            v = rb_rational_new(v, INT2FIX(1));
+        }
+    }
+    if ((flag & NUM_SUFFIX_I) > 0 && c == 'i') {
+        c = nextc();
+        if (ISALNUM(c) || c == '_') {
+            pushback(c);
+            pushback('i');
+            goto finish;
+        }
+
+        v = rb_complex_new(INT2FIX(0), v);
+    }
+    pushback(c);
+
+finish:
+    set_yylval_literal(v);
+    switch (TYPE(v)) {
+    case T_FIXNUM: case T_BIGNUM:
+        return tINTEGER;
+    case T_FLOAT:
+        return tFLOAT;
+    case T_RATIONAL:
+        return tRATIONAL;
+    case T_COMPLEX:
+        return tIMAGINARY;
+    default:
+        break;
+    }
+    UNREACHABLE;
+}
+
 #ifdef RIPPER
 static void
 ripper_dispatch_heredoc_end(struct parser_params *parser)
@@ -7384,6 +7473,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7473
       case '5': case '6': case '7': case '8': case '9':
 	{
 	    int is_float, seen_point, seen_e, nondigit;
+            VALUE v;
 
 	    is_float = seen_point = seen_e = nondigit = 0;
 	    lex_state = EXPR_END;
@@ -7417,8 +7507,8 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7507
 			no_digits();
 		    }
 		    else if (nondigit) goto trailing_uc;
-		    set_yylval_literal(rb_cstr_to_inum(tok(), 16, FALSE));
-		    return tINTEGER;
+                    v = rb_cstr_to_inum(tok(), 16, FALSE);
+                    return number_literal_suffix(v, NUM_SUFFIX_ALL);
 		}
 		if (c == 'b' || c == 'B') {
 		    /* binary */
@@ -7441,8 +7531,8 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7531
 			no_digits();
 		    }
 		    else if (nondigit) goto trailing_uc;
-		    set_yylval_literal(rb_cstr_to_inum(tok(), 2, FALSE));
-		    return tINTEGER;
+                    v = rb_cstr_to_inum(tok(), 2, FALSE);
+                    return number_literal_suffix(v, NUM_SUFFIX_ALL);
 		}
 		if (c == 'd' || c == 'D') {
 		    /* decimal */
@@ -7465,8 +7555,8 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7555
 			no_digits();
 		    }
 		    else if (nondigit) goto trailing_uc;
-		    set_yylval_literal(rb_cstr_to_inum(tok(), 10, FALSE));
-		    return tINTEGER;
+                    v = rb_cstr_to_inum(tok(), 10, FALSE);
+                    return number_literal_suffix(v, NUM_SUFFIX_ALL);
 		}
 		if (c == '_') {
 		    /* 0_0 */
@@ -7497,8 +7587,8 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7587
 			pushback(c);
 			tokfix();
 			if (nondigit) goto trailing_uc;
-			set_yylval_literal(rb_cstr_to_inum(tok(), 8, FALSE));
-			return tINTEGER;
+                        v = rb_cstr_to_inum(tok(), 8, FALSE);
+                        return number_literal_suffix(v, NUM_SUFFIX_ALL);
 		    }
 		    if (nondigit) {
 			pushback(c);
@@ -7514,8 +7604,7 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7604
 		}
 		else {
 		    pushback(c);
-                    set_yylval_literal(INT2FIX(0));
-		    return tINTEGER;
+                    return number_literal_suffix(INT2FIX(0), NUM_SUFFIX_ALL);
 		}
 	    }
 
@@ -7597,11 +7686,11 @@ parser_yylex(struct parser_params *parse https://github.com/ruby/ruby/blob/trunk/parse.y#L7686
 		    rb_warningS("Float %s out of range", tok());
 		    errno = 0;
 		}
-                set_yylval_literal(DBL2NUM(d));
-		return tFLOAT;
+                v = DBL2NUM(d);
+                return number_literal_suffix(v, seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
 	    }
-	    set_yylval_literal(rb_cstr_to_inum(tok(), 10, FALSE));
-	    return tINTEGER;
+            v = rb_cstr_to_inum(tok(), 10, FALSE);
+            return number_literal_suffix(v, NUM_SUFFIX_ALL);
 	}
 
       case ')':
Index: rational.c
===================================================================
--- rational.c	(revision 42310)
+++ rational.c	(revision 42311)
@@ -2004,6 +2004,60 @@ float_to_r(VALUE self) https://github.com/ruby/ruby/blob/trunk/rational.c#L2004
 #endif
 }
 
+VALUE
+rb_flt_rationalize_with_prec(VALUE flt, VALUE prec)
+{
+    VALUE e, a, b, p, q;
+
+    e = f_abs(prec);
+    a = f_sub(flt, e);
+    b = f_add(flt, e);
+
+    if (f_eqeq_p(a, b))
+        return f_to_r(flt);
+
+    nurat_rationalize_internal(a, b, &p, &q);
+    return rb_rational_new2(p, q);
+}
+
+VALUE
+rb_flt_rationalize(VALUE flt)
+{
+    VALUE a, b, f, n, p, q;
+
+    float_decode_internal(flt, &f, &n);
+    if (f_zero_p(f) || f_positive_p(n))
+        return rb_rational_new1(f_lshift(f, n));
+
+#if FLT_RADIX == 2
+    {
+        VALUE two_times_f, den;
+
+        two_times_f = f_mul(TWO, f);
+        den = f_lshift(ONE, f_sub(ONE, n));
+
+        a = rb_rational_new2(f_sub(two_times_f, ONE), den);
+        b = rb_rational_new2(f_add(two_times_f, ONE), den);
+    }
+#else
+    {
+        VALUE radix_times_f, den;
+
+        radix_times_f = f_mul(INT2FIX(FLT_RADIX), f);
+        den = f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n));
+
+        a = rb_rational_new2(f_sub(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
+        b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
+    }
+#endif
+
+    if (f_eqeq_p(a, b))
+        return f_to_r(flt);
+
+    nurat_rationalize_internal(a, b, &p, &q);
+    return rb_rational_new2(p, q);
+}
+
 /*
  * call-seq:
  *    flt.rationalize([eps])  ->  rational
@@ -2021,53 +2075,19 @@ float_to_r(VALUE self) https://github.com/ruby/ruby/blob/trunk/rational.c#L2075
 static VALUE
 float_rationalize(int argc, VALUE *argv, VALUE self)
 {
-    VALUE e, a, b, p, q;
+    VALUE e;
 
     if (f_negative_p(self))
-	return f_negate(float_rationalize(argc, argv, f_abs(self)));
+        return f_negate(float_rationalize(argc, argv, f_abs(self)));
 
     rb_scan_args(argc, argv, "01", &e);
 
     if (argc != 0) {
-	e = f_abs(e);
-	a = f_sub(self, e);
-	b = f_add(self, e);
+        return rb_flt_rationalize_with_prec(self, e);
     }
     else {
-	VALUE f, n;
-
-	float_decode_internal(self, &f, &n);
-	if (f_zero_p(f) || f_positive_p(n))
-	    return rb_rational_new1(f_lshift(f, n));
-
-#if FLT_RADIX == 2
-	{
-	    VALUE two_times_f, den;
-
-	    two_times_f = f_mul(TWO, f);
-	    den = f_lshift(ONE, f_sub(ONE, n));
-
-	    a = rb_rational_new2(f_sub(two_times_f, ONE), den);
-	    b = rb_rational_new2(f_add(two_times_f, ONE), den);
-	}
-#else
-	{
-	    VALUE radix_times_f, den;
-
-	    radix_times_f = f_mul(INT2FIX(FLT_RADIX), f);
-	    den = f_expt(INT2FIX(FLT_RADIX), f_sub(ONE, n));
-
-	    a = rb_rational_new2(f_sub(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
-	    b = rb_rational_new2(f_add(radix_times_f, INT2FIX(FLT_RADIX - 1)), den);
-	}
-#endif
+        return rb_flt_rationalize(self);
     }
-
-    if (f_eqeq_p(a, b))
-	return f_to_r(self);
-
-    nurat_rationalize_internal(a, b, &p, &q);
-    return rb_rational_new2(p, q);
 }
 
 #include <ctype.h>

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]