diff options
author | S-H-GAMELINKS <[email protected]> | 2024-01-05 12:03:11 +0900 |
---|---|---|
committer | Yuichiro Kaneko <[email protected]> | 2024-01-07 09:24:34 +0900 |
commit | 1b8d01136c3ff6c60325c7609d61e19ac42acd9f (patch) | |
tree | 99e027e7711867464c30a72d20f9e56a96e87a83 /ruby_parser.c | |
parent | 76afbda5b566148b9e73939e0ff9b8464d59806c (diff) |
Introduce Numeric Node's
Diffstat (limited to 'ruby_parser.c')
-rw-r--r-- | ruby_parser.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/ruby_parser.c b/ruby_parser.c index 94209b9aba..800b59f637 100644 --- a/ruby_parser.c +++ b/ruby_parser.c @@ -4,6 +4,135 @@ #include "rubyparser.h" +static VALUE +compile_negative_numeric(VALUE val) +{ + if (FIXNUM_P(val)) { + return LONG2FIX(-FIX2LONG(val)); + } + if (SPECIAL_CONST_P(val)) { +#if USE_FLONUM + if (FLONUM_P(val)) { + return DBL2NUM(-RFLOAT_VALUE(val)); + } +#endif + } + switch (OBJ_BUILTIN_TYPE(val)) + { + case T_BIGNUM: + BIGNUM_NEGATE(val); + val = rb_big_norm(val); + break; + case T_RATIONAL: + RATIONAL_SET_NUM(val, compile_negative_numeric(RRATIONAL(val)->num)); + break; + case T_COMPLEX: + RCOMPLEX_SET_REAL(val, compile_negative_numeric(RCOMPLEX(val)->real)); + RCOMPLEX_SET_IMAG(val, compile_negative_numeric(RCOMPLEX(val)->imag)); + break; + case T_FLOAT: + val = DBL2NUM(-RFLOAT_VALUE(val)); + break; + default: + val = LONG2FIX(-FIX2LONG(val)); + break; + } + return val; +} + +static VALUE +compile_numeric_literal(char* val, int base) +{ + return rb_cstr_to_inum(val, base, FALSE); +} + +VALUE +rb_node_integer_literal_val(rb_node_integer_t* node) +{ + VALUE val = compile_numeric_literal(node->val, node->base); + if (node->minus) { + val = compile_negative_numeric(val); + } + return val; +} + +VALUE +rb_node_float_literal_val(rb_node_float_t* node) +{ + double d = strtod(node->val, 0); + if (node->minus) { + d = -d; + } + VALUE val = DBL2NUM(d); + return val; +} + +static VALUE +compile_rational_literal(char* node_val, int base, int seen_point) +{ + VALUE lit; + char* val = strdup(node_val); + if (seen_point > 0) { + int len = (int)(strlen(val)); + char *point = &val[seen_point]; + size_t fraclen = len-seen_point-1; + memmove(point, point+1, fraclen+1); + + lit = rb_rational_new(compile_numeric_literal(val, base), rb_int_positive_pow(10, fraclen)); + } else { + lit = rb_rational_raw1(compile_numeric_literal(val, base)); + } + + free(val); + + return lit; +} + +VALUE +rb_node_rational_literal_val(rb_node_rational_t* node) +{ + VALUE lit; + + lit = compile_rational_literal(node->val, node->base, node->seen_point); + + if (node->minus) { + lit = compile_negative_numeric(lit); + } + + return lit; +} + +VALUE +rb_node_imaginary_literal_val(rb_node_imaginary_t* node) +{ + VALUE lit; + + enum rb_numeric_type type = node->type; + + switch (type) { + case integer_literal: + lit = compile_numeric_literal(node->val, node->base); + break; + case float_literal:{ + double d = strtod(node->val, 0); + lit = DBL2NUM(d); + break; + } + case rational_literal: + lit = compile_rational_literal(node->val, node->base, node->seen_point); + break; + default: + rb_bug("unreachable"); + } + + lit = rb_complex_raw(INT2FIX(0), lit); + + if (node->minus) { + lit = compile_negative_numeric(lit); + } + return lit; +} + #ifdef UNIVERSAL_PARSER #include "internal.h" |