shithub: femtolisp

Download patch

ref: 23e857034070229923a7b3b800d608ab0e14236d
parent: 4679ff506c0070253da0d452b3fcfaf9bf047130
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sun Nov 3 02:34:28 EST 2024

length builtin: detect cycles and return infinity if there is any

--- a/builtins.c
+++ b/builtins.c
@@ -88,8 +88,21 @@
 		return fixnum(vector_size(a));
 	if(a == FL_NIL)
 		return fixnum(0);
-	if(iscons(a))
-		return fixnum(llength(a));
+	if(iscons(a)){
+		size_t n = 0;
+		value_t v = a, v2 = a;
+		do{
+			n++;
+			v = cdr_(v);
+			v2 = cdr_(v2);
+			if(iscons(v2))
+				v2 = cdr_(v2);
+		}while(iscons(v) && iscons(v2) && v != v2);
+		if(iscons(v2))
+			return mk_double(D_PINF);
+		n += llength(v);
+		return fixnum(n);
+	}
 	if(iscprim(a)){
 		cv = (cvalue_t*)ptr(a);
 		if(cp_class(cv) == bytetype)
--- a/test/unittest.lsp
+++ b/test/unittest.lsp
@@ -355,5 +355,9 @@
 (assert (equal? (append '(1 2)) '(1 2)))
 (assert (equal? (append '(1 2) '(3 4)) '(1 2 3 4)))
 
+(define a '(1))
+(set-cdr! a a)
+(assert (equal? (length a) +inf.0))
+
 (princ "all tests pass\n")
 #t