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

2@file 

3@brief Convert R into Python 

4""" 

5import sys 

6from antlr4 import ParseTreeListener, ParseTreeWalker 

7from pyquickhelper.pycode import remove_extra_spaces_and_pep8 

8from .RParser import RParser 

9from .RLexer import RLexer 

10from .antlr_grammar_use import parse_code 

11 

12 

13class R2PyConversionError(Exception): 

14 """ 

15 Raised when conversion cannot be done. 

16 """ 

17 

18 def __init__(self, node, message, sofar, sostack): 

19 """ 

20 """ 

21 try: 

22 text = node.symbol.text 

23 except AttributeError: 

24 text = "ERROR" 

25 mes = "Unable to convert\n'{0}'\n{1}\n{2}\nPARENT\n'{3}'\n{4}\n---SOFAR---\n{5}\n---SOSTACK---\n{6}\n---END---".format( 

26 text, type(node), node, ("" if isinstance( 

27 node, str) else node.parentCtx), 

28 (str if isinstance(node, str) else type(node.parentCtx)), sofar, sostack) 

29 mes += "\n------------\nMESSAGE=\n" + str(message) 

30 Exception.__init__(self, mes) 

31 

32 

33class TreeStringListener(ParseTreeListener): 

34 """ 

35 This class is an attempt to run through the tree and convert it into 

36 a string. 

37 """ 

38 

39 def __init__(self, parser, fLOG=None): 

40 """ 

41 constructor 

42 

43 @param parser parser used to parse the code 

44 @param fLOG logging function 

45 """ 

46 ParseTreeListener.__init__(self) 

47 self.buffer = [] 

48 self.level = 0 

49 self.parser = parser 

50 self.stack = [] 

51 self.elements = [] 

52 self.indent = 0 

53 self.block = [] 

54 self.memo = [] 

55 self.imports = set() 

56 self.in_formula = False 

57 self._fLOG = fLOG 

58 self.indent_level = {} 

59 self.add_lambda = False 

60 

61 def fLOG(self, *l, **p): 

62 """ 

63 logging 

64 """ 

65 if self._fLOG: 

66 self._fLOG(*l, **p) 

67 

68 def get_python(self): 

69 """ 

70 Get the Python code for the R code. 

71 

72 @return Python code 

73 """ 

74 def modify(s): 

75 if s.startswith("from"): 

76 return s 

77 else: 

78 return "import {0}".format(s) 

79 imports = "\n".join(modify(i) for i in sorted(self.imports)) 

80 if len(imports) > 0: 

81 imports += "\n\n" 

82 return imports + "".join(self.elements) 

83 

84 def add_code(self, node): 

85 """ 

86 Converts one node into :epkg:`python`. 

