11import ast
22import keyword
3+ from _ast import ClassDef
34from pathlib import Path
45from typing import List , Dict
56
67import astor
7- from lionwebpython .language import Language , Concept , Interface , Containment , Property
8+ from lionwebpython .language import Language , Concept , Interface , Containment , Property , Feature
89from lionwebpython .language .classifier import Classifier
910from lionwebpython .language .enumeration import Enumeration
1011from lionwebpython .language .primitive_type import PrimitiveType
1516from pylasu .lionweb .utils import calculate_field_name
1617
1718
18- def topological_classifiers_sort (classifiers : List [Classifier ]) -> List [Classifier ]:
19- id_to_concept = {el .get_id (): el for el in classifiers }
20-
21- # Build graph edges: child -> [parents]
19+ def _identify_topological_deps (classifiers : List [Classifier ], id_to_concept ) -> Dict [str , List [str ]]:
2220 graph : Dict [str , List [str ]] = {el .get_id (): [] for el in classifiers }
2321 for c in classifiers :
2422 if isinstance (c , Concept ):
@@ -34,6 +32,14 @@ def topological_classifiers_sort(classifiers: List[Classifier]) -> List[Classifi
3432 pass
3533 else :
3634 raise ValueError ()
35+ return graph
36+
37+
38+ def topological_classifiers_sort (classifiers : List [Classifier ]) -> List [Classifier ]:
39+ id_to_concept = {el .get_id (): el for el in classifiers }
40+
41+ # Build graph edges: child -> [parents]
42+ graph : Dict [str , List [str ]] = _identify_topological_deps (classifiers , id_to_concept )
3743
3844 visited = set ()
3945 sorted_list = []
@@ -54,6 +60,99 @@ def visit(name: str):
5460 return sorted_list
5561
5662
63+ def _generate_from_containment (feature : Containment , classdef : ClassDef ):
64+ field_name = calculate_field_name (feature )
65+ type = feature .get_type ().get_name ()
66+ if feature .is_multiple ():
67+ type = f"List[{ type } ]"
68+ elif feature .is_optional ():
69+ type = f"Optional[{ type } ]"
70+ field = ast .AnnAssign (
71+ target = ast .Name (id = field_name , ctx = ast .Store ()),
72+ annotation = ast .Constant (value = type ),
73+ value = None ,
74+ simple = 1 ,
75+ )
76+ if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
77+ classdef .body = []
78+ classdef .body .append (field )
79+
80+
81+ def _generate_from_feature (feature : Feature , classdef : ClassDef ):
82+ if isinstance (feature , Containment ):
83+ _generate_from_containment (feature , classdef )
84+ elif isinstance (feature , Reference ):
85+ field_name = feature .get_name ()
86+ if field_name in keyword .kwlist :
87+ field_name = f"{ field_name } _"
88+ type = f"ReferenceByName[{ feature .get_type ().get_name ()} ]"
89+ if feature .is_optional ():
90+ type = f"Optional[{ type } ]"
91+ field = ast .AnnAssign (
92+ target = ast .Name (id = field_name , ctx = ast .Store ()),
93+ annotation = ast .Constant (value = type ),
94+ value = None ,
95+ simple = 1 ,
96+ )
97+ if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
98+ classdef .body = []
99+ classdef .body .append (field )
100+ elif isinstance (feature , Property ):
101+ field_name = feature .get_name ()
102+ if field_name in keyword .kwlist :
103+ field_name = f"{ field_name } _"
104+ type = feature .get_type ().get_name ()
105+ if feature .is_optional ():
106+ type = f"Optional[{ type } ]"
107+ field = ast .AnnAssign (
108+ target = ast .Name (id = field_name , ctx = ast .Store ()),
109+ annotation = ast .Constant (value = type ),
110+ value = None ,
111+ simple = 1 ,
112+ )
113+ if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
114+ classdef .body = []
115+ classdef .body .append (field )
116+ else :
117+ raise ValueError ()
118+
119+
120+ def _generate_from_concept (classifier : Concept ) -> ClassDef :
121+ bases = []
122+ if classifier .get_extended_concept ().id == StarLasuBaseLanguage .get_astnode (LionWebVersion .V2023_1 ).id :
123+ if len (classifier .get_implemented ()) == 0 :
124+ bases .append ('Node' )
125+ else :
126+ bases .append (classifier .get_extended_concept ().get_name ())
127+ special_interfaces = {
128+ 'com-strumenta-StarLasu-Expression-id' : 'StarLasuExpression' ,
129+ 'com-strumenta-StarLasu-Statement-id' : 'StarLasuStatement' ,
130+ 'com-strumenta-StarLasu-PlaceholderElement-id' : 'StarLasuPlaceholderElement' ,
131+ 'com-strumenta-StarLasu-Parameter-id' : 'StarLasuParameter' ,
132+ 'com-strumenta-StarLasu-Documentation-id' : 'StarLasuDocumentation' ,
133+ 'com-strumenta-StarLasu-BehaviorDeclaration-id' : 'StarLasuBehaviorDeclaration' ,
134+ 'com-strumenta-StarLasu-EntityDeclaration-id' : 'StarLasuEntityDeclaration' ,
135+ 'LionCore-builtins-INamed' : 'StarLasuNamed'
136+ }
137+ for i in classifier .get_implemented ():
138+ if i .get_id () in special_interfaces :
139+ bases .append (special_interfaces [i .get_id ()])
140+ else :
141+ bases .append (i .get_name ())
142+ # if classifier.is_abstract():
143+ # bases.append('ABC')
144+ dataclass_decorator = ast .Name (id = "dataclass" , ctx = ast .Load ())
145+ classdef = ast .ClassDef (classifier .get_name (), bases = bases ,
146+ keywords = [],
147+ body = [ast .Pass ()],
148+ decorator_list = [dataclass_decorator ])
149+
150+ for feature in classifier .get_features ():
151+ _generate_from_feature (feature , classdef )
152+
153+ return classdef
154+
155+
57156def ast_generation (click , language : Language , output ):
58157 import_abc = ast .ImportFrom (
59158 module = 'abc' ,
@@ -127,94 +226,7 @@ def ast_generation(click, language: Language, output):
127226
128227 for classifier in sorted_classifier :
129228 if isinstance (classifier , Concept ):
130- bases = []
131- if classifier .get_extended_concept ().id == StarLasuBaseLanguage .get_astnode (LionWebVersion .V2023_1 ).id :
132- if len (classifier .get_implemented ()) == 0 :
133- bases .append ('Node' )
134- else :
135- bases .append (classifier .get_extended_concept ().get_name ())
136- for i in classifier .get_implemented ():
137- if i .get_id () == 'com-strumenta-StarLasu-Expression-id' :
138- bases .append ('StarLasuExpression' )
139- elif i .get_id () == 'com-strumenta-StarLasu-Statement-id' :
140- bases .append ('StarLasuStatement' )
141- elif i .get_id () == 'com-strumenta-StarLasu-PlaceholderElement-id' :
142- bases .append ('StarLasuPlaceholderElement' )
143- elif i .get_id () == 'com-strumenta-StarLasu-Parameter-id' :
144- bases .append ('StarLasuParameter' )
145- elif i .get_id () == 'com-strumenta-StarLasu-Documentation-id' :
146- bases .append ('StarLasuDocumentation' )
147- elif i .get_id () == 'com-strumenta-StarLasu-TypeAnnotation-id' :
148- bases .append ('StarLasuTypeAnnotation' )
149- elif i .get_id () == 'com-strumenta-StarLasu-BehaviorDeclaration-id' :
150- bases .append ('StarLasuBehaviorDeclaration' )
151- elif i .get_id () == 'com-strumenta-StarLasu-EntityDeclaration-id' :
152- bases .append ('StarLasuEntityDeclaration' )
153- elif i .get_id () == 'LionCore-builtins-INamed' :
154- bases .append ('StarLasuNamed' )
155- else :
156- bases .append (i .get_name ())
157- # if classifier.is_abstract():
158- # bases.append('ABC')
159- dataclass_decorator = ast .Name (id = "dataclass" , ctx = ast .Load ())
160- classdef = ast .ClassDef (classifier .get_name (), bases = bases ,
161- keywords = [],
162- body = [ast .Pass ()],
163- decorator_list = [dataclass_decorator ])
164-
165- for feature in classifier .get_features ():
166- if isinstance (feature , Containment ):
167- field_name = calculate_field_name (feature )
168- type = feature .get_type ().get_name ()
169- if feature .is_multiple ():
170- type = f"List[{ type } ]"
171- elif feature .is_optional ():
172- type = f"Optional[{ type } ]"
173- field = ast .AnnAssign (
174- target = ast .Name (id = field_name , ctx = ast .Store ()),
175- annotation = ast .Constant (value = type ),
176- value = None ,
177- simple = 1 ,
178- )
179- if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
180- classdef .body = []
181- classdef .body .append (field )
182- elif isinstance (feature , Reference ):
183- field_name = feature .get_name ()
184- if field_name in keyword .kwlist :
185- field_name = f"{ field_name } _"
186- type = f"ReferenceByName[{ feature .get_type ().get_name ()} ]"
187- if feature .is_optional ():
188- type = f"Optional[{ type } ]"
189- field = ast .AnnAssign (
190- target = ast .Name (id = field_name , ctx = ast .Store ()),
191- annotation = ast .Constant (value = type ),
192- value = None ,
193- simple = 1 ,
194- )
195- if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
196- classdef .body = []
197- classdef .body .append (field )
198- elif isinstance (feature , Property ):
199- field_name = feature .get_name ()
200- if field_name in keyword .kwlist :
201- field_name = f"{ field_name } _"
202- type = feature .get_type ().get_name ()
203- if feature .is_optional ():
204- type = f"Optional[{ type } ]"
205- field = ast .AnnAssign (
206- target = ast .Name (id = field_name , ctx = ast .Store ()),
207- annotation = ast .Constant (value = type ),
208- value = None ,
209- simple = 1 ,
210- )
211- if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
212- classdef .body = []
213- classdef .body .append (field )
214- else :
215- raise ValueError ()
216-
217- module .body .append (classdef )
229+ module .body .append (_generate_from_concept (classifier ))
218230 elif isinstance (classifier , Interface ):
219231 bases = []
220232 if len (classifier .get_extended_interfaces ()) == 0 :
0 commit comments