The Meson Build System
http://mesonbuild.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
8.9 KiB
238 lines
8.9 KiB
# 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 |
|
|
|
|
|
@dataclasses.dataclass |
|
class Builder: |
|
|
|
filename: str |
|
|
|
def _token(self, tid: 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, self.filename, -1, -1, -1, (-1, -1), value) |
|
|
|
def _symbol(self, val: str) -> mparser.SymbolNode: |
|
return mparser.SymbolNode(self._token('', val)) |
|
|
|
def assign(self, value: mparser.BaseNode, varname: str) -> mparser.AssignmentNode: |
|
return mparser.AssignmentNode(self.identifier(varname), self._symbol('='), value) |
|
|
|
def string(self, value: str) -> mparser.StringNode: |
|
"""Build A StringNode |
|
|
|
:param value: the value of the string |
|
:return: A StringNode |
|
""" |
|
return mparser.StringNode(self._token('string', value)) |
|
|
|
def number(self, value: int) -> mparser.NumberNode: |
|
"""Build A NumberNode |
|
|
|
:param value: the value of the number |
|
:return: A NumberNode |
|
""" |
|
return mparser.NumberNode(self._token('number', str(value))) |
|
|
|
def bool(self, value: builtins.bool) -> mparser.BooleanNode: |
|
"""Build A BooleanNode |
|
|
|
:param value: the value of the boolean |
|
:return: A BooleanNode |
|
""" |
|
return mparser.BooleanNode(self._token('bool', value)) |
|
|
|
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 |
|
""" |
|
args = mparser.ArgumentNode(self._token('array', 'unused')) |
|
args.arguments = value |
|
return mparser.ArrayNode(self._symbol('['), args, self._symbol(']')) |
|
|
|
def dict(self, value: T.Dict[mparser.BaseNode, mparser.BaseNode]) -> mparser.DictNode: |
|
"""Build an Dictionary Node |
|
|
|
:param value: A dict of nodes to insert into the dictionary |
|
:return: An DictNode built from the arguments |
|
""" |
|
args = mparser.ArgumentNode(self._token('dict', 'unused')) |
|
for key, val in value.items(): |
|
args.set_kwarg_no_check(key, val) |
|
return mparser.DictNode(self._symbol('{'), args, self._symbol('}')) |
|
|
|
def identifier(self, value: str) -> mparser.IdNode: |
|
"""Build A IdNode |
|
|
|
:param value: the value of the boolean |
|
:return: A BooleanNode |
|
""" |
|
return mparser.IdNode(self._token('id', value)) |
|
|
|
def method(self, name: str, id_: mparser.BaseNode, |
|
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(self._token('array', 'unused')) |
|
if pos is not None: |
|
args.arguments = pos |
|
if kw is not None: |
|
args.kwargs = {self.identifier(k): v for k, v in kw.items()} |
|
return mparser.MethodNode(id_, self._symbol('.'), self.identifier(name), self._symbol('('), args, self._symbol(')')) |
|
|
|
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 |
|
""" |
|
args = mparser.ArgumentNode(self._token('array', 'unused')) |
|
if pos is not None: |
|
args.arguments = pos |
|
if kw is not None: |
|
args.kwargs = {self.identifier(k): v for k, v in kw.items()} |
|
return mparser.FunctionNode(self.identifier(name), self._symbol('('), args, self._symbol(')')) |
|
|
|
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 comparison node |
|
""" |
|
return mparser.ComparisonNode('==', lhs, self._symbol('=='), rhs) |
|
|
|
def not_equal(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.ComparisonNode: |
|
"""Create an inequality operation |
|
|
|
:param lhs: The left hand side of the "!=" |
|
:param rhs: the right hand side of the "!=" |
|
:return: A comparison node |
|
""" |
|
return mparser.ComparisonNode('!=', lhs, self._symbol('!='), rhs) |
|
|
|
def in_(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.ComparisonNode: |
|
"""Create an "in" operation |
|
|
|
:param lhs: The left hand side of the "in" |
|
:param rhs: the right hand side of the "in" |
|
:return: A comparison node |
|
""" |
|
return mparser.ComparisonNode('in', lhs, self._symbol('in'), rhs) |
|
|
|
def not_in(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.ComparisonNode: |
|
"""Create an "not in" operation |
|
|
|
:param lhs: The left hand side of the "not in" |
|
:param rhs: the right hand side of the "not in" |
|
:return: A comparison node |
|
""" |
|
return mparser.ComparisonNode('notin', lhs, self._symbol('not in'), 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 mparser.OrNode(lhs, self._symbol('or'), 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 mparser.AndNode(lhs, self._symbol('and'), rhs) |
|
|
|
def not_(self, value: mparser.BaseNode) -> mparser.NotNode: |
|
"""Create a not node |
|
|
|
:param value: The value to negate |
|
:return: The NotNode |
|
""" |
|
return mparser.NotNode(self._token('not', ''), self._symbol('not'), value) |
|
|
|
def block(self, lines: T.List[mparser.BaseNode]) -> mparser.CodeBlockNode: |
|
block = mparser.CodeBlockNode(self._token('node', '')) |
|
block.lines = lines |
|
return block |
|
|
|
def plus(self, lhs: mparser.BaseNode, rhs: mparser.BaseNode) -> mparser.ArithmeticNode: |
|
"""Create an addition node |
|
|
|
:param lhs: The left of the addition |
|
:param rhs: The right of the addition |
|
:return: The ArithmeticNode |
|
""" |
|
return mparser.ArithmeticNode('add', lhs, self._symbol('+'), rhs) |
|
|
|
def plusassign(self, value: mparser.BaseNode, varname: str) -> mparser.PlusAssignmentNode: |
|
"""Create a "+=" node |
|
|
|
:param value: The value to add |
|
:param varname: The variable to assign |
|
:return: The PlusAssignmentNode |
|
""" |
|
return mparser.PlusAssignmentNode(self.identifier(varname), self._symbol('+='), value) |
|
|
|
def if_(self, condition: mparser.BaseNode, block: mparser.CodeBlockNode) -> mparser.IfClauseNode: |
|
"""Create a "if" block |
|
|
|
:param condition: The condition |
|
:param block: Lines inside the condition |
|
:return: The IfClauseNode |
|
""" |
|
clause = mparser.IfClauseNode(condition) |
|
clause.ifs.append(mparser.IfNode(clause, self._symbol('if'), condition, block)) |
|
clause.elseblock = mparser.EmptyNode(-1, -1, self.filename) |
|
return clause |
|
|
|
def foreach(self, varnames: T.List[str], items: mparser.BaseNode, block: mparser.CodeBlockNode) -> mparser.ForeachClauseNode: |
|
"""Create a "foreach" loop |
|
|
|
:param varnames: Iterator variable names (one for list, two for dict). |
|
:param items: The list of dict to iterate |
|
:param block: Lines inside the loop |
|
:return: The ForeachClauseNode |
|
""" |
|
varids = [self.identifier(i) for i in varnames] |
|
commas = [self._symbol(',') for i in range(len(varnames) - 1)] |
|
return mparser.ForeachClauseNode(self._symbol('foreach'), varids, commas, self._symbol(':'), items, block, self._symbol('endforeach'))
|
|
|