Skip to content

Commit 7f585d2

Browse files
Chore: Implement IT.
1 parent bde4602 commit 7f585d2

6 files changed

Lines changed: 95 additions & 14 deletions

File tree

compiler/src/modules/parser/expr.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,14 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
367367
self.chunk.emit(OpCode::GetItem, 0);
368368
} else {
369369
self.eat(TokenType::Rsqb);
370+
// Chained subscript assignment: a[i][j] = v
371+
if !is_slice && matches!(self.peek(), Some(TokenType::Equal)) {
372+
self.advance();
373+
self.expr();
374+
self.chunk.emit(OpCode::StoreItem, 0);
375+
self.chunk.emit(OpCode::LoadNone, 0);
376+
return;
377+
}
370378
self.chunk.emit(OpCode::GetItem, 0);
371379
}
372380
}

compiler/src/modules/parser/stmt.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,17 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
123123
false
124124
}
125125
Some(TokenType::Nonlocal) => {
126-
self.emit_name_list(OpCode::Nonlocal);
126+
self.advance();
127+
loop {
128+
let t = self.advance();
129+
let name = self.lexeme(&t).to_string();
130+
let idx = self.chunk.push_name(&name);
131+
self.chunk.emit(OpCode::Nonlocal, idx);
132+
if !self.chunk.nonlocals.contains(&name) {
133+
self.chunk.nonlocals.push(name);
134+
}
135+
if !self.eat_if(TokenType::Comma) { break; }
136+
}
127137
false
128138
}
129139
Some(TokenType::Assert) => {

compiler/src/modules/parser/types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ pub struct SSAChunk {
103103
pub overflow: bool,
104104
pub prev_slots: Vec<Option<u16>>,
105105
pub phi_map: Vec<usize>,
106+
pub nonlocals: Vec<String>,
106107
pub(super) name_index: HashMap<String, u16>
107108
}
108109

compiler/src/modules/vm/handlers/function.rs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,29 @@ impl<'a> VM<'a> {
111111
HashMap::with_capacity_and_hasher(body.names.len(), Default::default());
112112
for (i, n) in body.names.iter().enumerate() { body_map.insert(n.as_str(), i); }
113113

114-
for (i, param) in params.iter().enumerate() {
115-
if i >= positional.len() { break; }
116-
let pname = format!("{}_0", param.trim_start_matches('*'));
117-
if let Some(&s) = body_map.get(pname.as_str()) {
118-
fn_slots[s] = Some(positional[i]);
114+
let mut pos_idx = 0usize;
115+
for param in params.iter() {
116+
if let Some(star_name) = param.strip_prefix("**") {
117+
// **kwargs: not yet supported, skip
118+
let _ = star_name;
119+
} else if let Some(var_name) = param.strip_prefix('*') {
120+
// *args: collect all remaining positionals into a list
121+
let rest: Vec<Val> = positional[pos_idx..].to_vec();
122+
pos_idx = positional.len();
123+
let list_val = self.heap.alloc(
124+
HeapObj::List(Rc::new(RefCell::new(rest)))
125+
)?;
126+
let pname = format!("{}_0", var_name);
127+
if let Some(&s) = body_map.get(pname.as_str()) {
128+
fn_slots[s] = Some(list_val);
129+
}
130+
} else {
131+
if pos_idx >= positional.len() { continue; }
132+
let pname = format!("{}_0", param);
133+
if let Some(&s) = body_map.get(pname.as_str()) {
134+
fn_slots[s] = Some(positional[pos_idx]);
135+
}
136+
pos_idx += 1;
119137
}
120138
}
121139

@@ -183,13 +201,37 @@ impl<'a> VM<'a> {
183201
self.live_slots.extend(slots.iter().flatten().copied());
184202
self.observed_impure.push(false);
185203

186-
// Capturar el Result; cleanup corre incondicionalmente antes de propagar Err.
187204
let exec_result = self.exec(body, &mut fn_slots);
188205

189206
let callee_impure = self.observed_impure.pop().unwrap_or(true);
190207
self.live_slots.truncate(snap);
191208
self.depth -= 1;
192209

210+
// Write back nonlocal variables to the caller's slots.
211+
for base in &body.nonlocals {
212+
// Find the highest-versioned value in the callee's slots.
213+
let best = body.names.iter().enumerate()
214+
.filter_map(|(i, n)| {
215+
let p = n.rfind('_')?;
216+
(n[..p] == **base).then_some(())?;
217+
let ver: u32 = n[p+1..].parse().ok()?;
218+
Some((ver, fn_slots[i]?))
219+
})
220+
.max_by_key(|(ver, _)| *ver)
221+
.map(|(_, val)| val);
222+
223+
if let Some(val) = best {
224+
// Update all versions of this name in the caller's slots.
225+
for (si, sname) in chunk.names.iter().enumerate() {
226+
if let Some(p) = sname.rfind('_') {
227+
if &sname[..p] == base.as_str() && si < slots.len() {
228+
slots[si] = Some(val);
229+
}
230+
}
231+
}
232+
}
233+
}
234+
193235
let result = exec_result?;
194236
if callee_impure { self.mark_impure(); }
195237

compiler/src/modules/vm/ops.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -276,12 +276,28 @@ impl<'a> VM<'a> {
276276
if let (Some(ba), Some(bb)) = (self.to_bigint(a), self.to_bigint(b)) {
277277
return self.bigint_to_val(ba.mul(&bb));
278278
}
279-
let (str_val, count) = if a.is_heap() && b.is_int() { (a, b.as_int()) }
280-
else if a.is_int() && b.is_heap() { (b, a.as_int()) }
281-
else { return Err(VmErr::Type("unsupported operand type(s) for '*'")); };
282-
if let HeapObj::Str(s) = self.heap.get(str_val) {
283-
let r = s.repeat(count.max(0) as usize);
284-
return self.heap.alloc(HeapObj::Str(r));
279+
let (seq_val, count) = if a.is_heap() && b.is_int() { (a, b.as_int()) }
280+
else if a.is_int() && b.is_heap() { (b, a.as_int()) }
281+
else { return Err(VmErr::Type("unsupported operand type(s) for '*'")); };
282+
let n = count.max(0) as usize;
283+
match self.heap.get(seq_val) {
284+
HeapObj::Str(s) => {
285+
let r = s.repeat(n);
286+
return self.heap.alloc(HeapObj::Str(r));
287+
}
288+
HeapObj::List(rc) => {
289+
let src = rc.borrow().clone();
290+
let mut out = Vec::with_capacity(src.len() * n);
291+
for _ in 0..n { out.extend_from_slice(&src); }
292+
return self.heap.alloc(HeapObj::List(Rc::new(RefCell::new(out))));
293+
}
294+
HeapObj::Tuple(v) => {
295+
let src = v.clone();
296+
let mut out = Vec::with_capacity(src.len() * n);
297+
for _ in 0..n { out.extend_from_slice(&src); }
298+
return self.heap.alloc(HeapObj::Tuple(out));
299+
}
300+
_ => {}
285301
}
286302
Err(VmErr::Type("unsupported operand type(s) for '*'"))
287303
}

compiler/tests/cases/vm.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,5 +370,9 @@
370370
{"src": "d = {'a':1}\nprint(d.get('a'))", "output": ["1"], "result": "None"},
371371
{"src": "d = {'a':1}\nprint(d.get('z', 0))", "output": ["0"], "result": "None"},
372372
{"src": "d = {'a':1,'b':2}\nd.update({'b':9,'c':3})\nprint(d)", "output": ["{'a': 1, 'b': 9, 'c': 3}"], "result": "None"},
373-
{"src": "d = {'a':1}\nd.pop('a')\nprint(d)", "output": ["{}"], "result": "None"}
373+
{"src": "d = {'a':1}\nd.pop('a')\nprint(d)", "output": ["{}"], "result": "None"},
374+
{"src": "for i in range(3):\n if i == 1:\n break\nelse:\n print('done')\nprint('end')", "output": ["end"], "result": "None"},
375+
{"src": "def outer():\n x = 0\n def inner():\n nonlocal x\n x += 1\n inner()\n inner()\n return x\nprint(outer())", "output": ["2"], "result": "None"},
376+
{"src": "def f(*args):\n return sum(args)\nprint(f(1,2,3))", "output": ["6"], "result": "None"},
377+
{"src": "matrix = [[0]*3 for _ in range(3)]\nmatrix[1][1] = 5\nprint(matrix[1][1])", "output": ["5"], "result": "None"}
374378
]

0 commit comments

Comments
 (0)