87 """ 

88 name = self.terminal_node_name(node) 

89 text = node.symbol.text 

90 

91 if self.in_formula: 

92 if text in (",", "\n"): 

93 self.stack.append(("Formop", '"')) 

94 self.in_formula = False 

95 self.fLOG("[TreeStringListener]", len(self.block), 

96 "~" if self.in_formula else " ", name, text) 

97 else: 

98 self.fLOG("[TreeStringListener]", len(self.block), " ", name, text) 

99 

100 if name == "Parse": 

101 if text.startswith("#"): 

102 # Comment 

103 self.elements.append(text.strip("\n")) 

104 self.elements.append("\n") 

105 return self.add_code_final() 

106 elif text in (";", "\n"): 

107 # End of an instruction 

108 self.empty_stack() 

109 if len(self.elements) > 0 and self.elements[-1] != '\n': 

110 self.elements.append("\n") 

111 return self.add_code_final() 

112 elif text == "<EOF>": 

113 return self.add_code_final() 

114 elif len(text.strip()) == 0: 

115 return self.add_code_final() 

116 elif name == "Identifier": 

117 name_parent = self.terminal_node_name(node.parentCtx) 

118 if name_parent == "Formula_simple_A": 

119 if self.in_formula: 

120 raise R2PyConversionError(node, name, "".join( 

121 self.elements), "\n".join(str(_) for _ in self.stack)) 

122 self.stack.append(("Formop", '"')) 

123 self.in_formula = True 

124 elif name_parent == "Functioncall": 

125 if text == "system.time": 

126 self.add_lambda = True 

127 else: 

128 self.add_lambda = False 

129 self.stack.append(("Functioncall", "")) 

130 if text == "list": 

131 self.imports.add("from python2r_helper import list_or_dict") 

132 self.stack.append((name, "list_or_dict")) 

133 elif text == "is": 

134 self.imports.add("from python2r_helper import is_") 

135 self.stack.append((name, "is_")) 

136 elif text == "(" and self.add_lambda: 

137 self.stack.append((name, "lambda: ")) 

138 self.stack.append((name, node)) 

139 else: 

140 self.stack.append((name, node)) 

141 return self.add_code_final() 

142 elif name in ("Affectop", "Comparison"): 

143 self.stack.append((name, node)) 

144 return self.add_code_final() 

145 elif name == "Constant": 

146 self.stack.append((name, node)) 

147 return self.add_code_final() 

148 elif name == "Boolean": 

149 self.stack.append((name, node)) 

150 return self.add_code_final() 

151 elif name in ("Functiondef", "Functiondefargs", "Functiondefbody"): 

152 if text == "{": 

153 self.empty_stack() 

154 if len(self.block) == 0: 

155 raise R2PyConversionError(node, name, "".join( 

156 self.elements), "\n".join(str(_) for _ in self.stack)) 

157 self.block[-1] = True 

158 return self.add_code_final() 

159 elif text == "}": 

160 self.empty_stack() 

161 if len(self.block) == 0: 

162 raise R2PyConversionError(node, name, "".join( 

163 self.elements), "\n".join(str(_) for _ in self.stack)) 

164 self.block.pop() 

165 self.indent -= 1 

166 self.fLOG( 

167 "[TreeStringListener.add_code*] indent -= 1", "--", self.indent) 

168 return self.add_code_final() 

169 elif text == '\n': 

170 return self.add_code_final() 

171 elif text in ('(', ')', 'function'): 

172 self.stack.append((name, node)) 

173 return self.add_code_final() 

174 elif name == "Functiondefargslambda": 

175 if text == "(": 

176 return self.add_code_final() 

177 elif text == ")": 

178 self.stack.append((name, ":")) 

179 return self.add_code_final() 

180 elif name == "Expr": 

181 if text.startswith("#"): 

182 # Comment 

183 self.elements.append(" " * self.indent) 

184 self.elements.append(text.strip("\n")) 

185 self.elements.append("\n") 

186 return self.add_code_final() 

187 if text in ('(', ')', '[', ']', "+", "-", "|", "&", "||", "&&", "[[", "]]"): 

188 self.stack.append((None, node)) 

189 return self.add_code_final() 

190 if text == "!": 

191 self.stack.append(("Not!", node)) 

192 return self.add_code_final() 

193 if text == "%*%": 

194 if sys.version_info[:2] >= (3, 6): 

195 self.stack.append((name, "@")) 

196 else: 

197 self.stack.append((name, "*")) 

198 return self.add_code_final() 

199 if text in ("%>%", "%<%", "%+%", "%-%", "%/%"): 

200 self.stack.append((name, text.replace("%", ""))) 

201 return self.add_code_final() 

202 if text == "\n": 

203 self.empty_stack() 

204 if len(self.elements) > 0 and self.elements[-1] != '\n': 

205 self.elements.append("\n") 

206 return self.add_code_final() 

207 if text == "break": 

208 self.stack.append((name, node)) 

209 return self.add_code_final() 

210 if text == "{": 

211 self.empty_stack() 

212 if len(self.block) == 0: 

213 # We are in an expression. 

214 self.stack.append((name, "(")) 

215 return self.add_code_final() 

216 else: 

217 self.block[-1] = True 

218 return self.add_code_final() 

219 if text == "}": 

220 # We are in an expression. 

221 self.empty_stack() 

222 if len(self.block) == 0: 

223 self.stack.append((name, ")")) 

224 return self.add_code_final() 

225 else: 

226 self.block.pop() 

227 self.indent -= 1 

228 self.fLOG( 

229 "[TreeStringListener.add_code] indent -= 1", "--", self.indent) 

230 return self.add_code_final() 

231 elif name == "Form": 

232 if text == "...": 

233 self.stack.append((None, "*args")) 

234 return self.add_code_final() 

235 else: 

236 self.stack.append((None, node)) 

237 return self.add_code_final() 

238 elif name == "Argumentname": 

239 self.stack.append((name, node)) 

240 return self.add_code_final() 

241 elif name == "Formlist": 

242 self.stack.append((None, node)) 

243 return self.add_code_final() 

244 elif name == "Functioncall": 

245 if text == ')': 

246 self.stack.append((name, node)) 

247 return self.add_code_final() 

248 if text == '(': 

249 self.stack.append((name, node)) 

250 if self.add_lambda: 

251 self.stack.append((name, "lambda: ")) 

252 return self.add_code_final() 

253 if text == '\n': 

254 return self.add_code_final() 

255 elif name == "Affectation": 

256 if text == '\n': 

257 return self.add_code_final() 

258 elif name in ("Sub", "Subnobracket"): 

259 if text == '=': 

260 # Named parameter. 

261 self.stack.append((name, node)) 

262 return self.add_code_final() 

263 if text == ':': 

264 self.stack.append((name, node)) 

265 return self.add_code_final() 

266 if text == '...': 

267 self.stack.append((name, "*args")) 

268 return self.add_code_final() 

269 elif name == "Sublist": 

270 if text == ",": 

271 self.stack.append((name, node)) 

272 return self.add_code_final() 

273 if text == '\n': 

274 return self.add_code_final() 

275 elif name in ("Exprlist", "Rightexpr"): 

276 if text.startswith("#"): 

277 # Comment 

278 self.empty_stack() 

279 self.elements.append(" ") 

280 self.elements.append(text.strip("\n")) 

281 self.elements.append("\n") 

282 return self.add_code_final() 

283 if text in (";", "\n"): 

284 if self.search_parents(node, "Inlinefunction"): 

285 self.empty_stack() 

286 self.stack.append(("Inlinefunction", text)) 

287 return self.add_code_final() 

288 else: 

289 self.empty_stack() 

290 if len(self.elements) > 0 and self.elements[-1] != '\n': 

291 self.elements.append("\n") 

292 return self.add_code_final() 

293 elif name == "Elseif": 

294 if text == "if": 

295 if id(node.parentCtx.parentCtx) not in self.indent_level: 

296 raise R2PyConversionError(node, name, "".join( 

297 self.elements), "\n".join(str(_) for _ in self.stack)) 

298 else: 

299 if self.indent_level[id(node.parentCtx.parentCtx)] != self.indent: 

300 raise R2PyConversionError(node, name, "".join( 

301 self.elements), "\n".join(str(_) for _ in self.stack)) 

302 self.stack.append((name, "elif")) 

303 return self.add_code_final() 

304 elif text == "else": 

305 # We do nothing. If follows. 

306 return self.add_code_final() 

307 else: 

308 # There should be nothing else. 

309 pass 

310 elif name == "Ifelseexpr" or name == "Ifexpr": 

311 if self.search_parents(node, "Sublist") or self.search_parents(node, "Affectation", 2): 

312 if text == "if": 

313 self.stack.append((name, node)) 

314 return self.add_code_final() 

315 elif text == "else": 

316 self.stack.append((name, node)) 

317 return self.add_code_final() 

318 elif text in ("(", ")"): 

319 self.stack.append((name, node)) 

320 return self.add_code_final() 

321 elif text == "\n": 

322 raise R2PyConversionError(node, name, "".join( 

323 self.elements), "\n".join(str(_) for _ in self.stack)) 

324 else: 

325 

326 if text == "if": 

327 self.indent_level[id(node.parentCtx)] = self.indent 

328 self.stack.append((name, node)) 

329 return self.add_code_final() 

330 elif text == "else": 

331 if id(node.parentCtx) not in self.indent_level: 

332 raise R2PyConversionError(node, name, "".join( 

333 self.elements), "\n".join(str(_) for _ in self.stack)) 

334 else: 

335 if self.indent_level[id(node.parentCtx)] != self.indent: 

336 raise R2PyConversionError(node, name, "".join( 

337 self.elements), "\n".join(str(_) for _ in self.stack)) 

338 if len(self.stack): 

339 # It does follow } 

340 self.empty_stack() 

341 if len(self.elements) > 0 and self.elements[-1] != '\n': 

342 self.elements.append("\n") 

343 

344 self.stack.append((name, node)) 

345 self.stack.append((":EOL", None)) 

346 return self.add_code_final() 

347 elif text == ")": 

348 self.stack.append((":EOL", None)) 

349 return self.add_code_final() 

350 elif text in ('(', "\n"): 

351 return self.add_code_final() 

352 elif name == "Forexpr": 

353 if text == "for": 

354 self.stack.append((name, node)) 

355 return self.add_code_final() 

356 elif text in ('(', ')'): 

357 return self.add_code_final() 

358 elif text == "in": 

359 self.stack.append((name, node)) 

360 return self.add_code_final() 

361 elif name == "Whileexpr": 

362 if text == "while": 

363 self.stack.append((name, node)) 

364 return self.add_code_final() 

365 elif text in ('(', ')'): 

366 return self.add_code_final() 

367 elif name == "Rangeop": 

368 if text == ":": 

369 self.memo.append("range") 

370 self.stack.append((name, node)) 

371 return self.add_code_final() 

372 elif text == ":::": 

373 self.stack.append(("Dotop_static", node)) 

374 return self.add_code_final() 

375 elif name == "Returnexpr": 

376 if text == "return": 

377 self.stack.append((name, node)) 

378 return self.add_code_final() 

379 if text in ('(', ')'): 

380 return self.add_code_final() 

381 elif name == "Formop": 

382 if text == "~": 

383 self.imports.add("patsy") 

384 self.stack.append((name, node)) 

385 return self.add_code_final() 

386 elif name == "Sublistadd": 

387 if text == "+": 

388 self.stack.append((name, node)) 

389 return self.add_code_final() 

390 elif text == "\n": 

391 return self.add_code_final() 

392 elif name == "Dotop": 

393 if text in ("$", "@"): 

394 self.stack.append((name, node)) 

395 return self.add_code_final() 

396 elif name == "Formula_simple_A": 

397 if text == ".": 

398 self.stack.append((None, ".")) 

399 return self.add_code_final() 

400 elif name == "Formula_simple_C": 

401 if text in ("(", ")", "~"): 

402 self.stack.append((name, node)) 

403 return self.add_code_final() 

404 elif name == "Formula_simple_B": 

405 if text == "within": 

406 self.imports.add("from python2r_helper import within") 

407 self.stack.append((name, node)) 

408 return self.add_code_final() 

409 elif text in ("(",): 

410 self.stack.append((name, node)) 

411 return self.add_code_final() 

412 elif text == "{": 

413 return self.add_code_final() 

414 elif text == "}": 

415 return self.add_code_final() 

416 elif text == ",": 

417 self.stack.append((name, node)) 

418 self.stack.append(("Formop", '"')) 

419 return self.add_code_final() 

420 elif text == ";": 

421 self.stack.append(("Formop", '"')) 

422 self.stack.append((name, ",")) 

423 self.stack.append(("Formop", '"')) 

424 return self.add_code_final() 

425 elif text == ")": 

426 self.stack.append(("Formop", '"')) 

427 self.stack.append((name, node)) 

428 return self.add_code_final() 

429 elif name == "Operator": 

430 if text == "%%": 

431 self.stack.append((name, "%")) 

432 return self.add_code_final() 

433 elif text == "^": 

434 self.stack.append((name, "**")) 

435 return self.add_code_final() 

436 else: 

437 self.stack.append((name, node)) 

438 return self.add_code_final() 

439 elif name in ("Range_simple", "Range_complexe"): 

440 if text == ":": 

441 self.stack.append((name, ",")) 

442 return self.add_code_final() 

443 else: 

444 self.stack.append((name, node)) 

445 return self.add_code_final() 

446 elif name in ("Intersection_simple", "Intersection_complexe"): 

447 if text == "%in%": 

448 self.stack.append((name, node)) 

449 return self.add_code_final() 

450 else: 

451 self.stack.append((name, node)) 

452 return self.add_code_final() 

453 elif name == "Implicit_column_name": 

454 if text == ".": 

455 self.imports.add("from python2r_helper import ImplicitColumn") 

456 self.stack.append(("Identifier", "ImplicitColumn")) 

457 self.stack.append((name, node)) 

458 return self.add_code_final() 

459 elif text in ("(", ")"): 

460 return self.add_code_final() 

461 elif name == "Inlinefunction": 

462 if text == "{": 

463 self.inlinefunction = [] 

464 self.stack.append((name, "compile_inline_function('''\n")) 

465 return self.add_code_final() 

466 elif text in ("\n", ";"): 

467 if hasattr(self, "inlinefunction") and len(self.inlinefunction) > 0: 

468 self.stack.append((name, text)) 

469 return self.add_code_final() 

470 elif text == "}": 

471 self.stack.append((name, "''')")) 

472 self.inlinefunction = [] 

473 return self.add_code_final() 

474 else: 

475 self.inlinefunction.append((name, node)) 

476 return self.add_code_final() 

477 

478 self.stack.append((name, node)) 

479 return self.add_code_final() 

480 

481 if text.startswith("#"): 

482 # Comment 

483 self.elements.append(" " * self.indent) 

484 self.elements.append(text.strip("\n")) 

485 self.elements.append("\n") 

486 return self.add_code_final() 

487 

488 raise R2PyConversionError(node, name, "".join( 

489 self.elements), "\n".join(str(_) for _ in self.stack)) 

490 

491 def add_code_final(self): 

492 """ 

