Skip to content

Commit ea30de7

Browse files
Feat: Implement phi support (including phi colission).
1 parent fbb3a42 commit ea30de7

3 files changed

Lines changed: 67 additions & 20 deletions

File tree

compiler/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn main() {
2929

3030
initialize_logger();
3131

32-
let source = "x = 10\nif x > 20:\ny = 1\nelif x > 5:\ny = 2\nelse:\ny = 3";
32+
let source = "x: int = 0\nif cond: x = 1\nelse: x = 2\ny = x";
3333

3434
let chunk = modules::parser::Parser::new(source, modules::lexer::lexer(source)).parse();
3535

compiler/src/modules/parser.rs

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ impl SSAChunk {
8282
}
8383

8484
struct JoinNode {
85-
phis: Vec<Phi>,
86-
backup: HashMap<String, u32>,
85+
backup: HashMap<String, u32>
8786
}
8887

8988
pub struct Parser<'src, I: Iterator<Item = Token>> {
@@ -148,14 +147,25 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
148147
self.chunk.emit(OpCode::LoadName, i);
149148
}
150149

151-
fn enter_block(&mut self) { self.join_stack.push(JoinNode { phis: Vec::new(), backup: self.ssa_versions.clone() }); }
150+
fn enter_block(&mut self) {
151+
self.join_stack.push(JoinNode { backup: self.ssa_versions.clone() });
152+
}
153+
152154
fn commit_block(&mut self) {
153-
if let Some(mut j) = self.join_stack.pop() {
154-
for phi in j.phis {
155-
let i = self.chunk.push_name(&phi.target);
156-
self.chunk.emit(OpCode::Phi, i);
157-
}
155+
if let Some(j) = self.join_stack.pop() {
156+
let post = self.ssa_versions.clone();
158157
self.ssa_versions = j.backup;
158+
for (name, post_ver) in &post {
159+
let pre_ver = self.ssa_versions.get(name).copied().unwrap_or(0);
160+
if *post_ver != pre_ver {
161+
// parte desde post_ver, no desde backup, evita colisión
162+
self.ssa_versions.insert(name.to_string(), *post_ver);
163+
let new_ver = self.increment_version(name);
164+
let ssa = format!("{}_{}", name, new_ver);
165+
let i = self.chunk.push_name(&ssa);
166+
self.chunk.emit(OpCode::Phi, i);
167+
}
168+
}
159169
}
160170
}
161171

@@ -175,17 +185,24 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
175185

176186
fn stmt(&mut self) {
177187
match self.peek() {
178-
Some(TokenType::If) => self.if_stmt(),
188+
Some(TokenType::If) => self.if_stmt(),
179189
Some(TokenType::While) => self.while_stmt(),
180190
Some(TokenType::For) => self.for_stmt(),
191+
Some(TokenType::Name) => { let t = self.advance(); self.name_stmt(t); }
181192
_ => self.expr()
182193
}
183194
}
184195

185196
fn while_stmt(&mut self) { self.advance(); self.enter_block(); self.expr(); self.chunk.emit(OpCode::PopTop, 0); if matches!(self.peek(), Some(TokenType::Colon)) { self.advance(); } self.stmt(); self.commit_block(); }
186197

187198
fn if_stmt(&mut self) {
188-
self.advance(); // consume 'if' o 'elif'
199+
self.advance(); // consume 'if'
200+
self.enter_block(); // un solo bloque para toda la cadena
201+
self.if_body(); // parsea if / elif* / else?
202+
self.commit_block(); // un solo join point al final
203+
}
204+
205+
fn if_body(&mut self) {
189206
self.expr();
190207
self.chunk.emit(OpCode::JumpIfFalse, 0);
191208
let jf = self.chunk.instructions.len() - 1;
@@ -194,9 +211,25 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
194211
self.chunk.emit(OpCode::PopTop, 0);
195212

196213
match self.peek() {
197-
Some(TokenType::Elif) => { self.chunk.emit(OpCode::Jump, 0); let jmp = self.chunk.instructions.len() - 1; self.patch(jf); self.if_stmt(); self.patch(jmp); }
198-
Some(TokenType::Else) => { self.advance(); self.chunk.emit(OpCode::Jump, 0); let jmp = self.chunk.instructions.len() - 1; self.patch(jf); self.eat(TokenType::Colon); self.stmt(); self.chunk.emit(OpCode::PopTop, 0); self.patch(jmp); }
199-
_ => { self.patch(jf); }
214+
Some(TokenType::Elif) => {
215+
self.advance(); // consume 'elif'
216+
self.chunk.emit(OpCode::Jump, 0);
217+
let jmp = self.chunk.instructions.len() - 1;
218+
self.patch(jf);
219+
self.if_body(); // recursivo SIN enter/commit
220+
self.patch(jmp);
221+
}
222+
Some(TokenType::Else) => {
223+
self.advance();
224+
self.chunk.emit(OpCode::Jump, 0);
225+
let jmp = self.chunk.instructions.len() - 1;
226+
self.patch(jf);
227+
self.eat(TokenType::Colon);
228+
self.stmt();
229+
self.chunk.emit(OpCode::PopTop, 0);
230+
self.patch(jmp);
231+
}
232+
_ => { self.patch(jf); }
200233
}
201234
}
202235

@@ -313,14 +346,21 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
313346
self.chunk.emit(OpCode::LoadConst, i);
314347
}
315348

316-
fn name(&mut self, t: Token) {
349+
fn name_stmt(&mut self, t: Token) { // solo desde stmt()
317350
let name = self.lexeme(&t).to_string();
318-
319351
if self.eat_if(TokenType::Colon) {
320-
let ann = { let t = self.advance(); self.lexeme(&t).to_string() };
321-
self.chunk.annotations.insert(name.clone(), ann);
352+
if matches!(self.peek(), Some(TokenType::Name)) {
353+
let ann = { let t = self.advance(); self.lexeme(&t).to_string() };
354+
self.chunk.annotations.insert(name.clone(), ann);
355+
}
356+
if !matches!(self.peek(), Some(TokenType::Equal)) { return; }
322357
}
358+
self.name(t); // delega: lógica en un solo lugar
359+
self.binary_op();
360+
}
323361

362+
fn name(&mut self, t: Token) { // solo desde expr()
363+
let name = self.lexeme(&t).to_string();
324364
match self.peek() {
325365
Some(TokenType::Equal) => self.assign(name),
326366
Some(TokenType::Lpar) => self.call(name),

compiler/tests/cases/parser_cases.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,15 @@
6565
{
6666
"src": "x = 10\nif x > 20:\ny = 1\nelif x > 5:\ny = 2\nelse:\ny = 3",
6767
"constants": ["10", "20", "1", "5", "2", "3"],
68-
"names": ["x_1", "y_1", "y_2", "y_3"],
69-
"instructions": [["LoadConst",0], ["StoreName",0], ["PopTop",0], ["LoadName",0], ["LoadConst",1], ["Gt",0], ["JumpIfFalse",11], ["LoadConst",2], ["StoreName",1], ["PopTop",0], ["Jump",22], ["LoadName",0], ["LoadConst",3], ["Gt",0], ["JumpIfFalse",19], ["LoadConst",4], ["StoreName",2], ["PopTop",0], ["Jump",22], ["LoadConst",5], ["StoreName",3], ["PopTop",0], ["ReturnValue",0]],
68+
"names": ["x_1", "y_1", "y_2", "y_3", "y_4"],
69+
"instructions": [["LoadConst",0], ["StoreName",0], ["PopTop",0], ["LoadName",0], ["LoadConst",1], ["Gt",0], ["JumpIfFalse",11], ["LoadConst",2], ["StoreName",1], ["PopTop",0], ["Jump",22], ["LoadName",0], ["LoadConst",3], ["Gt",0], ["JumpIfFalse",19], ["LoadConst",4], ["StoreName",2], ["PopTop",0], ["Jump",22], ["LoadConst",5], ["StoreName",3], ["PopTop",0], ["Phi",4], ["ReturnValue",0]],
70+
"annotations": {}
71+
},
72+
{
73+
"src": "x = 0\nif a:\nx = 1\nelif b:\nx = 2\nelse:\nx = 3\ny = x",
74+
"constants": ["0", "1", "2", "3"],
75+
"names": ["x_1", "a_0", "x_2", "b_0", "x_3", "x_4", "x_5", "y_1"],
76+
"instructions": [["LoadConst",0], ["StoreName",0], ["PopTop",0], ["LoadName",1], ["JumpIfFalse",9], ["LoadConst",1], ["StoreName",2], ["PopTop",0], ["Jump",18], ["LoadName",3], ["JumpIfFalse",15], ["LoadConst",2], ["StoreName",4], ["PopTop",0], ["Jump",18], ["LoadConst",3], ["StoreName",5], ["PopTop",0], ["Phi",6], ["LoadName",6], ["StoreName",7], ["PopTop",0], ["ReturnValue",0]],
7077
"annotations": {}
7178
}
7279
]

0 commit comments

Comments
 (0)