Skip to content

Commit 61199f7

Browse files
s-kyboundKyriel Abad
andauthored
Implement the CSET machine, along with macros (#1728)
* add prelimiary framework for macro system * Allow Scheme data types as part of control * add functionality to scheme eval metaprocedure * update macro skeleton * add pattern matching system prototype * complete first iteration of pattern matching functions * finish first implementation of pattern matcher * update tests for call/cc * complete CSEP machine behaviour for standard syntax forms * add tags to modified estree nodes, and deparser * fix pattern matching logic * allow let, cond, etc... to be defined in the prelude * allow runtime checks for basic forms * remove hack of storing scheme lists in estree nodes * fix behaviour of ... in macros * fix tests with scheme * undo fix tests with scheme * reduce strictness of scm-slang parser for FULL_SCHEME * add more error-checking for CSEP machine * add tests for CSEP machine and macros * rename csep machine to cset machine * implement the macro environment * improve behaviour of CSET machine * fix formatting issues * Clean up helper functions * create apply metaprocedure * add tests for base cset machine and apply * add named let to scheme prelude --------- Co-authored-by: Kyriel Abad <e0969219@u.nus.edu>
1 parent 6652336 commit 61199f7

28 files changed

+3137
-63
lines changed

src/alt-langs/mapper.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,11 @@ export function mapResult(context: Context): (x: Result) => Result {
4040
// there is no need for a mapper in this case.
4141
return x => x
4242
}
43-
}
43+
}
44+
45+
export const isSchemeLanguage = (context: Context) =>
46+
context.chapter === Chapter.SCHEME_1 ||
47+
context.chapter === Chapter.SCHEME_2 ||
48+
context.chapter === Chapter.SCHEME_3 ||
49+
context.chapter === Chapter.SCHEME_4 ||
50+
context.chapter === Chapter.FULL_SCHEME

src/createContext.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import { makeWrapper } from './utils/makeWrapper'
3838
import * as operators from './utils/operators'
3939
import { stringify } from './utils/stringify'
4040
import { schemeVisualise } from './alt-langs/scheme/scheme-mapper'
41+
import { cset_apply, cset_eval } from './cse-machine/scheme-macros'
42+
import { Transformers } from './cse-machine/interpreter'
4143

