From b01ae087f5f54b0777201c83440fb6777648acd8 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 24 Feb 2022 13:26:51 -0800 Subject: [PATCH] cargo: Add a builder module to the cargo package This is a helper, currently only used by cargo. It could be moved later if there are other users. --- mesonbuild/cargo/__init__.py | 0 mesonbuild/cargo/builder.py | 284 +++++++++++++++++++++++++++++++++++ run_mypy.py | 1 + 3 files changed, 285 insertions(+) create mode 100644 mesonbuild/cargo/__init__.py create mode 100644 mesonbuild/cargo/builder.py diff --git a/mesonbuild/cargo/__init__.py b/mesonbuild/cargo/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/mesonbuild/cargo/builder.py b/mesonbuild/cargo/builder.py new file mode 100644 index 000000000..49bc65db5 --- /dev/null +++ b/mesonbuild/cargo/builder.py @@ -0,0 +1,284 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2022-2023 Intel Corporation + +"""Provides helpers for building AST + +This is meant to make building Meson AST from foreign (largely declarative) +build descriptions easier. +""" + +from __future__ import annotations +import builtins +import dataclasses +import typing as T + +from .. import mparser + + +def _token(tid: str, filename: str, value: mparser.TV_TokenTypes) -> mparser.Token[mparser.TV_TokenTypes]: + """Create a Token object, but with the line numbers stubbed out. + + :param tid: the token id (such as string, number, etc) + :param filename: the filename that the token was generated from + :param value: the value of the token + :return: A Token object + """ + return mparser.Token(tid, filename, -1, -1, -1, (-1, -1), value) + + +def string(value: str, filename: str) -> mparser.StringNode: + """Build A StringNode + + :param value: the value of the string + :param filename: the file that the value came from + :return: A StringNode + """ + return mparser.StringNode(_token('string', filename, value)) + + +def number(value: int, filename: str) -> mparser.NumberNode: + """Build A NumberNode + + :param value: the value of the number + :param filename: the file that the value came from + :return: A NumberNode + """ + return mparser.NumberNode(_token('number', filename, value)) + + +def bool(value: builtins.bool, filename: str) -> mparser.BooleanNode: + """Build A BooleanNode + + :param value: the value of the boolean + :param filename: the file that the value came from + :return: A BooleanNode + """ + return mparser.BooleanNode(_token('bool', filename, value)) + + +def array(value: T.List[mparser.BaseNode], filename: str) -> mparser.ArrayNode: + """Build an Array Node + + :param value: A list of nodes to insert into the array + :param filename: The file the array is from + :return: An ArrayNode built from the arguments + """ + args = mparser.ArgumentNode(_token('array', filename, 'unused')) + args.arguments = value + return mparser.ArrayNode(args, -1, -1, -1, -1) + + +def identifier(value: str, filename: str) -> mparser.IdNode: + """Build A IdNode + + :param value: the value of the boolean + :param filename: the file that the value came from + :return: A BooleanNode + """ + return mparser.IdNode(_token('id', filename, value)) + + +def method(name: str, id_: mparser.IdNode, + pos: T.Optional[T.List[mparser.BaseNode]] = None, + kw: T.Optional[T.Mapping[str, mparser.BaseNode]] = None, + ) -> mparser.MethodNode: + """Create a method call. + + :param name: the name of the method + :param id_: the object to call the method of + :param pos: a list of positional arguments, defaults to None + :param kw: a dictionary of keyword arguments, defaults to None + :return: a method call object + """ + args = mparser.ArgumentNode(_token('array', id_.filename, 'unused')) + if pos is not None: + args.arguments = pos + if kw is not None: + args.kwargs = {identifier(k, id_.filename): v for k, v in kw.items()} + return mparser.MethodNode(id_.filename, -1, -1, id_, name, args) + + +def function(name: str, filename: str, + pos: T.Optional[T.List[mparser.BaseNode]] = None, + kw: T.Optional[T.Mapping[str, mparser.BaseNode]] = None, + ) -> mparser.FunctionNode: + """Create a function call. + + :param name: the name of the function + :param filename: The name of the current file being evaluated + :param pos: a list of positional arguments, defaults to None + :param kw: a dictionary of keyword arguments, defaults to None + :return: a method call object + """ + args = mparser.ArgumentNode(_token('array', filename, 'unused')) + if pos is not None: + args.arguments = pos + if kw is not None: + args.kwargs = {identifier(k, filename): v for k, v in kw.items()} + return mparser.FunctionNode(filename, -1, -1, -1, -1, name, args) + + +def equal(lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.ComparisonNode: + """Create an equality operation + + :param lhs: The left hand side of the equal + :param rhs: the right hand side of the equal + :return: A compraison node + """ + return mparser.ComparisonNode('==', lhs, rhs) + + +def or_(lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.OrNode: + """Create and OrNode + + :param lhs: The Left of the Node + :param rhs: The Right of the Node + :return: The OrNode + """ + return mparser.OrNode(lhs, rhs) + + +def and_(lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.AndNode: + """Create an AndNode + + :param lhs: The left of the And + :param rhs: The right of the And + :return: The AndNode + """ + return mparser.AndNode(lhs, rhs) + + +def not_(value: mparser.BaseNode, filename: str) -> mparser.NotNode: + """Create a not node + + :param value: The value to negate + :param filename: the string filename + :return: The NotNode + """ + return mparser.NotNode(_token('not', filename, ''), value) + + +def assign(value: mparser.BaseNode, varname: str, filename: str) -> mparser.AssignmentNode: + """Create an AssignmentNode + + :param value: The rvalue + :param varname: The lvalue + :param filename: The filename + :return: An AssignmentNode + """ + return mparser.AssignmentNode(filename, -1, -1, varname, value) + + +def block(filename: str) -> mparser.CodeBlockNode: + return mparser.CodeBlockNode(_token('node', filename, '')) + + +@dataclasses.dataclass +class Builder: + + filename: str + + def assign(self, value: mparser.BaseNode, varname: str) -> mparser.AssignmentNode: + return assign(value, varname, self.filename) + + def string(self, value: str) -> mparser.StringNode: + """Build A StringNode + + :param value: the value of the string + :return: A StringNode + """ + return string(value, self.filename) + + def number(self, value: int) -> mparser.NumberNode: + """Build A NumberNode + + :param value: the value of the number + :return: A NumberNode + """ + return number(value, self.filename) + + def bool(self, value: builtins.bool) -> mparser.BooleanNode: + """Build A BooleanNode + + :param value: the value of the boolean + :return: A BooleanNode + """ + return bool(value, self.filename) + + def array(self, value: T.List[mparser.BaseNode]) -> mparser.ArrayNode: + """Build an Array Node + + :param value: A list of nodes to insert into the array + :return: An ArrayNode built from the arguments + """ + return array(value, self.filename) + + def identifier(self, value: str) -> mparser.IdNode: + """Build A IdNode + + :param value: the value of the boolean + :return: A BooleanNode + """ + return identifier(value, self.filename) + + def method(self, name: str, id_: mparser.IdNode, + pos: T.Optional[T.List[mparser.BaseNode]] = None, + kw: T.Optional[T.Mapping[str, mparser.BaseNode]] = None, + ) -> mparser.MethodNode: + """Create a method call. + + :param name: the name of the method + :param id_: the object to call the method of + :param pos: a list of positional arguments, defaults to None + :param kw: a dictionary of keyword arguments, defaults to None + :return: a method call object + """ + return method(name, id_, pos or [], kw or {}) + + def function(self, name: str, + pos: T.Optional[T.List[mparser.BaseNode]] = None, + kw: T.Optional[T.Mapping[str, mparser.BaseNode]] = None, + ) -> mparser.FunctionNode: + """Create a function call. + + :param name: the name of the function + :param pos: a list of positional arguments, defaults to None + :param kw: a dictionary of keyword arguments, defaults to None + :return: a method call object + """ + return function(name, self.filename, pos or [], kw or {}) + + def equal(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.ComparisonNode: + """Create an equality operation + + :param lhs: The left hand side of the equal + :param rhs: the right hand side of the equal + :return: A compraison node + """ + return equal(lhs, rhs) + + def or_(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.OrNode: + """Create and OrNode + + :param lhs: The Left of the Node + :param rhs: The Right of the Node + :return: The OrNode + """ + return or_(lhs, rhs) + + def and_(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.AndNode: + """Create an AndNode + + :param lhs: The left of the And + :param rhs: The right of the And + :return: The AndNode + """ + return and_(lhs, rhs) + + def not_(self, value: mparser.BaseNode, filename: str) -> mparser.NotNode: + """Create a not node + + :param value: The value to negate + :return: The NotNode + """ + return not_(value, self.filename) diff --git a/run_mypy.py b/run_mypy.py index 338968d49..158f765bb 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -12,6 +12,7 @@ from mesonbuild.mesonlib import version_compare modules = [ # fully typed submodules # 'mesonbuild/ast/', + 'mesonbuild/cargo/', 'mesonbuild/cmake/', 'mesonbuild/compilers/', 'mesonbuild/dependencies/',