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 = []
@@ -53,6 +59,100 @@ def visit(name: str):
5359
5460 return sorted_list
5561
62+
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+
56156def ast_generation (click , language : Language , output ):
57157 import_abc = ast .ImportFrom (
58158 module = 'abc' ,
@@ -126,98 +226,12 @@ def ast_generation(click, language: Language, output):
126226
127227 for classifier in sorted_classifier :
128228 if isinstance (classifier , Concept ):
129- bases = []
130- if classifier .get_extended_concept ().id == StarLasuBaseLanguage .get_astnode (LionWebVersion .V2023_1 ).id :
131- bases .append ('Node' )
132- else :
133- bases .append (classifier .get_extended_concept ().get_name ())
134- for i in classifier .get_implemented ():
135- if i .get_id () == 'com-strumenta-StarLasu-Expression-id' :
136- bases .append ('StarLasuExpression' )
137- elif i .get_id () == 'com-strumenta-StarLasu-Statement-id' :
138- bases .append ('StarLasuStatement' )
139- elif i .get_id () == 'com-strumenta-StarLasu-PlaceholderElement-id' :
140- bases .append ('StarLasuPlaceholderElement' )
141- elif i .get_id () == 'com-strumenta-StarLasu-Parameter-id' :
142- bases .append ('StarLasuParameter' )
143- elif i .get_id () == 'com-strumenta-StarLasu-Documentation-id' :
144- bases .append ('StarLasuDocumentation' )
145- elif i .get_id () == 'com-strumenta-StarLasu-TypeAnnotation-id' :
146- bases .append ('StarLasuTypeAnnotation' )
147- elif i .get_id () == 'com-strumenta-StarLasu-BehaviorDeclaration-id' :
148- bases .append ('StarLasuBehaviorDeclaration' )
149- elif i .get_id () == 'com-strumenta-StarLasu-EntityDeclaration-id' :
150- bases .append ('StarLasuEntityDeclaration' )
151- elif i .get_id () == 'LionCore-builtins-INamed' :
152- bases .append ('StarLasuNamed' )
153- else :
154- bases .append (i .get_name ())
155- if classifier .is_abstract ():
156- bases .append ('ABC' )
157- dataclass_decorator = ast .Name (id = "dataclass" , ctx = ast .Load ())
158- classdef = ast .ClassDef (classifier .get_name (), bases = bases ,
159- keywords = [],
160- body = [ast .Pass ()],
161- decorator_list = [dataclass_decorator ])
162-
163- for feature in classifier .get_features ():
164- if isinstance (feature , Containment ):
165- field_name = calculate_field_name (feature )
166- type = feature .get_type ().get_name ()
167- if feature .is_multiple ():
168- type = f"List[{ type } ]"
169- elif feature .is_optional ():
170- type = f"Optional[{ type } ]"
171- field = ast .AnnAssign (
172- target = ast .Name (id = field_name , ctx = ast .Store ()),
173- annotation = ast .Constant (value = type ),
174- value = None ,
175- simple = 1 ,
176- )
177- if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
178- classdef .body = []
179- classdef .body .append (field )
180- elif isinstance (feature , Reference ):
181- field_name = feature .get_name ()
182- if field_name in keyword .kwlist :
183- field_name = f"{ field_name } _"
184- type = f"ReferenceByName[{ feature .get_type ().get_name ()} ]"
185- if feature .is_optional ():
186- type = f"Optional[{ type } ]"
187- field = ast .AnnAssign (
188- target = ast .Name (id = field_name , ctx = ast .Store ()),
189- annotation = ast .Constant (value = type ),
190- value = None ,
191- simple = 1 ,
192- )
193- if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
194- classdef .body = []
195- classdef .body .append (field )
196- elif isinstance (feature , Property ):
197- field_name = feature .get_name ()
198- if field_name in keyword .kwlist :
199- field_name = f"{ field_name } _"
200- type = feature .get_type ().get_name ()
201- if feature .is_optional ():
202- type = f"Optional[{ type } ]"
203- field = ast .AnnAssign (
204- target = ast .Name (id = field_name , ctx = ast .Store ()),
205- annotation = ast .Constant (value = type ),
206- value = None ,
207- simple = 1 ,
208- )
209- if len (classdef .body ) == 1 and isinstance (classdef .body [0 ], ast .Pass ):
210- classdef .body = []
211- classdef .body .append (field )
212- else :
213- raise ValueError ()
214-
215- module .body .append (classdef )
229+ module .body .append (_generate_from_concept (classifier ))
216230 elif isinstance (classifier , Interface ):
217231 bases = []
218232 if len (classifier .get_extended_interfaces ()) == 0 :
219233 bases .append ("Node" )
220- bases .append ("ABC" )
234+ # bases.append("ABC")
221235
222236 classdef = ast .ClassDef (classifier .get_name (), bases = bases ,
223237 keywords = [],
@@ -232,4 +246,4 @@ def ast_generation(click, language: Language, output):
232246 output_path = Path (output )
233247 output_path .mkdir (parents = True , exist_ok = True )
234248 with Path (f"{ output } /ast.py" ).open ("w" , encoding = "utf-8" ) as f :
235- f .write (generated_code )
249+ f .write (generated_code )
0 commit comments