Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief Parses :epkg:`C# `.
5"""
6from antlr4.tree.Tree import TerminalNodeImpl
7from antlr4 import ParseTreeWalker
8from ..languages.antlr_grammar_use import get_parser_lexer, parse_code
9from ..languages.CSharpParserListener import CSharpParserListener
12class CSharpElement:
13 """
14 Base class of a :epkg:`C#` element.
15 """
17 _kinds = {'class', 'method', 'domain', 'type'}
18 _privates = {'public', 'private', 'protected'}
20 def __init__(self, domain, name, doc=None, source=None, code=None, **kwargs):
21 """
22 @param domain domain
23 @param name name
24 @param doc documentation
25 @param source source file
26 @param code code
27 """
28 self.name = name
29 self.doc = doc
30 self.domain = domain
31 self.source = source
32 self.code = code
33 self.options = kwargs
35 def __str__(self):
36 """
37 usual
38 """
39 return f"{self.name}"
42class CSharpDomain(CSharpElement):
43 """
44 Base class of a :epkg:`C#` domaon.
45 """
47 def __init__(self, domain, name, doc=None, source=None, code=None, **kwargs):
48 """
49 @param domain domain
50 @param name name
51 @param doc documentation
52 @param source source file
53 @param code code
54 """
55 if "{" in domain or "{" in name:
56 raise ValueError(
57 "Issue with domain name\ndomain={0}\nname={1}".format(domain, name))
58 CSharpElement.__init__(self, domain, name, doc, source, code, **kwargs)
60 def __str__(self):
61 """
62 usual
63 """
64 return f"namespace {self.name}"
67class CSharpVariable(CSharpElement):
68 """
69 :epkg:`C#` variables
70 """
72 def __init__(self, domain, name, typ, value=None, doc=None, source=None, code=None, **kwargs):
73 """
74 @param domain domain
75 @param name name
76 @param typ type
77 @param value default value if it exists
78 @param doc documentation
79 @param source source file
80 @param code code
81 """
82 CSharpElement.__init__(self, domain, name, doc=doc,
83 source=source, code=code, **kwargs)
84 if not isinstance(typ, CSharpType):
85 raise TypeError("typ must be of type CSharpType")
86 self.type = typ
87 self.value = value
89 def __str__(self):
90 """
91 usual
92 """
93 if isinstance(self.value, str):
94 v = self.value.replace('"', '\\"')
95 value = f'"{v}"'
96 else:
97 value = self.value
98 return f"{self.type} {self.name} = {value}"
101class CSharpType(CSharpVariable):
102 """
103 :epkg:`C#` type
104 """
106 def __init__(self, domain, name, typ, doc=None, source=None, code=None, **kwargs):
107 """
108 @param domain domain
109 @param name name
110 @param typ type
111 @param source source file
112 @param code code
113 """
114 CSharpVariable.__init__(
115 self, domain, name, typ=typ, doc=doc, source=source, code=code, **kwargs)
117 def __str__(self):
118 """
119 usual
120 """
121 return f"{self.name}"
124class CSharpMethod(CSharpElement):
125 """
126 :epkg:`C#` function.
127 """
129 def __init__(self, domain, name, rtype, params=None, private='public',
130 static=False, doc=None, source=None, code=None, **kwargs):
131 """
132 @param domain domain
133 @param name name
134 @param rtype return type
135 @param private private, public or protected
136 @param static static or not
137 @param parameters parameters
138 @param doc documentation
139 @param code code
140 """
141 CSharpElement.__init__(self, domain, name, doc=doc,
142 source=source, code=code, **kwargs)
143 if private not in CSharpElement._privates:
144 raise ValueError(
145 f"Unable to find '{private}' in {CSharpElement._privates}.")
146 self.params = params
147 self.source = source
148 self.static = static
149 self.private = private
150 self.rtype = rtype
152 def __str__(self):
153 """
154 usual
155 """
156 pars = ", ".join(str(p) for p in self.params)
157 return f"{self.domain}.{self.name} ({self.kind})"
160class CSharpClass(CSharpElement):
161 """
162 :epkg:`C#` class.
163 """
165 def __init__(self, domain, name, methods=None, constants=None,
166 params=None, private='public', static=False,
167 doc=None, source=None, code=None, **kwargs):
168 """
169 @param domain domain
170 @param name name
171 @param methods methods
172 @param constants constants
173 @param private private, public or protected
174 @param static static or not
175 @param doc documentation
176 @param source source file
177 @param code code
178 """
179 CSharpElement.__init__(self, domain, name, doc=doc,
180 source=source, code=code, **kwargs)
181 if private not in CSharpElement._privates:
182 raise ValueError(
183 f"Unable to find '{private}' in {CSharpElement._privates}.")
184 self.source = source
185 self.static = static
186 self.private = private
187 self.methods = methods
188 self.contansts = constants
190 def __str__(self):
191 """
192 usual
193 """
194 return f"class {self.domain}.{self.name}"
197class CSharpParserListenerSignatures(CSharpParserListener):
198 """
199 :epkg:`C#` Listener
200 """
202 def __init__(self, parser, source):
203 """
204 constructor
206 @param parser parser used to parse the code
207 """
208 CSharpParserListener.__init__(self)
209 self.buffer = []
210 self.parser = parser
211 self._elements = []
212 self._context = []
213 self._obj = None
214 self._source = source
216 def stack_element(self, el):
217 """
218 Adds an element.
219 """
220 self._obj = el
222 def enter_body(self):
223 """
224 Adds an element.
225 """
226 if self._obj is None:
227 raise RuntimeError("self._obj cannot be None")
228 self._context.append(self._obj)
230 def exit_body(self):
231 """
232 Adds an element.
233 """
234 el = self._context.pop()
235 if el is None:
236 raise RuntimeError("el cannot be None")
237 self._elements.append(el)
239 # def enterEveryRule(self, ctx):
240 # pass
242 # def leaveEveryRule(self, ctx):
243 # pass
245 def get_code(self, ctx):
246 line, col = ctx.start.line, ctx.start.column
247 class_name = ctx.__class__.__name__
248 return class_name, line, col
250 def enumerate_all_children(self, ctx):
251 """
252 Enumerate all children.
254 @param ctx context
255 @return iterator
256 """
258 def roll(ctx):
259 if not isinstance(ctx, TerminalNodeImpl):
260 yield ctx
261 for ch in ctx.getChildren():
262 for r in roll(ch):
263 yield r
264 for r in roll(ctx):
265 yield r
267 ############
268 # namespace
269 ############
271 def enterNamespace_declaration(self, ctx):
272 self._namespace_code = ctx.getText()
274 def enterNamespace_body(self, ctx):
275 pass
277 def enterNamespace_or_type_name(self, ctx):
278 code = getattr(self, '_namespace_code', None)
279 if code:
280 self._namespace_code = None
281 name = ctx.getText()
282 children = list(self.enumerate_all_children(ctx))
283 line1 = ctx.start.line
284 line2 = ctx.stop.line
285 self.stack_element(CSharpDomain(
286 name, name, code=code, source=self._source, lines=[line1, line2]))
287 self.enter_body()
289 def exitNamespace_or_type_name(self, ctx):
290 pass
292 def exitNamespace_body(self, ctx):
293 self.exit_body()
295 def exitNamespace_declaration(self, ctx):
296 pass
299class CSharpParser:
300 """
301 Parses :epkg:`C#`.
302 """
304 def __init__(self):
305 """
306 """
307 clparser, cllexer = get_parser_lexer("C#")
308 self._parser = clparser
309 self._lexer = cllexer
311 def parse(self, code, source=None):
312 """
313 Returns all elements of codes inside a string.
315 @param code string
316 @param source source
317 @return list of @see cl CSharpElement
318 """
319 self._source = source
320 parser = parse_code(code, self._parser, self._lexer)
321 tree = parser.compilation_unit()
322 walker = ParseTreeWalker()
323 listen = CSharpParserListenerSignatures(parser, source)
324 walker.walk(listen, tree)
325 return listen._elements