|
|
|
@ -12,12 +12,12 @@ |
|
|
|
|
# See the License for the specific language governing permissions and |
|
|
|
|
# limitations under the License. |
|
|
|
|
from __future__ import annotations |
|
|
|
|
|
|
|
|
|
from dataclasses import dataclass |
|
|
|
|
from dataclasses import dataclass, field |
|
|
|
|
import re |
|
|
|
|
import codecs |
|
|
|
|
import os |
|
|
|
|
import typing as T |
|
|
|
|
|
|
|
|
|
from .mesonlib import MesonException |
|
|
|
|
from . import mlog |
|
|
|
|
|
|
|
|
@ -240,13 +240,13 @@ class Lexer: |
|
|
|
|
if not matched: |
|
|
|
|
raise ParseException('lexer', self.getline(line_start), lineno, col) |
|
|
|
|
|
|
|
|
|
@dataclass(eq=False) |
|
|
|
|
@dataclass |
|
|
|
|
class BaseNode: |
|
|
|
|
lineno: int |
|
|
|
|
colno: int |
|
|
|
|
filename: str |
|
|
|
|
end_lineno: T.Optional[int] = None |
|
|
|
|
end_colno: T.Optional[int] = None |
|
|
|
|
lineno: int = field(hash=False) |
|
|
|
|
colno: int = field(hash=False) |
|
|
|
|
filename: str = field(hash=False) |
|
|
|
|
end_lineno: T.Optional[int] = field(default=None, hash=False) |
|
|
|
|
end_colno: T.Optional[int] = field(default=None, hash=False) |
|
|
|
|
|
|
|
|
|
def __post_init__(self) -> None: |
|
|
|
|
if self.end_lineno is None: |
|
|
|
@ -266,57 +266,63 @@ class BaseNode: |
|
|
|
|
if callable(func): |
|
|
|
|
func(self) |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class ElementaryNode(T.Generic[TV_TokenTypes], BaseNode): |
|
|
|
|
|
|
|
|
|
value: TV_TokenTypes # type: ignore[misc] |
|
|
|
|
bytespan: T.Tuple[int, int] = field(hash=False) # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, token: Token[TV_TokenTypes]): |
|
|
|
|
super().__init__(token.lineno, token.colno, token.filename) |
|
|
|
|
self.value = token.value # type: TV_TokenTypes |
|
|
|
|
self.bytespan = token.bytespan # type: T.Tuple[int, int] |
|
|
|
|
self.value = token.value |
|
|
|
|
self.bytespan = token.bytespan |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class BooleanNode(ElementaryNode[bool]): |
|
|
|
|
def __init__(self, token: Token[bool]): |
|
|
|
|
super().__init__(token) |
|
|
|
|
assert isinstance(self.value, bool) |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class IdNode(ElementaryNode[str]): |
|
|
|
|
def __init__(self, token: Token[str]): |
|
|
|
|
super().__init__(token) |
|
|
|
|
assert isinstance(self.value, str) |
|
|
|
|
|
|
|
|
|
def __str__(self) -> str: |
|
|
|
|
return "Id node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class NumberNode(ElementaryNode[int]): |
|
|
|
|
def __init__(self, token: Token[int]): |
|
|
|
|
super().__init__(token) |
|
|
|
|
assert isinstance(self.value, int) |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class StringNode(ElementaryNode[str]): |
|
|
|
|
def __init__(self, token: Token[str]): |
|
|
|
|
super().__init__(token) |
|
|
|
|
assert isinstance(self.value, str) |
|
|
|
|
|
|
|
|
|
def __str__(self) -> str: |
|
|
|
|
return "String node: '%s' (%d, %d)." % (self.value, self.lineno, self.colno) |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class FormatStringNode(ElementaryNode[str]): |
|
|
|
|
def __init__(self, token: Token[str]): |
|
|
|
|
super().__init__(token) |
|
|
|
|
assert isinstance(self.value, str) |
|
|
|
|
|
|
|
|
|
def __str__(self) -> str: |
|
|
|
|
return f"Format string node: '{self.value}' ({self.lineno}, {self.colno})." |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class MultilineFormatStringNode(FormatStringNode): |
|
|
|
|
def __str__(self) -> str: |
|
|
|
|
return f"Multiline Format string node: '{self.value}' ({self.lineno}, {self.colno})." |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class ContinueNode(ElementaryNode): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class BreakNode(ElementaryNode): |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
@dataclass(init=False) |
|
|
|
|
class ArgumentNode(BaseNode): |
|
|
|
|
|
|
|
|
|
arguments: T.List[BaseNode] # type: ignore[misc] |
|
|
|
|
commas: T.List[Token] # type: ignore[misc] |
|
|
|
|
kwargs: T.Dict[BaseNode, BaseNode] # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, token: Token[TV_TokenTypes]): |
|
|
|
|
super().__init__(token.lineno, token.colno, token.filename) |
|
|
|
|
self.arguments = [] # type: T.List[BaseNode] |
|
|
|
@ -357,12 +363,20 @@ class ArgumentNode(BaseNode): |
|
|
|
|
def __len__(self) -> int: |
|
|
|
|
return self.num_args() # Fixme |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class ArrayNode(BaseNode): |
|
|
|
|
|
|
|
|
|
args: ArgumentNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, args: ArgumentNode, lineno: int, colno: int, end_lineno: int, end_colno: int): |
|
|
|
|
super().__init__(lineno, colno, args.filename, end_lineno=end_lineno, end_colno=end_colno) |
|
|
|
|
self.args = args # type: ArgumentNode |
|
|
|
|
self.args = args |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class DictNode(BaseNode): |
|
|
|
|
|
|
|
|
|
args: ArgumentNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, args: ArgumentNode, lineno: int, colno: int, end_lineno: int, end_colno: int): |
|
|
|
|
super().__init__(lineno, colno, args.filename, end_lineno=end_lineno, end_colno=end_colno) |
|
|
|
|
self.args = args |
|
|
|
@ -372,95 +386,177 @@ class EmptyNode(BaseNode): |
|
|
|
|
super().__init__(lineno, colno, filename) |
|
|
|
|
self.value = None |
|
|
|
|
|
|
|
|
|
def __eq__(self, other: object) -> bool: |
|
|
|
|
return isinstance(other, EmptyNode) |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class OrNode(BaseNode): |
|
|
|
|
|
|
|
|
|
left: BaseNode # type: ignore[misc] |
|
|
|
|
right: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, left: BaseNode, right: BaseNode): |
|
|
|
|
super().__init__(left.lineno, left.colno, left.filename) |
|
|
|
|
self.left = left # type: BaseNode |
|
|
|
|
self.right = right # type: BaseNode |
|
|
|
|
self.left = left |
|
|
|
|
self.right = right |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class AndNode(BaseNode): |
|
|
|
|
|
|
|
|
|
left: BaseNode # type: ignore[misc] |
|
|
|
|
right: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, left: BaseNode, right: BaseNode): |
|
|
|
|
super().__init__(left.lineno, left.colno, left.filename) |
|
|
|
|
self.left = left # type: BaseNode |
|
|
|
|
self.right = right # type: BaseNode |
|
|
|
|
self.left = left |
|
|
|
|
self.right = right |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class ComparisonNode(BaseNode): |
|
|
|
|
|
|
|
|
|
left: BaseNode # type: ignore[misc] |
|
|
|
|
right: BaseNode # type: ignore[misc] |
|
|
|
|
ctype: COMPARISONS # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, ctype: COMPARISONS, left: BaseNode, right: BaseNode): |
|
|
|
|
super().__init__(left.lineno, left.colno, left.filename) |
|
|
|
|
self.left = left # type: BaseNode |
|
|
|
|
self.right = right # type: BaseNode |
|
|
|
|
self.left = left |
|
|
|
|
self.right = right |
|
|
|
|
self.ctype = ctype |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class ArithmeticNode(BaseNode): |
|
|
|
|
|
|
|
|
|
left: BaseNode # type: ignore[misc] |
|
|
|
|
right: BaseNode # type: ignore[misc] |
|
|
|
|
# TODO: use a Literal for operation |
|
|
|
|
operation: str # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, operation: str, left: BaseNode, right: BaseNode): |
|
|
|
|
super().__init__(left.lineno, left.colno, left.filename) |
|
|
|
|
self.left = left # type: BaseNode |
|
|
|
|
self.right = right # type: BaseNode |
|
|
|
|
self.operation = operation # type: str |
|
|
|
|
self.left = left |
|
|
|
|
self.right = right |
|
|
|
|
self.operation = operation |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class NotNode(BaseNode): |
|
|
|
|
|
|
|
|
|
value: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, token: Token[TV_TokenTypes], value: BaseNode): |
|
|
|
|
super().__init__(token.lineno, token.colno, token.filename) |
|
|
|
|
self.value = value # type: BaseNode |
|
|
|
|
self.value = value |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class CodeBlockNode(BaseNode): |
|
|
|
|
|
|
|
|
|
lines: T.List[BaseNode] # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, token: Token[TV_TokenTypes]): |
|
|
|
|
super().__init__(token.lineno, token.colno, token.filename) |
|
|
|
|
self.lines = [] # type: T.List[BaseNode] |
|
|
|
|
self.lines = [] |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class IndexNode(BaseNode): |
|
|
|
|
|
|
|
|
|
iobject: BaseNode # type: ignore[misc] |
|
|
|
|
index: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, iobject: BaseNode, index: BaseNode): |
|
|
|
|
super().__init__(iobject.lineno, iobject.colno, iobject.filename) |
|
|
|
|
self.iobject = iobject # type: BaseNode |
|
|
|
|
self.index = index # type: BaseNode |
|
|
|
|
self.iobject = iobject |
|
|
|
|
self.index = index |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class MethodNode(BaseNode): |
|
|
|
|
|
|
|
|
|
source_object: BaseNode # type: ignore[misc] |
|
|
|
|
name: str # type: ignore[misc] |
|
|
|
|
args: ArgumentNode = field(hash=False) # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, filename: str, lineno: int, colno: int, source_object: BaseNode, name: str, args: ArgumentNode): |
|
|
|
|
super().__init__(lineno, colno, filename) |
|
|
|
|
self.source_object = source_object # type: BaseNode |
|
|
|
|
self.name = name # type: str |
|
|
|
|
self.source_object = source_object |
|
|
|
|
self.name = name |
|
|
|
|
assert isinstance(self.name, str) |
|
|
|
|
self.args = args # type: ArgumentNode |
|
|
|
|
self.args = args |
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class FunctionNode(BaseNode): |
|
|
|
|
|
|
|
|
|
func_name: str # type: ignore[misc] |
|
|
|
|
args: ArgumentNode = field(hash=False) # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, filename: str, lineno: int, colno: int, end_lineno: int, end_colno: int, func_name: str, args: ArgumentNode): |
|
|
|
|
super().__init__(lineno, colno, filename, end_lineno=end_lineno, end_colno=end_colno) |
|
|
|
|
self.func_name = func_name # type: str |
|
|
|
|
self.func_name = func_name |
|
|
|
|
assert isinstance(func_name, str) |
|
|
|
|
self.args = args # type: ArgumentNode |
|
|
|
|
self.args = args |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class AssignmentNode(BaseNode): |
|
|
|
|
|
|
|
|
|
var_name: str # type: ignore[misc] |
|
|
|
|
value: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, filename: str, lineno: int, colno: int, var_name: str, value: BaseNode): |
|
|
|
|
super().__init__(lineno, colno, filename) |
|
|
|
|
self.var_name = var_name # type: str |
|
|
|
|
self.var_name = var_name |
|
|
|
|
assert isinstance(var_name, str) |
|
|
|
|
self.value = value # type: BaseNode |
|
|
|
|
self.value = value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(init=False, unsafe_hash=True) |
|
|
|
|
class PlusAssignmentNode(BaseNode): |
|
|
|
|
|
|
|
|
|
var_name: str # type: ignore[misc] |
|
|
|
|
value: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, filename: str, lineno: int, colno: int, var_name: str, value: BaseNode): |
|
|
|
|
super().__init__(lineno, colno, filename) |
|
|
|
|
self.var_name = var_name # type: str |
|
|
|
|
self.var_name = var_name |
|
|
|
|
assert isinstance(var_name, str) |
|
|
|
|
self.value = value # type: BaseNode |
|
|
|
|
self.value = value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(init=False) |
|
|
|
|
class ForeachClauseNode(BaseNode): |
|
|
|
|
|
|
|
|
|
varnames: T.List[str] # type: ignore[misc] |
|
|
|
|
items: BaseNode # type: ignore[misc] |
|
|
|
|
block: CodeBlockNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, token: Token, varnames: T.List[str], items: BaseNode, block: CodeBlockNode): |
|
|
|
|
super().__init__(token.lineno, token.colno, token.filename) |
|
|
|
|
self.varnames = varnames # type: T.List[str] |
|
|
|
|
self.items = items # type: BaseNode |
|
|
|
|
self.block = block # type: CodeBlockNode |
|
|
|
|
self.varnames = varnames |
|
|
|
|
self.items = items |
|
|
|
|
self.block = block |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(init=False) |
|
|
|
|
class IfNode(BaseNode): |
|
|
|
|
|
|
|
|
|
condition: BaseNode # type: ignore[misc] |
|
|
|
|
block: CodeBlockNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, linenode: BaseNode, condition: BaseNode, block: CodeBlockNode): |
|
|
|
|
super().__init__(linenode.lineno, linenode.colno, linenode.filename) |
|
|
|
|
self.condition = condition # type: BaseNode |
|
|
|
|
self.block = block # type: CodeBlockNode |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(init=False) |
|
|
|
|
class IfClauseNode(BaseNode): |
|
|
|
|
|
|
|
|
|
ifs: T.List[IfNode] # type: ignore[misc] |
|
|
|
|
elseblock: T.Union[EmptyNode, CodeBlockNode] # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, linenode: BaseNode): |
|
|
|
|
super().__init__(linenode.lineno, linenode.colno, linenode.filename) |
|
|
|
|
self.ifs = [] # type: T.List[IfNode] |
|
|
|
|
self.elseblock = None # type: T.Union[EmptyNode, CodeBlockNode] |
|
|
|
|
self.ifs = [] |
|
|
|
|
self.elseblock = None |
|
|
|
|
|
|
|
|
|
class TestCaseClauseNode(BaseNode): |
|
|
|
|
def __init__(self, condition: BaseNode, block: CodeBlockNode): |
|
|
|
@ -468,12 +564,23 @@ class TestCaseClauseNode(BaseNode): |
|
|
|
|
self.condition = condition |
|
|
|
|
self.block = block |
|
|
|
|
|
|
|
|
|
@dataclass(init=False) |
|
|
|
|
class UMinusNode(BaseNode): |
|
|
|
|
|
|
|
|
|
value: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, current_location: Token, value: BaseNode): |
|
|
|
|
super().__init__(current_location.lineno, current_location.colno, current_location.filename) |
|
|
|
|
self.value = value # type: BaseNode |
|
|
|
|
self.value = value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(init=False) |
|
|
|
|
class TernaryNode(BaseNode): |
|
|
|
|
|
|
|
|
|
condition: BaseNode # type: ignore[misc] |
|
|
|
|
trueblock: BaseNode # type: ignore[misc] |
|
|
|
|
falseblock: BaseNode # type: ignore[misc] |
|
|
|
|
|
|
|
|
|
def __init__(self, condition: BaseNode, trueblock: BaseNode, falseblock: BaseNode): |
|
|
|
|
super().__init__(condition.lineno, condition.colno, condition.filename) |
|
|
|
|
self.condition = condition # type: BaseNode |
|
|
|
|