shithub: sl

Download patch

ref: c6aa991371c01426c0925b61776f957823425799
parent: 21733d5e5d65afc738084fdb6165480ecd2ab14c
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Tue Jan 28 21:10:34 EST 2025

number->string: support bignums and floats/doubles

--- a/src/string.c
+++ b/src/string.c
@@ -369,22 +369,41 @@
 	value_t n = args[0];
 	int neg = 0;
 	uint64_t num;
+	int radix = 10;
+	if(nargs == 2)
+		radix = get_radix_arg(args[1]);
 	if(isfixnum(n))
 		num = numval(n);
-	else if(!iscprim(n))
+	else if(iscprim(n)){
+		void *data = ptr(n);
+		if(cp_numtype(data) < T_FLOAT)
+			num = conv_to_uint64(cp_data(data), cp_numtype(data));
+		else if(radix != 10)
+			lerrorf(FL_ArgError, "invalid radix with floating point");
+		else
+			return fn_builtin_string(args, nargs);
+	}else if(iscvalue(n) && cp_numtype(ptr(n)) == T_MPINT){
+		if(radix != 16 && radix != 10 && radix != 8 && radix != 4 && radix != 2)
+			lerrorf(FL_ArgError, "invalid radix with bignum");
+		mpint *i = *(mpint**)cv_data(ptr(n));
+		char *s = mptoa(i, radix, nil, 0);
+		assert(s != nil);
+		if(radix == 16){ /* FFFF → ffff */
+			for(int k = 0; s[k]; k++)
+				s[k] = tolower(s[k]);
+		}
+		n = string_from_cstr(s);
+		MEM_FREE(s);
+		return n;
+	}else{
 		type_error("integer", n);
-	else
-		num = conv_to_uint64(cp_data(ptr(n)), cp_numtype(ptr(n)));
+	}
 	if(numval(fl_compare(args[0], fixnum(0), false)) < 0){
 		num = -num;
 		neg = 1;
 	}
-	unsigned long radix = 10;
-	if(nargs == 2)
-		radix = get_radix_arg(args[1]);
-	char buf[128];
-	char *str = uint2str(buf, sizeof(buf), num, radix);
-	if(neg && str > &buf[0])
+	char buf[128], *str = uint2str(buf, sizeof(buf), num, radix);
+	if(neg && str > buf)
 		*(--str) = '-';
 	return string_from_cstr(str);
 }
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -547,5 +547,10 @@
 (assert (equal? #f (char-lower-case? #\П)))
 (assert (equal? #f (char-lower-case? #\nul)))
 
+(assert (equal? "1.5" (number->string 1.5)))
+(assert (equal? "-3039" (number->string (int16 -12345) 16)))
+(assert (equal? "111111111111111111111111111111111" (number->string   111111111111111111111111111111111)))
+(assert (equal? "fffffffffffffffffffffffffffffffff" (number->string 0xfffffffffffffffffffffffffffffffff 16)))
+
 (princ "all tests pass")
 (newline)
--