Skip to content

Commit f89e5ea

Browse files
committed
implement functions
1 parent 5a75127 commit f89e5ea

File tree

4 files changed

+162
-38
lines changed

4 files changed

+162
-38
lines changed

lang/examples/test.modu

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,7 @@
1-
let a = 1;
2-
let b = 1.5;
1+
fn test(a, b) {
2+
print(a, " + ", b);
3+
return a + b;
4+
}
35

4-
print("a = ", a);
5-
6-
a += 1;
7-
8-
print("a += 1; a = ", a);
9-
10-
a *= 2;
11-
12-
print("a *= 2; a = ", a);
13-
14-
a /= 2;
15-
16-
print("a /= 2; a = ", a);
17-
18-
a -= -3;
19-
20-
print("a -= -3; a = ", a);
21-
22-
a %= 2;
23-
24-
print("a %= 2; a = ", a);
25-
26-
print((1 + (2 * 3) - 4) / 5); // = 0.6
6+
print(test(1, 2));
7+
print(int("test"));

lang/src/compiler/compiler.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ impl Compiler {
2020
}
2121
}
2222

23+
fn is_void(expr: &Expr) -> bool {
24+
matches!(
25+
expr,
26+
Expr::Let { .. }
27+
| Expr::Assign { .. }
28+
| Expr::Function { .. }
29+
)
30+
}
31+
2332
// chunk shit
2433

