Skip to content

Commit 16b80af

Browse files
Feat: Operator precedence, while loop, call_range, poptop.
1 parent ea30de7 commit 16b80af

4 files changed

Lines changed: 127 additions & 72 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: int = 0\nif cond: x = 1\nelse: x = 2\ny = x";
32+
let source = "result = 2 + 3 * 7";
3333

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

compiler/src/modules/parser.rs

Lines changed: 121 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ pub enum OpCode {
5959
}
6060

6161
#[derive(Debug)] pub struct Instruction { pub opcode: OpCode, pub operand: u16 }
62-
#[derive(Debug)] pub enum Value { Str(String), Int(i64), Float(f64), Bool(bool), None, Range(i64, i64, i64) }
63-
64-
#[derive(Debug)] pub struct Phi { pub target: String, pub operands: Vec<(u32, String)> }
62+
#[derive(Debug)] pub enum Value { Str(String), Int(i64), Float(f64), Bool(bool), None }
6563

6664
#[derive(Default)]
6765
pub struct SSAChunk {
@@ -123,8 +121,8 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
123121

124122
pub fn parse(mut self) -> SSAChunk {
125123
while !self.at_end() {
126-
let is_compound = matches!(self.peek(),
127-
Some(TokenType::For | TokenType::If | TokenType::While));
124+
let is_compound = matches!(self.peek(),
125+
Some(TokenType::For | TokenType::If | TokenType::While | TokenType::Def));
128126
self.stmt();
129127
if !self.at_end() && !is_compound { self.chunk.emit(OpCode::PopTop, 0); }
130128
}
@@ -189,11 +187,24 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
189187
Some(TokenType::While) => self.while_stmt(),
190188
Some(TokenType::For) => self.for_stmt(),
191189
Some(TokenType::Name) => { let t = self.advance(); self.name_stmt(t); }
190+
Some(TokenType::Def) => { self.advance(); self.func_def(); }
192191
_ => self.expr()
193192
}
194193
}
195194

196-
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(); }
195+
fn while_stmt(&mut self) {
196+
self.advance();
197+
self.enter_block();
198+
let loop_start = self.chunk.instructions.len() as u16;
199+
self.expr();
200+
self.chunk.emit(OpCode::JumpIfFalse, 0);
201+
let jf = self.chunk.instructions.len() - 1;
202+
self.eat(TokenType::Colon);
203+
self.stmt();
204+
self.chunk.emit(OpCode::Jump, loop_start);
205+
self.patch(jf);
206+
self.commit_block();
207+
}
197208

198209
fn if_stmt(&mut self) {
199210
self.advance(); // consume 'if'
@@ -266,44 +277,6 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
266277
if matches!(self.peek(), Some(k) if k == kind) { self.advance(); true } else { false }
267278
}
268279

