1# Copyright 2019 The Meson development team 2 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6 7# http://www.apache.org/licenses/LICENSE-2.0 8 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# This class contains the basic functionality needed to run any interpreter 16# or an interpreter-based tool 17 18from .. import mparser 19from . import AstVisitor 20import re 21import typing as T 22 23arithmic_map = { 24 'add': '+', 25 'sub': '-', 26 'mod': '%', 27 'mul': '*', 28 'div': '/' 29} 30 31class AstPrinter(AstVisitor): 32 def __init__(self, indent: int = 2, arg_newline_cutoff: int = 5): 33 self.result = '' 34 self.indent = indent 35 self.arg_newline_cutoff = arg_newline_cutoff 36 self.ci = '' 37 self.is_newline = True 38 self.last_level = 0 39 40 def post_process(self) -> None: 41 self.result = re.sub(r'\s+\n', '\n', self.result) 42 43 def append(self, data: str, node: mparser.BaseNode) -> None: 44 self.last_level = node.level 45 if self.is_newline: 46 self.result += ' ' * (node.level * self.indent) 47 self.result += data 48 self.is_newline = False 49 50 def append_padded(self, data: str, node: mparser.BaseNode) -> None: 51 if self.result and self.result[-1] not in [' ', '\n']: 52 data = ' ' + data 53 self.append(data + ' ', node) 54 55 def newline(self) -> None: 56 self.result += '\n' 57 self.is_newline = True 58 59 def visit_BooleanNode(self, node: mparser.BooleanNode) -> None: 60 self.append('true' if node.value else 'false', node) 61 62 def visit_IdNode(self, node: mparser.IdNode) -> None: 63 assert isinstance(node.value, str) 64 self.append(node.value, node) 65 66 def visit_NumberNode(self, node: mparser.NumberNode) -> None: 67 self.append(str(node.value), node) 68 69 def visit_StringNode(self, node: mparser.StringNode) -> None: 70 assert isinstance(node.value, str) 71 self.append("'" + node.value + "'", node) 72 73 def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: 74 assert isinstance(node.value, str) 75 self.append("f'" + node.value + "'", node) 76 77 def visit_ContinueNode(self, node: mparser.ContinueNode) -> None: 78 self.append('continue', node) 79 80 def visit_BreakNode(self, node: mparser.BreakNode) -> None: 81 self.append('break', node) 82 83 def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: 84 self.append('[', node) 85 node.args.accept(self) 86 self.append(']', node) 87 88 def visit_DictNode(self, node: mparser.DictNode) -> None: 89 self.append('{', node) 90 node.args.accept(self) 91 self.append('}', node) 92 93 def visit_OrNode(self, node: mparser.OrNode) -> None: 94 node.left.accept(self) 95 self.append_padded('or', node) 96 node.right.accept(self) 97 98 def visit_AndNode(self, node: mparser.AndNode) -> None: 99 node.left.accept(self) 100 self.append_padded('and', node) 101 node.right.accept(self) 102 103 def visit_ComparisonNode(self, node: mparser.ComparisonNode) -> None: 104 node.left.accept(self) 105 self.append_padded(node.ctype, node) 106 node.right.accept(self) 107 108 def visit_ArithmeticNode(self, node: mparser.ArithmeticNode) -> None: 109 node.left.accept(self) 110 self.append_padded(arithmic_map[node.operation], node) 111 node.right.accept(self) 112 113 def visit_NotNode(self, node: mparser.NotNode) -> None: 114 self.append_padded('not', node) 115 node.value.accept(self) 116 117 def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: 118 for i in node.lines: 119 i.accept(self) 120 self.newline() 121 122 def visit_IndexNode(self, node: mparser.IndexNode) -> None: 123 node.iobject.accept(self) 124 self.append('[', node) 125 node.index.accept(self) 126 self.append(']', node) 127 128 def visit_MethodNode(self, node: mparser.MethodNode) -> None: 129 node.source_object.accept(self) 130 self.append('.' + node.name + '(', node) 131 node.args.accept(self) 132 self.append(')', node) 133 134 def visit_FunctionNode(self, node: mparser.FunctionNode) -> None: 135 self.append(node.func_name + '(', node) 136 node.args.accept(self) 137 self.append(')', node) 138 139 def visit_AssignmentNode(self, node: mparser.AssignmentNode) -> None: 140 self.append(node.var_name + ' = ', node) 141 node.value.accept(self) 142 143 def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode) -> None: 144 self.append(node.var_name + ' += ', node) 145 node.value.accept(self) 146 147 def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: 148 varnames = [x for x in node.varnames] 149 self.append_padded('foreach', node) 150 self.append_padded(', '.join(varnames), node) 151 self.append_padded(':', node) 152 node.items.accept(self) 153 self.newline() 154 node.block.accept(self) 155 self.append('endforeach', node) 156 157 def visit_IfClauseNode(self, node: mparser.IfClauseNode) -> None: 158 prefix = '' 159 for i in node.ifs: 160 self.append_padded(prefix + 'if', node) 161 prefix = 'el' 162 i.accept(self) 163 if not isinstance(node.elseblock, mparser.EmptyNode): 164 self.append('else', node) 165 node.elseblock.accept(self) 166 self.append('endif', node) 167 168 def visit_UMinusNode(self, node: mparser.UMinusNode) -> None: 169 self.append_padded('-', node) 170 node.value.accept(self) 171 172 def visit_IfNode(self, node: mparser.IfNode) -> None: 173 node.condition.accept(self) 174 self.newline() 175 node.block.accept(self) 176 177 def visit_TernaryNode(self, node: mparser.TernaryNode) -> None: 178 node.condition.accept(self) 179 self.append_padded('?', node) 180 node.trueblock.accept(self) 181 self.append_padded(':', node) 182 node.falseblock.accept(self) 183 184 def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None: 185 break_args = (len(node.arguments) + len(node.kwargs)) > self.arg_newline_cutoff 186 for i in node.arguments + list(node.kwargs.values()): 187 if not isinstance(i, (mparser.ElementaryNode, mparser.IndexNode)): 188 break_args = True 189 if break_args: 190 self.newline() 191 for i in node.arguments: 192 i.accept(self) 193 self.append(', ', node) 194 if break_args: 195 self.newline() 196 for key, val in node.kwargs.items(): 197 key.accept(self) 198 self.append_padded(':', node) 199 val.accept(self) 200 self.append(', ', node) 201 if break_args: 202 self.newline() 203 if break_args: 204 self.result = re.sub(r', \n$', '\n', self.result) 205 else: 206 self.result = re.sub(r', $', '', self.result) 207 208class AstJSONPrinter(AstVisitor): 209 def __init__(self) -> None: 210 self.result = {} # type: T.Dict[str, T.Any] 211 self.current = self.result 212 213 def _accept(self, key: str, node: mparser.BaseNode) -> None: 214 old = self.current 215 data = {} # type: T.Dict[str, T.Any] 216 self.current = data 217 node.accept(self) 218 self.current = old 219 self.current[key] = data 220 221 def _accept_list(self, key: str, nodes: T.Sequence[mparser.BaseNode]) -> None: 222 old = self.current 223 datalist = [] # type: T.List[T.Dict[str, T.Any]] 224 for i in nodes: 225 self.current = {} 226 i.accept(self) 227 datalist += [self.current] 228 self.current = old 229 self.current[key] = datalist 230 231 def _raw_accept(self, node: mparser.BaseNode, data: T.Dict[str, T.Any]) -> None: 232 old = self.current 233 self.current = data 234 node.accept(self) 235 self.current = old 236 237 def setbase(self, node: mparser.BaseNode) -> None: 238 self.current['node'] = type(node).__name__ 239 self.current['lineno'] = node.lineno 240 self.current['colno'] = node.colno 241 self.current['end_lineno'] = node.end_lineno 242 self.current['end_colno'] = node.end_colno 243 244 def visit_default_func(self, node: mparser.BaseNode) -> None: 245 self.setbase(node) 246 247 def gen_ElementaryNode(self, node: mparser.ElementaryNode) -> None: 248 self.current['value'] = node.value 249 self.setbase(node) 250 251 def visit_BooleanNode(self, node: mparser.BooleanNode) -> None: 252 self.gen_ElementaryNode(node) 253 254 def visit_IdNode(self, node: mparser.IdNode) -> None: 255 self.gen_ElementaryNode(node) 256 257 def visit_NumberNode(self, node: mparser.NumberNode) -> None: 258 self.gen_ElementaryNode(node) 259 260 def visit_StringNode(self, node: mparser.StringNode) -> None: 261 self.gen_ElementaryNode(node) 262 263 def visit_FormatStringNode(self, node: mparser.FormatStringNode) -> None: 264 self.gen_ElementaryNode(node) 265 266 def visit_ArrayNode(self, node: mparser.ArrayNode) -> None: 267 self._accept('args', node.args) 268 self.setbase(node) 269 270 def visit_DictNode(self, node: mparser.DictNode) -> None: 271 self._accept('args', node.args) 272 self.setbase(node) 273 274 def visit_OrNode(self, node: mparser.OrNode) -> None: 275 self._accept('left', node.left) 276 self._accept('right', node.right) 277 self.setbase(node) 278 279 def visit_AndNode(self, node: mparser.AndNode) -> None: 280 self._accept('left', node.left) 281 self._accept('right', node.right) 282 self.setbase(node) 283 284 def visit_ComparisonNode(self, node: mparser.ComparisonNode) -> None: 285 self._accept('left', node.left) 286 self._accept('right', node.right) 287 self.current['ctype'] = node.ctype 288 self.setbase(node) 289 290 def visit_ArithmeticNode(self, node: mparser.ArithmeticNode) -> None: 291 self._accept('left', node.left) 292 self._accept('right', node.right) 293 self.current['op'] = arithmic_map[node.operation] 294 self.setbase(node) 295 296 def visit_NotNode(self, node: mparser.NotNode) -> None: 297 self._accept('right', node.value) 298 self.setbase(node) 299 300 def visit_CodeBlockNode(self, node: mparser.CodeBlockNode) -> None: 301 self._accept_list('lines', node.lines) 302 self.setbase(node) 303 304 def visit_IndexNode(self, node: mparser.IndexNode) -> None: 305 self._accept('object', node.iobject) 306 self._accept('index', node.index) 307 self.setbase(node) 308 309 def visit_MethodNode(self, node: mparser.MethodNode) -> None: 310 self._accept('object', node.source_object) 311 self._accept('args', node.args) 312 self.current['name'] = node.name 313 self.setbase(node) 314 315 def visit_FunctionNode(self, node: mparser.FunctionNode) -> None: 316 self._accept('args', node.args) 317 self.current['name'] = node.func_name 318 self.setbase(node) 319 320 def visit_AssignmentNode(self, node: mparser.AssignmentNode) -> None: 321 self._accept('value', node.value) 322 self.current['var_name'] = node.var_name 323 self.setbase(node) 324 325 def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode) -> None: 326 self._accept('value', node.value) 327 self.current['var_name'] = node.var_name 328 self.setbase(node) 329 330 def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode) -> None: 331 self._accept('items', node.items) 332 self._accept('block', node.block) 333 self.current['varnames'] = node.varnames 334 self.setbase(node) 335 336 def visit_IfClauseNode(self, node: mparser.IfClauseNode) -> None: 337 self._accept_list('ifs', node.ifs) 338 self._accept('else', node.elseblock) 339 self.setbase(node) 340 341 def visit_UMinusNode(self, node: mparser.UMinusNode) -> None: 342 self._accept('right', node.value) 343 self.setbase(node) 344 345 def visit_IfNode(self, node: mparser.IfNode) -> None: 346 self._accept('condition', node.condition) 347 self._accept('block', node.block) 348 self.setbase(node) 349 350 def visit_TernaryNode(self, node: mparser.TernaryNode) -> None: 351 self._accept('condition', node.condition) 352 self._accept('true', node.trueblock) 353 self._accept('false', node.falseblock) 354 self.setbase(node) 355 356 def visit_ArgumentNode(self, node: mparser.ArgumentNode) -> None: 357 self._accept_list('positional', node.arguments) 358 kwargs_list = [] # type: T.List[T.Dict[str, T.Dict[str, T.Any]]] 359 for key, val in node.kwargs.items(): 360 key_res = {} # type: T.Dict[str, T.Any] 361 val_res = {} # type: T.Dict[str, T.Any] 362 self._raw_accept(key, key_res) 363 self._raw_accept(val, val_res) 364 kwargs_list += [{'key': key_res, 'val': val_res}] 365 self.current['kwargs'] = kwargs_list 366 self.setbase(node) 367