@@ -51,6 +51,7 @@ heavy::ExternFunction mul;
5151heavy::ExternFunction gt;
5252heavy::ExternFunction lt;
5353heavy::ExternFunction list;
54+ heavy::ExternFunction length;
5455heavy::ExternFunction cons;
5556heavy::ExternFunction car;
5657heavy::ExternFunction cdr;
@@ -577,6 +578,31 @@ void list(Context& C, ValueRefs Args) {
577578 C.Cont (C.CreateList (Args));
578579}
579580
581+ void length (Context& C, ValueRefs Args) {
582+ if (Args.size () != 1 )
583+ return C.RaiseError (" invalid arity" );
584+
585+ Value Cur = Args[0 ];
586+ Value CurFast = Cur;
587+ int32_t Count = 0 ;
588+ while (!isa<Empty>(Cur)) {
589+ Pair* P1 = dyn_cast<Pair>(Cur);
590+ Pair* P2 = dyn_cast_or_null<Pair>(CurFast);
591+ if (!P1)
592+ return C.RaiseError (" expecting a list" );
593+
594+ Cur = P1->Cdr ;
595+ CurFast = P2 ? P2->Cdr .cdr () : nullptr ;
596+
597+ if (Cur == CurFast)
598+ return C.RaiseError (" cycle detected" );
599+
600+ ++Count;
601+ }
602+
603+ return C.Cont (Int{Count});
604+ }
605+
580606void cons (Context& C, ValueRefs Args) {
581607 if (Args.size () != 2 )
582608 return C.RaiseError (" invalid arity" );
@@ -842,6 +868,7 @@ void HEAVY_BASE_INIT(heavy::Context& Context) {
842868 HEAVY_BASE_VAR (gt) = heavy::base::gt;
843869 HEAVY_BASE_VAR (lt) = heavy::base::lt;
844870 HEAVY_BASE_VAR (list) = heavy::base::list;
871+ HEAVY_BASE_VAR (length) = heavy::base::length;
845872 HEAVY_BASE_VAR (cons) = heavy::base::cons;
846873 HEAVY_BASE_VAR (car) = heavy::base::car;
847874 HEAVY_BASE_VAR (cdr) = heavy::base::cdr;
@@ -918,6 +945,7 @@ void HEAVY_BASE_LOAD_MODULE(heavy::Context& Context) {
918945 {" >" , HEAVY_BASE_VAR (gt)},
919946 {" <" , HEAVY_BASE_VAR (lt)},
920947 {" list" , HEAVY_BASE_VAR (list)},
948+ {" length" , HEAVY_BASE_VAR (length)},
921949 {" cons" , HEAVY_BASE_VAR (cons)},
922950 {" car" , HEAVY_BASE_VAR (car)},
923951 {" cdr" , HEAVY_BASE_VAR (cdr)},
0 commit comments