mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Initial suffix support
This commit is contained in:
committed by
Yukihiro "Matz" Matsumoto
parent
7f1f499b22
commit
8808219e6d
@@ -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)
|
||||
{
|
||||
return cons((node*)NODE_FLOAT, (node*)strdup(s));
|
||||
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 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
MRuby::Gem::Specification.new('mruby-complex') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Complex class'
|
||||
end
|
||||
@@ -0,0 +1,95 @@
|
||||
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
|
||||
@@ -0,0 +1,3 @@
|
||||
assert 'Complex' do
|
||||
assert_equal Complex, 0i.class
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
MRuby::Gem::Specification.new('mruby-rational') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Rational class'
|
||||
end
|
||||
@@ -0,0 +1,46 @@
|
||||
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
|
||||
@@ -0,0 +1,3 @@
|
||||
assert 'Rational' do
|
||||
assert_equal Rational, 0r.class
|
||||
end
|
||||
Reference in New Issue
Block a user