1
+ import base64
2
+ import re
3
+ from typing import Optional
4
+
5
+ from lionwebpython .language import Language , Concept , Property , Containment
6
+ from lionwebpython .language .classifier import Classifier
7
+ from lionwebpython .language .lioncore_builtins import LionCoreBuiltins
8
+ from lionwebpython .model .classifier_instance_utils import ClassifierInstanceUtils
9
+ from lionwebpython .model .impl .dynamic_node import DynamicNode
10
+ from lionwebpython .model .node import Node
11
+ from lionwebpython .lionweb_version import LionWebVersion
12
+ from lionwebpython .serialization .json_serialization import JsonSerialization
13
+
14
+ LW_REFERENCE_VERSION = LionWebVersion .V2023_1
15
+
16
+ CODEBASE_LANGUAGE = Language (lion_web_version = LW_REFERENCE_VERSION , name = "Codebase" ,
17
+ id = "strumenta-codebase" , version = "1" , key = "strumenta-codebase" )
18
+
19
+ CODEBASE_FILE = Concept (lion_web_version = LW_REFERENCE_VERSION , name = "CodebaseFile" ,
20
+ id = "strumenta-codebase-file" , key = "strumenta-codebase-file" )
21
+ CODEBASE_LANGUAGE .add_element (CODEBASE_FILE )
22
+
23
+ CODEBASE_FILE_LANGUAGE_NAME = Property (lion_web_version = LW_REFERENCE_VERSION , name = "language_name" ,
24
+ id = "strumenta-codebase-file-language-name" )
25
+ CODEBASE_FILE .add_feature (CODEBASE_FILE_LANGUAGE_NAME )
26
+ CODEBASE_FILE_LANGUAGE_NAME .set_key ("strumenta-codebase-file-language-name" )
27
+ CODEBASE_FILE_LANGUAGE_NAME .set_optional (False )
28
+ CODEBASE_FILE_LANGUAGE_NAME .set_type (LionCoreBuiltins .get_string (LW_REFERENCE_VERSION ))
29
+
30
+ CODEBASE_FILE_RELATIVE_PATH = Property (lion_web_version = LW_REFERENCE_VERSION , name = "relative_path" ,
31
+ id = "strumenta-codebase-file-relative-path" )
32
+ CODEBASE_FILE .add_feature (CODEBASE_FILE_RELATIVE_PATH )
33
+ CODEBASE_FILE_RELATIVE_PATH .set_key ("strumenta-codebase-file-relative-path" )
34
+ CODEBASE_FILE_RELATIVE_PATH .set_optional (False )
35
+ CODEBASE_FILE_RELATIVE_PATH .set_type (LionCoreBuiltins .get_string (LW_REFERENCE_VERSION ))
36
+
37
+ CODEBASE_FILE_CODE = Property (lion_web_version = LW_REFERENCE_VERSION , name = "code" ,
38
+ id = "strumenta-codebase-file-code" )
39
+ CODEBASE_FILE .add_feature (CODEBASE_FILE_CODE )
40
+ CODEBASE_FILE_CODE .set_key ("strumenta-codebase-file-code" )
41
+ CODEBASE_FILE_CODE .set_optional (False )
42
+ CODEBASE_FILE_CODE .set_type (LionCoreBuiltins .get_string (LW_REFERENCE_VERSION ))
43
+
44
+ CODEBASE_FILE_AST = Containment (lion_web_version = LW_REFERENCE_VERSION , name = "ast" ,
45
+ id = "strumenta-codebase-file-ast" )
46
+ CODEBASE_FILE .add_feature (CODEBASE_FILE_AST )
47
+ CODEBASE_FILE_AST .set_key ("strumenta-codebase-file-ast" )
48
+ CODEBASE_FILE_AST .set_optional (True )
49
+ CODEBASE_FILE_AST .set_multiple (False )
50
+ CODEBASE_FILE_AST .set_type (LionCoreBuiltins .get_node (LW_REFERENCE_VERSION ))
51
+
52
+
53
+ def to_lionweb_identifier (s : str ) -> str :
54
+ """
55
+ Converts a given string into a valid LionWeb identifier.
56
+
57
+ Rules:
58
+ - Starts with a letter (a-z, A-Z) or underscore (_)
59
+ - Only contains letters, digits (0-9), and underscores (_)
60
+ - Replaces invalid characters with underscores (_)
61
+ - Ensures the identifier does not start with a digit
62
+
63
+ Args:
64
+ s (str): Input string to be converted.
65
+
66
+ Returns:
67
+ str: Valid LionWeb identifier.
68
+ """
69
+ # Replace invalid characters with underscores
70
+ s = re .sub (r'[^a-zA-Z0-9_]' , '_' , s )
71
+
72
+ # Ensure it does not start with a digit by prefixing with "_"
73
+ if s and s [0 ].isdigit ():
74
+ s = "_" + s
75
+
76
+ # Ensure the identifier is not empty
77
+ return s if s else "_"
78
+
79
+ class CodebaseFile (DynamicNode ):
80
+ language_name : str
81
+ relative_path : str
82
+ code : str
83
+ ast : Optional [Node ]
84
+
85
+ @property
86
+ def language_name (self ):
87
+ return ClassifierInstanceUtils .get_property_value_by_name (self , 'language_name' )
88
+
89
+ @language_name .setter
90
+ def language_name (self , value ):
91
+ ClassifierInstanceUtils .set_property_value_by_name (self , 'language_name' , value )
92
+
93
+ @property
94
+ def relative_path (self ):
95
+ return ClassifierInstanceUtils .get_property_value_by_name (self , 'relative_path' )
96
+
97
+ @relative_path .setter
98
+ def relative_path (self , value ):
99
+ ClassifierInstanceUtils .set_property_value_by_name (self , 'relative_path' , value )
100
+
101
+ @property
102
+ def code (self ):
103
+ return ClassifierInstanceUtils .get_property_value_by_name (self , 'code' )
104
+
105
+ @code .setter
106
+ def code (self , value ):
107
+ ClassifierInstanceUtils .set_property_value_by_name (self , 'code' , value )
108
+
109
+ @property
110
+ def ast (self ):
111
+ containment = self .get_classifier ().get_containment_by_name ('ast' )
112
+ children = self .get_children (containment = containment )
113
+ if len (children ) == 0 :
114
+ return None
115
+ else :
116
+ return children [0 ]
117
+
118
+ @ast .setter
119
+ def ast (self , value ):
120
+ containment = self .get_classifier ().get_containment_by_name ('ast' )
121
+ children = self .get_children (containment = containment )
122
+ if value is None :
123
+ if len (children ) != 0 :
124
+ self .remove_child (child = children [0 ])
125
+ else :
126
+ if len (children ) != 0 :
127
+ self .remove_child (child = children [0 ])
128
+ self .add_child (containment = containment , child = value )
129
+
130
+ def __init__ (self , language_name : str , relative_path : str , code : str , ast : Optional [Node ] = None , id : Optional [str ] = None ):
131
+ super ().__init__ (id or f"codebase_file_{ to_lionweb_identifier (relative_path )} " , CODEBASE_FILE )
132
+ self .language_name = language_name
133
+ self .relative_path = relative_path
134
+ self .code = code
135
+ self .ast = ast
136
+
137
+
138
+ def codebase_deserializer (classifier , serialized_instance ,
139
+ deserialized_instances_by_id , properties_values ) -> CodebaseFile :
140
+ language_name = properties_values [classifier .get_property_by_name ('language_name' )]
141
+ relative_path = properties_values [classifier .get_property_by_name ('relative_path' )]
142
+ code = properties_values [classifier .get_property_by_name ('code' )]
143
+ return CodebaseFile (language_name = language_name , relative_path = relative_path , code = code , id = serialized_instance .id )
144
+
145
+
146
+ def register_codebase_deserializers (jsonser : JsonSerialization ):
147
+ jsonser .instantiator .register_custom_deserializer (CODEBASE_FILE .get_id (), codebase_deserializer )
0 commit comments