summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--bootstraptest/test_literal_suffix.rb2
-rw-r--r--parse.y138
3 files changed, 92 insertions, 59 deletions
diff --git a/ChangeLog b/ChangeLog
index 0fd4bc2ba1..93a4c08a24 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,13 @@
-Fri Aug 2 23:14:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Fri Aug 2 23:14:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_number_literal_suffix): return bit set of found
+ suffixes.
+
+ * parse.y (parser_set_number_literal, parser_set_integer_literal):
+ split from parser_number_literal_suffix to set yyvlal.
+
+ * parse.y (parser_yylex): parse rational number literal with decimal
+ point precisely.
* parse.y (simple_numeric): integrate numeric literals and simplify
numeric rules.
diff --git a/bootstraptest/test_literal_suffix.rb b/bootstraptest/test_literal_suffix.rb
index 5f86904128..4316c9e040 100644
--- a/bootstraptest/test_literal_suffix.rb
+++ b/bootstraptest/test_literal_suffix.rb
@@ -43,6 +43,8 @@ assert_equal '0+10.0i', '1e1i'
assert_equal 'Complex', '1e1i.class'
assert_equal '1', '1if true'
assert_equal '1', '1rescue nil'
+assert_equal '10000000000000000001/10000000000000000000',
+ '1.0000000000000000001r'
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}
diff --git a/parse.y b/parse.y
index ea132e7b77..b17d986738 100644
--- a/parse.y
+++ b/parse.y
@@ -5024,7 +5024,9 @@ static int parser_here_document(struct parser_params*,NODE*);
# 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))
+# define number_literal_suffix(f) parser_number_literal_suffix(parser, (f))
+# define set_number_literal(v, t, f) parser_set_number_literal(parser, (v), (t), (f))
+# define set_integer_literal(v, f) parser_set_integer_literal(parser, (v), (f))
#ifndef RIPPER
# define set_yylval_str(x) (yylval.node = NEW_STR(x))
@@ -6382,51 +6384,54 @@ parser_whole_match_p(struct parser_params *parser,
#define NUM_SUFFIX_ALL 3
static int
-parser_number_literal_suffix(struct parser_params *parser, VALUE v, int const flag)
+parser_number_literal_suffix(struct parser_params *parser, int mask)
{
- 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;
- }
+ int c, result = 0;
+ const char *lastp = lex_p;
- if (RB_TYPE_P(v, T_FLOAT)) {
- v = rb_flt_rationalize(v);
- }
- else {
- v = rb_rational_new(v, INT2FIX(1));
- }
+ while ((c = nextc()) != -1) {
+ if ((mask & NUM_SUFFIX_I) && c == 'i') {
+ result |= (mask & NUM_SUFFIX_I);
+ mask &= ~NUM_SUFFIX_I;
+ /* r after i, rational of complex is disallowed */
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if ((mask & NUM_SUFFIX_R) && c == 'r') {
+ result |= (mask & NUM_SUFFIX_R);
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if (!ISASCII(c) || ISALPHA(c) || c == '_') {
+ lex_p = lastp;
+ return 0;
+ }
+ pushback(c);
+ break;
}
- if ((flag & NUM_SUFFIX_I) > 0 && c == 'i') {
- c = nextc();
- if (ISALNUM(c) || c == '_') {
- pushback(c);
- pushback('i');
- goto finish;
- }
+ return result;
+}
- v = rb_complex_new(INT2FIX(0), v);
+static int
+parser_set_number_literal(struct parser_params *parser, VALUE v, int type, int suffix)
+{
+ if (suffix & NUM_SUFFIX_I) {
+ v = rb_complex_raw(INT2FIX(0), v);
+ type = tIMAGINARY;
}
- 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;
+ return type;
+}
+
+static int
+parser_set_integer_literal(struct parser_params *parser, VALUE v, int suffix)
+{
+ int type = tINTEGER;
+ if (suffix & NUM_SUFFIX_R) {
+ v = rb_rational_new(v, INT2FIX(1));
+ type = tRATIONAL;
}
- UNREACHABLE;
+ return set_number_literal(v, type, suffix);
}
#ifdef RIPPER
@@ -7425,7 +7430,7 @@ parser_yylex(struct parser_params *parser)
case '5': case '6': case '7': case '8': case '9':
{
int is_float, seen_point, seen_e, nondigit;
- VALUE v;
+ int suffix;
is_float = seen_point = seen_e = nondigit = 0;
lex_state = EXPR_END;
@@ -7459,8 +7464,8 @@ parser_yylex(struct parser_params *parser)
no_digits();
}
else if (nondigit) goto trailing_uc;
- v = rb_cstr_to_inum(tok(), 16, FALSE);
- return number_literal_suffix(v, NUM_SUFFIX_ALL);
+ suffix = number_literal_suffix(NUM_SUFFIX_ALL);
+ return set_integer_literal(rb_cstr_to_inum(tok(), 16, FALSE), suffix);
}
if (c == 'b' || c == 'B') {
/* binary */
@@ -7483,8 +7488,8 @@ parser_yylex(struct parser_params *parser)
no_digits();
}
else if (nondigit) goto trailing_uc;
- v = rb_cstr_to_inum(tok(), 2, FALSE);
- return number_literal_suffix(v, NUM_SUFFIX_ALL);
+ suffix = number_literal_suffix(NUM_SUFFIX_ALL);
+ return set_integer_literal(rb_cstr_to_inum(tok(), 2, FALSE), suffix);
}
if (c == 'd' || c == 'D') {
/* decimal */
@@ -7507,8 +7512,8 @@ parser_yylex(struct parser_params *parser)
no_digits();
}
else if (nondigit) goto trailing_uc;
- v = rb_cstr_to_inum(tok(), 10, FALSE);
- return number_literal_suffix(v, NUM_SUFFIX_ALL);
+ suffix = number_literal_suffix(NUM_SUFFIX_ALL);
+ return set_integer_literal(rb_cstr_to_inum(tok(), 10, FALSE), suffix);
}
if (c == '_') {
/* 0_0 */
@@ -7539,8 +7544,8 @@ parser_yylex(struct parser_params *parser)
pushback(c);
tokfix();
if (nondigit) goto trailing_uc;
- v = rb_cstr_to_inum(tok(), 8, FALSE);
- return number_literal_suffix(v, NUM_SUFFIX_ALL);
+ suffix = number_literal_suffix(NUM_SUFFIX_ALL);
+ return set_integer_literal(rb_cstr_to_inum(tok(), 8, FALSE), suffix);
}
if (nondigit) {
pushback(c);
@@ -7556,7 +7561,8 @@ parser_yylex(struct parser_params *parser)
}
else {
pushback(c);
- return number_literal_suffix(INT2FIX(0), NUM_SUFFIX_ALL);
+ suffix = number_literal_suffix(NUM_SUFFIX_ALL);
+ return set_integer_literal(INT2FIX(0), suffix);
}
}
@@ -7581,10 +7587,10 @@ parser_yylex(struct parser_params *parser)
}
c = c0;
}
+ seen_point = toklen();
tokadd('.');
tokadd(c);
is_float++;
- seen_point++;
nondigit = 0;
break;
@@ -7633,16 +7639,32 @@ parser_yylex(struct parser_params *parser)
}
tokfix();
if (is_float) {
- double d = strtod(tok(), 0);
- if (errno == ERANGE) {
- rb_warningS("Float %s out of range", tok());
- errno = 0;
+ int type = tFLOAT;
+ VALUE v;
+
+ suffix = number_literal_suffix(seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
+ if (suffix & NUM_SUFFIX_R) {
+ char *point = &tok()[seen_point];
+ size_t fraclen = toklen()-seen_point-1;
+ type = tRATIONAL;
+ memmove(point, point+1, fraclen+1);
+ v = rb_cstr_to_inum(tok(), 10, FALSE);
+ *point = '1';
+ memset(point+1, '0', fraclen);
+ v = rb_rational_new(v, rb_cstr_to_inum(point, 10, FALSE));
+ }
+ else {
+ double d = strtod(tok(), 0);
+ if (errno == ERANGE) {
+ rb_warningS("Float %s out of range", tok());
+ errno = 0;
+ }
+ v = DBL2NUM(d);
}
- v = DBL2NUM(d);
- return number_literal_suffix(v, seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
+ return set_number_literal(v, type, suffix);
}
- v = rb_cstr_to_inum(tok(), 10, FALSE);
- return number_literal_suffix(v, NUM_SUFFIX_ALL);
+ suffix = number_literal_suffix(NUM_SUFFIX_ALL);
+ return set_integer_literal(rb_cstr_to_inum(tok(), 10, FALSE), suffix);
}
case ')':