Skip to content

Commit d7e436d

Browse files
committed
Add more features to stdlib
1 parent b9d1104 commit d7e436d

File tree

8 files changed

+541
-4
lines changed

8 files changed

+541
-4
lines changed

lisp/stdlib.lisp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
; Standard Library for Lisp VM
2+
; Higher-order functions that can't be efficiently implemented in native code
3+
4+
; Map: apply function to each element of a list
5+
(def map (fn (f lst)
6+
(if (nil? lst)
7+
nil
8+
(cons (f (car lst)) (map f (cdr lst))))))
9+
10+
; Filter: keep only elements that satisfy the predicate
11+
(def filter (fn (pred lst)
12+
(if (nil? lst)
13+
nil
14+
(if (pred (car lst))
15+
(cons (car lst) (filter pred (cdr lst)))
16+
(filter pred (cdr lst))))))
17+
18+
; Fold (reduce): combine elements from left to right
19+
(def fold (fn (f init lst)
20+
(if (nil? lst)
21+
init
22+
(fold f (f init (car lst)) (cdr lst)))))
23+
24+
; Fold-right: combine elements from right to left
25+
(def fold-right (fn (f init lst)
26+
(if (nil? lst)
27+
init
28+
(f (car lst) (fold-right f init (cdr lst))))))

lisp/test_basics.lisp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
; Test basic functionality
2+
13
; Arithmetic
24
(println "Testing arithmetic...")
35
(def result (+ 1 2 3))

lisp/test_macros.lisp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1+
; Test macro functionality
2+
13
(println "Testing macros...")
24

3-
; Defining an 'unless' macro
5+
; Define an 'unless' macro
46
(defmacro unless (cond body)
57
(list 'if cond nil body))
68

79
(if (= (unless false 42) 42)
810
(println " unless macro: passed")
911
(println " unless macro: FAILED"))
1012

11-
; Defining an 'inc' macro
13+
; Define an 'inc' macro
1214
(defmacro inc (x)
1315
(list '+ x 1))
1416

1517
(if (= (inc 5) 6)
1618
(println " inc macro: passed")
1719
(println " inc macro: FAILED"))
1820

19-
; Defining a 'double' macro
21+
; Define a 'double' macro
2022
(defmacro double (x)
2123
(list '* x 2))
2224

lisp/test_pure_functions.lisp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
; Test pure function detection and compile-time evaluation
2+
13
(println "Testing pure function detection...")
24

3-
; Defining a pure function
5+
; Define a pure function
46
(def square (fn (n) (* n n)))
57

68
; This should work (pure function with constant arg could be folded)

lisp/test_stdlib.lisp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
; Test Standard Library Functions
2+
; Tests for logic operators, list functions, string functions, and I/O
3+
4+
; ============================================
5+
; Test short-circuiting logic operators
6+
; ============================================
7+
8+
(println "Testing logic operators...")
9+
10+
; Test: and with no arguments
11+
(def test1 (and))
12+
(if (= test1 true)
13+
(println "✓ (and) => true")
14+
(println "✗ (and) failed"))
15+
16+
; Test: and with one argument
17+
(def test2 (and 42))
18+
(if (= test2 42)
19+
(println "✓ (and 42) => 42")
20+
(println "✗ (and 42) failed"))
21+
22+
; Test: and short-circuits on false
23+
(def test3 (and true false (/ 1 0))) ; Should not divide by zero
24+
(if (= test3 false)
25+
(println "✓ (and true false ...) short-circuits")
26+
(println "✗ (and) short-circuit failed"))
27+
28+
; Test: and returns last value when all true
29+
(def test4 (and 1 2 3))
30+
(if (= test4 3)
31+
(println "✓ (and 1 2 3) => 3")
32+
(println "✗ (and 1 2 3) failed"))
33+
34+
; Test: or with no arguments
35+
(def test5 (or))
36+
(if (= test5 false)
37+
(println "✓ (or) => false")
38+
(println "✗ (or) failed"))
39+
40+
; Test: or with one argument
41+
(def test6 (or 42))
42+
(if (= test6 42)
43+
(println "✓ (or 42) => 42")
44+
(println "✗ (or 42) failed"))
45+
46+
; Test: or short-circuits on true
47+
(def test7 (or false true (/ 1 0))) ; Should not divide by zero
48+
(if (= test7 true)
49+
(println "✓ (or false true ...) short-circuits")
50+
(println "✗ (or) short-circuit failed"))
51+
52+
; Test: or returns last value when all false
53+
(def test8 (or false nil false))
54+
(if (= test8 false)
55+
(println "✓ (or false nil false) => false")
56+
(println "✗ (or false nil false) failed"))
57+
58+
; ============================================
59+
; Test list functions
60+
; ============================================
61+
62+
(println "\nTesting list functions...")
63+
64+
; Test: nth on list
65+
(def lst (list 10 20 30 40 50))
66+
(def test9 (nth lst 0))
67+
(if (= test9 10)
68+
(println "✓ (nth lst 0) => 10")
69+
(println "✗ (nth lst 0) failed"))
70+
71+
(def test10 (nth lst 2))
72+
(if (= test10 30)
73+
(println "✓ (nth lst 2) => 30")
74+
(println "✗ (nth lst 2) failed"))
75+
76+
; Test: append
77+
(def test11 (append (list 1 2) (list 3 4) (list 5 6)))
78+
(def test11-len (length test11))
79+
(if (= test11-len 6)
80+
(println "✓ (append ...) => list of length 6")
81+
(println "✗ (append) failed"))
82+
83+
; Test: reverse
84+
(def test12 (reverse (list 1 2 3 4 5)))
85+
(def test12-first (nth test12 0))
86+
(if (= test12-first 5)
87+
(println "✓ (reverse (list 1 2 3 4 5)) => (5 4 3 2 1)")
88+
(println "✗ (reverse) failed"))
89+
90+
; ============================================
91+
; Test string functions
92+
; ============================================
93+
94+
(println "\nTesting string functions...")
95+
96+
; Test: string-length
97+
(def test13 (string-length "hello"))
98+
(if (= test13 5)
99+
(println "✓ (string-length \"hello\") => 5")
100+
(println "✗ (string-length) failed"))
101+
102+
; Test: string-append
103+
(def test14 (string-append "hello" " " "world"))
104+
(if (= test14 "hello world")
105+
(println "✓ (string-append ...) => \"hello world\"")
106+
(println "✗ (string-append) failed"))
107+
108+
; Test: substring
109+
(def test15 (substring "hello world" 0 5))
110+
(if (= test15 "hello")
111+
(println "✓ (substring \"hello world\" 0 5) => \"hello\"")
112+
(println "✗ (substring) failed"))
113+
114+
(def test16 (substring "hello world" 6 11))
115+
(if (= test16 "world")
116+
(println "✓ (substring \"hello world\" 6 11) => \"world\"")
117+
(println "✗ (substring) failed"))
118+
119+
; Test: string->list
120+
(def test17 (string->list "abc"))
121+
(def test17-len (length test17))
122+
(if (= test17-len 3)
123+
(println "✓ (string->list \"abc\") => list of length 3")
124+
(println "✗ (string->list) failed"))
125+
126+
; Test: list->string
127+
(def test18 (list->string (list "h" "e" "l" "l" "o")))
128+
(if (= test18 "hello")
129+
(println "✓ (list->string ...) => \"hello\"")
130+
(println "✗ (list->string) failed"))
131+
132+
; Test: format
133+
(def test19 (format "Hello, ~a!" "world"))
134+
(if (= test19 "Hello, world!")
135+
(println "✓ (format \"Hello, ~a!\" \"world\") => \"Hello, world!\"")
136+
(println "✗ (format) failed"))
137+
138+
(def test20 (format "The answer is ~a" 42))
139+
(if (= test20 "The answer is 42")
140+
(println "✓ (format \"The answer is ~a\" 42) => \"The answer is 42\"")
141+
(println "✗ (format) failed"))
142+
143+
; ============================================
144+
; Test I/O functions
145+
; ============================================
146+
147+
(println "\nTesting I/O functions...")
148+
149+
; Test: write-file and read-file
150+
(def test-content "Hello from Lisp VM!\nLine 2\nLine 3")
151+
(write-file "/tmp/lisp-test.txt" test-content)
152+
(def read-content (read-file "/tmp/lisp-test.txt"))
153+
(if (= read-content test-content)
154+
(println "✓ write-file and read-file work correctly")
155+
(println "✗ write-file or read-file failed"))
156+
157+
(println "\nAll standard library tests completed!")

lisp/test_tco.lisp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
; Test tail call optimization
2+
13
(println "Testing tail call optimization...")
24

35
; Sum function with accumulator (tail recursive)

src/compiler.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,8 @@ impl Compiler {
690690
match sym {
691691
"quote" => return self.compile_quote(&items[1..], dest),
692692
"if" => return self.compile_if(&items[1..], dest, tail_pos),
693+
"and" => return self.compile_and(&items[1..], dest),
694+
"or" => return self.compile_or(&items[1..], dest),
693695
"def" => return self.compile_def(&items[1..], dest),
694696
"let" => return self.compile_let(&items[1..], dest, tail_pos),
695697
"fn" => return self.compile_fn(&items[1..], dest),
@@ -774,6 +776,76 @@ impl Compiler {
774776
Ok(())
775777
}
776778

779+
fn compile_and(&mut self, args: &[Value], dest: Reg) -> Result<(), String> {
780+
// (and) => true
781+
if args.is_empty() {
782+
self.emit(Op::load_true(dest));
783+
return Ok(());
784+
}
785+
786+
// (and x) => x
787+
if args.len() == 1 {
788+
return self.compile_expr(&args[0], dest, false);
789+
}
790+
791+
// (and x y z ...) => short-circuit evaluation
792+
// Evaluate each expression, if any is false, jump to end with false
793+
let mut jump_to_end = Vec::new();
794+
795+
for (i, arg) in args.iter().enumerate() {
796+
self.compile_expr(arg, dest, false)?;
797+
798+
// For all but the last, check if false and jump to end
799+
if i < args.len() - 1 {
800+
let jump = self.emit(Op::jump_if_false(dest, 0));
801+
jump_to_end.push(jump);
802+
}
803+
}
804+
805+
// Patch all jumps to end (dest already has the last value or the false value)
806+
let end = self.chunk.current_pos();
807+
for jump in jump_to_end {
808+
self.chunk.patch_jump(jump, end);
809+
}
810+
811+
Ok(())
812+
}
813+
814+
fn compile_or(&mut self, args: &[Value], dest: Reg) -> Result<(), String> {
815+
// (or) => false
816+
if args.is_empty() {
817+
self.emit(Op::load_false(dest));
818+
return Ok(());
819+
}
820+
821+
// (or x) => x
822+
if args.len() == 1 {
823+
return self.compile_expr(&args[0], dest, false);
824+
}
825+
826+
// (or x y z ...) => short-circuit evaluation
827+
// Evaluate each expression, if any is true, jump to end with that value
828+
let mut jump_to_end = Vec::new();
829+
830+
for (i, arg) in args.iter().enumerate() {
831+
self.compile_expr(arg, dest, false)?;
832+
833+
// For all but the last, check if true and jump to end
834+
if i < args.len() - 1 {
835+
let jump = self.emit(Op::jump_if_true(dest, 0));
836+
jump_to_end.push(jump);
837+
}
838+
}
839+
840+
// Patch all jumps to end (dest already has the last value or the true value)
841+
let end = self.chunk.current_pos();
842+
for jump in jump_to_end {
843+
self.chunk.patch_jump(jump, end);
844+
}
845+
846+
Ok(())
847+
}
848+
777849
/// Try to compile a comparison condition as a combined compare-and-jump opcode
778850
/// Returns Some(jump_pos) if successful, None if condition is not a simple comparison
779851
///

0 commit comments

Comments
 (0)