|
11 | 11 | # See the java2python.config.default and java2python.lang.selector modules to
|
12 | 12 | # understand how and when selectors are associated with these callables.
|
13 | 13 |
|
| 14 | +import re |
| 15 | +from logging import warn |
| 16 | + |
14 | 17 | import keyword
|
15 | 18 | import types
|
16 | 19 |
|
@@ -89,6 +92,65 @@ def lengthToLen(node, config):
|
89 | 92 | expr.addChild(ident)
|
90 | 93 |
|
91 | 94 |
|
| 95 | +def formatSyntaxTransf(match): |
| 96 | + """ Helper function for formatString AST transform. |
| 97 | +
|
| 98 | + Translates the Java Formatter syntax into Python .format syntax. |
| 99 | +
|
| 100 | + This function gets called by re.sub which matches all the %...$... groups |
| 101 | + inside a format specifier string. |
| 102 | + """ |
| 103 | + groups = match.groupdict() |
| 104 | + result = '{' |
| 105 | + # TODO: add flags, width and precision |
| 106 | + if(groups['idx']): |
| 107 | + idx = int(groups['idx'][:-1]) |
| 108 | + result += str(idx - 1) # Py starts count from 0 |
| 109 | + result += ':' + groups['convers'] + '}' |
| 110 | + |
| 111 | + return result |
| 112 | + |
| 113 | +def formatString(node, config): |
| 114 | + """ Transforms string formatting like 'String.format("%d %2$s", i, s)' |
| 115 | + into '"{:d} {2:s}".format(i, s)'. |
| 116 | + """ |
| 117 | + dot = node.parent |
| 118 | + method = dot.parent |
| 119 | + arg_list = method.firstChildOfType(tokens.ARGUMENT_LIST) |
| 120 | + call_args = [arg for arg in arg_list.childrenOfType(tokens.EXPR)] |
| 121 | + args = [arg.firstChildOfType(tokens.IDENT) for arg in call_args[1:]] |
| 122 | + |
| 123 | + # Translate format syntax (if format == string_literal) |
| 124 | + format = call_args[0].firstChildOfType(tokens.STRING_LITERAL) |
| 125 | + if format: |
| 126 | + format.token.text = \ |
| 127 | + re.sub(r'%(?P<idx>\d+\$)?(?P<convers>[scdoxefg])', |
| 128 | + formatSyntaxTransf, |
| 129 | + format.token.text, |
| 130 | + flags=re.IGNORECASE) |
| 131 | + else: |
| 132 | + # Translation should happen at runtime |
| 133 | + format = call_args[0].firstChild() |
| 134 | + if format.type == tokens.IDENT: |
| 135 | + # String variable |
| 136 | + warn('Formatting string %s is not automatically translated.' |
| 137 | + % str(format.token.text)) |
| 138 | + else: |
| 139 | + # Function that returns String |
| 140 | + warn('Formatting string returned by %s() is not automatically translated.' |
| 141 | + % str(format.firstChildOfType(tokens.IDENT).token.text)) |
| 142 | + |
| 143 | + left_ident = dot.children[0] |
| 144 | + right_ident = dot.children[1] |
| 145 | + |
| 146 | + # Change AST |
| 147 | + arg_list.children.remove(format.parent) |
| 148 | + dot.children.remove(left_ident) |
| 149 | + dot.children.remove(right_ident) |
| 150 | + dot.addChild(format) |
| 151 | + dot.addChild(right_ident) |
| 152 | + |
| 153 | + |
92 | 154 | def typeSub(node, config):
|
93 | 155 | """ Maps specific, well-known Java types to their Python counterparts.
|
94 | 156 |
|
|
0 commit comments