Skip to content

Commit d9a699e

Browse files
committed
Working on Deserializer Generation
1 parent 686c566 commit d9a699e

File tree

3 files changed

+113
-8
lines changed

3 files changed

+113
-8
lines changed

pylasu/lionweb/ast_generation.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from lionwebpython.lionweb_version import LionWebVersion
1313

1414
from pylasu.lionweb.starlasu import StarLasuBaseLanguage
15+
from pylasu.lionweb.utils import calculate_field_name
1516

1617

1718
def topological_classifiers_sort(classifiers: List[Classifier]) -> List[Classifier]:
@@ -161,9 +162,7 @@ def ast_generation(click, language: Language, output):
161162

162163
for feature in classifier.get_features():
163164
if isinstance(feature, Containment):
164-
field_name = feature.get_name()
165-
if field_name in keyword.kwlist:
166-
field_name = f"{field_name}_"
165+
field_name = calculate_field_name(feature)
167166
type = feature.get_type().get_name()
168167
if feature.is_multiple():
169168
type = f"List[{type}]"

pylasu/lionweb/deserializer_generation.py

+100-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from lionwebpython.lionweb_version import LionWebVersion
1313

1414
from pylasu.lionweb.starlasu import StarLasuBaseLanguage
15-
from pylasu.lionweb.utils import to_snake_case
15+
from pylasu.lionweb.utils import to_snake_case, calculate_field_name
1616

1717

1818
def make_cond(enumeration_name: str, member_name: str):
@@ -42,6 +42,95 @@ def make_return(enumeration_name: str, member_name: str):
4242
)
4343
)
4444

45+
def generate_register_deserializers_func(language: Language) -> ast.FunctionDef:
46+
fd = ast.FunctionDef(
47+
name="register_deserializers",
48+
args=ast.arguments(
49+
posonlyargs=[],
50+
args=[
51+
ast.arg(arg="json_serialization", annotation=ast.Name(id="JsonSerialization", ctx=ast.Load()))
52+
],
53+
kwonlyargs=[],
54+
kw_defaults=[],
55+
defaults=[]
56+
),
57+
body=[
58+
],
59+
decorator_list=[],
60+
returns=None
61+
)
62+
for e in language.get_elements():
63+
if isinstance(e, Enumeration):
64+
fd.body.append(ast.Expr(
65+
value=ast.Call(
66+
func=ast.Attribute(
67+
value=ast.Attribute(
68+
value=ast.Name(id="json_serialization", ctx=ast.Load()),
69+
attr="primitive_values_serialization",
70+
ctx=ast.Load()
71+
),
72+
attr="register_deserializer",
73+
ctx=ast.Load()
74+
),
75+
args=[
76+
ast.Constant(value=e.get_id()),
77+
ast.Name(id=f"_deserialize_{to_snake_case(e.get_name())}", ctx=ast.Load())
78+
],
79+
keywords=[]
80+
)
81+
))
82+
elif isinstance(e, Concept):
83+
fd.body.append(ast.Expr(
84+
value=ast.Call(
85+
func=ast.Attribute(
86+
value=ast.Attribute(
87+
value=ast.Name(id="json_serialization", ctx=ast.Load()),
88+
attr="instantiator",
89+
ctx=ast.Load()
90+
),
91+
attr="register_custom_deserializer",
92+
ctx=ast.Load()
93+
),
94+
args=[
95+
ast.Constant(value=e.get_id()),
96+
ast.Name(id=f"_deserialize_{to_snake_case(e.get_name())}", ctx=ast.Load())
97+
],
98+
keywords=[]
99+
)
100+
))
101+
return fd
102+
103+
def generate_concept_deserializer(concept: Concept) -> ast.FunctionDef:
104+
constructor_assignments = []
105+
for f in concept.all_features():
106+
field_name = calculate_field_name(f)
107+
constructor_assignments.append(ast.keyword(arg=field_name, value=ast.Constant(value=f.get_name())))
108+
return ast.FunctionDef(
109+
name=f"_deserialize_{to_snake_case(concept.get_name())}",
110+
args=ast.arguments(
111+
posonlyargs=[],
112+
args=[
113+
ast.arg(arg="classifier"),
114+
ast.arg(arg="serialized_instance"),
115+
ast.arg(arg="deserialized_instances_by_id"),
116+
ast.arg(arg="properties_values")
117+
],
118+
kwonlyargs=[],
119+
kw_defaults=[],
120+
defaults=[]
121+
),
122+
body=[
123+
ast.Return(
124+
value=ast.Call(
125+
func=ast.Name(id=concept.get_name(), ctx=ast.Load()),
126+
args=[],
127+
keywords=constructor_assignments
128+
)
129+
)
130+
],
131+
decorator_list=[],
132+
returns=ast.Name(id=concept.get_name(), ctx=ast.Load())
133+
)
45134

46135
def deserializer_generation(click, language: Language, output):
47136
import_abc = ast.ImportFrom(
@@ -92,12 +181,15 @@ def deserializer_generation(click, language: Language, output):
92181
names=[ast.alias(name=e.get_name(), asname=None) for e in language.get_elements() if isinstance(e, PrimitiveType)],
93182
level=0
94183
)
184+
import_json_serialization = ast.ImportFrom(
185+
module='lionwebpython.serialization.json_serialization',
186+
names=[ast.alias(name='JsonSerialization', asname=None)],
187+
level=0
188+
)
95189
module = ast.Module(body=[import_abc, import_dataclass, import_typing, import_enum, import_starlasu, import_node,
96-
import_ast, import_primitives],
190+
import_ast, import_primitives, import_json_serialization],
97191
type_ignores=[])
98192

99-
100-
101193
for e in language.get_elements():
102194
if isinstance(e, Enumeration):
103195
arg_serialized = ast.arg(arg="serialized", annotation=ast.Name(id="str", ctx=ast.Load()))
@@ -154,6 +246,10 @@ def deserializer_generation(click, language: Language, output):
154246
returns=ast.Constant(value=e.get_name())
155247
)
156248
module.body.append(func_def)
249+
elif isinstance(e, Concept):
250+
module.body.append(generate_concept_deserializer(e))
251+
252+
module.body.append(generate_register_deserializers_func(language))
157253

158254
generated_code = astor.to_source(module)
159255
output_path = Path(output)

pylasu/lionweb/utils.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1+
import keyword
12
import re
23

4+
from lionwebpython.language import Feature
5+
6+
37
def to_snake_case(name: str) -> str:
48
# Replace capital letters with _lowercase, except at the beginning
59
name = re.sub(r'(.)([A-Z][a-z]+)', r'\1_\2', name)
610
name = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name)
7-
return name.lower()
11+
return name.lower()
12+
13+
def calculate_field_name(feature: Feature) -> str:
14+
field_name = feature.get_name()
15+
if field_name in keyword.kwlist:
16+
field_name = f"{field_name}_"
17+
return field_name

0 commit comments

Comments
 (0)