Skip to content

Commit 615fb51

Browse files
authored
Disable function expressions (#96)
* Add failing test for disallowed function expression * Disallow using old-school function definitions and named function declarations as expressions
1 parent cac3928 commit 615fb51

File tree

5 files changed

+37
-6
lines changed

5 files changed

+37
-6
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "js-slang",
3-
"version": "0.1.9",
3+
"version": "0.1.10",
44
"description": "Javascript-based interpreter for slang, written in Typescript",
55
"author": {
66
"name": "Source Academy",

src/__tests__/__snapshots__/disallowed_syntax.ts.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ exports[`Cannot leave blank expressions in for loops 3`] = `"Line 2: For stateme
88

99
exports[`Cannot leave blank expressions in for loops 4`] = `"Line 2: For statement cannot have empty init,test,update expressions."`;
1010

11+
exports[`Cannot use js function expressions 1`] = `"Line 2: Function expressions are not allowed"`;
12+
1113
exports[`Cannot use update expressions 1`] = `"Line 3: Update expressions are not allowed"`;
14+
15+
exports[`DEFINITELY CANNOT use named function declarations as expressions 1`] = `"Line 2: Function expressions are not allowed"`;

src/__tests__/disallowed_syntax.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,32 @@ test("Cannot use update expressions", () => {
5757
});
5858
});
5959

60+
test("Cannot use js function expressions", () => {
61+
const code = `
62+
map(function(x) {
63+
return x + 1;
64+
}, list(1));
65+
`;
66+
const context = mockContext(3);
67+
const promise = runInContext(code, context, { scheduler: "preemptive" });
68+
return promise.then(obj => {
69+
expect(obj.status).toBe("error");
70+
const errors = parseError(context.errors);
71+
expect(errors).toMatchSnapshot();
72+
});
73+
});
74+
75+
test("DEFINITELY CANNOT use named function declarations as expressions", () => {
76+
const code = `
77+
map(function a(x) {
78+
return x + 1;
79+
}, list(1));
80+
`;
81+
const context = mockContext(3);
82+
const promise = runInContext(code, context, { scheduler: "preemptive" });
83+
return promise.then(obj => {
84+
expect(obj.status).toBe("error");
85+
const errors = parseError(context.errors);
86+
expect(errors).toMatchSnapshot();
87+
});
88+
});

src/interpreter.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,6 @@ export const evaluators: { [nodeType: string]: Evaluator<es.Node> } = {
175175
}
176176
return res
177177
},
178-
FunctionExpression: function*(node: es.FunctionExpression, context: Context) {
179-
return new Closure(node, currentFrame(context), context)
180-
},
181178
ArrowFunctionExpression: function*(node: es.Function, context: Context) {
182179
return new ArrowClosure(node, currentFrame(context), context)
183180
},

src/syntaxTypes.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const syntaxTypes: { [nodeName: string]: number } = {
1111
BinaryExpression: 1,
1212
LogicalExpression: 1,
1313
ConditionalExpression: 1,
14-
FunctionExpression: 1,
1514
ArrowFunctionExpression: 1,
1615
Identifier: 1,
1716
Literal: 1,
@@ -45,7 +44,9 @@ const syntaxTypes: { [nodeName: string]: number } = {
4544
CatchClause: Infinity,
4645
DoWhileStatement: Infinity,
4746
ForInStatement: Infinity,
48-
SequenceExpression: Infinity
47+
SequenceExpression: Infinity,
48+
FunctionExpression: Infinity,
49+
4950
}
5051

5152
export default syntaxTypes

0 commit comments

Comments
 (0)