493 Adds extra characters if needed. 

494 """ 

495 pass 

496 

497 def empty_stack(self): 

498 """ 

499 Empties the stack. 

500 """ 

501 if len(self.stack) > 0 and len(self.block) > 0 and not self.block[-1]: 

502 self.indent -= 1 

503 self.fLOG("[TreeStringListener.empty_stack] indent -= 1", 

504 "--", self.indent) 

505 self.block.pop() 

506 

507 is_function_def = False 

508 is_for = False 

509 as_namespace = False 

510 for ipos, (name, node) in enumerate(self.stack): 

511 if name == "Functiondef" and not self.search_parents(node, "Functiondefargslambda", 3): 

512 is_function_def = True 

513 break 

514 elif name == "Forexpr": 

515 is_for = True 

516 break 

517 elif name == "Whileexpr": 

518 is_for = True 

519 break 

520 elif name == "Identifier": 

521 text = node if isinstance(node, str) else node.symbol.text 

522 if text == "asNamespace": 

523 as_namespace = True 

524 break 

525 

526 if self.indent > 0: 

527 self.elements.append(" " * self.indent) 

528 

529 if is_function_def: 

530 self.elements.append("\n") 

531 function_name = self.stack[0][1] if isinstance( 

532 self.stack[0][1], str) else self.stack[0][1].symbol.text 

533 self.fLOG( 

534 "[TreeStringListener.empty_stack] add function '{0}'".format(function_name)) 

535 self.elements.append(" " * self.indent) 

536 self.elements.append("def") 

537 self.elements.append(" ") 

538 function_name = function_name.strip( 

539 '"').replace('.', "_").replace("-", "_") 

540 self.elements.append(function_name) 

541 self.stack = self.stack[3:] 

542 last = self.stack[-1][1].symbol.text 

543 if last != ")": 

544 raise R2PyConversionError(self.stack[-1][1], last, "".join( 

545 self.elements), "\n".join(str(_) for _ in self.stack)) 

546 

547 # We store some end character we need to add. 

548 closure = {} 

549 

550 for ipos, (name, node) in enumerate(self.stack): 

551 

552 if name == "Functioncall" and node == "": 

553 # Silent addition. 

554 continue 

555 

556 self.fLOG( 

557 " cl={0} n={1} - {2}".format(len(closure), name, node)) 

558 

559 if len(closure) > 0 and not isinstance(node, str): 

560 rem = [] 

561 for k, (leave_node, symbol) in closure.items(): 

562 b = self.has_parent(node, leave_node) 

563 if not b: 

564 rem.append(k) 

565 args = [symbol, self.terminal_node_name(leave_node), 

566 self.terminal_node_name(node), node.symbol.text] 

567 self.fLOG( 

568 " closure '{0}' - L-{1} C-{2} ({3})".format(*args)) 

569 self.elements.append(symbol) 

570 for r in rem: 

571 del closure[r] 

572 

573 converted = self.to_python(name, node) 

574 

575 if name == "Identifier": 

576 converted = converted.replace(".", "_") 

577 elif name in ("Ifexpr", "Ifelseexpr"): 

578 if node.symbol.text in ("(", ")") and (self.search_parents(node, "Sublist") or 

579 self.search_parents(node, "Affectation", 2)): 

580 self.fLOG( 

581 " inlineif {0} - '{1}'".format(name, node.symbol.text)) 

582 if node.symbol.text == "(": 

583 converted = "(" 

584 else: 

585 # We need to add ) when leaving this node. 

586 converted = "," 

587 closure[id(node.parentCtx)] = (node.parentCtx, ")") 

588 elif name == "Affectop" and self.stack[0][0] in ("Functioncall", "Inlinefunction") and \ 

589 self.stack[0][1] == "": 

590 # How to deal with syntax names(df) = something. 

591 # We add set add a bracket at the end. 

592 converted = ".set(" 

593 closure[id(node.parentCtx.parentCtx)] = ( 

594 node.parentCtx.parentCtx, ")") 

595 elif name == "Formula_simple_C": 

596 if converted == "(": 

597 self.elements.append('"') 

598 closure[id(node.parentCtx)] = (node.parentCtx, '"') 

599 

600 if as_namespace and converted == "=": 

601 converted = "." 

602 

603 if self.indent > 0 and converted and self.elements[-1] == "\n": 

604 self.elements.append(" " * self.indent) 

605 

606 self.elements.append(converted) 

607 self.elements.append(" ") 

608 if is_for and len(self.memo) > 0 and converted == "in": 

609 self.elements.append(self.memo[-1]) 

610 self.elements.append('(') 

611 if name == ":EOL": 

612 self.elements.append(":") 

613 self.elements.append("\n") 

614 self.indent += 1 

615 self.fLOG( 

616 "[TreeStringListener.empty_stack-1] indent += 1", "--", self.indent) 

617 self.block.append(False) 

618 

619 if len(closure) > 0: 

620 for k, (leave_node, symbol) in closure.items(): 

621 self.elements.append(symbol) 

622 # closure = {} 

623 

624 if is_function_def or is_for: 

625 if is_for and len(self.memo) > 0: 

626 self.elements.append(")") 

627 self.elements.append(":") 

628 self.elements.append("\n") 

629 self.indent += 1 

630 self.fLOG( 

631 "[TreeStringListener.empty_stack-2] indent += 1", "--", self.indent) 

632 self.block.append(False) 

633 

634 self.stack.clear() 

635 self.memo.clear() 

636 

637 def search_parents(self, node, substring, max_depth=None): 

638 """ 

