Skip to content

Commit ab96b2e

Browse files
committed
Add if, and, or
And, or behave correctly with respect to short-circuiting. This is not testable, unfortuantely.
1 parent 9be1508 commit ab96b2e

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

tinylisp.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@
4848
return interpret(input[2], letCtx);
4949
}
5050

51+
var if_ = function(input, ctx) {
52+
return interpret(input[1], ctx) ?
53+
interpret(input[2], ctx) :
54+
interpret(input[3], ctx);
55+
}
56+
57+
var shortCircuit = function(input, ctx, tshort) {
58+
input.shift();
59+
var expr;
60+
while ((expr = input.shift())) {
61+
if (interpret(expr, ctx) == tshort)
62+
return tshort;
63+
}
64+
return !tshort;
65+
}
66+
5167
var fn = function(input, ctx) {
5268
return {
5369
type: "function",
@@ -65,6 +81,9 @@
6581
case "lambda": return lambda(input, ctx);
6682
case "letrec": return let(input, ctx, true);
6783
case "let": return let(input, ctx, false);
84+
case "if": return if_(input, ctx);
85+
case "or": return shortCircuit(input, ctx, true);
86+
case "and": return shortCircuit(input, ctx, false);
6887
default:
6988
var list = input.map(function(x) { return interpret(x, ctx); });
7089
if (list[0].type === "function") {

tinylisp.spec.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,5 +157,46 @@ describe('tinyLisp', function() {
157157
expect(t.interpret(t.parse("(letrec () 42)"))).toEqual(42);
158158
});
159159
});
160+
161+
describe('if', function() {
162+
it('should choose the right branch', function() {
163+
expect(t.interpret(t.parse("(if 1 42 4711)"))).toEqual(42);
164+
expect(t.interpret(t.parse("(if 0 42 4711)"))).toEqual(4711);
165+
});
166+
});
167+
168+
describe('and', function() {
169+
it('should be true when empty', function() {
170+
expect(t.interpret(t.parse("(and)"))).toEqual(true);
171+
});
172+
173+
it('should be false if any operand is false', function() {
174+
expect(t.interpret(t.parse("(and 1 1 0 1)"))).toEqual(false);
175+
expect(t.interpret(t.parse("(and 0 1"))).toEqual(false);
176+
expect(t.interpret(t.parse("(and 1 0"))).toEqual(false);
177+
});
178+
179+
it('should be true if all operands are true', function() {
180+
expect(t.interpret(t.parse("(and 1 1"))).toEqual(true);
181+
expect(t.interpret(t.parse("(and 1"))).toEqual(true);
182+
});
183+
});
184+
185+
describe('or', function() {
186+
it('should be false when empty', function() {
187+
expect(t.interpret(t.parse("(or)"))).toEqual(false);
188+
});
189+
190+
it('should be true if any operand is true', function() {
191+
expect(t.interpret(t.parse("(or 1 1 0 1)"))).toEqual(true);
192+
expect(t.interpret(t.parse("(or 0 1"))).toEqual(true);
193+
expect(t.interpret(t.parse("(or 1 0"))).toEqual(true);
194+
});
195+
196+
it('should be false if all operands are false', function() {
197+
expect(t.interpret(t.parse("(or 0 0"))).toEqual(false);
198+
expect(t.interpret(t.parse("(or 0"))).toEqual(false);
199+
});
200+
});
160201
});
161202
});

0 commit comments

Comments
 (0)