3
3
from enum import Enum , EnumMeta
4
4
from types import resolve_bases
5
5
6
- from pyecore .ecore import EAttribute , ECollection , EObject , EPackage , EReference , MetaEClass , EBoolean , EString , EInt , EEnum
6
+ from pyecore .ecore import EAttribute , ECollection , EObject , EPackage , EReference , MetaEClass , EBoolean , EString , EInt , \
7
+ EEnum
7
8
from pyecore .resources import Resource
8
-
9
9
from pylasu import StrumentaLanguageSupport as starlasu
10
10
from pylasu .StrumentaLanguageSupport import ASTNode
11
11
from pylasu .emf .model import find_eclassifier
14
14
15
15
16
16
class MetamodelBuilder :
17
- def __init__ (self , package_name : str , ns_uri : str , ns_prefix : str = None , resource : Resource = None ):
17
+ def __init__ (self , package_name : str , ns_uri : str , ns_prefix : str = None , resource : Resource = None ,
18
+ base_node_class : type = Node ):
18
19
self .package = EPackage (package_name , ns_uri , ns_prefix )
19
20
if resource :
20
21
resource .append (self .package )
@@ -23,13 +24,14 @@ def __init__(self, package_name: str, ns_uri: str, ns_prefix: str = None, resour
23
24
int : EInt ,
24
25
str : EString ,
25
26
}
27
+ self .base_node_class = base_node_class
26
28
self .forward_references = []
27
29
28
30
def can_provide_class (self , cls : type ):
29
31
return cls .__module__ == self .package .name
30
32
31
33
def provide_class (self , cls : type ):
32
- if cls == Node :
34
+ if cls == self . base_node_class :
33
35
return ASTNode
34
36
if not self .can_provide_class (cls ):
35
37
if self .package .eResource :
@@ -44,15 +46,17 @@ def provide_class(self, cls: type):
44
46
"position" : EReference ("position" , starlasu .Position , containment = True )
45
47
}
46
48
for attr in anns if anns else []:
47
- if is_dataclass (cls ):
49
+ if attr .startswith ('_' ):
50
+ continue
51
+ elif is_dataclass (cls ):
48
52
field = next ((f for f in fields (cls ) if f .name == attr ), None )
49
53
if isinstance (field , InternalField ):
50
54
continue
51
55
attr_type = anns [attr ]
52
56
nmspc [attr ] = self .to_structural_feature (attr , attr_type )
53
57
bases = []
54
58
for c in cls .__mro__ [1 :]:
55
- if c == Node :
59
+ if c == self . base_node_class :
56
60
bases .append (ASTNode )
57
61
elif self .can_provide_class (c ):
58
62
bases .append (self .provide_class (c ))
@@ -69,7 +73,15 @@ def provide_class(self, cls: type):
69
73
self .forward_references = [(t , r ) for t , r in self .forward_references if not r .eType ]
70
74
return eclass
71
75
72
- def to_structural_feature (self , attr , attr_type ):
76
+ def to_structural_feature (self , attr , attr_type , unsupported_type_handler = None ):
77
+ def raise_on_unsupported_type (attr_type , attr ):
78
+ raise Exception ("Unsupported type " + str (attr_type ) + " for attribute " + attr )
79
+
80
+ def default_unsupported_type (_ , __ ):
81
+ return EObject
82
+
83
+ if not unsupported_type_handler :
84
+ unsupported_type_handler = raise_on_unsupported_type
73
85
if isinstance (attr_type , str ):
74
86
resolved = self .package .getEClassifier (attr_type )
75
87
if resolved :
@@ -82,21 +94,24 @@ def to_structural_feature(self, attr, attr_type):
82
94
return EAttribute (attr , self .data_types [attr_type ])
83
95
elif attr_type == object :
84
96
return EAttribute (attr )
85
- elif isinstance (attr_type , type ) and issubclass (attr_type , Node ):
97
+ elif isinstance (attr_type , type ) and issubclass (attr_type , self . base_node_class ):
86
98
return EReference (attr , self .provide_class (attr_type ), containment = True )
87
- elif typing .get_origin (attr_type ) == list :
99
+ elif isinstance (typing .get_origin (attr_type ), type ) and \
100
+ issubclass (typing .get_origin (attr_type ), typing .Sequence ):
88
101
type_args = typing .get_args (attr_type )
89
102
if type_args and len (type_args ) == 1 :
90
- ft = self .to_structural_feature (attr , type_args [0 ])
103
+ ft = self .to_structural_feature (attr , type_args [0 ], default_unsupported_type )
91
104
ft .upperBound = - 1
92
105
return ft
106
+ elif typing .get_origin (attr_type ) == typing .Union :
107
+ return EReference (attr , EObject , containment = True ) # TODO here we could refine the type better
93
108
elif isinstance (attr_type , EnumMeta ) and issubclass (attr_type , Enum ):
94
109
tp = EEnum (name = attr_type .__name__ , literals = attr_type .__members__ )
95
110
tp .ePackage = self .package
96
111
self .data_types [attr_type ] = tp
97
112
return EAttribute (attr , tp )
98
113
else :
99
- raise Exception ( "Unsupported type " + str ( attr_type ) + " for attribute " + attr )
114
+ return unsupported_type_handler ( attr_type , attr )
100
115
101
116
def generate (self ):
102
117
if self .forward_references :
0 commit comments