Skip to content

Commit 702cbdd

Browse files
committed
field_of function
1 parent ffba370 commit 702cbdd

File tree

3 files changed

+19
-6
lines changed

3 files changed

+19
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
All notable changes to this project from version 0.4.0 upwards are documented in this file.
33
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
44

5-
## [0.9.0]Not yet released
5+
## [0.9.0]2025-07-23
66

77
### Added
88
- `PylasuANTLRParser` class modeled after the Kolasu equivalent
9+
- _field_of_ function to make AST transformers slightly more type-safe
910

1011
## [0.8.1] – 2025-02-21
1112

pylasu/transformation/transformation.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import functools
2-
from dataclasses import dataclass, field
2+
from dataclasses import dataclass, field, Field, fields
33
from inspect import signature
44
from typing import Any, Dict, Callable, TypeVar, Generic, Optional, List, Set, Iterable, Type, Union
55

@@ -29,6 +29,14 @@ def set(self, node: Node, value):
2929
return setattr(node, self.name, value)
3030

3131

32+
def field_of(cl: type, name: str) -> Field:
33+
class_fields = fields(cl)
34+
for fld in class_fields:
35+
if fld.name == name:
36+
return fld
37+
raise Exception(f"Field {name} not found in {cl}")
38+
39+
3240
@dataclass
3341
class NodeFactory(Generic[Source, Output]):
3442
constructor: node_factory_constructor_type
@@ -37,8 +45,8 @@ class NodeFactory(Generic[Source, Output]):
3745

3846
def with_child(
3947
self,
40-
setter: Union[Callable[[Target, Optional[Child]], None], PropertyRef],
41-
getter: Union[Callable[[Source], Optional[Any]], PropertyRef],
48+
setter: Union[Callable[[Target, Optional[Child]], None], PropertyRef, Field],
49+
getter: Union[Callable[[Source], Optional[Any]], PropertyRef, Field],
4250
name: Optional[str] = None,
4351
target_type: Optional[type] = None
4452
) -> "NodeFactory[Source, Output]":
@@ -50,8 +58,12 @@ def with_child(
5058
prefix = ""
5159
if isinstance(getter, PropertyRef):
5260
getter = getter.get
61+
elif isinstance(getter, Field):
62+
getter = PropertyRef(getter.name).get
5363
if isinstance(setter, PropertyRef):
5464
setter = setter.set
65+
elif isinstance(setter, Field):
66+
setter = PropertyRef(setter.name).set
5567
self.children[prefix + name] = ChildNodeFactory(prefix + name, getter, setter)
5668
return self
5769

tests/mapping/test_parse_tree_to_ast_transformers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from pylasu.mapping.parse_tree_to_ast_transformer import ParseTreeToASTTransformer
88
from pylasu.model import Node, Named, ReferenceByName
9-
from pylasu.transformation.transformation import PropertyRef
9+
from pylasu.transformation.transformation import PropertyRef, field_of
1010
from tests.antlr_entity.AntlrEntityLexer import AntlrEntityLexer
1111
from tests.antlr_entity.AntlrEntityParser import AntlrEntityParser
1212

@@ -50,7 +50,7 @@ class ParseTreeToASTTransformerTest(unittest.TestCase):
5050
def test_simple_entities_transformer(self):
5151
transformer = ParseTreeToASTTransformer(allow_generic_node=False)
5252
transformer.register_node_factory(AntlrEntityParser.ModuleContext, lambda ctx: EModule(name=ctx.name.text)) \
53-
.with_child(PropertyRef("entities"), AntlrEntityParser.ModuleContext.entity)
53+
.with_child(field_of(EModule, "entities"), AntlrEntityParser.ModuleContext.entity)
5454
transformer.register_node_factory(AntlrEntityParser.EntityContext, lambda ctx: EEntity(name=ctx.name.text))
5555
expected_ast = EModule("M", [EEntity("FOO", []), EEntity("BAR", [])])
5656
actual_ast = transformer.transform(self.parse_entities("""

0 commit comments

Comments
 (0)