summaryrefslogtreecommitdiff
path: root/lib9p/idl/__init__.py
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-01-14 20:14:46 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-01-14 20:14:46 -0700
commit287e11381634b879dc82b23eacb693a31c52f9ef (patch)
tree236d11893dafb8f45141fdacc7d6f47cc0aa8529 /lib9p/idl/__init__.py
parentf7c75fe0113cdbd3e13b4e22edf76d9456c4b064 (diff)
parent6e48efec92b3357b2b762d14994d2f812a3b6ef7 (diff)
Merge branch 'lukeshu/9p-idl-defs'
Diffstat (limited to 'lib9p/idl/__init__.py')
-rw-r--r--lib9p/idl/__init__.py31
1 files changed, 25 insertions, 6 deletions
diff --git a/lib9p/idl/__init__.py b/lib9p/idl/__init__.py
index 920d02d..ab45ed0 100644
--- a/lib9p/idl/__init__.py
+++ b/lib9p/idl/__init__.py
@@ -1,12 +1,12 @@
# lib9p/idl/__init__.py - A parser for .9p specification files.
#
-# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+# Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
# SPDX-License-Identifier: AGPL-3.0-or-later
import enum
import os.path
import re
-from typing import Callable, Literal, TypeAlias, TypeVar, cast
+from typing import Callable, Literal, TypeVar, cast
__all__ = [
# entrypoint
@@ -50,8 +50,11 @@ class Number:
prim: Primitive
+ vals: dict[str, str]
+
def __init__(self) -> None:
self.in_versions = set()
+ self.vals = {}
@property
def static_size(self) -> int:
@@ -181,8 +184,7 @@ class Message(Struct):
return self.members[1].val.tokens[0].val
-Type: TypeAlias = Primitive | Number | Bitfield | Struct | Message
-# type Type = Primitive | Number | Bitfield | Struct | Message # Change to this once we have Python 3.13
+type Type = Primitive | Number | Bitfield | Struct | Message
T = TypeVar("T", Number, Bitfield, Struct, Message)
# Parse ########################################################################
@@ -196,12 +198,27 @@ re_memtype = f"(?:{re_symname}|{re_priname})" # typenames that a struct member
re_expr = f"(?:(?:-|\\+|[0-9]+|&?{re_symname})+)"
+re_numspec = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>\\S+)"
+
re_bitspec_bit = f"(?P<bit>[0-9]+)\\s*=\\s*(?P<name>{re_symname})"
re_bitspec_alias = f"(?P<name>{re_symname})\\s*=\\s*(?P<val>\\S+)"
re_memberspec = f"(?:(?P<cnt>{re_symname})\\*\\()?(?P<name>{re_symname})\\[(?P<typ>{re_memtype})(?:,max=(?P<max>{re_expr})|,val=(?P<val>{re_expr}))*\\]\\)?"
+def parse_numspec(ver: str, n: Number, spec: str) -> None:
+ spec = spec.strip()
+
+ if m := re.fullmatch(re_numspec, spec):
+ name = m.group("name")
+ val = m.group("val")
+ if name in n.vals:
+ raise ValueError(f"{n.name}: name {repr(name)} already assigned")
+ n.vals[name] = val
+ else:
+ raise SyntaxError(f"invalid num spec {repr(spec)}")
+
+
def parse_bitspec(ver: str, bf: Bitfield, spec: str) -> None:
spec = spec.strip()
@@ -266,7 +283,7 @@ def parse_members(ver: str, env: dict[str, Type], struct: Struct, specs: str) ->
raise ValueError(f"duplicate member name {repr(member.name)}")
if m.group("typ") not in env:
- raise NameError(f"Unknown type {repr(m.group(2))}")
+ raise NameError(f"Unknown type {repr(m.group('typ'))}")
member.typ = env[m.group("typ")]
if cnt := m.group("cnt"):
@@ -434,6 +451,8 @@ def parse_file(
match prev:
case Bitfield():
parse_bitspec(version, prev, m.group("specs"))
+ case Number():
+ parse_numspec(version, prev, m.group("specs"))
case Struct(): # and Message()
parse_members(version, env, prev, m.group("specs"))
case _:
@@ -448,7 +467,7 @@ def parse_file(
typs: list[Type] = [x for x in env.values() if not isinstance(x, Primitive)]
for typ in [typ for typ in typs if isinstance(typ, Struct)]:
- valid_syms = ["end", *["&" + m.name for m in typ.members]]
+ valid_syms = ["end", "s32_max", "s64_max", *["&" + m.name for m in typ.members]]
for member in typ.members:
for tok in [*member.max.tokens, *member.val.tokens]:
if isinstance(tok, ExprSym) and tok.name not in valid_syms: