| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | """Parser for bytecodes.inst.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from dataclasses import dataclass, field | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  | from typing import NamedTuple, Callable, TypeVar, Literal, cast | 
					
						
							| 
									
										
										
										
											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) | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |             return None | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |         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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-18 22:42:45 +09:00
										 |  |  |     def __repr__(self) -> str: | 
					
						
							| 
									
										
										
										
											2023-03-03 20:59:21 -08:00
										 |  |  |         return f"<{self.owner.filename}: {self.begin}-{self.end}>" | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @dataclass | 
					
						
							|  |  |  | class Node: | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |     context: Context | None = field(init=False, compare=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 "" | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |         return lx.to_text(self.tokens, dedent) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def tokens(self) -> list[lx.Token]: | 
					
						
							|  |  |  |         context = self.context | 
					
						
							|  |  |  |         if not context: | 
					
						
							|  |  |  |             return [] | 
					
						
							|  |  |  |         tokens = context.owner.tokens | 
					
						
							|  |  |  |         begin = context.begin | 
					
						
							|  |  |  |         end = context.end | 
					
						
							|  |  |  |         return tokens[begin:end] | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @dataclass | 
					
						
							|  |  |  | class Block(Node): | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |     # This just holds a context which has the list of tokens. | 
					
						
							|  |  |  |     pass | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 19:59:19 -08:00
										 |  |  | @dataclass | 
					
						
							| 
									
										
										
										
											2022-11-17 17:06:07 -08:00
										 |  |  | class StackEffect(Node): | 
					
						
							| 
									
										
										
										
											2023-08-04 09:35:56 -07:00
										 |  |  |     name: str = field(compare=False)  # __eq__ only uses type, cond, size | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |     type: str = ""  # Optional `:type` | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |     cond: str = ""  # Optional `if (cond)` | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |     size: str = ""  # Optional `[size]` | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |     # Note: size cannot be combined with type or cond | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-18 22:42:45 +09:00
										 |  |  |     def __repr__(self) -> str: | 
					
						
							| 
									
										
										
										
											2023-08-04 09:35:56 -07:00
										 |  |  |         items = [self.name, self.type, self.cond, self.size] | 
					
						
							|  |  |  |         while items and items[-1] == "": | 
					
						
							|  |  |  |             del items[-1] | 
					
						
							|  |  |  |         return f"StackEffect({', '.join(repr(item) for item in items)})" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | @dataclass | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  | class Expression(Node): | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |     size: str | 
					
						
							| 
									
										
										
										
											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): | 
					
						
							| 
									
										
										
										
											2023-11-07 09:42:39 +00:00
										 |  |  |     annotations : list[str] | 
					
						
							| 
									
										
										
										
											2023-06-12 11:19:04 -07: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): | 
					
						
							| 
									
										
										
										
											2023-11-07 09:42:39 +00:00
										 |  |  |     annotations : list[str] | 
					
						
							| 
									
										
										
										
											2023-06-12 11:19:04 -07:00
										 |  |  |     kind: Literal["inst", "op"] | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     name: str | 
					
						
							|  |  |  |     inputs: list[InputEffect] | 
					
						
							|  |  |  |     outputs: list[OutputEffect] | 
					
						
							| 
									
										
										
										
											2022-11-08 08:22:56 -08:00
										 |  |  |     block: Block | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 09:35:56 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 22:31:59 +01:00
										 |  |  | @dataclass | 
					
						
							|  |  |  | class Pseudo(Node): | 
					
						
							|  |  |  |     name: str | 
					
						
							|  |  |  |     targets: list[str]  # opcodes this can be replaced by | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Parser(PLexer): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     @contextual | 
					
						
							| 
									
										
										
										
											2023-06-12 10:47:08 -07:00
										 |  |  |     def definition(self) -> InstDef | Macro | Pseudo | Family | None: | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |         if macro := self.macro_def(): | 
					
						
							|  |  |  |             return macro | 
					
						
							|  |  |  |         if family := self.family_def(): | 
					
						
							|  |  |  |             return family | 
					
						
							| 
									
										
										
										
											2023-06-11 22:31:59 +01:00
										 |  |  |         if pseudo := self.pseudo_def(): | 
					
						
							|  |  |  |             return pseudo | 
					
						
							| 
									
										
										
										
											2023-11-07 09:42:39 +00:00
										 |  |  |         if inst := self.inst_def(): | 
					
						
							|  |  |  |             return inst | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											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(): | 
					
						
							| 
									
										
										
										
											2023-01-05 13:01:07 -08:00
										 |  |  |                 return InstDef( | 
					
						
							| 
									
										
										
										
											2023-11-07 09:42:39 +00:00
										 |  |  |                     hdr.annotations, | 
					
						
							| 
									
										
										
										
											2023-08-04 09:35:56 -07:00
										 |  |  |                     hdr.kind, | 
					
						
							|  |  |  |                     hdr.name, | 
					
						
							|  |  |  |                     hdr.inputs, | 
					
						
							|  |  |  |                     hdr.outputs, | 
					
						
							|  |  |  |                     block, | 
					
						
							| 
									
										
										
										
											2023-01-05 13:01:07 -08:00
										 |  |  |                 ) | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2023-11-07 09:42:39 +00:00
										 |  |  |         # annotation* inst(NAME, (inputs -- outputs)) | 
					
						
							|  |  |  |         # | annotation* op(NAME, (inputs -- outputs)) | 
					
						
							|  |  |  |         annotations = [] | 
					
						
							|  |  |  |         while anno := self.expect(lx.ANNOTATION): | 
					
						
							|  |  |  |             annotations.append(anno.text) | 
					
						
							|  |  |  |         tkn = self.expect(lx.INST) | 
					
						
							|  |  |  |         if not tkn: | 
					
						
							|  |  |  |             tkn = self.expect(lx.OP) | 
					
						
							|  |  |  |         if tkn: | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |             kind = cast(Literal["inst", "op"], tkn.text) | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2023-11-07 09:42:39 +00:00
										 |  |  |                             return InstHeader(annotations, kind, name, inp, outp) | 
					
						
							| 
									
										
										
										
											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(): | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |             inp = cast(InputEffect, inp) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |             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) | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -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
										 |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def stack_effect(self) -> StackEffect | None: | 
					
						
							| 
									
										
										
										
											2023-08-07 21:32:42 -07:00
										 |  |  |         #   IDENTIFIER [':' IDENTIFIER [TIMES]] ['if' '(' expression ')'] | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |         # | IDENTIFIER '[' expression ']' | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |         if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |             type_text = "" | 
					
						
							| 
									
										
											  
											
												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
										 |  |  |             if self.expect(lx.COLON): | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |                 type_text = self.require(lx.IDENTIFIER).text.strip() | 
					
						
							| 
									
										
										
										
											2023-08-07 21:32:42 -07:00
										 |  |  |                 if self.expect(lx.TIMES): | 
					
						
							|  |  |  |                     type_text += " *" | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |             cond_text = "" | 
					
						
							|  |  |  |             if self.expect(lx.IF): | 
					
						
							|  |  |  |                 self.require(lx.LPAREN) | 
					
						
							|  |  |  |                 if not (cond := self.expression()): | 
					
						
							|  |  |  |                     raise self.make_syntax_error("Expected condition") | 
					
						
							|  |  |  |                 self.require(lx.RPAREN) | 
					
						
							|  |  |  |                 cond_text = cond.text.strip() | 
					
						
							|  |  |  |             size_text = "" | 
					
						
							|  |  |  |             if self.expect(lx.LBRACKET): | 
					
						
							|  |  |  |                 if type_text or cond_text: | 
					
						
							|  |  |  |                     raise self.make_syntax_error("Unexpected [") | 
					
						
							|  |  |  |                 if not (size := self.expression()): | 
					
						
							|  |  |  |                     raise self.make_syntax_error("Expected expression") | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |                 self.require(lx.RBRACKET) | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |                 type_text = "PyObject **" | 
					
						
							|  |  |  |                 size_text = size.text.strip() | 
					
						
							|  |  |  |             return StackEffect(tkn.text, type_text, cond_text, size_text) | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |     def expression(self) -> Expression | None: | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |         tokens: list[lx.Token] = [] | 
					
						
							| 
									
										
										
										
											2023-02-07 17:35:55 -08:00
										 |  |  |         level = 1 | 
					
						
							|  |  |  |         while tkn := self.peek(): | 
					
						
							|  |  |  |             if tkn.kind in (lx.LBRACKET, lx.LPAREN): | 
					
						
							|  |  |  |                 level += 1 | 
					
						
							|  |  |  |             elif tkn.kind in (lx.RBRACKET, lx.RPAREN): | 
					
						
							|  |  |  |                 level -= 1 | 
					
						
							|  |  |  |                 if level == 0: | 
					
						
							|  |  |  |                     break | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |             tokens.append(tkn) | 
					
						
							|  |  |  |             self.next() | 
					
						
							|  |  |  |         if not tokens: | 
					
						
							|  |  |  |             return None | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |         return Expression(lx.to_text(tokens).strip()) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-12 10:47:08 -07:00
										 |  |  |     # def ops(self) -> list[OpName] | None: | 
					
						
							|  |  |  |     #     if op := self.op(): | 
					
						
							|  |  |  |     #         ops = [op] | 
					
						
							|  |  |  |     #         while self.expect(lx.PLUS): | 
					
						
							|  |  |  |     #             if op := self.op(): | 
					
						
							|  |  |  |     #                 ops.append(op) | 
					
						
							|  |  |  |     #         return ops | 
					
						
							| 
									
										
										
										
											2022-11-06 09:40:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |     @contextual | 
					
						
							|  |  |  |     def op(self) -> OpName | None: | 
					
						
							|  |  |  |         if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							|  |  |  |             return OpName(tkn.text) | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @contextual | 
					
						
							|  |  |  |     def macro_def(self) -> Macro | None: | 
					
						
							| 
									
										
										
										
											2023-11-07 09:42:39 +00:00
										 |  |  |         if tkn := self.expect(lx.MACRO): | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def uops(self) -> list[UOp] | None: | 
					
						
							|  |  |  |         if uop := self.uop(): | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |             uop = cast(UOp, uop) | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |             uops = [uop] | 
					
						
							|  |  |  |             while self.expect(lx.PLUS): | 
					
						
							|  |  |  |                 if uop := self.uop(): | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |                     uop = cast(UOp, uop) | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  |                     uops.append(uop) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     raise self.make_syntax_error("Expected op name or cache effect") | 
					
						
							|  |  |  |             return uops | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @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) | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-12-02 19:57:30 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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)): | 
					
						
							| 
									
										
										
										
											2023-09-07 14:39:03 +01:00
										 |  |  |                             if not (size := self.expect(lx.NUMBER)): | 
					
						
							|  |  |  |                                 raise self.make_syntax_error("Expected identifier or number") | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-11 22:31:59 +01:00
										 |  |  |     @contextual | 
					
						
							|  |  |  |     def pseudo_def(self) -> Pseudo | None: | 
					
						
							|  |  |  |         if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "pseudo": | 
					
						
							|  |  |  |             size = None | 
					
						
							|  |  |  |             if self.expect(lx.LPAREN): | 
					
						
							|  |  |  |                 if tkn := self.expect(lx.IDENTIFIER): | 
					
						
							|  |  |  |                     if self.expect(lx.RPAREN): | 
					
						
							|  |  |  |                         if self.expect(lx.EQUALS): | 
					
						
							|  |  |  |                             if not self.expect(lx.LBRACE): | 
					
						
							|  |  |  |                                 raise self.make_syntax_error("Expected {") | 
					
						
							|  |  |  |                             if members := self.members(): | 
					
						
							|  |  |  |                                 if self.expect(lx.RBRACE) and self.expect(lx.SEMI): | 
					
						
							| 
									
										
										
										
											2023-08-04 09:35:56 -07:00
										 |  |  |                                     return Pseudo(tkn.text, members) | 
					
						
							| 
									
										
										
										
											2023-06-11 22:31:59 +01: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 | 
					
						
							| 
									
										
										
										
											2023-01-29 17:28:39 -08:00
										 |  |  |     def block(self) -> Block | None: | 
					
						
							| 
									
										
										
										
											2023-01-17 15:59:19 -08:00
										 |  |  |         if self.c_blob(): | 
					
						
							|  |  |  |             return Block() | 
					
						
							| 
									
										
										
										
											2023-07-24 09:38:23 -07:00
										 |  |  |         return None | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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): | 
					
						
							| 
									
										
										
										
											2023-01-13 17:06:45 -08:00
										 |  |  |             tokens.append(tkn) | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |             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 | 
					
						
							|  |  |  |         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: | 
					
						
							| 
									
										
										
										
											2023-06-12 10:47:08 -07:00
										 |  |  |             with open(filename, "r") as f: | 
					
						
							| 
									
										
										
										
											2022-11-02 21:31:26 -07:00
										 |  |  |                 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) |