Commit 8808219e authored by Ukrainskiy Sergey's avatar Ukrainskiy Sergey Committed by Yukihiro "Matz" Matsumoto

Initial suffix support

parent 7f1f499b
......@@ -63,6 +63,9 @@
# endif
#endif
#define MRB_COMPLEX_NUMBERS
#define MRB_RATIONAL_NUMBERS
/* define on big endian machines; used by MRB_NAN_BOXING, etc. */
#ifndef MRB_ENDIAN_BIG
# if (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \
......
......@@ -68,6 +68,12 @@ MRuby::GemBox.new do |conf|
# Use Enumerator::Lazy class (require mruby-enumerator)
conf.gem :core => "mruby-enum-lazy"
# Use Complex class
#conf.gem :core => "mruby-complex"
# Use Rational class
#conf.gem :core => "mruby-rational"
# Use toplevel object (main) methods extension
conf.gem :core => "mruby-toplevel-ext"
......
......@@ -76,6 +76,24 @@ typedef unsigned int stack_type;
#define nint(x) ((node*)(intptr_t)(x))
#define intn(x) ((int)(intptr_t)(x))
#if defined(MRB_COMPLEX_NUMBERS) || defined(MRB_RATIONAL_NUMBERS)
#define MRB_SUFFIX_SUPPORT
#ifdef MRB_RATIONAL_NUMBERS
#define NUM_SUFFIX_R (1<<0)
#else
#define NUM_SUFFIX_R 0
#endif
#ifdef MRB_COMPLEX_NUMBERS
#define NUM_SUFFIX_I (1<<1)
#else
#define NUM_SUFFIX_I 0
#endif
#define NUM_SUFFIX_ALL (NUM_SUFFIX_R | NUM_SUFFIX_I)
#endif
static inline mrb_sym
intern_cstr_gen(parser_state *p, const char *s)
{
......@@ -842,19 +860,62 @@ new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b)
return list4((node*)NODE_OP_ASGN, a, nsym(op), b);
}
#ifdef MRB_COMPLEX_NUMBERS
static node*
new_imaginary(parser_state *p, node *imaginary);
#endif
#ifdef MRB_RATIONAL_NUMBERS
static node*
new_rational(parser_state *p, node *rational)
{
return new_call(p, new_const(p, intern_cstr("Rational")), intern_cstr("new"), list1(list1(rational)), 1);
}
#endif
/* (:int . i) */
static node*
new_int(parser_state *p, const char *s, int base)
new_int(parser_state *p, const char *s, int base, int suffix)
{
return list3((node*)NODE_INT, (node*)strdup(s), nint(base));
node* result = list3((node*)NODE_INT, (node*)strdup(s), nint(base));
#ifdef MRB_RATIONAL_NUMBERS
if (suffix & NUM_SUFFIX_R) {
result = new_rational(p, result);
}
#endif
#ifdef MRB_COMPLEX_NUMBERS
if (suffix & NUM_SUFFIX_I) {
result = new_imaginary(p, result);
}
#endif
return result;
}
#ifndef MRB_WITHOUT_FLOAT
/* (:float . i) */
static node*
new_float(parser_state *p, const char *s)
new_float(parser_state *p, const char *s, int suffix)
{
node* result = cons((node*)NODE_FLOAT, (node*)strdup(s));
#ifdef MRB_RATIONAL_NUMBERS
if (suffix & NUM_SUFFIX_R) {
result = new_rational(p, result);
}
#endif
#ifdef MRB_COMPLEX_NUMBERS
if (suffix & NUM_SUFFIX_I) {
result = new_imaginary(p, result);
}
#endif
return result;
}
#endif
#ifdef MRB_COMPLEX_NUMBERS
static node*
new_imaginary(parser_state *p, node *imaginary)
{
return cons((node*)NODE_FLOAT, (node*)strdup(s));
return new_call(p, new_const(p, intern_cstr("Complex")), intern_cstr("new"), list1(list2(new_int(p, "0", 10, 0), imaginary)), 1);
}
#endif
......@@ -3192,7 +3253,7 @@ var_ref : variable
char buf[16];
dump_int(p->lineno, buf);
$$ = new_int(p, buf, 10);
$$ = new_int(p, buf, 10, 0);
}
| keyword__ENCODING__
{
......@@ -4520,6 +4581,45 @@ parse_string(parser_state *p)
return tSTRING;
}
#ifdef MRB_SUFFIX_SUPPORT
static int
number_literal_suffix(parser_state *p, int mask)
{
int c, result = 0;
node *list = 0;
int column = p->column;
while ((c = nextc(p)) != -1) {
list = push(list, (node*)(intptr_t)c);
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 == '_') {
p->column = column;
if (p->pb) {
p->pb = append((node*)list, p->pb);
}
else {
p->pb = list;
}
return 0;
}
pushback(p, c);
break;
}
return result;
}
#endif
static int
heredoc_identifier(parser_state *p)
......@@ -5094,6 +5194,7 @@ parser_yylex(parser_state *p)
case '5': case '6': case '7': case '8': case '9':
{
int is_float, seen_point, seen_e, nondigit;
int suffix;
is_float = seen_point = seen_e = nondigit = 0;
p->lstate = EXPR_ENDARG;
......@@ -5127,7 +5228,10 @@ parser_yylex(parser_state *p)
no_digits();
}
else if (nondigit) goto trailing_uc;
pylval.nd = new_int(p, tok(p), 16);
#ifdef MRB_SUFFIX_SUPPORT
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
#endif
pylval.nd = new_int(p, tok(p), 16, suffix);
return tINTEGER;
}
if (c == 'b' || c == 'B') {
......@@ -5151,7 +5255,10 @@ parser_yylex(parser_state *p)
no_digits();
}
else if (nondigit) goto trailing_uc;
pylval.nd = new_int(p, tok(p), 2);
#ifdef MRB_SUFFIX_SUPPORT
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
#endif
pylval.nd = new_int(p, tok(p), 2, suffix);
return tINTEGER;
}
if (c == 'd' || c == 'D') {
......@@ -5175,7 +5282,10 @@ parser_yylex(parser_state *p)
no_digits();
}
else if (nondigit) goto trailing_uc;
pylval.nd = new_int(p, tok(p), 10);
#ifdef MRB_SUFFIX_SUPPORT
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
#endif
pylval.nd = new_int(p, tok(p), 10, suffix);
return tINTEGER;
}
if (c == '_') {
......@@ -5208,7 +5318,10 @@ parser_yylex(parser_state *p)
pushback(p, c);
tokfix(p);
if (nondigit) goto trailing_uc;
pylval.nd = new_int(p, tok(p), 8);
#ifdef MRB_SUFFIX_SUPPORT
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
#endif
pylval.nd = new_int(p, tok(p), 8, suffix);
return tINTEGER;
}
if (nondigit) {
......@@ -5225,7 +5338,10 @@ parser_yylex(parser_state *p)
}
else {
pushback(p, c);
pylval.nd = new_int(p, "0", 10);
#ifdef MRB_SUFFIX_SUPPORT
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
#endif
pylval.nd = new_int(p, "0", 10, suffix);
return tINTEGER;
}
}
......@@ -5299,7 +5415,7 @@ parser_yylex(parser_state *p)
if (is_float) {
#ifdef MRB_WITHOUT_FLOAT
yywarning(p, "floating point numbers are not supported");
pylval.nd = new_int(p, "0", 10);
pylval.nd = new_int(p, "0", 10, 0);
return tINTEGER;
#else
double d;
......@@ -5314,11 +5430,17 @@ parser_yylex(parser_state *p)
yywarning_s(p, "float out of range", tok(p));
errno = 0;
}
pylval.nd = new_float(p, tok(p));
#ifdef MRB_SUFFIX_SUPPORT
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
#endif
pylval.nd = new_float(p, tok(p), suffix);
return tFLOAT;
#endif
}
pylval.nd = new_int(p, tok(p), 10);
#ifdef MRB_SUFFIX_SUPPORT
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
#endif
pylval.nd = new_int(p, tok(p), 10, suffix);
return tINTEGER;
}
......
MRuby::Gem::Specification.new('mruby-complex') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Complex class'
end
class Complex < Numeric
def initialize(real = 0, imaginary = 0)
@real = real
@imaginary = imaginary
end
def inspect
"(#{to_s})"
end
def to_s
"#{real}#{'+'}#{imaginary}i"
end
def +@
Complex.new(real, imaginary)
end
def -@
Complex.new(-real, -imaginary)
end
def +(rhs)
if rhs.is_a? Complex
Complex.new(real + rhs.real, imaginary + rhs.imaginary)
elsif rhs.is_a? Numeric
Complex.new(real + rhs, imaginary)
end
end
def -(rhs)
if rhs.is_a? Complex
Complex.new(real - rhs.real, imaginary - rhs.imaginary)
elsif rhs.is_a? Numeric
Complex.new(real - rhs, imaginary)
end
end
def *(rhs)
if rhs.is_a? Complex
Complex.new(real * rhs.real - imaginary * rhs.imaginary, real * rhs.imaginary + rhs.real * imaginary)
elsif rhs.is_a? Numeric
Complex.new(real * rhs, imaginary * rhs)
end
end
def /(rhs)
if rhs.is_a? Complex
div = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary
Complex.new((real * rhs.real + imaginary * rhs.imaginary) / div, (rhs.real * imaginary - real * rhs.imaginary) / div)
elsif rhs.is_a? Numeric
Complex.new(real / rhs, imaginary / rhs)
end
end
attr_reader :real, :imaginary
end
def Complex(real = 0, imaginary = 0)
Complex.new(real, imaginary)
end
module ForwardOperatorToComplex
def __forward_operator_to_complex(op, &b)
original_operator_name = "__original_operator_#{op}_complex"
alias_method original_operator_name, op
define_method op do |rhs|
if rhs.is_a? Complex
Complex.new(self).send(op, rhs)
else
send(original_operator_name, rhs)
end
end
end
def __forward_operators_to_complex
__forward_operator_to_complex :+
__forward_operator_to_complex :-
__forward_operator_to_complex :*
__forward_operator_to_complex :/
singleton_class.undef_method :__forward_operator_to_complex
singleton_class.undef_method :__forward_operators_to_complex
end
end
class Fixnum
extend ForwardOperatorToComplex
__forward_operators_to_complex
end
class Float
extend ForwardOperatorToComplex
__forward_operators_to_complex
end
\ No newline at end of file
assert 'Complex' do
assert_equal Complex, 0i.class
end
\ No newline at end of file
MRuby::Gem::Specification.new('mruby-rational') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Rational class'
end
class Rational < Numeric
def initialize(numerator = 0, denominator = 1)
@numerator = numerator
@denominator = denominator
end
attr_reader :numerator, :denominator
end
def Rational(numerator = 0, denominator = 1)
Rational.new(numerator, denominator)
end
module ForwardOperatorToRational
def __forward_operator_to_rational(op, &b)
original_operator_name = "__original_operator_#{op}_rational"
alias_method original_operator_name, op
define_method op do |rhs|
if rhs.is_a? Rational
Rational.new(self).send(op, rhs)
else
send(original_operator_name, rhs)
end
end
end
def __forward_operators_to_rational
__forward_operator_to_rational :+
__forward_operator_to_rational :-
__forward_operator_to_rational :*
__forward_operator_to_rational :/
singleton_class.undef_method :__forward_operator_to_rational
singleton_class.undef_method :__forward_operators_to_rational
end
end
class Fixnum
extend ForwardOperatorToRational
__forward_operators_to_rational
end
class Float
extend ForwardOperatorToRational
__forward_operators_to_rational
end
\ No newline at end of file
assert 'Rational' do
assert_equal Rational, 0r.class
end
\ No newline at end of file
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