4244
export class LazyBuiltIn {
4345
func: (...arg0: any) => any
@@ -117,6 +119,7 @@ const createEmptyRuntime = () => ({
117119
nodes: [],
118120
control: null,
119121
stash: null,
122+
transformers: new Transformers(),
120123
objectCount: 0,
121124
envSteps: -1,
122125
envStepsTotal: 0,
@@ -450,16 +453,14 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn
450453
if (context.chapter <= +Chapter.SCHEME_1 && context.chapter >= +Chapter.FULL_SCHEME) {
451454
switch (context.chapter) {
452455
case Chapter.FULL_SCHEME:
456+
// Introduction to eval
457+
// eval metaprocedure
458+
defineBuiltin(context, '$scheme_ZXZhbA$61$$61$(xs)', cset_eval)
459+
453460
case Chapter.SCHEME_4:
454461
// Introduction to call/cc
455462
defineBuiltin(context, 'call$47$cc(f)', call_with_current_continuation)
456463

457-
// Introduction to eval
458-
459-
// Scheme apply
460-
// ^ is needed in Schemes 2 and 3 to apply to call functions with rest parameters,
461-
// so we move it there.
462-
463464
case Chapter.SCHEME_3:
464465
// Introduction to mutable values, streams
465466

@@ -497,10 +498,6 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn
497498
defineBuiltin(context, 'list$45$$62$vector(xs)', scheme_libs.list$45$$62$vector)
498499

499500
case Chapter.SCHEME_2:
500-
// Splicing builtin resolvers
501-
// defineBuiltin(context, '$36$make$45$splice(expr)', scheme_libs.make_splice)
502-
// defineBuiltin(context, '$36$resolve$45$splice(xs)', scheme_libs.resolve_splice)
503-
504501
// Scheme pairs
505502
defineBuiltin(context, 'cons(left, right)', scheme_libs.cons)
506503
defineBuiltin(context, 'xcons(right, left)', scheme_libs.xcons)
@@ -622,11 +619,16 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn
622619
defineBuiltin(context, 'list$45$$62$string(xs)', scheme_libs.list$45$$62$string)
623620

624621
// Scheme apply is needed here to help in the definition of the Scheme Prelude.
625-
defineBuiltin(context, 'apply(f, ...args)', scheme_libs.apply, 2)
622+
defineBuiltin(context, 'apply(f, ...args)', cset_apply, 2)
626623

627624
case Chapter.SCHEME_1:
628625
// Display
629-
defineBuiltin(context, 'display(val)', (val: any) => display(schemeVisualise(val)))
626+
defineBuiltin(
627+
context,
628+
'display(val, prepend = undefined)',
629+
(val: any, ...str: string[]) => display(schemeVisualise(val), ...str),
630+
1
631+
)
630632
defineBuiltin(context, 'newline()', () => display(''))
631633

632634
// I/O
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`eval of strings: expectResult 1`] = `
4+
Object {
5+
"alertResult": Array [],
6+
"code": "
7+
(eval \\"hello\\")
8+
",
9+
"displayResult": Array [],
10+
"numErrors": 0,
11+
"parsedErrors": "",
12+
"result": "hello",
13+
"resultStatus": "finished",
14+
"visualiseListResult": Array [],
15+
}
16+
`;
17+
18+
exports[`incorrect use of apply throws error (insufficient arguments): expectParsedError 1`] = `
19+
Object {
20+
"alertResult": Array [],
21+
"code": "
22+
(apply)
23+
",
24+
"displayResult": Array [],
25+
"numErrors": 1,
26+
"parsedErrors": "Expected 2 arguments, but got 0.",
27+
"result": undefined,
28+
"resultStatus": "error",
29+
"visualiseListResult": Array [],
30+
}
31+
`;
32+
33+
exports[`incorrect use of apply throws error (last argument not a list): expectParsedError 1`] = `
34+
Object {
35+
"alertResult": Array [],
36+
"code": "
37+
(apply + 1 2 3)
38+
",
39+
"displayResult": Array [],
40+
"numErrors": 1,
41+
"parsedErrors": "Error: Last argument of apply must be a list",
42+
"result": undefined,
43+
"resultStatus": "error",
44+
"visualiseListResult": Array [],
45+
}
46+
`;
47+
48+
exports[`multi-operand apply: expectResult 1`] = `
49+
Object {
50+
"alertResult": Array [],
51+
"code": "
52+
(define args '(1 2 3 4 5))
53+
(apply + 6 7 8 9 10 args)
54+
",
55+
"displayResult": Array [],
56+
"numErrors": 0,
57+
"parsedErrors": "",
58+
"result": SchemeInteger {
59+
"numberType": 1,
60+
"value": 55n,
61+
},
62+
"resultStatus": "finished",
63+
"visualiseListResult": Array [],
64+
}
65+
`;
66+
67+
exports[`two-operand apply: expectResult 1`] = `
68+
Object {
69+
"alertResult": Array [],
70+
"code": "
71+
(define args '(1 2))
72+
(apply + args)
73+
",
74+
"displayResult": Array [],
75+
"numErrors": 0,
76+
"parsedErrors": "",
77+
"result": SchemeInteger {
78+
"numberType": 1,
79+
"value": 3n,
80+
},
81+
"resultStatus": "finished",
82+
"visualiseListResult": Array [],
83+
}
84+
`;
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`eval of application: expectResult 1`] = `
4+
Object {
5+
"alertResult": Array [],
6+
"code": "
7+
(eval '(+ 1 2))
8+
",
9+
"displayResult": Array [],
10+
"numErrors": 0,
11+
"parsedErrors": "",
12+
"result": SchemeInteger {
13+
"numberType": 1,
14+
"value": 3n,
15+
},
16+
"resultStatus": "finished",
17+
"visualiseListResult": Array [],
18+
}
19+
`;
20+
21+
exports[`eval of begin: expectResult 1`] = `
22+
Object {
23+
"alertResult": Array [],
24+
"code": "
25+
(eval '(begin 1 2 3))
26+
",
27+
"displayResult": Array [],
28+
"numErrors": 0,
29+
"parsedErrors": "",
30+
"result": SchemeInteger {
31+
"numberType": 1,
32+
"value": 3n,
33+
},
34+
"resultStatus": "finished",
35+
"visualiseListResult": Array [],
36+
}
37+
`;
38+
39+
exports[`eval of booleans: expectResult 1`] = `
40+
Object {
41+
"alertResult": Array [],
42+
"code": "
43+
(eval #t)
44+
",
45+
"displayResult": Array [],
46+
"numErrors": 0,
47+
"parsedErrors": "",
48+
"result": true,
49+
"resultStatus": "finished",
50+
"visualiseListResult": Array [],
51+
}
52+
`;
53+
54+
exports[`eval of define: expectResult 1`] = `
55+
Object {
56+
"alertResult": Array [],
57+
"code": "
58+
(eval '(define x 1))
59+
x
60+
",
61+
"displayResult": Array [],
62+
"numErrors": 0,
63+
"parsedErrors": "",
64+
"result": SchemeInteger {
65+
"numberType": 1,
66+
"value": 1n,
67+
},
68+
"resultStatus": "finished",
69+
"visualiseListResult": Array [],
70+
}
71+
`;
72+
73+
exports[`eval of empty list: expectParsedError 1`] = `
74+
Object {
75+
"alertResult": Array [],
76+
"code": "
77+
(eval '())
78+
",
79+
"displayResult": Array [],
80+
"numErrors": 1,
81+
"parsedErrors": "Error: Cannot evaluate null",
82+
"result": undefined,
83+
"resultStatus": "error",
84+
"visualiseListResult": Array [],
85+
}
86+
`;
87+
88+
exports[`eval of if: expectResult 1`] = `
89+
Object {
90+
"alertResult": Array [],
91+
"code": "
92+
(eval '(if #t 1 2))
93+
",
94+
"displayResult": Array [],
95+
"numErrors": 0,
96+
"parsedErrors": "",
97+
"result": SchemeInteger {
98+
"numberType": 1,
99+
"value": 1n,
100+
},
101+
"resultStatus": "finished",
102+
"visualiseListResult": Array [],
103+
}
104+
`;
105+
106+
exports[`eval of lambda: expectResult 1`] = `
107+
Object {
108+
"alertResult": Array [],
109+
"code": "
110+
(eval '(lambda (x) x))
111+
",
112+
"displayResult": Array [],
113+
"numErrors": 0,
114+
"parsedErrors": "",
115+
"result": [Function],
116+
"resultStatus": "finished",
117+
"visualiseListResult": Array [],
118+
}
119+
`;
120+
121+
exports[`eval of numbers: expectResult 1`] = `
122+
Object {
123+
"alertResult": Array [],
124+
"code": "
125+
(eval 1)
126+
",
127+
"displayResult": Array [],
128+
"numErrors": 0,
129+
"parsedErrors": "",
130+
"result": SchemeInteger {
131+
"numberType": 1,
132+
"value": 1n,
133+
},
134+
"resultStatus": "finished",
135+
"visualiseListResult": Array [],
136+
}
137+
`;
138+
139+
exports[`eval of quote: expectResult 1`] = `
140+
Object {
141+
"alertResult": Array [],
142+
"code": "
143+
(eval '(quote (1 2 3)))
144+
",
145+
"displayResult": Array [],
146+
"numErrors": 0,
147+
"parsedErrors": "",
148+
"result": Array [
149+
SchemeInteger {
150+
"numberType": 1,
151+
"value": 1n,
152+
},
153+
Array [
154+
SchemeInteger {
155+
"numberType": 1,
156+
"value": 2n,
157+
},
158+
Array [
159+
SchemeInteger {
160+
"numberType": 1,
161+
"value": 3n,
162+
},
163+
null,
164+
],
165+
],
166+
],
167+
"resultStatus": "finished",
168+
"visualiseListResult": Array [],
169+
}
170+
`;
171+
172+
exports[`eval of set!: expectResult 1`] = `
173+
Object {
174+
"alertResult": Array [],
175+
"code": "
176+
(define x 2)
177+
(eval '(set! x 1))
178+
x
179+
",
180+
"displayResult": Array [],
181+
"numErrors": 0,
182+
"parsedErrors": "",
183+
"result": SchemeInteger {
184+
"numberType": 1,
185+
"value": 1n,
186+
},
187+
"resultStatus": "finished",
188+
"visualiseListResult": Array [],
189+
}
190+
`;
191+
192+
exports[`eval of strings: expectResult 1`] = `
193+
Object {
194+
"alertResult": Array [],
195+
"code": "
196+
(eval \\"hello\\")
197+
",
198+
"displayResult": Array [],
199+
"numErrors": 0,
200+
"parsedErrors": "",
201+
"result": "hello",
202+
"resultStatus": "finished",
203+
"visualiseListResult": Array [],
204+
}
205+
`;
206+
207+
exports[`eval of symbols: expectResult 1`] = `
208+
Object {
209+
"alertResult": Array [],
210+
"code": "
211+
(define hello 1)
212+
(eval 'hello)
213+
",
214+
"displayResult": Array [],
215+
"numErrors": 0,
216+
"parsedErrors": "",
217+
"result": SchemeInteger {
218+
"numberType": 1,
219+
"value": 1n,
220+
},
221+
"resultStatus": "finished",
222+
"visualiseListResult": Array [],
223+
}
224+
`;

0 commit comments

Comments
 (0)