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