269-
fn expr(&mut self) {
270-
let t = self.advance();
271-
match t.kind {
272-
TokenType::Name => self.name(t),
273-
TokenType::Def => { self.func_def(); return; },
274-
TokenType::String => self.emit_const(Value::Str(parse_string(self.lexeme(&t)))),
275-
TokenType::Int | TokenType::Float => self.parse_number(self.lexeme(&t), t.kind),
276-
TokenType::True => self.emit_const(Value::Bool(true)),
277-
TokenType::False => self.emit_const(Value::Bool(false)),
278-
TokenType::None => self.emit_const(Value::None),
279-
TokenType::FstringStart => self.fstring(),
280-
TokenType::Minus => { self.expr(); self.chunk.emit(OpCode::Minus, 0); },
281-
TokenType::Not => { self.expr(); self.chunk.emit(OpCode::Not, 0); }
282-
TokenType::Lbrace => self.dict_literal(),
283-
TokenType::Lsqb => self.list_literal(),
284-
_ => {}
285-
}
286-
self.binary_op();
287-
}
288-
289-
fn binary_op(&mut self) {
290-
match self.peek() {
291-
Some(TokenType::Plus) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Add, 0); }
292-
Some(TokenType::Minus) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Sub, 0); }
293-
Some(TokenType::Star) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Mul, 0); }
294-
Some(TokenType::Slash) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Div, 0); }
295-
Some(TokenType::EqEqual) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Eq, 0); }
296-
Some(TokenType::NotEqual) => { self.advance(); self.expr(); self.chunk.emit(OpCode::NotEq, 0); }
297-
Some(TokenType::Less) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Lt, 0); }
298-
Some(TokenType::Greater) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Gt, 0); }
299-
Some(TokenType::LessEqual) => { self.advance(); self.expr(); self.chunk.emit(OpCode::LtEq, 0); }
300-
Some(TokenType::GreaterEqual) => { self.advance(); self.expr(); self.chunk.emit(OpCode::GtEq, 0); }
301-
Some(TokenType::And) => { self.advance(); self.expr(); self.chunk.emit(OpCode::And, 0); }
302-
Some(TokenType::Or) => { self.advance(); self.expr(); self.chunk.emit(OpCode::Or, 0); }
303-
_ => {}
304-
}
305-
}
306-
307280
fn dict_literal(&mut self) {
308281
let mut pairs = 0u16;
309282
while !matches!(self.peek(), Some(TokenType::Rbrace) | None) {
@@ -346,17 +319,112 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
346319
self.chunk.emit(OpCode::LoadConst, i);
347320
}
348321

349-
fn name_stmt(&mut self, t: Token) { // solo desde stmt()
322+
fn name_stmt(&mut self, t: Token) {
350323
let name = self.lexeme(&t).to_string();
324+
325+
// anotación de tipo
351326
if self.eat_if(TokenType::Colon) {
352327
if matches!(self.peek(), Some(TokenType::Name)) {
353328
let ann = { let t = self.advance(); self.lexeme(&t).to_string() };
354329
self.chunk.annotations.insert(name.clone(), ann);
355330
}
356331
if !matches!(self.peek(), Some(TokenType::Equal)) { return; }
357332
}
358-
self.name(t); // delega: lógica en un solo lugar
359-
self.binary_op();
333+
334+
// assign y call no necesitan la cadena de precedencia
335+
match self.peek() {
336+
Some(TokenType::Equal) => { self.assign(name); return; }
337+
Some(TokenType::Lpar) => { self.call(name); return; }
338+
_ => {}
339+
}
340+
341+
self.emit_load_ssa(name);
342+
self.mul_tail();
343+
self.add_tail();
344+
self.cmp_tail();
345+
self.and_tail();
346+
self.or_tail();
347+
}
348+
349+
fn or_tail(&mut self) {
350+
while matches!(self.peek(), Some(TokenType::Or)) {
351+
self.advance(); self.parse_and(); self.chunk.emit(OpCode::Or, 0);
352+
}
353+
}
354+
fn and_tail(&mut self) {
355+
while matches!(self.peek(), Some(TokenType::And)) {
356+
self.advance(); self.parse_not(); self.chunk.emit(OpCode::And, 0);
357+
}
358+
}
359+
fn cmp_tail(&mut self) {
360+
match self.peek() {
361+
Some(TokenType::EqEqual) => { self.advance(); self.parse_add(); self.chunk.emit(OpCode::Eq, 0); }
362+
Some(TokenType::NotEqual) => { self.advance(); self.parse_add(); self.chunk.emit(OpCode::NotEq, 0); }
363+
Some(TokenType::Less) => { self.advance(); self.parse_add(); self.chunk.emit(OpCode::Lt, 0); }
364+
Some(TokenType::Greater) => { self.advance(); self.parse_add(); self.chunk.emit(OpCode::Gt, 0); }
365+
Some(TokenType::LessEqual) => { self.advance(); self.parse_add(); self.chunk.emit(OpCode::LtEq, 0); }
366+
Some(TokenType::GreaterEqual) => { self.advance(); self.parse_add(); self.chunk.emit(OpCode::GtEq, 0); }
367+
_ => {}
368+
}
369+
}
370+
fn add_tail(&mut self) {
371+
while matches!(self.peek(), Some(TokenType::Plus | TokenType::Minus)) {
372+
match self.peek() {
373+
Some(TokenType::Plus) => { self.advance(); self.parse_mul(); self.chunk.emit(OpCode::Add, 0); }
374+
Some(TokenType::Minus) => { self.advance(); self.parse_mul(); self.chunk.emit(OpCode::Sub, 0); }
375+
_ => break,
376+
}
377+
}
378+
}
379+
fn mul_tail(&mut self) {
380+
while matches!(self.peek(), Some(TokenType::Star | TokenType::Slash)) {
381+
match self.peek() {
382+
Some(TokenType::Star) => { self.advance(); self.parse_unary(); self.chunk.emit(OpCode::Mul, 0); }
383+
Some(TokenType::Slash) => { self.advance(); self.parse_unary(); self.chunk.emit(OpCode::Div, 0); }
384+
_ => break,
385+
}
386+
}
387+
}
388+
389+
fn expr(&mut self) { self.parse_or(); }
390+
391+
fn parse_or(&mut self) { self.parse_and(); self.or_tail(); }
392+
fn parse_and(&mut self) { self.parse_not(); self.and_tail(); }
393+
fn parse_add(&mut self) { self.parse_mul(); self.add_tail(); }
394+
fn parse_mul(&mut self) { self.parse_unary(); self.mul_tail(); }
395+
fn parse_cmp(&mut self) { self.parse_add(); self.cmp_tail(); }
396+
397+
fn parse_unary(&mut self) {
398+
match self.peek() {
399+
Some(TokenType::Minus) => { self.advance(); self.parse_unary(); self.chunk.emit(OpCode::Minus, 0); }
400+
Some(TokenType::Not) => { self.advance(); self.parse_unary(); self.chunk.emit(OpCode::Not, 0); }
401+
_ => self.parse_atom(),
402+
}
403+
}
404+
405+
fn parse_not(&mut self) {
406+
if matches!(self.peek(), Some(TokenType::Not)) {
407+
self.advance(); self.parse_not(); self.chunk.emit(OpCode::Not, 0);
408+
} else {
409+
self.parse_cmp();
410+
}
411+
}
412+
413+
fn parse_atom(&mut self) {
414+
let t = self.advance();
415+
match t.kind {
416+
TokenType::Name => self.name(t),
417+
TokenType::String => self.emit_const(Value::Str(parse_string(self.lexeme(&t)))),
418+
TokenType::Int | TokenType::Float => self.parse_number(self.lexeme(&t), t.kind),
419+
TokenType::True => self.emit_const(Value::Bool(true)),
420+
TokenType::False => self.emit_const(Value::Bool(false)),
421+
TokenType::None => self.emit_const(Value::None),
422+
TokenType::FstringStart => self.fstring(),
423+
TokenType::Lbrace => self.dict_literal(),
424+
TokenType::Lsqb => self.list_literal(),
425+
TokenType::Lpar => { self.expr(); self.eat(TokenType::Rpar); }
426+
_ => {}
427+
}
360428
}
361429

362430
fn name(&mut self, t: Token) { // solo desde expr()
@@ -476,27 +544,15 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
476544
}
477545

478546
fn call_range(&mut self) {
479-
self.advance();
480-
let mut args = Vec::new();
547+
self.advance(); // consume '('
548+
let mut argc = 0u16;
481549
while !matches!(self.peek(), Some(TokenType::Rpar) | None) {
482-
let tok = self.advance();
483-
if let TokenType::Int = tok.kind {
484-
args.push(self.lexeme(&tok).replace('_', "").parse::<i64>().unwrap_or(0));
485-
}
550+
self.expr(); // ← cualquier expr
551+
argc += 1;
486552
if matches!(self.peek(), Some(TokenType::Comma)) { self.advance(); }
487553
}
488-
self.advance();
489-
490-
let (start, stop, step) = match args.as_slice() {
491-
[stop] => (0, *stop, 1),
492-
[start, stop] => (*start, *stop, 1),
493-
[start, stop, step] => (*start, *stop, *step),
494-
_ => (0, 0, 1),
495-
};
496-
497-
let i = self.chunk.push_const(Value::Range(start, stop, step));
498-
self.chunk.emit(OpCode::LoadConst, i);
499-
self.chunk.emit(OpCode::CallRange, 1);
554+
self.advance(); // consume ')'
555+
self.chunk.emit(OpCode::CallRange, argc); // VM recibe argc en stack
500556
}
501557

502558
fn fstring(&mut self) {

compiler/tests/cases/parser_cases.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
},
3030
{
3131
"src": "range(4)",
32-
"constants": ["Range(0, 4, 1)"],
32+
"constants": ["4"],
3333
"names": [],
34-
"instructions": [["LoadConst",0], ["CallRange",1], ["PopTop",0], ["ReturnValue",0]],
34+
"instructions": [["LoadConst", 0], ["CallRange", 1], ["PopTop", 0], ["ReturnValue", 0]],
3535
"annotations": {}
3636
},
3737
{
@@ -45,12 +45,12 @@
4545
"src": "def add(a, b): a + b\nresult = add(1, 2)",
4646
"constants": ["1", "2"],
4747
"names": ["add_1", "result_1"],
48-
"instructions": [["MakeFunction",0], ["StoreName",0], ["PopTop",0], ["LoadName",0], ["LoadConst",0], ["LoadConst",1], ["Call",2], ["StoreName",1], ["PopTop",0], ["ReturnValue",0]],
48+
"instructions": [["MakeFunction",0], ["StoreName",0], ["LoadName",0], ["LoadConst",0], ["LoadConst",1], ["Call",2], ["StoreName",1], ["PopTop",0], ["ReturnValue",0]],
4949
"annotations": {}
5050
},
5151
{
5252
"src": "total = 0\nfor i in range(5):\ntotal = total + i",
53-
"constants": ["0", "Range(0, 5, 1)"],
53+
"constants": ["0", "5"],
5454
"names": ["total_1", "i_1", "total_2"],
5555
"instructions": [["LoadConst",0], ["StoreName",0], ["PopTop",0], ["LoadConst",1], ["CallRange",1], ["GetIter",0], ["ForIter",14], ["StoreName",1], ["LoadName",0], ["LoadName",1], ["Add",0], ["StoreName",2], ["PopTop",0], ["Jump",6], ["ReturnValue",0]],
5656
"annotations": {}

compiler/tests/parser_test.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ mod parser_test {
3434
Value::Int(i) => i.to_string(),
3535
Value::Float(f) => f.to_string(),
3636
Value::Bool(b) => b.to_string(),
37-
Value::None => "None".to_string(),
38-
Value::Range(start, stop, step) => format!("Range({}, {}, {})", start, stop, step),
37+
Value::None => "None".to_string()
3938
}).collect();
4039

4140
let got_instructions: Vec<(String, u16)> = SSAChunk.instructions.iter()

0 commit comments

Comments
 (0)