| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | """Parser for bytecodes.inst.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from dataclasses import dataclass, field | 
					
						
							| 
									
										
										
										
											2022-11-22 16:04:57 -08:00
										 |  |  | from typing import NamedTuple, Callable, TypeVar, Literal | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | import lexer as lx | 
					
						
							|  |  |  | from plexer import PLexer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | P = TypeVar("P", bound="Parser") | 
					
						
							|  |  |  | N = TypeVar("N", bound="Node") | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def contextual(func: Callable[[P], N | None]) -> Callable[[P], N | None]: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |     # Decorator to wrap grammar methods. | 
					
						
							|  |  |  |     # Resets position if `func` returns None. | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     def contextual_wrapper(self: P) -> N | None: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         begin = self.getpos() | 
					
						
							|  |  |  |         res = func(self) | 
					
						
							|  |  |  |         if res is None: | 
					
						
							|  |  |  |             self.setpos(begin) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         end = self.getpos() | 
					
						
							|  |  |  |         res.context = Context(begin, end, self) | 
					
						
							|  |  |  |         return res | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |     return contextual_wrapper | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Context(NamedTuple): | 
					
						
							|  |  |  |     begin: int | 
					
						
							|  |  |  |     end: int | 
					
						
							|  |  |  |     owner: PLexer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return f"<{self.begin}-{self.end}>" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @dataclass | 
					
						
							|  |  |  | class Node: | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     context: Context | None = field(init=False, default=None) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def text(self) -> str: | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |         return self.to_text() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def to_text(self, dedent: int = 0) -> str: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         context = self.context | 
					
						
							|  |  |  |         if not context: | 
					
						
							|  |  |  |             return "" | 
					
						
							|  |  |  |         tokens = context.owner.tokens | 
					
						
							|  |  |  |         begin = context.begin | 
					
						
							|  |  |  |         end = context.end | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |         return lx.to_text(tokens[begin:end], dedent) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @dataclass | 
					
						
							|  |  |  | class Block(Node): | 
					
						
							|  |  |  |     tokens: list[lx.Token] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  | @dataclass | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  | class StackEffect(Node): | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |     name: str | 
					
						
							| 
									
										
											  
											
												GH-98831: Typed stack effects, and more instructions converted (#99764)
Stack effects can now have a type, e.g. `inst(X, (left, right -- jump/uint64_t)) { ... }`.
Instructions converted to the non-legacy format:
* COMPARE_OP
* COMPARE_OP_FLOAT_JUMP
* COMPARE_OP_INT_JUMP
* COMPARE_OP_STR_JUMP
* STORE_ATTR
* DELETE_ATTR
* STORE_GLOBAL
* STORE_ATTR_INSTANCE_VALUE
* STORE_ATTR_WITH_HINT
* STORE_ATTR_SLOT, and complete the store_attr family
* Complete the store_subscr family: STORE_SUBSCR{,DICT,LIST_INT}
  (STORE_SUBSCR was alread half converted,
  but wasn't using cache effects yet.)
* DELETE_SUBSCR
* PRINT_EXPR
* INTERPRETER_EXIT (a bit weird, ends in return)
* RETURN_VALUE
* GET_AITER (had to restructure it some)
  The original had mysterious `SET_TOP(NULL)` before `goto error`.
  I assume those just account for `obj` having been decref'ed,
  so I got rid of them in favor of the cleanup implied by `ERROR_IF()`.
* LIST_APPEND (a bit unhappy with it)
* SET_ADD (also a bit unhappy with it)
Various other improvements/refactorings as well.
											
										 
											2022-12-08 13:31:27 -08:00
										 |  |  |     type: str = "" | 
					
						
							|  |  |  |     # TODO: array, condition | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @dataclass | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  | class CacheEffect(Node): | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |     name: str | 
					
						
							|  |  |  |     size: int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | @dataclass | 
					
						
							|  |  |  | class OpName(Node): | 
					
						
							|  |  |  |     name: str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  | InputEffect = StackEffect | CacheEffect | 
					
						
							|  |  |  | OutputEffect = StackEffect | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | UOp = OpName | CacheEffect | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | @dataclass | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  | class InstHeader(Node): | 
					
						
							| 
									
										
										
										
											2022-11-22 16:04:57 -08:00
										 |  |  |     kind: Literal["inst", "op"] | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |     name: str | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |     inputs: list[InputEffect] | 
					
						
							|  |  |  |     outputs: list[OutputEffect] | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @dataclass | 
					
						
							|  |  |  | class InstDef(Node): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     kind: Literal["inst", "op"] | 
					
						
							|  |  |  |     name: str | 
					
						
							|  |  |  |     inputs: list[InputEffect] | 
					
						
							|  |  |  |     outputs: list[OutputEffect] | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  |     block: Block | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | @dataclass | 
					
						
							|  |  |  | class Super(Node): | 
					
						
							|  |  |  |     name: str | 
					
						
							|  |  |  |     ops: list[OpName] | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  | @dataclass | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | class Macro(Node): | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |     name: str | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     uops: list[UOp] | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | @dataclass | 
					
						
							|  |  |  | class Family(Node): | 
					
						
							|  |  |  |     name: str | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |     size: str  # Variable giving the cache size in code units | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |     members: list[str] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Parser(PLexer): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     @contextual | 
					
						
							|  |  |  |     def definition(self) -> InstDef | Super | Macro | Family | None: | 
					
						
							|  |  |  |         if inst := self.inst_def(): | 
					
						
							|  |  |  |             return inst | 
					
						
							|  |  |  |         if super := self.super_def(): | 
					
						
							|  |  |  |             return super | 
					
						
							|  |  |  |         if macro := self.macro_def(): | 
					
						
							|  |  |  |             return macro | 
					
						
							|  |  |  |         if family := self.family_def(): | 
					
						
							|  |  |  |             return family | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def inst_def(self) -> InstDef | None: | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |         if hdr := self.inst_header(): | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |             if block := self.block(): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                 return InstDef(hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |             raise self.make_syntax_error("Expected block") | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  |     def inst_header(self) -> InstHeader | None: | 
					
						
							| 
									
										
										
										
											2022-11-22 16:04:57 -08:00
										 |  |  |         # inst(NAME) | 
					
						
							|  |  |  |         #   | inst(NAME, (inputs -- outputs)) | 
					
						
							|  |  |  |         #   | op(NAME, (inputs -- outputs)) | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |         # TODO: Make INST a keyword in the lexer. | 
					
						
							| 
									
										
										
										
											2022-11-22 16:04:57 -08:00
										 |  |  |         if (tkn := self.expect(lx.IDENTIFIER)) and (kind := tkn.text) in ("inst", "op"): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |             if self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER)): | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |                 name = tkn.text | 
					
						
							|  |  |  |                 if self.expect(lx.COMMA): | 
					
						
							| 
									
										
											  
											
												GH-98831: Typed stack effects, and more instructions converted (#99764)
Stack effects can now have a type, e.g. `inst(X, (left, right -- jump/uint64_t)) { ... }`.
Instructions converted to the non-legacy format:
* COMPARE_OP
* COMPARE_OP_FLOAT_JUMP
* COMPARE_OP_INT_JUMP
* COMPARE_OP_STR_JUMP
* STORE_ATTR
* DELETE_ATTR
* STORE_GLOBAL
* STORE_ATTR_INSTANCE_VALUE
* STORE_ATTR_WITH_HINT
* STORE_ATTR_SLOT, and complete the store_attr family
* Complete the store_subscr family: STORE_SUBSCR{,DICT,LIST_INT}
  (STORE_SUBSCR was alread half converted,
  but wasn't using cache effects yet.)
* DELETE_SUBSCR
* PRINT_EXPR
* INTERPRETER_EXIT (a bit weird, ends in return)
* RETURN_VALUE
* GET_AITER (had to restructure it some)
  The original had mysterious `SET_TOP(NULL)` before `goto error`.
  I assume those just account for `obj` having been decref'ed,
  so I got rid of them in favor of the cleanup implied by `ERROR_IF()`.
* LIST_APPEND (a bit unhappy with it)
* SET_ADD (also a bit unhappy with it)
Various other improvements/refactorings as well.
											
										 
											2022-12-08 13:31:27 -08:00
										 |  |  |                     inp, outp = self.io_effect() | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  |                     if self.expect(lx.RPAREN): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                         if (tkn := self.peek()) and tkn.kind == lx.LBRACE: | 
					
						
							| 
									
										
										
										
											2022-11-22 16:04:57 -08:00
										 |  |  |                             return InstHeader(kind, name, inp, outp) | 
					
						
							|  |  |  |                 elif self.expect(lx.RPAREN) and kind == "inst": | 
					
						
							|  |  |  |                     # No legacy stack effect if kind is "op". | 
					
						
							|  |  |  |                     return InstHeader(kind, name, [], []) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												GH-98831: Typed stack effects, and more instructions converted (#99764)
Stack effects can now have a type, e.g. `inst(X, (left, right -- jump/uint64_t)) { ... }`.
Instructions converted to the non-legacy format:
* COMPARE_OP
* COMPARE_OP_FLOAT_JUMP
* COMPARE_OP_INT_JUMP
* COMPARE_OP_STR_JUMP
* STORE_ATTR
* DELETE_ATTR
* STORE_GLOBAL
* STORE_ATTR_INSTANCE_VALUE
* STORE_ATTR_WITH_HINT
* STORE_ATTR_SLOT, and complete the store_attr family
* Complete the store_subscr family: STORE_SUBSCR{,DICT,LIST_INT}
  (STORE_SUBSCR was alread half converted,
  but wasn't using cache effects yet.)
* DELETE_SUBSCR
* PRINT_EXPR
* INTERPRETER_EXIT (a bit weird, ends in return)
* RETURN_VALUE
* GET_AITER (had to restructure it some)
  The original had mysterious `SET_TOP(NULL)` before `goto error`.
  I assume those just account for `obj` having been decref'ed,
  so I got rid of them in favor of the cleanup implied by `ERROR_IF()`.
* LIST_APPEND (a bit unhappy with it)
* SET_ADD (also a bit unhappy with it)
Various other improvements/refactorings as well.
											
										 
											2022-12-08 13:31:27 -08:00
										 |  |  |     def io_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         # '(' [inputs] '--' [outputs] ')' | 
					
						
							|  |  |  |         if self.expect(lx.LPAREN): | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |             inputs = self.inputs() or [] | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |             if self.expect(lx.MINUSMINUS): | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |                 outputs = self.outputs() or [] | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |                 if self.expect(lx.RPAREN): | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |                     return inputs, outputs | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         raise self.make_syntax_error("Expected stack effect") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |     def inputs(self) -> list[InputEffect] | None: | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |         # input (',' input)* | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         here = self.getpos() | 
					
						
							|  |  |  |         if inp := self.input(): | 
					
						
							|  |  |  |             near = self.getpos() | 
					
						
							|  |  |  |             if self.expect(lx.COMMA): | 
					
						
							|  |  |  |                 if rest := self.inputs(): | 
					
						
							|  |  |  |                     return [inp] + rest | 
					
						
							|  |  |  |             self.setpos(near) | 
					
						
							|  |  |  |             return [inp] | 
					
						
							|  |  |  |         self.setpos(here) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |     @contextual | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |     def input(self) -> InputEffect | None: | 
					
						
							| 
									
										
											  
											
												GH-98831: Typed stack effects, and more instructions converted (#99764)
Stack effects can now have a type, e.g. `inst(X, (left, right -- jump/uint64_t)) { ... }`.
Instructions converted to the non-legacy format:
* COMPARE_OP
* COMPARE_OP_FLOAT_JUMP
* COMPARE_OP_INT_JUMP
* COMPARE_OP_STR_JUMP
* STORE_ATTR
* DELETE_ATTR
* STORE_GLOBAL
* STORE_ATTR_INSTANCE_VALUE
* STORE_ATTR_WITH_HINT
* STORE_ATTR_SLOT, and complete the store_attr family
* Complete the store_subscr family: STORE_SUBSCR{,DICT,LIST_INT}
  (STORE_SUBSCR was alread half converted,
  but wasn't using cache effects yet.)
* DELETE_SUBSCR
* PRINT_EXPR
* INTERPRETER_EXIT (a bit weird, ends in return)
* RETURN_VALUE
* GET_AITER (had to restructure it some)
  The original had mysterious `SET_TOP(NULL)` before `goto error`.
  I assume those just account for `obj` having been decref'ed,
  so I got rid of them in favor of the cleanup implied by `ERROR_IF()`.
* LIST_APPEND (a bit unhappy with it)
* SET_ADD (also a bit unhappy with it)
Various other improvements/refactorings as well.
											
										 
											2022-12-08 13:31:27 -08:00
										 |  |  |         return self.cache_effect() or self.stack_effect() | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |     def outputs(self) -> list[OutputEffect] | None: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         # output (, output)* | 
					
						
							|  |  |  |         here = self.getpos() | 
					
						
							|  |  |  |         if outp := self.output(): | 
					
						
							|  |  |  |             near = self.getpos() | 
					
						
							|  |  |  |             if self.expect(lx.COMMA): | 
					
						
							|  |  |  |                 if rest := self.outputs(): | 
					
						
							|  |  |  |                     return [outp] + rest | 
					
						
							|  |  |  |             self.setpos(near) | 
					
						
							|  |  |  |             return [outp] | 
					
						
							|  |  |  |         self.setpos(here) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |     @contextual | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  |     def output(self) -> OutputEffect | None: | 
					
						
							| 
									
										
											  
											
												GH-98831: Typed stack effects, and more instructions converted (#99764)
Stack effects can now have a type, e.g. `inst(X, (left, right -- jump/uint64_t)) { ... }`.
Instructions converted to the non-legacy format:
* COMPARE_OP
* COMPARE_OP_FLOAT_JUMP
* COMPARE_OP_INT_JUMP
* COMPARE_OP_STR_JUMP
* STORE_ATTR
* DELETE_ATTR
* STORE_GLOBAL
* STORE_ATTR_INSTANCE_VALUE
* STORE_ATTR_WITH_HINT
* STORE_ATTR_SLOT, and complete the store_attr family
* Complete the store_subscr family: STORE_SUBSCR{,DICT,LIST_INT}
  (STORE_SUBSCR was alread half converted,
  but wasn't using cache effects yet.)
* DELETE_SUBSCR
* PRINT_EXPR
* INTERPRETER_EXIT (a bit weird, ends in return)
* RETURN_VALUE
* GET_AITER (had to restructure it some)
  The original had mysterious `SET_TOP(NULL)` before `goto error`.
  I assume those just account for `obj` having been decref'ed,
  so I got rid of them in favor of the cleanup implied by `ERROR_IF()`.
* LIST_APPEND (a bit unhappy with it)
* SET_ADD (also a bit unhappy with it)
Various other improvements/refactorings as well.
											
										 
											2022-12-08 13:31:27 -08:00
										 |  |  |         return self.stack_effect() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def cache_effect(self) -> CacheEffect | None: | 
					
						
							|  |  |  |         # IDENTIFIER '/' NUMBER | 
					
						
							|  |  |  |         if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							|  |  |  |             if self.expect(lx.DIVIDE): | 
					
						
							|  |  |  |                 num = self.require(lx.NUMBER).text | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     size = int(num) | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     raise self.make_syntax_error(f"Expected integer, got {num!r}") | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     return CacheEffect(tkn.text, size) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def stack_effect(self) -> StackEffect | None: | 
					
						
							|  |  |  |         # IDENTIFIER [':' IDENTIFIER] | 
					
						
							|  |  |  |         # TODO: Arrays, conditions | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |         if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							| 
									
										
											  
											
												GH-98831: Typed stack effects, and more instructions converted (#99764)
Stack effects can now have a type, e.g. `inst(X, (left, right -- jump/uint64_t)) { ... }`.
Instructions converted to the non-legacy format:
* COMPARE_OP
* COMPARE_OP_FLOAT_JUMP
* COMPARE_OP_INT_JUMP
* COMPARE_OP_STR_JUMP
* STORE_ATTR
* DELETE_ATTR
* STORE_GLOBAL
* STORE_ATTR_INSTANCE_VALUE
* STORE_ATTR_WITH_HINT
* STORE_ATTR_SLOT, and complete the store_attr family
* Complete the store_subscr family: STORE_SUBSCR{,DICT,LIST_INT}
  (STORE_SUBSCR was alread half converted,
  but wasn't using cache effects yet.)
* DELETE_SUBSCR
* PRINT_EXPR
* INTERPRETER_EXIT (a bit weird, ends in return)
* RETURN_VALUE
* GET_AITER (had to restructure it some)
  The original had mysterious `SET_TOP(NULL)` before `goto error`.
  I assume those just account for `obj` having been decref'ed,
  so I got rid of them in favor of the cleanup implied by `ERROR_IF()`.
* LIST_APPEND (a bit unhappy with it)
* SET_ADD (also a bit unhappy with it)
Various other improvements/refactorings as well.
											
										 
											2022-12-08 13:31:27 -08:00
										 |  |  |             type = "" | 
					
						
							|  |  |  |             if self.expect(lx.COLON): | 
					
						
							|  |  |  |                 type = self.require(lx.IDENTIFIER).text | 
					
						
							|  |  |  |             return StackEffect(tkn.text, type) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |     def super_def(self) -> Super | None: | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |         if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "super": | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |             if self.expect(lx.LPAREN): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                 if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |                     if self.expect(lx.RPAREN): | 
					
						
							|  |  |  |                         if self.expect(lx.EQUALS): | 
					
						
							|  |  |  |                             if ops := self.ops(): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                                 self.require(lx.SEMI) | 
					
						
							|  |  |  |                                 res = Super(tkn.text, ops) | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |                                 return res | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     def ops(self) -> list[OpName] | None: | 
					
						
							|  |  |  |         if op := self.op(): | 
					
						
							|  |  |  |             ops = [op] | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |             while self.expect(lx.PLUS): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                 if op := self.op(): | 
					
						
							|  |  |  |                     ops.append(op) | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |             return ops | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     @contextual | 
					
						
							|  |  |  |     def op(self) -> OpName | None: | 
					
						
							|  |  |  |         if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							|  |  |  |             return OpName(tkn.text) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def macro_def(self) -> Macro | None: | 
					
						
							|  |  |  |         if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "macro": | 
					
						
							|  |  |  |             if self.expect(lx.LPAREN): | 
					
						
							|  |  |  |                 if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							|  |  |  |                     if self.expect(lx.RPAREN): | 
					
						
							|  |  |  |                         if self.expect(lx.EQUALS): | 
					
						
							|  |  |  |                             if uops := self.uops(): | 
					
						
							|  |  |  |                                 self.require(lx.SEMI) | 
					
						
							|  |  |  |                                 res = Macro(tkn.text, uops) | 
					
						
							|  |  |  |                                 return res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def uops(self) -> list[UOp] | None: | 
					
						
							|  |  |  |         if uop := self.uop(): | 
					
						
							|  |  |  |             uops = [uop] | 
					
						
							|  |  |  |             while self.expect(lx.PLUS): | 
					
						
							|  |  |  |                 if uop := self.uop(): | 
					
						
							|  |  |  |                     uops.append(uop) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     raise self.make_syntax_error("Expected op name or cache effect") | 
					
						
							|  |  |  |             return uops | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def uop(self) -> UOp | None: | 
					
						
							|  |  |  |         if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							|  |  |  |             if self.expect(lx.DIVIDE): | 
					
						
							|  |  |  |                 if num := self.expect(lx.NUMBER): | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         size = int(num.text) | 
					
						
							|  |  |  |                     except ValueError: | 
					
						
							|  |  |  |                         raise self.make_syntax_error( | 
					
						
							|  |  |  |                             f"Expected integer, got {num.text!r}" | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         return CacheEffect(tkn.text, size) | 
					
						
							|  |  |  |                 raise self.make_syntax_error("Expected integer") | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return OpName(tkn.text) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  |     @contextual | 
					
						
							|  |  |  |     def family_def(self) -> Family | None: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "family": | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |             size = None | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |             if self.expect(lx.LPAREN): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                 if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |                     if self.expect(lx.COMMA): | 
					
						
							|  |  |  |                         if not (size := self.expect(lx.IDENTIFIER)): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                             raise self.make_syntax_error("Expected identifier") | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |                     if self.expect(lx.RPAREN): | 
					
						
							|  |  |  |                         if self.expect(lx.EQUALS): | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |                             if not self.expect(lx.LBRACE): | 
					
						
							|  |  |  |                                 raise self.make_syntax_error("Expected {") | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |                             if members := self.members(): | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |                                 if self.expect(lx.RBRACE) and self.expect(lx.SEMI): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                                     return Family( | 
					
						
							|  |  |  |                                         tkn.text, size.text if size else "", members | 
					
						
							|  |  |  |                                     ) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  |     def members(self) -> list[str] | None: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         here = self.getpos() | 
					
						
							|  |  |  |         if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  |             members = [tkn.text] | 
					
						
							|  |  |  |             while self.expect(lx.COMMA): | 
					
						
							|  |  |  |                 if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							|  |  |  |                     members.append(tkn.text) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             peek = self.peek() | 
					
						
							|  |  |  |             if not peek or peek.kind != lx.RBRACE: | 
					
						
							|  |  |  |                 raise self.make_syntax_error("Expected comma or right paren") | 
					
						
							|  |  |  |             return members | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         self.setpos(here) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def block(self) -> Block: | 
					
						
							|  |  |  |         tokens = self.c_blob() | 
					
						
							|  |  |  |         return Block(tokens) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  |     def c_blob(self) -> list[lx.Token]: | 
					
						
							|  |  |  |         tokens: list[lx.Token] = [] | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         level = 0 | 
					
						
							|  |  |  |         while tkn := self.next(raw=True): | 
					
						
							|  |  |  |             if tkn.kind in (lx.LBRACE, lx.LPAREN, lx.LBRACKET): | 
					
						
							|  |  |  |                 level += 1 | 
					
						
							|  |  |  |             elif tkn.kind in (lx.RBRACE, lx.RPAREN, lx.RBRACKET): | 
					
						
							|  |  |  |                 level -= 1 | 
					
						
							|  |  |  |                 if level <= 0: | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |             tokens.append(tkn) | 
					
						
							|  |  |  |         return tokens | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     import sys | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |     if sys.argv[1:]: | 
					
						
							|  |  |  |         filename = sys.argv[1] | 
					
						
							|  |  |  |         if filename == "-c" and sys.argv[2:]: | 
					
						
							|  |  |  |             src = sys.argv[2] | 
					
						
							| 
									
										
										
										
											2022-11-22 16:04:57 -08:00
										 |  |  |             filename = "<string>" | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         else: | 
					
						
							|  |  |  |             with open(filename) as f: | 
					
						
							|  |  |  |                 src = f.read() | 
					
						
							|  |  |  |             srclines = src.splitlines() | 
					
						
							|  |  |  |             begin = srclines.index("// BEGIN BYTECODES //") | 
					
						
							|  |  |  |             end = srclines.index("// END BYTECODES //") | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |             src = "\n".join(srclines[begin + 1 : end]) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2022-11-22 16:04:57 -08:00
										 |  |  |         filename = "<default>" | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         src = "if (x) { x.foo; // comment\n}" | 
					
						
							|  |  |  |     parser = Parser(src, filename) | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     x = parser.definition() | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |     print(x) |