639 Searches for a substring in parents' node name. 

640 

641 @param node current node 

642 @param substring substring to search 

643 @param max_depth number of parents to look at 

644 @return boolean 

645 """ 

646 if isinstance(node, str): 

647 return False 

648 depth = max_depth if max_depth else 0 

649 n = node.parentCtx 

650 while (max_depth is None or depth > 0) and n is not None: 

651 na = self.terminal_node_name(n) 

652 if substring in na: 

653 return True 

654 n = n.parentCtx 

655 depth -= 1 

656 return False 

657 

658 def has_parent(self, current, parent, depth=None): 

659 """ 

660 Tells if *parent* is one of the parents of *current*. 

661 

662 @param current current node 

663 @param parent parent to look for 

664 @return boolean 

665 """ 

666 if isinstance(current, str): 

667 raise NotImplementedError() 

668 if depth is None: 

669 ide = 0 

670 else: 

671 ide = depth 

672 n = current 

673 while (depth is None or ide > 0) and n is not None: 

674 if id(n) == id(parent): 

675 return True 

676 n = n.parentCtx 

677 ide -= 1 

678 return False 

679 

680 def to_python(self, name, node): 

681 """ 

682 Converts a couple *(name, node)* into :epkg:`Python`. 

683 """ 

684 if name == "Affectop": 

685 return "=" 

686 elif name == "Not": 

687 return " not " 

688 elif name == "Not!": 

689 return " ~ " 

690 elif name == "Boolean": 

691 text = node.symbol.text 

692 return text[0] + text[1:].lower() 

693 elif name == "Dotop": 

694 return "." 

695 elif name == "Dotop_static": 

696 return ".static." 

697 elif name == "Constant": 

698 text = node.symbol.text 

699 if text.startswith("`") and text.endswith("`") and len(text) > 1: 

700 return 'RCOL("{0}")'.format(text[1:-1]) 

701 if text == "NULL": 

702 return "None" 

703 if text.endswith("L"): 

704 # Integer 

705 return text[:-1] 

706 is_formula = self.search_parents(node, "Formula") 

707 if is_formula and text[0] == '"' and text[-1] == '"': 

708 return '\\"{0}\\"'.format(text[1:-1]) 

709 else: 

710 return text 

711 elif name == "Rangeop": 

712 text = node.symbol.text 

713 if text == ":": 

714 return "," 

715 else: 

716 return text 

717 elif name in ("Ifexpr", "Ifelseexpr"): 

718 text = node if isinstance(node, str) else node.symbol.text 

719 if text in ("if", "else") and (self.search_parents(node, "Sublist") or 

720 self.search_parents(node, "Affectation", 2)): 

721 if text == "if": 

722 self.imports.add("from python2r_helper import inlineif") 

723 return "inlineif" 

724 else: 

725 return "," 

726 else: 

727 return text 

728 elif name in ("Intersection_simple", "Intersection_complexe"): 

729 text = node.symbol.text 

730 if text == "%in%": 

731 return ") & set(" 

732 else: 

733 return text 

734 elif isinstance(node, str): 

735 return node 

736 elif node is None: 

737 return "" 

738 elif name == "Functiondef": 

739 if self.search_parents(node, "Functiondeflambda", 2): 

740 return "lambda" 

741 else: 

742 return node.symbol.text 

743 elif name == "Argumentname": 

744 text = node.symbol.text 

745 if text == "lambda": 

746 return "lambda_" 

747 else: 

748 return text.replace(".", "_") 

749 elif name == "Identifier": 

750 text = node.symbol.text 

751 if text == "c": 

752 # This is a tuple. 

753 self.imports.add("from python2r_helper import make_tuple") 

754 return "make_tuple" 

755 elif text == "class": 

756 parent_name = self.terminal_node_name(node.parentCtx) 

757 if parent_name in ("Functioncall", "Subnobracket"): 

758 self.imports.add("from python2r_helper import make_class") 

759 return "make_class" 

760 else: 

761 return text.replace(".", "_") 

762 elif text == "finally": 

763 self.imports.add("from python2r_helper import finallyR") 

764 return "finallyR" 

765 elif text == "lambda": 

766 return "lambda_" 

767 elif text in ("bquote", "ImplicitColumn"): 

768 self.imports.add( 

769 "from python2r_helper import {0}".format(text)) 

770 return text 

771 elif text == "try": 

772 parent_name = self.terminal_node_name(node.parentCtx) 

773 if parent_name == "Functioncall": 

774 self.imports.add("from python2r_helper import dotry") 

775 return "dotry" 

776 else: 

777 return text.replace(".", "_") 

778 else: 

779 return text.replace(".", "_") 

780 else: 

781 text = node.symbol.text 

782 if text == "c": 

783 # This is a tuple. 

784 self.imports.add("from python2r_helper import make_tuple") 

785 return "make_tuple" 

786 elif text == "&&": 

787 return "and" 

788 elif text == "||": 

789 return "or" 

790 else: 

791 return text 

792 

793 def terminal_node_name(self, node): 

794 """ 

