Merge pull request #4814 from mensinda/astVisitor
rewriter: Rewrote the meson rewriter - now works with AST modificationpull/4838/head
commit
733f9a7765
22 changed files with 1459 additions and 393 deletions
@ -0,0 +1,32 @@ |
||||
# Copyright 2019 The Meson development team |
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# This class contains the basic functionality needed to run any interpreter |
||||
# or an interpreter-based tool. |
||||
|
||||
__all__ = [ |
||||
'AstInterpreter', |
||||
'AstIDGenerator', |
||||
'AstIndentationGenerator', |
||||
'AstVisitor', |
||||
'AstPrinter', |
||||
'IntrospectionInterpreter', |
||||
'build_target_functions', |
||||
] |
||||
|
||||
from .interpreter import AstInterpreter |
||||
from .introspection import IntrospectionInterpreter, build_target_functions |
||||
from .visitor import AstVisitor |
||||
from .postprocess import AstIDGenerator, AstIndentationGenerator |
||||
from .printer import AstPrinter |
@ -0,0 +1,241 @@ |
||||
# Copyright 2018 The Meson development team |
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# This class contains the basic functionality needed to run any interpreter |
||||
# or an interpreter-based tool |
||||
|
||||
from . import AstInterpreter |
||||
from .. import compilers, environment, mesonlib, mparser, optinterpreter |
||||
from .. import coredata as cdata |
||||
from ..interpreterbase import InvalidArguments |
||||
from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary |
||||
import os |
||||
|
||||
build_target_functions = ['executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'] |
||||
|
||||
class IntrospectionHelper: |
||||
# mimic an argparse namespace |
||||
def __init__(self, cross_file): |
||||
self.cross_file = cross_file |
||||
self.native_file = None |
||||
self.cmd_line_options = {} |
||||
|
||||
class IntrospectionInterpreter(AstInterpreter): |
||||
# Interpreter to detect the options without a build directory |
||||
# Most of the code is stolen from interperter.Interpreter |
||||
def __init__(self, source_root, subdir, backend, cross_file=None, subproject='', subproject_dir='subprojects', env=None): |
||||
super().__init__(source_root, subdir) |
||||
|
||||
options = IntrospectionHelper(cross_file) |
||||
self.cross_file = cross_file |
||||
if env is None: |
||||
self.environment = environment.Environment(source_root, None, options) |
||||
else: |
||||
self.environment = env |
||||
self.subproject = subproject |
||||
self.subproject_dir = subproject_dir |
||||
self.coredata = self.environment.get_coredata() |
||||
self.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt') |
||||
self.backend = backend |
||||
self.default_options = {'backend': self.backend} |
||||
self.project_data = {} |
||||
self.targets = [] |
||||
|
||||
self.funcs.update({ |
||||
'add_languages': self.func_add_languages, |
||||
'executable': self.func_executable, |
||||
'jar': self.func_jar, |
||||
'library': self.func_library, |
||||
'project': self.func_project, |
||||
'shared_library': self.func_shared_lib, |
||||
'shared_module': self.func_shared_module, |
||||
'static_library': self.func_static_lib, |
||||
'both_libraries': self.func_both_lib, |
||||
}) |
||||
|
||||
def func_project(self, node, args, kwargs): |
||||
if len(args) < 1: |
||||
raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.') |
||||
|
||||
proj_name = args[0] |
||||
proj_vers = kwargs.get('version', 'undefined') |
||||
proj_langs = self.flatten_args(args[1:]) |
||||
if isinstance(proj_vers, mparser.ElementaryNode): |
||||
proj_vers = proj_vers.value |
||||
if not isinstance(proj_vers, str): |
||||
proj_vers = 'undefined' |
||||
self.project_data = {'descriptive_name': proj_name, 'version': proj_vers} |
||||
|
||||
if os.path.exists(self.option_file): |
||||
oi = optinterpreter.OptionInterpreter(self.subproject) |
||||
oi.process(self.option_file) |
||||
self.coredata.merge_user_options(oi.options) |
||||
|
||||
def_opts = self.flatten_args(kwargs.get('default_options', [])) |
||||
self.project_default_options = mesonlib.stringlistify(def_opts) |
||||
self.project_default_options = cdata.create_options_dict(self.project_default_options) |
||||
self.default_options.update(self.project_default_options) |
||||
self.coredata.set_default_options(self.default_options, self.subproject, self.environment.cmd_line_options) |
||||
|
||||
if not self.is_subproject() and 'subproject_dir' in kwargs: |
||||
spdirname = kwargs['subproject_dir'] |
||||
if isinstance(spdirname, str): |
||||
self.subproject_dir = spdirname |
||||
if not self.is_subproject(): |
||||
self.project_data['subprojects'] = [] |
||||
subprojects_dir = os.path.join(self.source_root, self.subproject_dir) |
||||
if os.path.isdir(subprojects_dir): |
||||
for i in os.listdir(subprojects_dir): |
||||
if os.path.isdir(os.path.join(subprojects_dir, i)): |
||||
self.do_subproject(i) |
||||
|
||||
self.coredata.init_backend_options(self.backend) |
||||
options = {k: v for k, v in self.environment.cmd_line_options.items() if k.startswith('backend_')} |
||||
|
||||
self.coredata.set_options(options) |
||||
self.func_add_languages(None, proj_langs, None) |
||||
|
||||
def do_subproject(self, dirname): |
||||
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir) |
||||
subpr = os.path.join(subproject_dir_abs, dirname) |
||||
try: |
||||
subi = IntrospectionInterpreter(subpr, '', self.backend, cross_file=self.cross_file, subproject=dirname, subproject_dir=self.subproject_dir, env=self.environment) |
||||
subi.analyze() |
||||
subi.project_data['name'] = dirname |
||||
self.project_data['subprojects'] += [subi.project_data] |
||||
except: |
||||
return |
||||
|
||||
def func_add_languages(self, node, args, kwargs): |
||||
args = self.flatten_args(args) |
||||
need_cross_compiler = self.environment.is_cross_build() |
||||
for lang in sorted(args, key=compilers.sort_clink): |
||||
lang = lang.lower() |
||||
if lang not in self.coredata.compilers: |
||||
self.environment.detect_compilers(lang, need_cross_compiler) |
||||
|
||||
def build_target(self, node, args, kwargs, targetclass): |
||||
if not args: |
||||
return |
||||
kwargs = self.flatten_kwargs(kwargs, True) |
||||
name = self.flatten_args(args)[0] |
||||
srcqueue = [node] |
||||
if 'sources' in kwargs: |
||||
srcqueue += kwargs['sources'] |
||||
|
||||
source_nodes = [] |
||||
while srcqueue: |
||||
curr = srcqueue.pop(0) |
||||
arg_node = None |
||||
if isinstance(curr, mparser.FunctionNode): |
||||
arg_node = curr.args |
||||
elif isinstance(curr, mparser.ArrayNode): |
||||
arg_node = curr.args |
||||
elif isinstance(curr, mparser.IdNode): |
||||
# Try to resolve the ID and append the node to the queue |
||||
id = curr.value |
||||
if id in self.assignments and self.assignments[id]: |
||||
node = self.assignments[id][0] |
||||
if isinstance(node, (mparser.ArrayNode, mparser.IdNode, mparser.FunctionNode)): |
||||
srcqueue += [node] |
||||
if arg_node is None: |
||||
continue |
||||
elemetary_nodes = list(filter(lambda x: isinstance(x, (str, mparser.StringNode)), arg_node.arguments)) |
||||
srcqueue += list(filter(lambda x: isinstance(x, (mparser.FunctionNode, mparser.ArrayNode, mparser.IdNode)), arg_node.arguments)) |
||||
# Pop the first element if the function is a build target function |
||||
if isinstance(curr, mparser.FunctionNode) and curr.func_name in build_target_functions: |
||||
elemetary_nodes.pop(0) |
||||
if elemetary_nodes: |
||||
source_nodes += [curr] |
||||
|
||||
# Filter out kwargs from other target types. For example 'soversion' |
||||
# passed to library() when default_library == 'static'. |
||||
kwargs = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs} |
||||
|
||||
is_cross = False |
||||
objects = [] |
||||
empty_sources = [] # Passing the unresolved sources list causes errors |
||||
target = targetclass(name, self.subdir, self.subproject, is_cross, empty_sources, objects, self.environment, kwargs) |
||||
|
||||
self.targets += [{ |
||||
'name': target.get_basename(), |
||||
'id': target.get_id(), |
||||
'type': target.get_typename(), |
||||
'defined_in': os.path.normpath(os.path.join(self.source_root, self.subdir, environment.build_filename)), |
||||
'subdir': self.subdir, |
||||
'build_by_default': target.build_by_default, |
||||
'sources': source_nodes, |
||||
'kwargs': kwargs, |
||||
'node': node, |
||||
}] |
||||
|
||||
return |
||||
|
||||
def build_library(self, node, args, kwargs): |
||||
default_library = self.coredata.get_builtin_option('default_library') |
||||
if default_library == 'shared': |
||||
return self.build_target(node, args, kwargs, SharedLibrary) |
||||
elif default_library == 'static': |
||||
return self.build_target(node, args, kwargs, StaticLibrary) |
||||
elif default_library == 'both': |
||||
return self.build_target(node, args, kwargs, SharedLibrary) |
||||
|
||||
def func_executable(self, node, args, kwargs): |
||||
return self.build_target(node, args, kwargs, Executable) |
||||
|
||||
def func_static_lib(self, node, args, kwargs): |
||||
return self.build_target(node, args, kwargs, StaticLibrary) |
||||
|
||||
def func_shared_lib(self, node, args, kwargs): |
||||
return self.build_target(node, args, kwargs, SharedLibrary) |
||||
|
||||
def func_both_lib(self, node, args, kwargs): |
||||
return self.build_target(node, args, kwargs, SharedLibrary) |
||||
|
||||
def func_shared_module(self, node, args, kwargs): |
||||
return self.build_target(node, args, kwargs, SharedModule) |
||||
|
||||
def func_library(self, node, args, kwargs): |
||||
return self.build_library(node, args, kwargs) |
||||
|
||||
def func_jar(self, node, args, kwargs): |
||||
return self.build_target(node, args, kwargs, Jar) |
||||
|
||||
def func_build_target(self, node, args, kwargs): |
||||
if 'target_type' not in kwargs: |
||||
return |
||||
target_type = kwargs.pop('target_type') |
||||
if isinstance(target_type, mparser.ElementaryNode): |
||||
target_type = target_type.value |
||||
if target_type == 'executable': |
||||
return self.build_target(node, args, kwargs, Executable) |
||||
elif target_type == 'shared_library': |
||||
return self.build_target(node, args, kwargs, SharedLibrary) |
||||
elif target_type == 'static_library': |
||||
return self.build_target(node, args, kwargs, StaticLibrary) |
||||
elif target_type == 'both_libraries': |
||||
return self.build_target(node, args, kwargs, SharedLibrary) |
||||
elif target_type == 'library': |
||||
return self.build_library(node, args, kwargs) |
||||
elif target_type == 'jar': |
||||
return self.build_target(node, args, kwargs, Jar) |
||||
|
||||
def is_subproject(self): |
||||
return self.subproject != '' |
||||
|
||||
def analyze(self): |
||||
self.load_root_meson_file() |
||||
self.sanity_check_ast() |
||||
self.parse_project() |
||||
self.run() |
@ -0,0 +1,86 @@ |
||||
# Copyright 2019 The Meson development team |
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# This class contains the basic functionality needed to run any interpreter |
||||
# or an interpreter-based tool |
||||
|
||||
from . import AstVisitor |
||||
from .. import mparser |
||||
|
||||
class AstIndentationGenerator(AstVisitor): |
||||
def __init__(self): |
||||
self.level = 0 |
||||
|
||||
def visit_default_func(self, node: mparser.BaseNode): |
||||
# Store the current level in the node |
||||
node.level = self.level |
||||
|
||||
def visit_ArrayNode(self, node: mparser.ArrayNode): |
||||
self.visit_default_func(node) |
||||
self.level += 1 |
||||
node.args.accept(self) |
||||
self.level -= 1 |
||||
|
||||
def visit_DictNode(self, node: mparser.DictNode): |
||||
self.visit_default_func(node) |
||||
self.level += 1 |
||||
node.args.accept(self) |
||||
self.level -= 1 |
||||
|
||||
def visit_MethodNode(self, node: mparser.MethodNode): |
||||
self.visit_default_func(node) |
||||
node.source_object.accept(self) |
||||
self.level += 1 |
||||
node.args.accept(self) |
||||
self.level -= 1 |
||||
|
||||
def visit_FunctionNode(self, node: mparser.FunctionNode): |
||||
self.visit_default_func(node) |
||||
self.level += 1 |
||||
node.args.accept(self) |
||||
self.level -= 1 |
||||
|
||||
def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode): |
||||
self.visit_default_func(node) |
||||
self.level += 1 |
||||
node.items.accept(self) |
||||
node.block.accept(self) |
||||
self.level -= 1 |
||||
|
||||
def visit_IfClauseNode(self, node: mparser.IfClauseNode): |
||||
self.visit_default_func(node) |
||||
for i in node.ifs: |
||||
i.accept(self) |
||||
if node.elseblock: |
||||
self.level += 1 |
||||
node.elseblock.accept(self) |
||||
self.level -= 1 |
||||
|
||||
def visit_IfNode(self, node: mparser.IfNode): |
||||
self.visit_default_func(node) |
||||
self.level += 1 |
||||
node.condition.accept(self) |
||||
node.block.accept(self) |
||||
self.level -= 1 |
||||
|
||||
class AstIDGenerator(AstVisitor): |
||||
def __init__(self): |
||||
self.counter = {} |
||||
|
||||
def visit_default_func(self, node: mparser.BaseNode): |
||||
name = type(node).__name__ |
||||
if name not in self.counter: |
||||
self.counter[name] = 0 |
||||
node.ast_id = name + '#' + str(self.counter[name]) |
||||
self.counter[name] += 1 |
@ -0,0 +1,203 @@ |
||||
# Copyright 2019 The Meson development team |
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# This class contains the basic functionality needed to run any interpreter |
||||
# or an interpreter-based tool |
||||
|
||||
from .. import mparser |
||||
from . import AstVisitor |
||||
import re |
||||
|
||||
arithmic_map = { |
||||
'add': '+', |
||||
'sub': '-', |
||||
'mod': '%', |
||||
'mul': '*', |
||||
'div': '/' |
||||
} |
||||
|
||||
class AstPrinter(AstVisitor): |
||||
def __init__(self, indent: int = 2, arg_newline_cutoff: int = 5): |
||||
self.result = '' |
||||
self.indent = indent |
||||
self.arg_newline_cutoff = arg_newline_cutoff |
||||
self.ci = '' |
||||
self.is_newline = True |
||||
self.last_level = 0 |
||||
|
||||
def post_process(self): |
||||
self.result = re.sub(r'\s+\n', '\n', self.result) |
||||
|
||||
def append(self, data: str, node: mparser.BaseNode): |
||||
level = 0 |
||||
if node and hasattr(node, 'level'): |
||||
level = node.level |
||||
else: |
||||
level = self.last_level |
||||
self.last_level = level |
||||
if self.is_newline: |
||||
self.result += ' ' * (level * self.indent) |
||||
self.result += data |
||||
self.is_newline = False |
||||
|
||||
def append_padded(self, data: str, node: mparser.BaseNode): |
||||
if self.result[-1] not in [' ', '\n']: |
||||
data = ' ' + data |
||||
self.append(data + ' ', node) |
||||
|
||||
def newline(self): |
||||
self.result += '\n' |
||||
self.is_newline = True |
||||
|
||||
def visit_BooleanNode(self, node: mparser.BooleanNode): |
||||
self.append('true' if node.value else 'false', node) |
||||
|
||||
def visit_IdNode(self, node: mparser.IdNode): |
||||
self.append(node.value, node) |
||||
|
||||
def visit_NumberNode(self, node: mparser.NumberNode): |
||||
self.append(str(node.value), node) |
||||
|
||||
def visit_StringNode(self, node: mparser.StringNode): |
||||
self.append("'" + node.value + "'", node) |
||||
|
||||
def visit_ContinueNode(self, node: mparser.ContinueNode): |
||||
self.append('continue', node) |
||||
|
||||
def visit_BreakNode(self, node: mparser.BreakNode): |
||||
self.append('break', node) |
||||
|
||||
def visit_ArrayNode(self, node: mparser.ArrayNode): |
||||
self.append('[', node) |
||||
node.args.accept(self) |
||||
self.append(']', node) |
||||
|
||||
def visit_DictNode(self, node: mparser.DictNode): |
||||
self.append('{', node) |
||||
node.args.accept(self) |
||||
self.append('}', node) |
||||
|
||||
def visit_OrNode(self, node: mparser.OrNode): |
||||
node.left.accept(self) |
||||
self.append_padded('or', node) |
||||
node.right.accept(self) |
||||
|
||||
def visit_AndNode(self, node: mparser.AndNode): |
||||
node.left.accept(self) |
||||
self.append_padded('and', node) |
||||
node.right.accept(self) |
||||
|
||||
def visit_ComparisonNode(self, node: mparser.ComparisonNode): |
||||
node.left.accept(self) |
||||
self.append_padded(mparser.comparison_map[node.ctype], node) |
||||
node.right.accept(self) |
||||
|
||||
def visit_ArithmeticNode(self, node: mparser.ArithmeticNode): |
||||
node.left.accept(self) |
||||
self.append_padded(arithmic_map[node.operation], node) |
||||
node.right.accept(self) |
||||
|
||||
def visit_NotNode(self, node: mparser.NotNode): |
||||
self.append_padded('not', node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_CodeBlockNode(self, node: mparser.CodeBlockNode): |
||||
for i in node.lines: |
||||
i.accept(self) |
||||
self.newline() |
||||
|
||||
def visit_IndexNode(self, node: mparser.IndexNode): |
||||
self.append('[', node) |
||||
node.index.accept(self) |
||||
self.append(']', node) |
||||
|
||||
def visit_MethodNode(self, node: mparser.MethodNode): |
||||
node.source_object.accept(self) |
||||
self.append('.' + node.name + '(', node) |
||||
node.args.accept(self) |
||||
self.append(')', node) |
||||
|
||||
def visit_FunctionNode(self, node: mparser.FunctionNode): |
||||
self.append(node.func_name + '(', node) |
||||
node.args.accept(self) |
||||
self.append(')', node) |
||||
|
||||
def visit_AssignmentNode(self, node: mparser.AssignmentNode): |
||||
self.append(node.var_name + ' = ', node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode): |
||||
self.append(node.var_name + ' += ', node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode): |
||||
varnames = [x.value for x in node.varnames] |
||||
self.append_padded('foreach', node) |
||||
self.append_padded(', '.join(varnames), node) |
||||
self.append_padded(':', node) |
||||
node.items.accept(self) |
||||
self.newline() |
||||
node.block.accept(self) |
||||
self.append('endforeach', node) |
||||
|
||||
def visit_IfClauseNode(self, node: mparser.IfClauseNode): |
||||
prefix = '' |
||||
for i in node.ifs: |
||||
self.append_padded(prefix + 'if', node) |
||||
prefix = 'el' |
||||
i.accept(self) |
||||
if node.elseblock: |
||||
self.append('else', node) |
||||
node.elseblock.accept(self) |
||||
self.append('endif', node) |
||||
|
||||
def visit_UMinusNode(self, node: mparser.UMinusNode): |
||||
self.append_padded('-', node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_IfNode(self, node: mparser.IfNode): |
||||
node.condition.accept(self) |
||||
self.newline() |
||||
node.block.accept(self) |
||||
|
||||
def visit_TernaryNode(self, node: mparser.TernaryNode): |
||||
node.condition.accept(self) |
||||
self.append_padded('?', node) |
||||
node.trueblock.accept(self) |
||||
self.append_padded(':', node) |
||||
node.falseblock.accept(self) |
||||
|
||||
def visit_ArgumentNode(self, node: mparser.ArgumentNode): |
||||
break_args = True if (len(node.arguments) + len(node.kwargs)) > self.arg_newline_cutoff else False |
||||
for i in node.arguments + list(node.kwargs.values()): |
||||
if not isinstance(i, mparser.ElementaryNode): |
||||
break_args = True |
||||
if break_args: |
||||
self.newline() |
||||
for i in node.arguments: |
||||
i.accept(self) |
||||
self.append(', ', node) |
||||
if break_args: |
||||
self.newline() |
||||
for key, val in node.kwargs.items(): |
||||
self.append(key, node) |
||||
self.append_padded(':', node) |
||||
val.accept(self) |
||||
self.append(', ', node) |
||||
if break_args: |
||||
self.newline() |
||||
if break_args: |
||||
self.result = re.sub(r', \n$', '\n', self.result) |
||||
else: |
||||
self.result = re.sub(r', $', '', self.result) |
@ -0,0 +1,140 @@ |
||||
# Copyright 2019 The Meson development team |
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# This class contains the basic functionality needed to run any interpreter |
||||
# or an interpreter-based tool |
||||
|
||||
from .. import mparser |
||||
|
||||
class AstVisitor: |
||||
def __init__(self): |
||||
pass |
||||
|
||||
def visit_default_func(self, node: mparser.BaseNode): |
||||
pass |
||||
|
||||
def visit_BooleanNode(self, node: mparser.BooleanNode): |
||||
self.visit_default_func(node) |
||||
|
||||
def visit_IdNode(self, node: mparser.IdNode): |
||||
self.visit_default_func(node) |
||||
|
||||
def visit_NumberNode(self, node: mparser.NumberNode): |
||||
self.visit_default_func(node) |
||||
|
||||
def visit_StringNode(self, node: mparser.StringNode): |
||||
self.visit_default_func(node) |
||||
|
||||
def visit_ContinueNode(self, node: mparser.ContinueNode): |
||||
self.visit_default_func(node) |
||||
|
||||
def visit_BreakNode(self, node: mparser.BreakNode): |
||||
self.visit_default_func(node) |
||||
|
||||
def visit_ArrayNode(self, node: mparser.ArrayNode): |
||||
self.visit_default_func(node) |
||||
node.args.accept(self) |
||||
|
||||
def visit_DictNode(self, node: mparser.DictNode): |
||||
self.visit_default_func(node) |
||||
node.args.accept(self) |
||||
|
||||
def visit_EmptyNode(self, node: mparser.EmptyNode): |
||||
self.visit_default_func(node) |
||||
|
||||
def visit_OrNode(self, node: mparser.OrNode): |
||||
self.visit_default_func(node) |
||||
node.left.accept(self) |
||||
node.right.accept(self) |
||||
|
||||
def visit_AndNode(self, node: mparser.AndNode): |
||||
self.visit_default_func(node) |
||||
node.left.accept(self) |
||||
node.right.accept(self) |
||||
|
||||
def visit_ComparisonNode(self, node: mparser.ComparisonNode): |
||||
self.visit_default_func(node) |
||||
node.left.accept(self) |
||||
node.right.accept(self) |
||||
|
||||
def visit_ArithmeticNode(self, node: mparser.ArithmeticNode): |
||||
self.visit_default_func(node) |
||||
node.left.accept(self) |
||||
node.right.accept(self) |
||||
|
||||
def visit_NotNode(self, node: mparser.NotNode): |
||||
self.visit_default_func(node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_CodeBlockNode(self, node: mparser.CodeBlockNode): |
||||
self.visit_default_func(node) |
||||
for i in node.lines: |
||||
i.accept(self) |
||||
|
||||
def visit_IndexNode(self, node: mparser.IndexNode): |
||||
self.visit_default_func(node) |
||||
node.index.accept(self) |
||||
|
||||
def visit_MethodNode(self, node: mparser.MethodNode): |
||||
self.visit_default_func(node) |
||||
node.source_object.accept(self) |
||||
node.args.accept(self) |
||||
|
||||
def visit_FunctionNode(self, node: mparser.FunctionNode): |
||||
self.visit_default_func(node) |
||||
node.args.accept(self) |
||||
|
||||
def visit_AssignmentNode(self, node: mparser.AssignmentNode): |
||||
self.visit_default_func(node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_PlusAssignmentNode(self, node: mparser.PlusAssignmentNode): |
||||
self.visit_default_func(node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_ForeachClauseNode(self, node: mparser.ForeachClauseNode): |
||||
self.visit_default_func(node) |
||||
node.items.accept(self) |
||||
node.block.accept(self) |
||||
|
||||
def visit_IfClauseNode(self, node: mparser.IfClauseNode): |
||||
self.visit_default_func(node) |
||||
for i in node.ifs: |
||||
i.accept(self) |
||||
if node.elseblock: |
||||
node.elseblock.accept(self) |
||||
|
||||
def visit_UMinusNode(self, node: mparser.UMinusNode): |
||||
self.visit_default_func(node) |
||||
node.value.accept(self) |
||||
|
||||
def visit_IfNode(self, node: mparser.IfNode): |
||||
self.visit_default_func(node) |
||||
node.condition.accept(self) |
||||
node.block.accept(self) |
||||
|
||||
def visit_TernaryNode(self, node: mparser.TernaryNode): |
||||
self.visit_default_func(node) |
||||
node.condition.accept(self) |
||||
node.trueblock.accept(self) |
||||
node.falseblock.accept(self) |
||||
|
||||
def visit_ArgumentNode(self, node: mparser.ArgumentNode): |
||||
self.visit_default_func(node) |
||||
for i in node.arguments: |
||||
i.accept(self) |
||||
for i in node.commas: |
||||
pass |
||||
for val in node.kwargs.values(): |
||||
val.accept(self) |
@ -0,0 +1,89 @@ |
||||
[ |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog1", |
||||
"operation": "src_add", |
||||
"sources": ["a1.cpp", "a2.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog2", |
||||
"operation": "src_add", |
||||
"sources": ["a7.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog3", |
||||
"operation": "src_add", |
||||
"sources": ["a5.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog4", |
||||
"operation": "src_add", |
||||
"sources": ["a5.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog5", |
||||
"operation": "src_add", |
||||
"sources": ["a3.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog6", |
||||
"operation": "src_add", |
||||
"sources": ["a4.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog9", |
||||
"operation": "src_add", |
||||
"sources": ["a6.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog1", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog2", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog3", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog4", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog5", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog6", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog7", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog8", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog9", |
||||
"operation": "test" |
||||
} |
||||
] |
@ -1,5 +0,0 @@ |
||||
project('rewritetest', 'c') |
||||
|
||||
sources = ['trivial.c'] |
||||
|
||||
exe = executable('trivialprog', 'notthere.c', sources) |
@ -0,0 +1,47 @@ |
||||
[ |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog1", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog2", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog3", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog4", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog5", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog6", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog7", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog8", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog9", |
||||
"operation": "test" |
||||
} |
||||
] |
@ -1,5 +1,18 @@ |
||||
project('rewritetest', 'c') |
||||
project('rewritetest', 'cpp') |
||||
|
||||
sources = ['trivial.c', 'notthere.c'] |
||||
src1 = ['main.cpp', 'fileA.cpp'] |
||||
src2 = files(['fileB.cpp', 'fileC.cpp']) |
||||
src3 = src1 |
||||
src4 = [src3] |
||||
|
||||
exe = executable('trivialprog', sources) |
||||
# Magic comment |
||||
|
||||
exe1 = executable('trivialprog1', src1) |
||||
exe2 = executable('trivialprog2', [src2]) |
||||
exe3 = executable('trivialprog3', ['main.cpp', 'fileA.cpp']) |
||||
exe4 = executable('trivialprog4', ['main.cpp', ['fileA.cpp']]) |
||||
exe5 = executable('trivialprog5', [src2, 'main.cpp']) |
||||
exe6 = executable('trivialprog6', 'main.cpp', 'fileA.cpp') |
||||
exe7 = executable('trivialprog7', 'fileB.cpp', src1, 'fileC.cpp') |
||||
exe8 = executable('trivialprog8', src3) |
||||
exe9 = executable('trivialprog9', src4) |
||||
|
@ -1,5 +0,0 @@ |
||||
project('rewritetest', 'c') |
||||
|
||||
sources = ['trivial.c'] |
||||
|
||||
exe = executable('trivialprog', sources) |
@ -0,0 +1,83 @@ |
||||
[ |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog1", |
||||
"operation": "src_rm", |
||||
"sources": ["fileA.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog3", |
||||
"operation": "src_rm", |
||||
"sources": ["fileA.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog4", |
||||
"operation": "src_rm", |
||||
"sources": ["fileA.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog5", |
||||
"operation": "src_rm", |
||||
"sources": ["fileB.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog6", |
||||
"operation": "src_rm", |
||||
"sources": ["fileA.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog7", |
||||
"operation": "src_rm", |
||||
"sources": ["fileB.cpp"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog1", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog2", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog3", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog4", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog5", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog6", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog7", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog8", |
||||
"operation": "test" |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "trivialprog9", |
||||
"operation": "test" |
||||
} |
||||
] |
@ -0,0 +1,13 @@ |
||||
[ |
||||
{ |
||||
"type": "target", |
||||
"target": "something", |
||||
"operation": "src_add", |
||||
"sources": ["third.c"] |
||||
}, |
||||
{ |
||||
"type": "target", |
||||
"target": "something", |
||||
"operation": "test" |
||||
} |
||||
] |
@ -0,0 +1,7 @@ |
||||
[ |
||||
{ |
||||
"type": "target", |
||||
"target": "something", |
||||
"operation": "test" |
||||
} |
||||
] |
@ -1 +0,0 @@ |
||||
srcs = ['first.c'] |
Loading…
Reference in new issue