Coverage for src/pyensae/languages/rconverterListener.py: 0%
653 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-03 02:16 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-03 02:16 +0200
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
13class R2PyConversionError(Exception):
14 """
15 Raised when conversion cannot be done.
16 """
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)
33class TreeStringListener(ParseTreeListener):
34 """
35 This class is an attempt to run through the tree and convert it into
36 a string.
37 """
39 def __init__(self, parser, fLOG=None):
40 """
41 constructor
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
61 def fLOG(self, *l, **p):
62 """
63 logging
64 """
65 if self._fLOG:
66 self._fLOG(*l, **p)
68 def get_python(self):
69 """
70 Get the Python code for the R code.
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)
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
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)
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:
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")
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()
478 self.stack.append((name, node))
479 return self.add_code_final()
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()
488 raise R2PyConversionError(node, name, "".join(
489 self.elements), "\n".join(str(_) for _ in self.stack))
491 def add_code_final(self):
492 """
493 Adds extra characters if needed.
494 """
495 pass
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()
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
526 if self.indent > 0:
527 self.elements.append(" " * self.indent)
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))
547 # We store some end character we need to add.
548 closure = {}
550 for ipos, (name, node) in enumerate(self.stack):
552 if name == "Functioncall" and node == "":
553 # Silent addition.
554 continue
556 self.fLOG(
557 " cl={0} n={1} - {2}".format(len(closure), name, node))
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]
573 converted = self.to_python(name, node)
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, '"')
600 if as_namespace and converted == "=":
601 converted = "."
603 if self.indent > 0 and converted and self.elements[-1] == "\n":
604 self.elements.append(" " * self.indent)
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)
619 if len(closure) > 0:
620 for k, (leave_node, symbol) in closure.items():
621 self.elements.append(symbol)
622 # closure = {}
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)
634 self.stack.clear()
635 self.memo.clear()
637 def search_parents(self, node, substring, max_depth=None):
638 """
639 Searches for a substring in parents' node name.
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
658 def has_parent(self, current, parent, depth=None):
659 """
660 Tells if *parent* is one of the parents of *current*.
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
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
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", "")
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)
814 def visitErrorNode(self, node):
815 """
816 event
817 """
818 text = (" " * self.level) + "error: " + str(node)
819 self.buffer.append(text)
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
831 def exitEveryRule(self, ctx):
832 """
833 event
834 """
835 self.level -= 1
836 text = (" " * self.level) + "- "
837 self.buffer.append(text)
839 def __str__(self):
840 """
841 usual
842 """
843 return self.get_python() + "\n----\n" + "\n".join(self.buffer)
845 def enterRanges(self, ctx):
846 """
847 event
848 """
849 self.fLOG(" add 'range('")
850 self.stack.append(("Ranges", "range("))
852 def exitRanges(self, ctx):
853 """
854 event
855 """
856 self.fLOG(" add ') # range'")
857 self.stack.append(("Ranges", ")"))
859 def enterIntersections(self, ctx):
860 """
861 event
862 """
863 self.fLOG(" add 'set('")
864 self.stack.append(("Intersections", "set("))
866 def exitIntersections(self, ctx):
867 """
868 event
869 """
870 self.fLOG(" add ') # set'")
871 self.stack.append(("Intersections", ")"))