795 Converts a terminal node into a rule name. 

796 """ 

797 return str(type(node.parentCtx)).split('.')[-1].strip("]['><").replace("Context", "") 

798 

799 def visitTerminal(self, node): 

800 """ 

801 event 

802 """ 

803 # node: ['symbol', 'parentCtx'] 

804 # node.symbol: ['source', 'type', 'channel', 'start', 'stop', 'tokenIndex', 'line', 'column', '_text'] 

805 # help(node.parentCtx) 

806 full_text = node.parentCtx.getText().replace("\n", " EOL ") 

807 text = node.symbol.text.replace("\n", " EOL ") 

808 stype = self.terminal_node_name(node) 

809 text = "{0} [{1} - {2}] {3}".format(" " * 

810 self.level, text, stype, full_text) 

811 self.buffer.append(text) 

812 self.add_code(node) 

813 

814 def visitErrorNode(self, node): 

815 """ 

816 event 

817 """ 

818 text = (" " * self.level) + "error: " + str(node) 

819 self.buffer.append(text) 

820 

821 def enterEveryRule(self, ctx): 

822 """ 

823 event 

824 """ 

825 kind = str(type(ctx)).split( 

826 ".")[-1].strip("'<>").replace("Context", "") 

827 text = (" " * self.level) + "+ {0}".format(kind) 

828 self.buffer.append(text) 

829 self.level += 1 

830 

831 def exitEveryRule(self, ctx): 

832 """ 

833 event 

834 """ 

835 self.level -= 1 

836 text = (" " * self.level) + "- " 

837 self.buffer.append(text) 

838 

839 def __str__(self): 

840 """ 

841 usual 

842 """ 

843 return self.get_python() + "\n----\n" + "\n".join(self.buffer) 

844 

845 def enterRanges(self, ctx): 

846 """ 

847 event 

848 """ 

849 self.fLOG(" add 'range('") 

850 self.stack.append(("Ranges", "range(")) 

851 

852 def exitRanges(self, ctx): 

853 """ 

854 event 

855 """ 

856 self.fLOG(" add ') # range'") 

857 self.stack.append(("Ranges", ")")) 

858 

859 def enterIntersections(self, ctx): 

860 """ 

861 event 

862 """ 

863 self.fLOG(" add 'set('") 

864 self.stack.append(("Intersections", "set(")) 

865 

866 def exitIntersections(self, ctx): 

867 """ 

868 event 

869 """ 

870 self.fLOG(" add ') # set'") 

871 self.stack.append(("Intersections", ")"))