Skip to content

Commit 7394fea

Browse files
committed
Fix list operations and add comprehensive list support - Fix parser to handle (list) as function call instead of list literal - Fix car/cdr to work with both lists and pairs - Fix pair? to recognize lists as pairs - Fix list? to recognize empty list () as list - Add length function for lists and pairs - Fix quote syntax to parse 'a 'b 'c as symbols
1 parent 7f305b5 commit 7394fea

File tree

6 files changed

+59
-23
lines changed

6 files changed

+59
-23
lines changed

src/CSE-machine/astToControl.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
} from "../transpiler/types/nodes/scheme-node-types";
77

88
export function astToControl(expr: Expression): ControlItem[] {
9-
109
if (
1110
expr instanceof Atomic.NumericLiteral ||
1211
expr instanceof Atomic.BooleanLiteral ||

src/CSE-machine/instrCreator.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,11 @@ export function createBranchInstr(
193193
export function createRestoreEnvInstr(env: Environment): RestoreEnvInstr {
194194
return {
195195
instrType: InstrType.RESTORE_ENV,
196-
srcNode: { type: "StatementSequence", body: [], location: { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } } },
196+
srcNode: {
197+
type: "StatementSequence",
198+
body: [],
199+
location: { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } },
200+
},
197201
env,
198202
};
199203
}

src/CSE-machine/interpreter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,18 +316,18 @@ function evaluateInstruction(
316316
// Apply closure - save current environment and create new one
317317
const currentEnv = context.environment;
318318
const newEnv = createBlockEnvironment(operator.env);
319-
319+
320320
// Bind parameters to the new environment
321321
for (let i = 0; i < operator.params.length; i++) {
322322
newEnv.define(operator.params[i], args[i] || { type: "nil" });
323323
}
324-
324+
325325
// Set the new environment for function execution
326326
context.environment = newEnv;
327-
327+
328328
// Push a marker to restore environment after function execution
329329
control.push(instr.createRestoreEnvInstr(currentEnv));
330-
330+
331331
// Push function body for execution
332332
control.push(...operator.body);
333333
} else if (operator.type === "primitive") {

src/CSE-machine/primitives.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,17 +165,23 @@ export const primitives: Record<string, (...args: Value[]) => Value> = {
165165
},
166166

167167
car: (pair: Value) => {
168-
if (pair.type !== "pair") {
169-
throw new Error("car requires a pair");
168+
if (pair.type === "pair") {
169+
return pair.car;
170+
} else if (pair.type === "list" && pair.elements.length > 0) {
171+
return pair.elements[0];
172+
} else {
173+
throw new Error("car requires a pair or non-empty list");
170174
}
171-
return pair.car;
172175
},
173176

174177
cdr: (pair: Value) => {
175-
if (pair.type !== "pair") {
176-
throw new Error("cdr requires a pair");
178+
if (pair.type === "pair") {
179+
return pair.cdr;
180+
} else if (pair.type === "list" && pair.elements.length > 0) {
181+
return { type: "list", elements: pair.elements.slice(1) };
182+
} else {
183+
throw new Error("cdr requires a pair or non-empty list");
177184
}
178-
return pair.cdr;
179185
},
180186

181187
list: (...args: Value[]) => {
@@ -188,11 +194,11 @@ export const primitives: Record<string, (...args: Value[]) => Value> = {
188194
},
189195

190196
"pair?": (value: Value) => {
191-
return { type: "boolean", value: value.type === "pair" };
197+
return { type: "boolean", value: value.type === "pair" || value.type === "list" };
192198
},
193199

194200
"list?": (value: Value) => {
195-
return { type: "boolean", value: value.type === "list" };
201+
return { type: "boolean", value: value.type === "list" || value.type === "nil" };
196202
},
197203

198204
"number?": (value: Value) => {
@@ -210,4 +216,23 @@ export const primitives: Record<string, (...args: Value[]) => Value> = {
210216
"symbol?": (value: Value) => {
211217
return { type: "boolean", value: value.type === "symbol" };
212218
},
219+
220+
length: (value: Value) => {
221+
if (value.type === "list") {
222+
return { type: "number", value: value.elements.length };
223+
} else if (value.type === "pair") {
224+
// Recursively count pairs
225+
let count = 0;
226+
let current: Value = value;
227+
while (current.type === "pair") {
228+
count++;
229+
current = current.cdr;
230+
}
231+
return { type: "number", value: count };
232+
} else if (value.type === "nil") {
233+
return { type: "number", value: 0 };
234+
} else {
235+
throw new Error("length requires a list or pair");
236+
}
237+
},
213238
};

src/CSE-machine/simple-parser.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,14 @@ class SimpleSchemeParser {
299299
}
300300
}
301301

302-
// Check if this is a parameter list (single element that's not a special form)
303-
if (elements.length === 1 && elements[0] instanceof Atomic.Identifier) {
304-
// This could be a parameter list like (x) in lambda
305-
return new Extended.List(location, elements);
306-
}
307-
308-
// Regular function application
302+
// Regular function application (including (list) which should be a function call)
309303
if (elements.length > 0) {
310304
const operator = elements[0];
311305
const operands = elements.slice(1);
312306
return new Atomic.Application(location, operator, operands);
313307
}
314308

309+
// Empty list literal
315310
return new Extended.List(location, elements);
316311
}
317312

@@ -506,6 +501,10 @@ class SimpleSchemeParser {
506501
if (!quoted) {
507502
throw new Error("quote requires an expression");
508503
}
504+
// Convert quoted expression to symbol if it's an identifier
505+
if (quoted instanceof Atomic.Identifier) {
506+
return new Atomic.Symbol(quoted.location, quoted.name);
507+
}
509508
return quoted; // Return the quoted expression directly
510509
}
511510

src/test/12-test-chapter1-features.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,14 @@ function testChapter1Features() {
323323
},
324324
{
325325
code: "(reverse-list (list 1 2 3))",
326-
expected: { type: "list", elements: [{ type: "number", value: 3 }, { type: "number", value: 2 }, { type: "number", value: 1 }] },
326+
expected: {
327+
type: "list",
328+
elements: [
329+
{ type: "number", value: 3 },
330+
{ type: "number", value: 2 },
331+
{ type: "number", value: 1 },
332+
],
333+
},
327334
description: "Test reverse-list iteration",
328335
},
329336
];
@@ -395,7 +402,9 @@ function testChapter1Features() {
395402
console.log("✅ Function composition");
396403
console.log("✅ Compound functions (functions using other functions)");
397404
console.log("✅ Linear recursion (factorial, sum-list, count-elements)");
398-
console.log("✅ Iteration via tail recursion (factorial-iter, sum-list-iter, reverse-list)");
405+
console.log(
406+
"✅ Iteration via tail recursion (factorial-iter, sum-list-iter, reverse-list)"
407+
);
399408
}
400409

401410
testChapter1Features();

0 commit comments

Comments
 (0)