Skip to content

Commit 87ba940

Browse files
authoredNov 17, 2021
Implement arity (#1170)
* Added arity test cases * Implement arity * Added arity doc * Updated environment snapshots * Prettied src\stdlib\__tests__\.misc.ts * Updated arity test snapshots * Updated arity to handle Closures
1 parent a644bbd commit 87ba940

File tree

8 files changed

+289
-0
lines changed

8 files changed

+289
-0
lines changed
 

‎docs/lib/misc.js

+8
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,11 @@ function stringify(v) {
159159
*/
160160
function char_at(s, i) {}
161161

162+
/**
163+
* Returns the number of parameters the given function <CODE>f</CODE> expects,
164+
* excluding the rest parameter.
165+
* @param {function} f - given function
166+
* @returns {number} number of parameters f expects
167+
*/
168+
function arity(f) {
169+
}

‎src/__tests__/__snapshots__/environment.ts.snap

+4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Object {
6363
"Infinity": Infinity,
6464
"NaN": NaN,
6565
"apply_in_underlying_javascript": [Function],
66+
"arity": [Function],
6667
"array_length": [Function],
6768
"char_at": [Function],
6869
"display": [Function],
@@ -206,6 +207,7 @@ Object {
206207
"Infinity": Infinity,
207208
"NaN": NaN,
208209
"apply_in_underlying_javascript": [Function],
210+
"arity": [Function],
209211
"array_length": [Function],
210212
"char_at": [Function],
211213
"display": [Function],
@@ -303,6 +305,7 @@ Object {
303305
"Infinity": Infinity,
304306
"NaN": NaN,
305307
"apply_in_underlying_javascript": [Function],
308+
"arity": [Function],
306309
"array_length": [Function],
307310
"char_at": [Function],
308311
"display": [Function],
@@ -392,6 +395,7 @@ Object {
392395
"Infinity": Infinity,
393396
"NaN": NaN,
394397
"apply_in_underlying_javascript": [Function],
398+
"arity": [Function],
395399
"array_length": [Function],
396400
"char_at": [Function],
397401
"display": [Function],

‎src/__tests__/__snapshots__/environmentTree.ts.snap

+66
Large diffs are not rendered by default.

‎src/createContext.ts

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn
276276
defineBuiltin(context, 'is_undefined(val)', misc.is_undefined)
277277
defineBuiltin(context, 'parse_int(str, radix)', misc.parse_int)
278278
defineBuiltin(context, 'char_at(str, index)', misc.char_at)
279+
defineBuiltin(context, 'arity(f)', misc.arity)
279280
defineBuiltin(context, 'undefined', undefined)
280281
defineBuiltin(context, 'NaN', NaN)
281282
defineBuiltin(context, 'Infinity', Infinity)

‎src/stdlib/__tests__/__snapshots__/misc.ts.snap

+110
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,115 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`arity ignores the rest parameter: expectResult 1`] = `
4+
Object {
5+
"alertResult": Array [],
6+
"code": "arity(display);",
7+
"displayResult": Array [],
8+
"numErrors": 0,
9+
"parsedErrors": "",
10+
"result": 1,
11+
"resultStatus": "finished",
12+
"visualiseListResult": Array [],
13+
}
14+
`;
15+
16+
exports[`arity with function with parameters is ok: expectResult 1`] = `
17+
Object {
18+
"alertResult": Array [],
19+
"code": "arity(arity);",
20+
"displayResult": Array [],
21+
"numErrors": 0,
22+
"parsedErrors": "",
23+
"result": 1,
24+
"resultStatus": "finished",
25+
"visualiseListResult": Array [],
26+
}
27+
`;
28+
29+
exports[`arity with non-function arg f throws error: expectParsedError 1`] = `
30+
Object {
31+
"alertResult": Array [],
32+
"code": "arity('function');",
33+
"displayResult": Array [],
34+
"numErrors": 1,
35+
"parsedErrors": "Line 1: Error: arity expects a function as argument",
36+
"result": undefined,
37+
"resultStatus": "error",
38+
"visualiseListResult": Array [],
39+
}
40+
`;
41+
42+
exports[`arity with nullary function is ok: expectResult 1`] = `
43+
Object {
44+
"alertResult": Array [],
45+
"code": "arity(math_random);",
46+
"displayResult": Array [],
47+
"numErrors": 0,
48+
"parsedErrors": "",
49+
"result": 0,
50+
"resultStatus": "finished",
51+
"visualiseListResult": Array [],
52+
}
53+
`;
54+
55+
exports[`arity with user-made function is ok: expectResult 1`] = `
56+
Object {
57+
"alertResult": Array [],
58+
"code": "function test(x, y) {
59+
return x + y;
60+
}
61+
arity(test);",
62+
"displayResult": Array [],
63+
"numErrors": 0,
64+
"parsedErrors": "",
65+
"result": 2,
66+
"resultStatus": "finished",
67+
"visualiseListResult": Array [],
68+
}
69+
`;
70+
71+
exports[`arity with user-made function with rest parameter is ok: expectResult 1`] = `
72+
Object {
73+
"alertResult": Array [],
74+
"code": "function test(...xs) {
75+
return xs;
76+
}
77+
arity(test);",
78+
"displayResult": Array [],
79+
"numErrors": 0,
80+
"parsedErrors": "",
81+
"result": 0,
82+
"resultStatus": "finished",
83+
"visualiseListResult": Array [],
84+
}
85+
`;
86+
87+
exports[`arity with user-made lambda function is ok: expectResult 1`] = `
88+
Object {
89+
"alertResult": Array [],
90+
"code": "arity(x => x);",
91+
"displayResult": Array [],
92+
"numErrors": 0,
93+
"parsedErrors": "",
94+
"result": 1,
95+
"resultStatus": "finished",
96+
"visualiseListResult": Array [],
97+
}
98+
`;
99+
100+
exports[`arity with user-made nullary function is ok: expectResult 1`] = `
101+
Object {
102+
"alertResult": Array [],
103+
"code": "arity(() => undefined);",
104+
"displayResult": Array [],
105+
"numErrors": 0,
106+
"parsedErrors": "",
107+
"result": 0,
108+
"resultStatus": "finished",
109+
"visualiseListResult": Array [],
110+
}
111+
`;
112+
3113
exports[`char_at with non nonnegative integer second argument errors: expectParsedError 1`] = `
4114
Object {
5115
"alertResult": Array [],

‎src/stdlib/__tests__/misc.ts

+78
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,81 @@ test('char_at with valid args (but index out of bounds) returns undefined', () =
105105
`
106106
).toBe(undefined)
107107
})
108+
109+
test('arity with nullary function is ok', () => {
110+
return expectResult(
111+
stripIndent`
112+
arity(math_random);
113+
`,
114+
{ chapter: 1, native: true }
115+
).toBe(0)
116+
})
117+
118+
test('arity with function with parameters is ok', () => {
119+
return expectResult(
120+
stripIndent`
121+
arity(arity);
122+
`,
123+
{ chapter: 1, native: true }
124+
).toBe(1)
125+
})
126+
127+
test('arity ignores the rest parameter', () => {
128+
return expectResult(
129+
stripIndent`
130+
arity(display);
131+
`,
132+
{ chapter: 1, native: true }
133+
).toBe(1)
134+
})
135+
136+
test('arity with user-made function is ok', () => {
137+
return expectResult(
138+
stripIndent`
139+
function test(x, y) {
140+
return x + y;
141+
}
142+
arity(test);
143+
`,
144+
{ chapter: 1, native: true }
145+
).toBe(2)
146+
})
147+
148+
test('arity with user-made lambda function is ok', () => {
149+
return expectResult(
150+
stripIndent`
151+
arity(x => x);
152+
`,
153+
{ chapter: 1, native: true }
154+
).toBe(1)
155+
})
156+
157+
test('arity with user-made nullary function is ok', () => {
158+
return expectResult(
159+
stripIndent`
160+
arity(() => undefined);
161+
`,
162+
{ chapter: 1, native: true }
163+
).toBe(0)
164+
})
165+
166+
test('arity with user-made function with rest parameter is ok', () => {
167+
return expectResult(
168+
stripIndent`
169+
function test(...xs) {
170+
return xs;
171+
}
172+
arity(test);
173+
`,
174+
{ chapter: 3, native: true }
175+
).toBe(0)
176+
})
177+
178+
test('arity with non-function arg f throws error', () => {
179+
return expectParsedError(
180+
stripIndent`
181+
arity('function');
182+
`,
183+
{ chapter: 1, native: true }
184+
).toMatchInlineSnapshot(`"Line 1: Error: arity expects a function as argument"`)
185+
})

‎src/stdlib/misc.ts

+20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Closure from '../interpreter/closure'
12
import { Context, Value } from '../types'
23
import { stringify } from '../utils/stringify'
34

@@ -109,6 +110,25 @@ export function char_at(str: string, index: number) {
109110
return str[index]
110111
}
111112

113+
/**
114+
* arity returns the number of parameters a given function `f` expects.
115+
*
116+
* @param f Function whose arity is to be found. Required.
117+
*
118+
* An error is thrown if `f` is not a function.
119+
*/
120+
export function arity(f: Function) {
121+
if (f instanceof Closure) {
122+
const params = f.node.params
123+
const hasVarArgs = params[params.length - 1]?.type === 'RestElement'
124+
return hasVarArgs ? params.length - 1 : params.length
125+
} else if (typeof f === 'function') {
126+
return f.length
127+
} else {
128+
throw new Error('arity expects a function as argument')
129+
}
130+
}
131+
112132
export function get_time() {
113133
return new Date().getTime()
114134
}

‎src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ exports[`Ensure no name clashes 1`] = `
1515
const is_undefined = nativeStorage.builtins.get(\\"is_undefined\\");
1616
const parse_int = nativeStorage.builtins.get(\\"parse_int\\");
1717
const char_at = nativeStorage.builtins.get(\\"char_at\\");
18+
const arity = nativeStorage.builtins.get(\\"arity\\");
1819
const undefined = nativeStorage.builtins.get(\\"undefined\\");
1920
const NaN = nativeStorage.builtins.get(\\"NaN\\");
2021
const Infinity = nativeStorage.builtins.get(\\"Infinity\\");
@@ -131,6 +132,7 @@ Object {
131132
const is_undefined = nativeStorage.builtins.get(\\"is_undefined\\");
132133
const parse_int = nativeStorage.builtins.get(\\"parse_int\\");
133134
const char_at = nativeStorage.builtins.get(\\"char_at\\");
135+
const arity = nativeStorage.builtins.get(\\"arity\\");
134136
const undefined = nativeStorage.builtins.get(\\"undefined\\");
135137
const NaN = nativeStorage.builtins.get(\\"NaN\\");
136138
const Infinity = nativeStorage.builtins.get(\\"Infinity\\");

0 commit comments

Comments
 (0)
Please sign in to comment.