mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
GH-98831: Add macro
and op
and their implementation to DSL (#99495)
Newly supported interpreter definition syntax: - `op(NAME, (input_stack_effects -- output_stack_effects)) { ... }` - `macro(NAME) = OP1 + OP2;` Also some other random improvements: - Convert `WITH_EXCEPT_START` to use stack effects - Fix lexer to balk at unrecognized characters, e.g. `@` - Fix moved output names; support object pointers in cache - Introduce `error()` method to print errors - Introduce read_uint16(p) as equivalent to `*p` Co-authored-by: Brandt Bucher <brandtbucher@gmail.com>
This commit is contained in:
parent
f1a4a6a587
commit
8f18ac04d3
7 changed files with 325 additions and 135 deletions
|
@ -1,7 +1,7 @@
|
|||
"""Parser for bytecodes.inst."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import NamedTuple, Callable, TypeVar
|
||||
from typing import NamedTuple, Callable, TypeVar, Literal
|
||||
|
||||
import lexer as lx
|
||||
from plexer import PLexer
|
||||
|
@ -74,6 +74,7 @@ OutputEffect = StackEffect
|
|||
|
||||
@dataclass
|
||||
class InstHeader(Node):
|
||||
kind: Literal["inst", "op"]
|
||||
name: str
|
||||
inputs: list[InputEffect]
|
||||
outputs: list[OutputEffect]
|
||||
|
@ -81,9 +82,14 @@ class InstHeader(Node):
|
|||
|
||||
@dataclass
|
||||
class InstDef(Node):
|
||||
# TODO: Merge InstHeader and InstDef
|
||||
header: InstHeader
|
||||
block: Block
|
||||
|
||||
@property
|
||||
def kind(self) -> str:
|
||||
return self.header.kind
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.header.name
|
||||
|
@ -93,12 +99,13 @@ class InstDef(Node):
|
|||
return self.header.inputs
|
||||
|
||||
@property
|
||||
def outputs(self) -> list[StackEffect]:
|
||||
def outputs(self) -> list[OutputEffect]:
|
||||
return self.header.outputs
|
||||
|
||||
|
||||
@dataclass
|
||||
class Super(Node):
|
||||
kind: Literal["macro", "super"]
|
||||
name: str
|
||||
ops: list[str]
|
||||
|
||||
|
@ -122,10 +129,12 @@ class Parser(PLexer):
|
|||
|
||||
@contextual
|
||||
def inst_header(self) -> InstHeader | None:
|
||||
# inst(NAME) | inst(NAME, (inputs -- outputs))
|
||||
# inst(NAME)
|
||||
# | inst(NAME, (inputs -- outputs))
|
||||
# | op(NAME, (inputs -- outputs))
|
||||
# TODO: Error out when there is something unexpected.
|
||||
# TODO: Make INST a keyword in the lexer.
|
||||
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "inst":
|
||||
if (tkn := self.expect(lx.IDENTIFIER)) and (kind := tkn.text) in ("inst", "op"):
|
||||
if (self.expect(lx.LPAREN)
|
||||
and (tkn := self.expect(lx.IDENTIFIER))):
|
||||
name = tkn.text
|
||||
|
@ -134,9 +143,10 @@ class Parser(PLexer):
|
|||
if self.expect(lx.RPAREN):
|
||||
if ((tkn := self.peek())
|
||||
and tkn.kind == lx.LBRACE):
|
||||
return InstHeader(name, inp, outp)
|
||||
elif self.expect(lx.RPAREN):
|
||||
return InstHeader(name, [], [])
|
||||
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, [], [])
|
||||
return None
|
||||
|
||||
def stack_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]:
|
||||
|
@ -200,13 +210,13 @@ class Parser(PLexer):
|
|||
|
||||
@contextual
|
||||
def super_def(self) -> Super | None:
|
||||
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "super":
|
||||
if (tkn := self.expect(lx.IDENTIFIER)) and (kind := tkn.text) in ("super", "macro"):
|
||||
if self.expect(lx.LPAREN):
|
||||
if (tkn := self.expect(lx.IDENTIFIER)):
|
||||
if self.expect(lx.RPAREN):
|
||||
if self.expect(lx.EQUALS):
|
||||
if ops := self.ops():
|
||||
res = Super(tkn.text, ops)
|
||||
res = Super(kind, tkn.text, ops)
|
||||
return res
|
||||
|
||||
def ops(self) -> list[str] | None:
|
||||
|
@ -278,7 +288,7 @@ if __name__ == "__main__":
|
|||
filename = sys.argv[1]
|
||||
if filename == "-c" and sys.argv[2:]:
|
||||
src = sys.argv[2]
|
||||
filename = None
|
||||
filename = "<string>"
|
||||
else:
|
||||
with open(filename) as f:
|
||||
src = f.read()
|
||||
|
@ -287,7 +297,7 @@ if __name__ == "__main__":
|
|||
end = srclines.index("// END BYTECODES //")
|
||||
src = "\n".join(srclines[begin+1 : end])
|
||||
else:
|
||||
filename = None
|
||||
filename = "<default>"
|
||||
src = "if (x) { x.foo; // comment\n}"
|
||||
parser = Parser(src, filename)
|
||||
x = parser.inst_def() or parser.super_def() or parser.family_def()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue