Skip to content

Commit 61313b6

Browse files
committed
#15 and #16: improve Ecore support and support of transpilation traces.
1 parent ef98171 commit 61313b6

File tree

7 files changed

+633
-17
lines changed

7 files changed

+633
-17
lines changed

pylasu/StrumentaLanguageSupport/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
ASTNode.destination.eType = Destination
2626
Issue.position.eType = Position
2727
# TODO eGenericType not supported ReferenceByName.referenced.eType =
28+
ReferenceByName.referenced.eType = ASTNode
2829
# TODO eGenericType not supported
2930
Result.root.eType = ASTNode
3031
Result.issues.eType = Issue

pylasu/emf/metamodel_builder.py

+26-11
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
from enum import Enum, EnumMeta
44
from types import resolve_bases
55

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
78
from pyecore.resources import Resource
8-
99
from pylasu import StrumentaLanguageSupport as starlasu
1010
from pylasu.StrumentaLanguageSupport import ASTNode
1111
from pylasu.emf.model import find_eclassifier
@@ -14,7 +14,8 @@
1414

1515

1616
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):
1819
self.package = EPackage(package_name, ns_uri, ns_prefix)
1920
if resource:
2021
resource.append(self.package)
@@ -23,13 +24,14 @@ def __init__(self, package_name: str, ns_uri: str, ns_prefix: str = None, resour
2324
int: EInt,
2425
str: EString,
2526
}
27+
self.base_node_class = base_node_class
2628
self.forward_references = []
2729

2830
def can_provide_class(self, cls: type):
2931
return cls.__module__ == self.package.name
3032

3133
def provide_class(self, cls: type):
32-
if cls == Node:
34+
if cls == self.base_node_class:
3335
return ASTNode
3436
if not self.can_provide_class(cls):
3537
if self.package.eResource:
@@ -44,15 +46,17 @@ def provide_class(self, cls: type):
4446
"position": EReference("position", starlasu.Position, containment=True)
4547
}
4648
for attr in anns if anns else []:
47-
if is_dataclass(cls):
49+
if attr.startswith('_'):
50+
continue
51+
elif is_dataclass(cls):
4852
field = next((f for f in fields(cls) if f.name == attr), None)
4953
if isinstance(field, InternalField):
5054
continue
5155
attr_type = anns[attr]
5256
nmspc[attr] = self.to_structural_feature(attr, attr_type)
5357
bases = []
5458
for c in cls.__mro__[1:]:
55-
if c == Node:
59+
if c == self.base_node_class:
5660
bases.append(ASTNode)
5761
elif self.can_provide_class(c):
5862
bases.append(self.provide_class(c))
@@ -69,7 +73,15 @@ def provide_class(self, cls: type):
6973
self.forward_references = [(t, r) for t, r in self.forward_references if not r.eType]
7074
return eclass
7175

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
7385
if isinstance(attr_type, str):
7486
resolved = self.package.getEClassifier(attr_type)
7587
if resolved:
@@ -82,21 +94,24 @@ def to_structural_feature(self, attr, attr_type):
8294
return EAttribute(attr, self.data_types[attr_type])
8395
elif attr_type == object:
8496
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):
8698
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):
88101
type_args = typing.get_args(attr_type)
89102
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)
91104
ft.upperBound = -1
92105
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
93108
elif isinstance(attr_type, EnumMeta) and issubclass(attr_type, Enum):
94109
tp = EEnum(name=attr_type.__name__, literals=attr_type.__members__)
95110
tp.ePackage = self.package
96111
self.data_types[attr_type] = tp
97112
return EAttribute(attr, tp)
98113
else:
99-
raise Exception("Unsupported type " + str(attr_type) + " for attribute " + attr)
114+
return unsupported_type_handler(attr_type, attr)
100115

101116
def generate(self):
102117
if self.forward_references:

pylasu/emf/model.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def to_eobject(self: Node, resource: Resource, mappings=None):
3434
if mappings is None:
3535
mappings = {}
3636
elif id(self) in mappings:
37-
return mappings[self]
37+
return mappings[id(self)]
3838
eclass = resource.find_eclassifier(type(self))
3939
if not eclass:
4040
raise Exception("Unknown classifier for " + str(type(self)))

pylasu/playground/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
from .transpilation_trace import TranspilationTrace
2-
from .transpilation_trace_ecore import TranspilationTrace as ETranspilationTrace
2+
from .transpilation_trace_ecore import JsonResource, TranspilationTrace as ETranspilationTrace

pylasu/playground/transpilation_trace.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from pyecore.resources import Resource, ResourceSet, URI
66

77
from pylasu import StrumentaLanguageSupport as starlasu
8-
from pylasu.emf.model import to_eobject
98
from pylasu.playground.transpilation_trace_ecore import TranspilationTrace as ETranspilationTrace, JsonResource
109
from pylasu.validation.validation import Result, Issue
1110

@@ -22,8 +21,8 @@ def to_eobject(self, resource: Resource):
2221
mappings = {}
2322
return ETranspilationTrace(
2423
original_code=self.original_code,
25-
source_result=starlasu.Result(root=to_eobject(self.source_result.root, resource, mappings)),
26-
target_result=starlasu.Result(root=to_eobject(self.target_result.root, resource, mappings)),
24+
source_result=starlasu.Result(root=self.source_result.root.to_eobject(resource, mappings)),
25+
target_result=starlasu.Result(root=self.target_result.root.to_eobject(resource, mappings)),
2726
generated_code=self.generated_code
2827
)
2928

pylasu/playground/transpilation_trace_ecore.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from io import IOBase, BytesIO
22

3-
from pyecore.ecore import EObject, MetaEClass, EAttribute, EString, EReference
3+
import pyecore.ecore
4+
from pyecore.ecore import EObject, MetaEClass, EAttribute, EString, EReference, EDataType
45
from pyecore.resources import ResourceSet, URI
56

67
from pyecore.resources.json import JsonResource as BaseJsonResource
@@ -19,6 +20,13 @@ def open_out_stream(self, other=None):
1920
else:
2021
return super().open_out_stream(other)
2122

23+
@staticmethod
24+
def serialize_eclass(eclass):
25+
if eclass.name == "EEnum" and issubclass(eclass, EDataType):
26+
return f'{pyecore.ecore.nsURI}#//EEnum'
27+
else:
28+
return f'{eclass.eRoot().nsURI}{eclass.eURIFragment()}'
29+
2230

2331
class TranspilationTrace(EObject, metaclass=MetaEClass):
2432
# Note: we use camelCase here because Pyecore's JSON serialization doesn't handle having different names for

0 commit comments

Comments
 (0)