Skip to content

Commit 397284c

Browse files
authored
feat: support closure (#147)
1 parent 92e723b commit 397284c

File tree

15 files changed

+254
-224
lines changed

15 files changed

+254
-224
lines changed

.gitpod.Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM gitpod/workspace-full-vnc:2023-03-06-18-43-51
1+
FROM gitpod/workspace-full-vnc
22

33
ENV TRIGGER_REBUILD=10
44

@@ -23,6 +23,6 @@ RUN git clone --depth 1 "https://github.com/emscripten-core/emsdk.git" $HOME/.em
2323
RUN brew install binaryen wabt wasm-pack
2424

2525
# fix Node.js path and use latest Node.js
26-
RUN brew install n && sudo /home/linuxbrew/.linuxbrew/bin/n latest && sudo /usr/local/bin/npm i -g yarn sao pnpm
26+
RUN brew install n && sudo /home/linuxbrew/.linuxbrew/bin/n latest && sudo /usr/local/bin/npm i -g yarn npm pnpm npm-check-updates
2727
ENV PATH=/usr/local/bin/:$PATH
2828
RUN printf "\nexport PATH="/usr/local/bin/:$PATH"\n" >> ~/.bashrc

.gitpod.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ tasks:
55
- init: time cargo build
66
command: cargo test
77
- init: cargo install cargo-insta && exit # cargo insta test && cargo insta accept to update snapshots
8-
- init: cd wasm && wasm-pack build --release --scope=gengjiawen && pnpm i
8+
- init: cd wasm && wasm-pack build --release --scope=gengjiawen && cd .. && pnpm i
99

1010
vscode:
1111
extensions:

compiler/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
1-
# WIP
1+
# monkey-rust
2+
![Rust](https://github.com/gengjiawen/monkey-rust/workflows/Rust/badge.svg)
3+
[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gengjiawen/monkey_rust)
4+
5+
This is a compiler for the Monkey programming language written in Rust
6+
7+
![The Monkey Programming Language](https://cloud.githubusercontent.com/assets/1013641/22617482/9c60c27c-eb09-11e6-9dfa-b04c7fe498ea.png)
8+
9+
## What’s Monkey?
10+
11+
Monkey has a C-like syntax, supports **variable bindings**, **prefix** and **infix operators**, has **first-class** and **higher-order functions**, can handle **closures** with ease and has **integers**, **booleans**, **arrays** and **hashes** built-in.
12+
13+
Official site is: https://monkeylang.org/. It's has various implementation languages :).
14+
15+
There is a book about learning how to make an interpreter: [Writing An Interpreter In Go](https://interpreterbook.com/#the-monkey-programming-language). This is where the Monkey programming language come from.

compiler/compiler.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ impl Compiler {
8484
fn compile_stmt(&mut self, s: &Statement) -> Result<(), CompileError> {
8585
match s {
8686
Statement::Let(let_statement) => {
87-
self.compile_expr(&let_statement.expr)?;
8887
let symbol = self
8988
.symbol_table
9089
.define(let_statement.identifier.kind.to_string());
90+
self.compile_expr(&let_statement.expr)?;
9191
if symbol.scope == SymbolScope::Global {
9292
self.emit(Opcode::OpSetGlobal, &vec![symbol.index]);
9393
} else {
@@ -234,6 +234,7 @@ impl Compiler {
234234
}
235235
Expression::FUNCTION(f) => {
236236
self.enter_scope();
237+
// f.name
237238
for param in f.params.iter() {
238239
self.symbol_table.define(param.name.clone());
239240
}
@@ -245,16 +246,20 @@ impl Compiler {
245246
self.emit(OpReturn, &vec![]);
246247
}
247248
let num_locals = self.symbol_table.num_definitions;
249+
let free_symbols = self.symbol_table.free_symbols.clone();
248250
let instructions = self.leave_scope();
251+
for x in free_symbols.clone() {
252+
self.load_symbol(&x);
253+
}
249254

250-
let compiled_function = object::CompiledFunction {
255+
let compiled_function = Rc::from(object::CompiledFunction {
251256
instructions: instructions.data,
252257
num_locals,
253258
num_parameters: f.params.len(),
254-
};
259+
});
255260

256-
let operands = vec![self.add_constant(Object::CompiledFunction(compiled_function))];
257-
self.emit(OpConst, &operands);
261+
let operands = vec![self.add_constant(Object::CompiledFunction(compiled_function)), free_symbols.len()];
262+
self.emit(OpClosure, &operands);
258263
}
259264
Expression::FunctionCall(fc) => {
260265
self.compile_expr(&fc.callee)?;
@@ -279,6 +284,12 @@ impl Compiler {
279284
SymbolScope::Builtin => {
280285
self.emit(OpGetBuiltin, &vec![symbol.index]);
281286
}
287+
SymbolScope::Free => {
288+
self.emit(OpGetFree, &vec![symbol.index]);
289+
}
290+
SymbolScope::Function => {
291+
self.emit(OpCurrentClosure, &vec![]);
292+
}
282293
}
283294
}
284295

compiler/compiler_function_test.rs

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#[cfg(test)]
22
mod tests {
3+
use std::rc::Rc;
34
use crate::compiler_test::{run_compiler_test, CompilerTestCase};
45
use crate::op_code::Opcode::*;
56
use crate::op_code::{concat_instructions, make_instructions};
@@ -13,20 +14,20 @@ mod tests {
1314
expected_constants: vec![
1415
Object::Integer(5),
1516
Object::Integer(10),
16-
Object::CompiledFunction(object::CompiledFunction {
17+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
1718
instructions: concat_instructions(&vec![
1819
make_instructions(OpConst, &vec![0]),
1920
make_instructions(OpConst, &vec![1]),
2021
make_instructions(OpAdd, &vec![0]),
2122
make_instructions(OpReturnValue, &vec![0]),
2223
])
23-
.data,
24+
.data,
2425
num_locals: 0,
2526
num_parameters: 0,
26-
}),
27+
})),
2728
],
2829
expected_instructions: vec![
29-
make_instructions(OpConst, &vec![2]),
30+
make_instructions(OpClosure, &vec![2, 0]),
3031
make_instructions(OpPop, &vec![0]),
3132
],
3233
},
@@ -35,20 +36,20 @@ mod tests {
3536
expected_constants: vec![
3637
Object::Integer(5),
3738
Object::Integer(10),
38-
Object::CompiledFunction(object::CompiledFunction {
39+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
3940
instructions: concat_instructions(&vec![
4041
make_instructions(OpConst, &vec![0]),
4142
make_instructions(OpConst, &vec![1]),
4243
make_instructions(OpAdd, &vec![0]),
4344
make_instructions(OpReturnValue, &vec![0]),
4445
])
45-
.data,
46+
.data,
4647
num_locals: 0,
4748
num_parameters: 0,
48-
}),
49+
})),
4950
],
5051
expected_instructions: vec![
51-
make_instructions(OpConst, &vec![2]),
52+
make_instructions(OpClosure, &vec![2, 0]),
5253
make_instructions(OpPop, &vec![0]),
5354
],
5455
},
@@ -57,20 +58,20 @@ mod tests {
5758
expected_constants: vec![
5859
Object::Integer(1),
5960
Object::Integer(2),
60-
Object::CompiledFunction(object::CompiledFunction {
61+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
6162
instructions: concat_instructions(&vec![
6263
make_instructions(OpConst, &vec![0]),
6364
make_instructions(OpPop, &vec![0]),
6465
make_instructions(OpConst, &vec![1]),
6566
make_instructions(OpReturnValue, &vec![0]),
6667
])
67-
.data,
68+
.data,
6869
num_locals: 0,
6970
num_parameters: 0,
70-
}),
71+
})),
7172
],
7273
expected_instructions: vec![
73-
make_instructions(OpConst, &vec![2]),
74+
make_instructions(OpClosure, &vec![2, 0]),
7475
make_instructions(OpPop, &vec![0]),
7576
],
7677
},
@@ -82,14 +83,14 @@ mod tests {
8283
fn test_function_without_return_value() {
8384
let tests = vec![CompilerTestCase {
8485
input: "fn() { }",
85-
expected_constants: vec![Object::CompiledFunction(object::CompiledFunction {
86+
expected_constants: vec![Object::CompiledFunction(Rc::from(object::CompiledFunction {
8687
instructions: concat_instructions(&vec![make_instructions(OpReturn, &vec![0])])
8788
.data,
8889
num_locals: 0,
8990
num_parameters: 0,
90-
})],
91+
}))],
9192
expected_instructions: vec![
92-
make_instructions(OpConst, &vec![0]),
93+
make_instructions(OpClosure, &vec![0, 0]),
9394
make_instructions(OpPop, &vec![0]),
9495
],
9596
}];
@@ -103,18 +104,18 @@ mod tests {
103104
input: "fn() { 24 }();",
104105
expected_constants: vec![
105106
Object::Integer(24),
106-
Object::CompiledFunction(object::CompiledFunction {
107+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
107108
instructions: concat_instructions(&vec![
108109
make_instructions(OpConst, &vec![0]),
109110
make_instructions(OpReturnValue, &vec![0]),
110111
])
111-
.data,
112+
.data,
112113
num_locals: 0,
113114
num_parameters: 0,
114-
}),
115+
})),
115116
],
116117
expected_instructions: vec![
117-
make_instructions(OpConst, &vec![1, 0]),
118+
make_instructions(OpClosure, &vec![1, 0]),
118119
make_instructions(OpCall, &vec![0]),
119120
make_instructions(OpPop, &vec![0]),
120121
],
@@ -123,18 +124,18 @@ mod tests {
123124
input: "let noArg = fn() { 24; }; noArg();",
124125
expected_constants: vec![
125126
Object::Integer(24),
126-
Object::CompiledFunction(object::CompiledFunction {
127+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
127128
instructions: concat_instructions(&vec![
128129
make_instructions(OpConst, &vec![0]),
129130
make_instructions(OpReturnValue, &vec![0]),
130131
])
131-
.data,
132+
.data,
132133
num_locals: 0,
133134
num_parameters: 0,
134-
}),
135+
})),
135136
],
136137
expected_instructions: vec![
137-
make_instructions(OpConst, &vec![1]),
138+
make_instructions(OpClosure, &vec![1, 0]),
138139
make_instructions(OpSetGlobal, &vec![0]),
139140
make_instructions(OpGetGlobal, &vec![0]),
140141
make_instructions(OpCall, &vec![0]),
@@ -144,19 +145,19 @@ mod tests {
144145
CompilerTestCase {
145146
input: "let oneArg = fn(a) { a; }; oneArg(24);",
146147
expected_constants: vec![
147-
Object::CompiledFunction(object::CompiledFunction {
148+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
148149
instructions: concat_instructions(&vec![
149150
make_instructions(OpGetLocal, &vec![0]),
150151
make_instructions(OpReturnValue, &vec![0]),
151152
])
152-
.data,
153+
.data,
153154
num_locals: 1,
154155
num_parameters: 1,
155-
}),
156+
})),
156157
Object::Integer(24),
157158
],
158159
expected_instructions: vec![
159-
make_instructions(OpConst, &vec![0]),
160+
make_instructions(OpClosure, &vec![0, 0]),
160161
make_instructions(OpSetGlobal, &vec![0]),
161162
make_instructions(OpGetGlobal, &vec![0]),
162163
make_instructions(OpConst, &vec![1]),
@@ -167,7 +168,7 @@ mod tests {
167168
CompilerTestCase {
168169
input: "let manyArg = fn(a, b, c) { a; b; c; }; manyArg(24, 25, 26);",
169170
expected_constants: vec![
170-
Object::CompiledFunction(object::CompiledFunction {
171+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
171172
instructions: concat_instructions(&vec![
172173
make_instructions(OpGetLocal, &vec![0]),
173174
make_instructions(OpPop, &vec![0]),
@@ -176,16 +177,16 @@ mod tests {
176177
make_instructions(OpGetLocal, &vec![2]),
177178
make_instructions(OpReturnValue, &vec![0]),
178179
])
179-
.data,
180+
.data,
180181
num_locals: 3,
181182
num_parameters: 3,
182-
}),
183+
})),
183184
Object::Integer(24),
184185
Object::Integer(25),
185186
Object::Integer(26),
186187
],
187188
expected_instructions: vec![
188-
make_instructions(OpConst, &vec![0]),
189+
make_instructions(OpClosure, &vec![0, 0]),
189190
make_instructions(OpSetGlobal, &vec![0]),
190191
make_instructions(OpGetGlobal, &vec![0]),
191192
make_instructions(OpConst, &vec![1]),
@@ -207,41 +208,41 @@ mod tests {
207208
input: "let num = 55; fn() { num; }",
208209
expected_constants: vec![
209210
Object::Integer(55),
210-
Object::CompiledFunction(object::CompiledFunction {
211+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
211212
instructions: concat_instructions(&vec![
212213
make_instructions(OpGetGlobal, &vec![0]),
213214
make_instructions(OpReturnValue, &vec![0]),
214215
])
215-
.data,
216+
.data,
216217
num_locals: 0,
217218
num_parameters: 0,
218-
}),
219+
})),
219220
],
220221
expected_instructions: vec![
221222
make_instructions(OpConst, &vec![0]),
222223
make_instructions(OpSetGlobal, &vec![0]),
223-
make_instructions(OpConst, &vec![1]),
224+
make_instructions(OpClosure, &vec![1, 0]),
224225
make_instructions(OpPop, &vec![0]),
225226
],
226227
},
227228
CompilerTestCase {
228229
input: "fn() { let num = 55; num; }",
229230
expected_constants: vec![
230231
Object::Integer(55),
231-
Object::CompiledFunction(object::CompiledFunction {
232+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
232233
instructions: concat_instructions(&vec![
233234
make_instructions(OpConst, &vec![0]),
234235
make_instructions(OpSetLocal, &vec![0]),
235236
make_instructions(OpGetLocal, &vec![0]),
236237
make_instructions(OpReturnValue, &vec![0]),
237238
])
238-
.data,
239+
.data,
239240
num_locals: 1,
240241
num_parameters: 0,
241-
}),
242+
})),
242243
],
243244
expected_instructions: vec![
244-
make_instructions(OpConst, &vec![1]),
245+
make_instructions(OpClosure, &vec![1, 0]),
245246
make_instructions(OpPop, &vec![0]),
246247
],
247248
},
@@ -250,7 +251,7 @@ mod tests {
250251
expected_constants: vec![
251252
Object::Integer(55),
252253
Object::Integer(77),
253-
Object::CompiledFunction(object::CompiledFunction {
254+
Object::CompiledFunction(Rc::from(object::CompiledFunction {
254255
instructions: concat_instructions(&vec![
255256
make_instructions(OpConst, &vec![0]),
256257
make_instructions(OpSetLocal, &vec![0]),
@@ -261,13 +262,13 @@ mod tests {
261262
make_instructions(OpAdd, &vec![0]),
262263
make_instructions(OpReturnValue, &vec![0]),
263264
])
264-
.data,
265+
.data,
265266
num_locals: 2,
266267
num_parameters: 0,
267-
}),
268+
})),
268269
],
269270
expected_instructions: vec![
270-
make_instructions(OpConst, &vec![2]),
271+
make_instructions(OpClosure, &vec![2, 0]),
271272
make_instructions(OpPop, &vec![0]),
272273
],
273274
},
@@ -295,19 +296,19 @@ mod tests {
295296
},
296297
CompilerTestCase {
297298
input: "fn() { len([]) }",
298-
expected_constants: vec![Object::CompiledFunction(object::CompiledFunction {
299+
expected_constants: vec![Object::CompiledFunction(Rc::from(object::CompiledFunction {
299300
instructions: concat_instructions(&vec![
300301
make_instructions(OpGetBuiltin, &vec![0]),
301302
make_instructions(OpArray, &vec![0]),
302303
make_instructions(OpCall, &vec![1]),
303304
make_instructions(OpReturnValue, &vec![0]),
304305
])
305-
.data,
306+
.data,
306307
num_locals: 0,
307308
num_parameters: 0,
308-
})],
309+
}))],
309310
expected_instructions: vec![
310-
make_instructions(OpConst, &vec![0]),
311+
make_instructions(OpClosure, &vec![0, 0]),
311312
make_instructions(OpPop, &vec![0]),
312313
],
313314
},

0 commit comments

Comments
 (0)