mruby/c VM Source Code release 4.0.0
Loading...
Searching...
No Matches
c_numeric.c
Go to the documentation of this file.
1
14
15/***** Feature test switches ************************************************/
16/***** System headers *******************************************************/
17//@cond
18#include "vm_config.h"
19#include <stdio.h>
20#include <limits.h>
21#if MRBC_USE_FLOAT
22#include <math.h>
23#endif
24//@endcond
25
26/***** Local headers ********************************************************/
27#include "mrubyc.h"
28
29/***** Constat values *******************************************************/
30/***** Macros ***************************************************************/
31#if MRBC_USE_FLOAT == 1
32#define MRBC_POW powf
33#else
34#define MRBC_POW pow
35#endif
36
37/***** Typedefs *************************************************************/
38/***** Function prototypes **************************************************/
39/***** Local variables ******************************************************/
40/***** Global variables *****************************************************/
41/***** Signal catching functions ********************************************/
42/***** Local functions ******************************************************/
43
44/***** Integer class ********************************************************/
45//================================================================
48static void c_integer_bitref(mrbc_vm *vm, mrbc_value v[], int argc)
49{
50 if( mrbc_integer(v[1]) < 0 ) {
51 SET_INT_RETURN( 0 );
52 } else {
53 mrbc_int_t mask = (argc == 1) ? 1 : (1 << mrbc_integer(v[2])) - 1;
54 SET_INT_RETURN( (mrbc_integer(v[0]) >> mrbc_integer(v[1])) & mask );
55 }
56}
57
58
59//================================================================
62static void c_integer_positive(mrbc_vm *vm, mrbc_value v[], int argc)
63{
64 // do nothing
65}
66
67
68//================================================================
71static void c_integer_negative(mrbc_vm *vm, mrbc_value v[], int argc)
72{
73 mrbc_int_t num = mrbc_integer(v[0]);
74 SET_INT_RETURN( -num );
75}
76
77
78//================================================================
81static void c_integer_power(mrbc_vm *vm, mrbc_value v[], int argc)
82{
83 if( mrbc_type(v[1]) == MRBC_TT_INTEGER ) {
84 mrbc_int_t x = 1;
85
86 if( mrbc_integer(v[1]) < 0 ) x = 0;
87 for( int i = 0; i < mrbc_integer(v[1]); i++ ) {
88 x *= mrbc_integer(v[0]);
89 }
90 SET_INT_RETURN( x );
91 }
92
93#if MRBC_USE_FLOAT && MRBC_USE_MATH
94 else if( mrbc_type(v[1]) == MRBC_TT_FLOAT ) {
96 }
97#endif
98}
99
100
101//================================================================
104static void c_integer_mod(mrbc_vm *vm, mrbc_value v[], int argc)
105{
106 if( mrbc_type(v[1]) != MRBC_TT_INTEGER ) {
107 mrbc_raise(vm, MRBC_CLASS(TypeError), 0 );
108 return;
109 }
110
111 mrbc_int_t v0 = v[0].i;
112 mrbc_int_t v1 = v[1].i;
113
114 if( v1 == 0 ) {
115 mrbc_raise(vm, MRBC_CLASS(ZeroDivisionError), 0 );
116 return;
117 }
118
119 mrbc_int_t ret = v0 % v1;
120
121 if( (ret != 0) && ((v0 ^ v1) < 0) ) ret += v1;
122 SET_INT_RETURN( ret );
123}
124
125
126//================================================================
129static void c_integer_and(mrbc_vm *vm, mrbc_value v[], int argc)
130{
131 mrbc_int_t num = mrbc_integer(v[1]);
132 SET_INT_RETURN(v->i & num);
133}
134
135
136//================================================================
139static void c_integer_or(mrbc_vm *vm, mrbc_value v[], int argc)
140{
141 mrbc_int_t num = mrbc_integer(v[1]);
142 SET_INT_RETURN(v->i | num);
143}
144
145
146//================================================================
149static void c_integer_xor(mrbc_vm *vm, mrbc_value v[], int argc)
150{
151 mrbc_int_t num = mrbc_integer(v[1]);
152 SET_INT_RETURN( v->i ^ num );
153}
154
155
156//================================================================
159static void c_integer_not(mrbc_vm *vm, mrbc_value v[], int argc)
160{
161 mrbc_int_t num = mrbc_integer(v[0]);
162 SET_INT_RETURN( ~num );
163}
164
165
166//----------------------------------------------------------------
170{
171 // Don't support environments that include padding in int.
172 const int INT_BITS = sizeof(mrbc_int_t) * CHAR_BIT;
173
174 if( y >= INT_BITS ) return 0;
175 if( y >= 0 ) return x << y;
176 if( y <= -INT_BITS ) return 0;
177 return x >> -y;
178}
179
180
181//================================================================
184static void c_integer_lshift(mrbc_vm *vm, mrbc_value v[], int argc)
185{
186 mrbc_int_t num = mrbc_integer(v[1]);
187 SET_INT_RETURN( shift(v->i, num) );
188}
189
190
191//================================================================
194static void c_integer_rshift(mrbc_vm *vm, mrbc_value v[], int argc)
195{
196 mrbc_int_t num = mrbc_integer(v[1]);
197 SET_INT_RETURN( shift(v->i, -num) );
198}
199
200
201//================================================================
204static void c_integer_plus(mrbc_vm *vm, mrbc_value v[], int argc)
205{
206 assert( mrbc_type(v[1]) == MRBC_TT_INTEGER );
207
209}
210
211
212//================================================================
215static void c_integer_minus(mrbc_vm *vm, mrbc_value v[], int argc)
216{
217 assert( mrbc_type(v[1]) == MRBC_TT_INTEGER );
218
220}
221
222
223//================================================================
226static void c_integer_gt_eq(mrbc_vm *vm, mrbc_value v[], int argc)
227{
228 assert( mrbc_type(v[1]) == MRBC_TT_INTEGER );
229
230 SET_BOOL_RETURN( mrbc_integer(v[0]) >= mrbc_integer(v[1]) );
231}
232
233
234//================================================================
237static void c_integer_abs(mrbc_vm *vm, mrbc_value v[], int argc)
238{
239 if( mrbc_integer(v[0]) < 0 ) {
240 mrbc_integer(v[0]) = -mrbc_integer(v[0]);
241 }
242}
243
244
245//================================================================
251static void c_numeric_clamp(mrbc_vm *vm, mrbc_value v[], int argc)
252{
253 if (argc != 2) {
254 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "wrong number of arguments");
255 return;
256 }
257 mrbc_value min = v[1];
258 mrbc_value max = v[2];
259 if (
260 (mrbc_type(min) != MRBC_TT_INTEGER && mrbc_type(min) != MRBC_TT_FLOAT) ||
262 ) {
263 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "comparison failed");
264 return;
265 }
266 if (mrbc_compare(&max, &min) < 0) {
267 mrbc_raise(vm, MRBC_CLASS(ArgumentError), "min argument must be smaller than max argument");
268 return;
269 }
270 if (mrbc_compare(&v[0], &min) < 0) {
271 SET_RETURN(min);
272 return;
273 }
274 if (mrbc_compare(&max, &v[0]) < 0) {
275 SET_RETURN(max);
276 return;
277 }
278 SET_RETURN(v[0]); /* return self */
279}
280
281
282#if MRBC_USE_FLOAT
283//================================================================
286static void c_integer_to_f(mrbc_vm *vm, mrbc_value v[], int argc)
287{
288 mrbc_float_t f = mrbc_integer(v[0]);
289 SET_FLOAT_RETURN( f );
290}
291#endif
292
293
294#if MRBC_USE_STRING
295//================================================================
299#if MRBC_USE_STRING_UTF8
300int mrbc_utf8_encode(int32_t codepoint, char *buf)
301{
302 if( codepoint < 0 || codepoint > 0x10FFFF ) {
303 return 0; // out of range
304 }
305 if( codepoint >= 0xD800 && codepoint <= 0xDFFF ) {
306 return 0; // surrogate pair - invalid in UTF-8
307 }
308
309 if( codepoint <= 0x7F ) {
310 buf[0] = (char)codepoint;
311 return 1;
312 } else if( codepoint <= 0x7FF ) {
313 buf[0] = (char)(0xC0 | (codepoint >> 6));
314 buf[1] = (char)(0x80 | (codepoint & 0x3F));
315 return 2;
316 } else if( codepoint <= 0xFFFF ) {
317 buf[0] = (char)(0xE0 | (codepoint >> 12));
318 buf[1] = (char)(0x80 | ((codepoint >> 6) & 0x3F));
319 buf[2] = (char)(0x80 | (codepoint & 0x3F));
320 return 3;
321 } else {
322 buf[0] = (char)(0xF0 | (codepoint >> 18));
323 buf[1] = (char)(0x80 | ((codepoint >> 12) & 0x3F));
324 buf[2] = (char)(0x80 | ((codepoint >> 6) & 0x3F));
325 buf[3] = (char)(0x80 | (codepoint & 0x3F));
326 return 4;
327 }
328}
329#endif
330
331//================================================================
334static void c_integer_chr(mrbc_vm *vm, mrbc_value v[], int argc)
335{
336#if MRBC_USE_STRING_UTF8
337 mrbc_int_t codepoint = mrbc_integer(v[0]);
338 char buf[5];
339 int len;
340
341 if( codepoint < 0 ) {
342 mrbc_raise(vm, MRBC_CLASS(RangeError), "out of char range");
343 return;
344 }
345 if( codepoint >= 0xD800 && codepoint <= 0xDFFF ) {
346 mrbc_raise(vm, MRBC_CLASS(RangeError), "invalid codepoint in UTF-8");
347 return;
348 }
349 if( codepoint > 0x10FFFF ) {
350 mrbc_raise(vm, MRBC_CLASS(RangeError), "out of char range");
351 return;
352 }
353
354 // chr without encoding argument only accepts 0..255
355 if( codepoint > 0xFF ) {
356 mrbc_raise(vm, MRBC_CLASS(RangeError), "out of char range");
357 return;
358 }
359
360 buf[0] = (char)codepoint;
361 len = 1;
362 mrbc_value value = mrbc_string_new(vm, buf, len);
363 SET_RETURN(value);
364#else
365 char buf[2] = { mrbc_integer(v[0]) };
366
367 mrbc_value value = mrbc_string_new(vm, buf, 1);
368 SET_RETURN(value);
369#endif
370}
371
372
373//================================================================
376static void c_integer_inspect(mrbc_vm *vm, mrbc_value v[], int argc)
377{
378 if( mrbc_type(v[0]) == MRBC_TT_CLASS ) {
379 mrbc_object_inspect(vm, v, argc);
380 return;
381 }
382
383 int base = 10;
384 if( argc ) {
385 base = mrbc_integer(v[1]);
386 if( base < 2 || base > 36 ) {
387 mrbc_raisef(vm, MRBC_CLASS(ArgumentError), "invalid radix %d", base);
388 return;
389 }
390 }
391
392 mrbc_printf_t pf;
393 char buf[16];
394 mrbc_printf_init( &pf, buf, sizeof(buf), NULL );
395 pf.fmt.type = 'd';
396 mrbc_printf_int( &pf, v->i, base );
397 mrbc_printf_end( &pf );
398
399 mrbc_value value = mrbc_string_new_cstr(vm, buf);
400 SET_RETURN(value);
401}
402#endif
403
404
405/* MRBC_AUTOGEN_METHOD_TABLE
406
407 CLASS("Integer")
408 FILE("_autogen_class_integer.h")
409
410 METHOD( "[]", c_integer_bitref )
411 METHOD( "+@", c_integer_positive )
412 METHOD( "-@", c_integer_negative )
413 METHOD( "**", c_integer_power )
414 METHOD( "%", c_integer_mod )
415 METHOD( "&", c_integer_and )
416 METHOD( "|", c_integer_or )
417 METHOD( "^", c_integer_xor )
418 METHOD( "~", c_integer_not )
419 METHOD( "<<", c_integer_lshift )
420 METHOD( ">>", c_integer_rshift )
421 METHOD( "+", c_integer_plus )
422 METHOD( "-", c_integer_minus )
423 METHOD( ">=", c_integer_gt_eq )
424 METHOD( "abs", c_integer_abs )
425 METHOD( "to_i", c_ineffect )
426 METHOD( "clamp", c_numeric_clamp )
427#if MRBC_USE_FLOAT
428 METHOD( "to_f", c_integer_to_f )
429#endif
430#if MRBC_USE_STRING
431 METHOD( "chr", c_integer_chr )
432 METHOD( "inspect", c_integer_inspect )
433 METHOD( "to_s", c_integer_inspect )
434#endif
435*/
436#include "_autogen_class_integer.h"
437
438
439
440/***** Float class **********************************************************/
441#if MRBC_USE_FLOAT
442
443//================================================================
446static void c_float_positive(mrbc_vm *vm, mrbc_value v[], int argc)
447{
448 // do nothing
449}
450
451
452//================================================================
455static void c_float_negative(mrbc_vm *vm, mrbc_value v[], int argc)
456{
457 mrbc_float_t num = mrbc_float(v[0]);
458 SET_FLOAT_RETURN( -num );
459}
460
461
462#if MRBC_USE_MATH
463//================================================================
466static void c_float_power(mrbc_vm *vm, mrbc_value v[], int argc)
467{
468 mrbc_float_t n = 0;
469 switch( mrbc_type(v[1]) ) {
470 case MRBC_TT_INTEGER: n = mrbc_integer(v[1]); break;
471 case MRBC_TT_FLOAT: n = mrbc_float(v[1]); break;
472 default: break;
473 }
474
476}
477#endif
478
479
480//================================================================
483static void c_float_abs(mrbc_vm *vm, mrbc_value v[], int argc)
484{
485 if( mrbc_float(v[0]) < 0 ) {
486 mrbc_float(v[0]) = -mrbc_float(v[0]);
487 }
488}
489
490
491//================================================================
494static void c_float_to_i(mrbc_vm *vm, mrbc_value v[], int argc)
495{
497 SET_INT_RETURN( i );
498}
499
500
501#if MRBC_USE_STRING
502//================================================================
505static void c_float_inspect(mrbc_vm *vm, mrbc_value v[], int argc)
506{
507 if( mrbc_type(v[0]) == MRBC_TT_CLASS ) {
508 mrbc_object_inspect(vm, v, argc);
509 return;
510 }
511
512 char buf[32];
513 mrbc_format_float(buf, sizeof(buf), v->d);
514 mrbc_value value = mrbc_string_new_cstr(vm, buf);
515 SET_RETURN(value);
516}
517#endif
518
519
520/* MRBC_AUTOGEN_METHOD_TABLE
521
522 CLASS("Float")
523 FILE("_autogen_class_float.h")
524
525 METHOD( "+@", c_float_positive )
526 METHOD( "-@", c_float_negative )
527#if MRBC_USE_MATH
528 METHOD( "**", c_float_power )
529#endif
530 METHOD( "abs", c_float_abs )
531 METHOD( "to_i", c_float_to_i )
532 METHOD( "to_f", c_ineffect )
533 METHOD( "clamp", c_numeric_clamp )
534#if MRBC_USE_STRING
535 METHOD( "inspect", c_float_inspect )
536 METHOD( "to_s", c_float_inspect )
537#endif
538*/
539#include "_autogen_class_float.h"
540
541#endif // MRBC_USE_FLOAT
#define mrbc_type(o)
Definition boxing_no.h:57
struct RObject mrbc_value
Value object. Default version.
#define mrbc_float(o)
Definition boxing_no.h:59
#define mrbc_integer(o)
Definition boxing_no.h:58
static mrbc_int_t shift(mrbc_int_t x, mrbc_int_t y)
Definition c_numeric.c:169
#define MRBC_POW
Definition c_numeric.c:32
void mrbc_object_inspect(mrbc_vm *vm, mrbc_value v[], int argc)
Definition c_object.c:83
mrbc_value mrbc_string_new(mrbc_vm *vm, const void *src, int len)
Definition c_string.c:64
static mrbc_value mrbc_string_new_cstr(mrbc_vm *vm, const char *src)
Definition c_string.h:91
#define MRBC_CLASS(cls)
Definition class.h:55
int mrbc_printf_int(mrbc_printf_t *pf, mrbc_int_t value, unsigned int base)
Definition console.c:788
static void mrbc_printf_end(mrbc_printf_t *pf)
Definition console.h:148
struct RPrintf mrbc_printf_t
printf tiny (mruby/c) version data container.
static void mrbc_printf_init(mrbc_printf_t *pf, char *buf, int size, const char *fstr)
Definition console.h:122
void mrbc_raise(struct VM *vm, struct RClass *exc_cls, const char *msg)
Definition error.c:145
void mrbc_raisef(struct VM *vm, struct RClass *exc_cls, const char *fstr,...)
Definition error.c:168
Include at once the necessary header files.
mrbc_float_t d
Definition boxing_no.h:24
mrbc_int_t i
Definition boxing_no.h:22
char type
format char. (e.g. 'd','f','x'...)
Definition console.h:51
struct RPrintfFormat fmt
Definition console.h:70
int mrbc_compare(const mrbc_value *v1, const mrbc_value *v2)
Definition value.c:68
void mrbc_format_float(char *buf, int bufsiz, mrbc_float_t flo)
Definition value.c:263
float mrbc_float_t
Definition value.h:52
int32_t mrbc_int_t
Definition value.h:47
#define SET_BOOL_RETURN(n)
Definition value.h:238
#define SET_INT_RETURN(n)
Definition value.h:243
@ MRBC_TT_FLOAT
Float.
Definition value.h:88
@ MRBC_TT_INTEGER
Integer.
Definition value.h:86
@ MRBC_TT_CLASS
Class.
Definition value.h:90
#define SET_RETURN(n)
Definition value.h:221
#define SET_FLOAT_RETURN(n)
Definition value.h:248
struct VM mrbc_vm
Virtual Machine.
Global configuration of mruby/c VM's.