2534
fn emit(&mut self, instruction: Instruction) {
@@ -53,9 +62,15 @@ impl Compiler {
5362

5463
pub fn compile_program(&mut self, ast: Vec<SpannedExpr>) -> Result<(), String> {
5564
for expr in ast {
56-
self.compile_expr(expr)?;
65+
self.compile_expr(expr.clone())?;
66+
67+
if !Self::is_void(&expr.node) {
68+
self.emit(Instruction::Pop);
69+
}
5770
}
5871

72+
self.chunks[self.current_chunk].locals_count = self.scope.max_slot;
73+
5974
Ok(())
6075
}
6176

@@ -197,6 +212,48 @@ impl Compiler {
197212
self.emit(Instruction::Mod);
198213
}
199214

215+
Expr::Function { name, args, body } => {
216+
let chunk_id = self.chunks.len();
217+
self.chunks.push(Chunk::new(name));
218+
219+
let saved_chunk = self.current_chunk;
220+
self.current_chunk = chunk_id;
221+
222+
let saved = self.scope.enter_function();
223+
for arg in args {
224+
self.scope.define_local(arg);
225+
}
226+
227+
self.compile_expr(*body.clone())?;
228+
self.emit(Instruction::Return);
229+
230+
let locals_count = self.scope.exit_function(saved);
231+
self.chunks[chunk_id].locals_count = locals_count;
232+
233+
self.current_chunk = saved_chunk;
234+
235+
let fn_value = Value::Function { chunk_id, arity: args.len() };
236+
let index = self.add_constant(fn_value);
237+
238+
self.emit(Instruction::Push(index));
239+
self.store_variable(name);
240+
},
241+
242+
Expr::Block(exprs) => {
243+
self.scope.push_scope();
244+
245+
for expr in exprs {
246+
self.compile_expr(expr.clone())?;
247+
}
248+
249+
self.scope.pop_scope();
250+
}
251+
252+
Expr::Return(v) => {
253+
self.compile_expr(*v.clone())?;
254+
self.emit(Instruction::Return);
255+
}
256+
200257
v => {
201258
dbg!(v);
202259
todo!();

lang/src/compiler/scope.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub struct Scope {
88
pub struct ScopeStack {
99
scopes: Vec<Scope>,
1010
next_slot: usize,
11-
max_slot: usize,
11+
pub max_slot: usize,
1212
function_depth: usize,
1313
}
1414

@@ -31,6 +31,32 @@ impl ScopeStack {
3131
self.function_depth > 0
3232
}
3333

34+
pub fn enter_function(&mut self) -> (usize, usize) {
35+
self.function_depth += 1;
36+
37+
let saved_next = self.next_slot;
38+
let saved_max = self.max_slot;
39+
40+
self.next_slot = 0;
41+
self.max_slot = 0;
42+
43+
self.push_scope();
44+
45+
(saved_next, saved_max)
46+
}
47+
48+
pub fn exit_function(&mut self, saved: (usize, usize)) -> usize {
49+
let locals_count = self.max_slot;
50+
51+
self.function_depth -= 1;
52+
53+
self.pop_scope();
54+
self.next_slot = saved.0;
55+
self.max_slot = saved.1;
56+
57+
locals_count
58+
}
59+
3460
pub fn resolve(&self, name: &str) -> Variable {
3561
for scope in self.scopes.iter().rev() {
3662
if let Some(&slot) = scope.locals.get(name) {
@@ -55,4 +81,15 @@ impl ScopeStack {
5581

5682
slot
5783
}
84+
85+
pub fn push_scope(&mut self) {
86+
self.scopes.push(Scope {
87+
locals: HashMap::new(),
88+
depth: self.scopes.len(),
89+
});
90+
}
91+
92+
pub fn pop_scope(&mut self) {
93+
self.scopes.pop();
94+
}
5895
}

lang/src/vm/vm.rs

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,6 @@ impl VM {
113113
self.stack.push(a.r#mod(&b)?);
114114
}
115115

116-
Instruction::StoreGlobal(name) => {
117-
let v = self.stack.pop().unwrap_or(Value::Null);
118-
self.globals.insert(name.clone(), v);
119-
}
120-
121-
Instruction::LoadGlobal(name) => {
122-
let v = self.globals.get(name).cloned().unwrap_or(Value::Null);
123-
self.stack.push(v);
124-
}
125-
126116
Instruction::Call(argc) => {
127117
let callee = self.stack[self.stack.len() - 1 - argc].clone();
128118

@@ -134,12 +124,71 @@ impl VM {
134124
let result = (func.func)(args);
135125
}
136126

127+
Value::Function { chunk_id, arity } => {
128+
if arity != *argc {
129+
return Err(format!("expected {} arguments but got {}", arity, argc));
130+
}
131+
132+
if self.frames.len() >= FRAMES_MAX {
133+
return Err("stack overflow".to_string());
134+
}
135+
136+
let base = self.stack.len() - argc;
137+
138+
let extra_locals = self.chunks[chunk_id].locals_count.saturating_sub(*argc);
139+
for _ in 0..extra_locals {
140+
self.stack.push(Value::Null);
141+
}
142+
143+
self.frames.push(CallFrame {
144+
chunk_id,
145+
ip: 0,
146+
base,
147+
});
148+
}
149+
137150
_ => {
138-
dbg!(callee);
151+
return Err(format!("{} is not a function", callee.type_name()));
139152
}
140153
}
141154
}
142155

156+
Instruction::Return => {
157+
let result = self.stack.pop().unwrap_or(Value::Null);
158+
let frame = self.frames.pop().unwrap();
159+
160+
if frame.base > 0 {
161+
self.stack.truncate(frame.base - 1);
162+
}
163+
164+
165+
self.stack.push(result);
166+
}
167+
168+
Instruction::Pop => {
169+
self.stack.pop();
170+
}
171+
172+
Instruction::StoreGlobal(name) => {
173+
let v = self.stack.pop().unwrap_or(Value::Null);
174+
self.globals.insert(name.clone(), v);
175+
}
176+
177+
Instruction::StoreLocal(slot) => {
178+
let v = self.stack.pop().unwrap_or(Value::Null);
179+
self.stack[frame.base + slot] = v;
180+
}
181+
182+
Instruction::LoadGlobal(name) => {
183+
let v = self.globals.get(name).cloned().unwrap_or(Value::Null);
184+
self.stack.push(v);
185+
}
186+
187+
Instruction::LoadLocal(slot) => {
188+
let v = self.stack[frame.base + slot].clone();
189+
self.stack.push(v);
190+
}
191+
143192
_ => {
144193
dbg!(instruction);
145194
todo!();

0 commit comments

Comments
 (0)