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:
Guido van Rossum 2022-11-22 16:04:57 -08:00 committed by GitHub
parent f1a4a6a587
commit 8f18ac04d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 325 additions and 135 deletions

View file

@ -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()