# 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 dataclasses import typing as T from .. import mparser if T.TYPE_CHECKING: import builtins 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)