Skip to content

Commit 89c0d9b

Browse files
Feat: bugfixes, comprehensions, genexpr, annotations, edge cases.
1 parent fb27f6e commit 89c0d9b

2 files changed

Lines changed: 133 additions & 12 deletions

File tree

compiler/src/modules/parser.rs

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub enum OpCode {
3838
In, NotIn, Is, IsNot, UnpackSequence, BuildTuple,
3939
SetupWith, ExitWith, Yield, Del, Assert, Global,
4040
Nonlocal, UnpackArgs, ListComp, SetComp, DictComp, BuildSet,
41-
RaiseFrom, UnpackEx
41+
RaiseFrom, UnpackEx, LoadEllipsis, GenExpr
4242
}
4343

4444
// ─── Builtin dispatch table (O(1) lookup) ───────────────────────────────────
@@ -96,6 +96,18 @@ impl SSAChunk {
9696
self.instructions.push(Instruction { opcode: op, operand });
9797
}
9898

99+
fn snapshot(&self) -> (usize, usize, usize) {
100+
(self.instructions.len(), self.constants.len(), self.names.len())
101+
}
102+
103+
fn restore(&mut self, (inst, consts, names): (usize, usize, usize)) {
104+
self.instructions.truncate(inst);
105+
self.constants.truncate(consts);
106+
for name in self.names.drain(names..) {
107+
self.name_index.remove(&name);
108+
}
109+
}
110+
99111
fn push_const(&mut self, v: Value) -> u16 {
100112
self.constants.push(v);
101113
(self.constants.len() - 1) as u16
@@ -619,12 +631,15 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
619631

620632
fn with_stmt(&mut self) {
621633
self.advance();
622-
self.expr();
623-
self.chunk.emit(OpCode::SetupWith, 0);
624-
if self.eat_if(TokenType::As) {
625-
let t = self.advance();
626-
let name = self.lexeme(&t).to_string();
627-
self.store_name(name);
634+
loop {
635+
self.expr();
636+
self.chunk.emit(OpCode::SetupWith, 0);
637+
if self.eat_if(TokenType::As) {
638+
let t = self.advance();
639+
let name = self.lexeme(&t).to_string();
640+
self.store_name(name);
641+
}
642+
if !self.eat_if(TokenType::Comma) { break; }
628643
}
629644
self.eat(TokenType::Colon);
630645
self.compile_block();
@@ -1051,17 +1066,32 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
10511066
let t = self.advance();
10521067
match t.kind {
10531068
TokenType::Name => self.name(t),
1054-
TokenType::String => self.emit_const(Value::Str(parse_string(self.lexeme(&t)))),
1069+
TokenType::String => {
1070+
let mut s = parse_string(self.lexeme(&t));
1071+
while matches!(self.peek(), Some(TokenType::String)) {
1072+
let t = self.advance();
1073+
s.push_str(&parse_string(self.lexeme(&t)));
1074+
}
1075+
self.emit_const(Value::Str(s));
1076+
}
1077+
TokenType::Complex => {
1078+
let raw = self.lexeme(&t).replace('_', "");
1079+
let s = raw.trim_end_matches(|c: char| c == 'j' || c == 'J');
1080+
self.emit_const(Value::Float(s.parse().unwrap_or(0.0)));
1081+
}
10551082
TokenType::Int | TokenType::Float => self.parse_number(self.lexeme(&t), t.kind),
10561083
TokenType::True => self.chunk.emit(OpCode::LoadTrue, 0),
10571084
TokenType::False => self.chunk.emit(OpCode::LoadFalse, 0),
10581085
TokenType::None => self.chunk.emit(OpCode::LoadNone, 0),
1086+
TokenType::Ellipsis => self.chunk.emit(OpCode::LoadEllipsis, 0),
10591087
TokenType::FstringStart => self.fstring(),
10601088
TokenType::Lbrace => self.brace_literal(),
10611089
TokenType::Lsqb => self.list_literal(),
10621090
TokenType::Lpar => {
10631091
self.expr();
1064-
if self.eat_if(TokenType::Comma) {
1092+
if matches!(self.peek(), Some(TokenType::For)) {
1093+
self.comprehension(OpCode::GenExpr);
1094+
} else if self.eat_if(TokenType::Comma) {
10651095
let mut count = 1u16;
10661096
while !matches!(self.peek(), Some(TokenType::Rpar) | None) {
10671097
self.expr();
@@ -1254,7 +1284,7 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
12541284
let t = self.advance();
12551285
let var = self.lexeme(&t).to_string();
12561286
self.eat(TokenType::In);
1257-
self.expr();
1287+
self.parse_or();
12581288
self.chunk.emit(OpCode::GetIter, 0);
12591289

12601290
let ls = self.chunk.instructions.len() as u16;
@@ -1265,8 +1295,8 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
12651295
let idx = self.chunk.push_name(&format!("{}_{}", var, ver));
12661296
self.chunk.emit(OpCode::StoreName, idx);
12671297

1268-
if self.eat_if(TokenType::If) {
1269-
self.expr();
1298+
while self.eat_if(TokenType::If) {
1299+
self.parse_or();
12701300
self.chunk.emit(OpCode::JumpIfFalse, ls);
12711301
}
12721302

@@ -1493,12 +1523,33 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
14931523
if self.eat_if(TokenType::Star) {
14941524
let p = self.advance();
14951525
params.push(format!("*{}", self.lexeme(&p)));
1526+
if self.eat_if(TokenType::Colon) {
1527+
while !matches!(self.peek(), Some(
1528+
TokenType::Equal | TokenType::Comma | TokenType::Rpar
1529+
) | None) {
1530+
self.advance();
1531+
}
1532+
}
14961533
} else if self.eat_if(TokenType::DoubleStar) {
14971534
let p = self.advance();
14981535
params.push(format!("**{}", self.lexeme(&p)));
1536+
if self.eat_if(TokenType::Colon) {
1537+
while !matches!(self.peek(), Some(
1538+
TokenType::Equal | TokenType::Comma | TokenType::Rpar
1539+
) | None) {
1540+
self.advance();
1541+
}
1542+
}
14991543
} else {
15001544
let p = self.advance();
15011545
params.push(self.lexeme(&p).to_string());
1546+
if self.eat_if(TokenType::Colon) {
1547+
while !matches!(self.peek(), Some(
1548+
TokenType::Equal | TokenType::Comma | TokenType::Rpar
1549+
) | None) {
1550+
self.advance();
1551+
}
1552+
}
15021553
if self.eat_if(TokenType::Equal) {
15031554
self.expr();
15041555
defaults += 1;
@@ -1507,6 +1558,11 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
15071558
if matches!(self.peek(), Some(TokenType::Comma)) { self.advance(); }
15081559
}
15091560
self.advance();
1561+
if self.eat_if(TokenType::Rarrow) {
1562+
while !matches!(self.peek(), Some(TokenType::Colon) | None) {
1563+
self.advance();
1564+
}
1565+
}
15101566
if matches!(self.peek(), Some(TokenType::Colon)) { self.advance(); }
15111567
(params, defaults)
15121568
}

compiler/tests/cases/parser_cases.json

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,5 +1035,70 @@
10351035
"names": ["i_0", "i_1", "j_1", "x_1"],
10361036
"instructions": [["LoadName",0], ["LoadConst",0], ["CallRange",1], ["GetIter",0], ["ForIter",13], ["StoreName",1], ["LoadConst",1], ["CallRange",1], ["GetIter",0], ["ForIter",12], ["StoreName",2], ["Jump",9], ["Jump",4], ["ListComp",0], ["StoreName",3], ["ReturnValue",0]],
10371037
"annotations": {}
1038+
},
1039+
{
1040+
"src": "with a, b:\n pass",
1041+
"constants": [],
1042+
"names": ["a_0", "b_0"],
1043+
"instructions": [["LoadName",0], ["SetupWith",0], ["LoadName",1], ["SetupWith",0], ["ExitWith",0], ["ReturnValue",0]],
1044+
"annotations": {}
1045+
},
1046+
{
1047+
"src": "with a as x, b as y:\n pass",
1048+
"constants": [],
1049+
"names": ["a_0", "x_1", "b_0", "y_1"],
1050+
"instructions": [["LoadName",0], ["SetupWith",0], ["StoreName",1], ["LoadName",2], ["SetupWith",0], ["StoreName",3], ["ExitWith",0], ["ReturnValue",0]],
1051+
"annotations": {}
1052+
},
1053+
{
1054+
"src": "x = 'hello' ' world'",
1055+
"constants": ["hello world"],
1056+
"names": ["x_1"],
1057+
"instructions": [["LoadConst",0], ["StoreName",0], ["ReturnValue",0]],
1058+
"annotations": {}
1059+
},
1060+
{
1061+
"src": "x = 3j",
1062+
"constants": ["3"],
1063+
"names": ["x_1"],
1064+
"instructions": [["LoadConst",0], ["StoreName",0], ["ReturnValue",0]],
1065+
"annotations": {}
1066+
},
1067+
{
1068+
"src": "x = ...",
1069+
"constants": [],
1070+
"names": ["x_1"],
1071+
"instructions": [["LoadEllipsis",0], ["StoreName",0], ["ReturnValue",0]],
1072+
"annotations": {}
1073+
},
1074+
{
1075+
"src": "x = [i for i in range(10) if i > 2 if i < 8]",
1076+
"constants": ["10", "2", "8"],
1077+
"names": ["i_0", "i_1", "x_1"],
1078+
"instructions": [["LoadName",0], ["LoadConst",0], ["CallRange",1], ["GetIter",0], ["ForIter",15], ["StoreName",1], ["LoadName",1], ["LoadConst",1], ["Gt",0], ["JumpIfFalse",4], ["LoadName",1], ["LoadConst",2], ["Lt",0], ["JumpIfFalse",4], ["Jump",4], ["ListComp",0], ["StoreName",2], ["ReturnValue",0]],
1079+
"annotations": {}
1080+
},
1081+
{
1082+
"src": "x = (i for i in range(3))",
1083+
"constants": ["3"],
1084+
"names": ["i_0", "i_1", "x_1"],
1085+
"instructions": [["LoadName",0], ["LoadConst",0], ["CallRange",1], ["GetIter",0], ["ForIter",7], ["StoreName",1], ["Jump",4], ["GenExpr",0], ["StoreName",2], ["ReturnValue",0]],
1086+
"annotations": {}
1087+
},
1088+
{
1089+
"src": "def f(x: int, y: str = 'a') -> bool:\n pass",
1090+
"constants": ["a"],
1091+
"names": ["f_1"],
1092+
"instructions": [["LoadConst",0], ["MakeFunction",0], ["StoreName",0], ["ReturnValue",0]],
1093+
"annotations": {},
1094+
"functions": 1
1095+
},
1096+
{
1097+
"src": "def f() -> int:\n pass",
1098+
"constants": [],
1099+
"names": ["f_1"],
1100+
"instructions": [["MakeFunction",0], ["StoreName",0], ["ReturnValue",0]],
1101+
"annotations": {},
1102+
"functions": 1
10381103
}
10391104
]

0 commit comments

Comments
 (0)