Skip to content

Commit 1115a3c

Browse files
committed
[Heavy] Add length function
1 parent 9f0b5ef commit 1115a3c

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

heavy/lib/Builtins.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ heavy::ExternFunction mul;
5151
heavy::ExternFunction gt;
5252
heavy::ExternFunction lt;
5353
heavy::ExternFunction list;
54+
heavy::ExternFunction length;
5455
heavy::ExternFunction cons;
5556
heavy::ExternFunction car;
5657
heavy::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+
580606
void 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)},

heavy/test/Evaluate/define-syntax.scm

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
(define-syntax my-lambda
66
(syntax-rules (=>)
77
((my-lambda formals => body)
8-
(lambda formals body (write ok)))))
8+
(lambda formals
9+
body
10+
(write ok)
11+
(write "lambda args#:")
12+
(write (length 'formals))))))
913

10-
; CHECK: (42 oops!)ok!
14+
; CHECK: (42 oops!)ok!"lambda args#:"1
1115
((lambda (ok)
1216
((my-lambda (x) => (write (list x ok))) 42))
1317
'oops!)

heavy/test/Evaluate/list.scm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,11 @@
8787
(append foo (list bar) baz))
8888
'(foo bar) 4 5 6))
8989
(newline)
90+
91+
; CHECK-NEXT: (0 1 2 3 4)
92+
(write
93+
(list (length '())
94+
(length '(9))
95+
(length '(9 42))
96+
(length '(9 (foo bar) 42))
97+
(length '((foo bar) 42 9 moo))))

0 commit comments

Comments
 (0)