mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
98 lines
2.5 KiB
Python
98 lines
2.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from dataclasses import dataclass
|
||
|
|
from dataclasses import field
|
||
|
|
from typing import List
|
||
|
|
from typing import Optional
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class Field:
|
||
|
|
name: str
|
||
|
|
type: str
|
||
|
|
is_array: bool = False
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class OpDef:
|
||
|
|
name: str
|
||
|
|
base: str
|
||
|
|
fields: List[Field] = field(default_factory=list)
|
||
|
|
is_terminator: bool = False # @terminator
|
||
|
|
is_nothrow: bool = False # @nothrow
|
||
|
|
|
||
|
|
|
||
|
|
def parse_bytecode_def(path: str) -> List[OpDef]:
|
||
|
|
with open(path, "r", encoding="utf-8") as f:
|
||
|
|
lines = f.readlines()
|
||
|
|
|
||
|
|
ops: List[OpDef] = []
|
||
|
|
current: Optional[OpDef] = None
|
||
|
|
in_op = False
|
||
|
|
|
||
|
|
for raw_line in lines:
|
||
|
|
stripped = raw_line.strip()
|
||
|
|
if not stripped:
|
||
|
|
continue
|
||
|
|
if stripped.startswith("//") or stripped.startswith("#"):
|
||
|
|
continue
|
||
|
|
|
||
|
|
if stripped.startswith("op "):
|
||
|
|
if in_op:
|
||
|
|
raise RuntimeError("Nested op blocks are not allowed")
|
||
|
|
in_op = True
|
||
|
|
|
||
|
|
rest = stripped[len("op ") :].strip()
|
||
|
|
if "<" in rest:
|
||
|
|
name_part, base_part = rest.split("<", 1)
|
||
|
|
name = name_part.strip()
|
||
|
|
base = base_part.strip()
|
||
|
|
else:
|
||
|
|
name = rest.strip()
|
||
|
|
base = "Instruction"
|
||
|
|
|
||
|
|
current = OpDef(name=name, base=base)
|
||
|
|
continue
|
||
|
|
|
||
|
|
if stripped == "endop":
|
||
|
|
if not in_op or current is None:
|
||
|
|
raise RuntimeError("endop without corresponding op")
|
||
|
|
ops.append(current)
|
||
|
|
current = None
|
||
|
|
in_op = False
|
||
|
|
continue
|
||
|
|
|
||
|
|
if not in_op:
|
||
|
|
continue
|
||
|
|
|
||
|
|
if stripped.startswith("@"):
|
||
|
|
if stripped == "@terminator":
|
||
|
|
current.is_terminator = True
|
||
|
|
elif stripped == "@nothrow":
|
||
|
|
current.is_nothrow = True
|
||
|
|
continue
|
||
|
|
|
||
|
|
if ":" not in stripped:
|
||
|
|
raise RuntimeError(f"Malformed field line: {stripped!r}")
|
||
|
|
lhs, rhs = stripped.split(":", 1)
|
||
|
|
field_name = lhs.strip()
|
||
|
|
field_type = rhs.strip()
|
||
|
|
is_array = False
|
||
|
|
if field_type.endswith("[]"):
|
||
|
|
is_array = True
|
||
|
|
field_type = field_type[:-2].strip()
|
||
|
|
current.fields.append(Field(name=field_name, type=field_type, is_array=is_array))
|
||
|
|
|
||
|
|
if in_op or current is not None:
|
||
|
|
raise RuntimeError("Unclosed op block at end of file")
|
||
|
|
|
||
|
|
return ops
|
||
|
|
|
||
|
|
|
||
|
|
__all__ = [
|
||
|
|
"Field",
|
||
|
|
"OpDef",
|
||
|
|
"parse_bytecode_def",
|
||
|
|
]
|