Hide keyboard shortcuts

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 

10 

11 

12class CSharpElement: 

13 """ 

14 Base class of a :epkg:`C#` element. 

15 """ 

16 

17 _kinds = {'class', 'method', 'domain', 'type'} 

18 _privates = {'public', 'private', 'protected'} 

19 

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 

34 

35 def __str__(self): 

36 """ 

37 usual 

38 """ 

39 return f"{self.name}" 

40 

41 

42class CSharpDomain(CSharpElement): 

43 """ 

44 Base class of a :epkg:`C#` domaon. 

45 """ 

46 

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) 

59 

60 def __str__(self): 

61 """ 

62 usual 

63 """ 

64 return f"namespace {self.name}" 

65 

66 

67class CSharpVariable(CSharpElement): 

68 """ 

69 :epkg:`C#` variables 

70 """ 

71 

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 

88 

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}" 

99 

100 

101class CSharpType(CSharpVariable): 

102 """ 

103 :epkg:`C#` type 

104 """ 

105 

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) 

116 

117 def __str__(self): 

118 """ 

119 usual 

120 """ 

121 return f"{self.name}" 

122 

123 

124class CSharpMethod(CSharpElement): 

125 """ 

126 :epkg:`C#` function. 

127 """ 

128 

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 

151 

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})" 

158 

159 

160class CSharpClass(CSharpElement): 

161 """ 

162 :epkg:`C#` class. 

163 """ 

164 

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 

189 

190 def __str__(self): 

191 """ 

192 usual 

193 """ 

194 return f"class {self.domain}.{self.name}" 

195 

196 

197class CSharpParserListenerSignatures(CSharpParserListener): 

198 """ 

199 :epkg:`C#` Listener 

200 """ 

201 

202 def __init__(self, parser, source): 

203 """ 

204 constructor 

205 

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 

215 

216 def stack_element(self, el): 

217 """ 

218 Adds an element. 

219 """ 

220 self._obj = el 

221 

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) 

229 

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) 

238 

239 # def enterEveryRule(self, ctx): 

240 # pass 

241 

242 # def leaveEveryRule(self, ctx): 

243 # pass 

244 

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 

249 

250 def enumerate_all_children(self, ctx): 

251 """ 

252 Enumerate all children. 

253 

254 @param ctx context 

255 @return iterator 

256 """ 

257 

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 

266 

267 ############ 

268 # namespace 

269 ############ 

270 

271 def enterNamespace_declaration(self, ctx): 

272 self._namespace_code = ctx.getText() 

273 

274 def enterNamespace_body(self, ctx): 

275 pass 

276 

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() 

288 

289 def exitNamespace_or_type_name(self, ctx): 

290 pass 

291 

292 def exitNamespace_body(self, ctx): 

293 self.exit_body() 

294 

295 def exitNamespace_declaration(self, ctx): 

296 pass 

297 

298 

299class CSharpParser: 

300 """ 

301 Parses :epkg:`C#`. 

302 """ 

303 

304 def __init__(self): 

305 """ 

306 """ 

307 clparser, cllexer = get_parser_lexer("C#") 

308 self._parser = clparser 

309 self._lexer = cllexer 

310 

311 def parse(self, code, source=None): 

312 """ 

313 Returns all elements of codes inside a string. 

314 

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