1# Copyright (C) 2021-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6from enum import Enum
7from copy import copy
8
9from . import grammar
10
11class Tree:
12    def __init__(self, label=None, children=[]):
13        self.label = label
14        self.children = copy(children)
15        self.scope = None
16
17        self.structure = None
18
19        self.package_range = None
20
21        self.deferred_range = None
22        self.context_scope = None
23        self.factory = None
24
25    def append_child(self, child):
26        self.children.append(child)
27
28    def register_structure(self, structure):
29        self.structure = structure
30
31    def complete_parsing(self):
32        i = 0
33        for elem in self.structure:
34            if isinstance(elem, str):
35                if elem.endswith("?"):
36                    if i < len(self.children):
37                        setattr(self, elem[:-1], self.children[i])
38                    else:
39                        setattr(self, elem[:-1], None)
40                    break
41                elif elem.endswith("*"):
42                    setattr(self, elem[:-1] + "s", self.children[i:])
43                    break
44                else:
45                    setattr(self, elem, self.children[i])
46                    i += 1
47
48class Direction(Enum):
49    TOPDOWN = 1
50    BOTTOMUP = 2
51    CUSTOMIZED = 3
52
53class Visitor:
54    def __init__(self, direction):
55        self.depth = 0
56        if direction == Direction.TOPDOWN:
57            self.visit = self._visit_topdown
58        elif direction == Direction.BOTTOMUP:
59            self.visit = self._visit_bottomup
60
61    def __visit_node(self, tree):
62        fn = getattr(self, tree.label, None)
63        if not fn:
64            fn = getattr(self, "default", None)
65        if fn:
66            return fn(tree)
67        else:
68            return True
69
70    def _visit_topdown(self, tree):
71        go_on = self.__visit_node(tree)
72        if go_on != False:
73            self.depth += 1
74            for child in tree.children:
75                if isinstance(child, Tree):
76                    self.visit(child)
77            self.depth -= 1
78
79    def _visit_bottomup(self, tree):
80        self.depth += 1
81        for child in tree.children:
82            if isinstance(child, Tree):
83                self.visit(child)
84        self.depth -= 1
85        self.__visit_node(tree)
86
87    def visit(self, tree):
88        raise NotImplementedError
89
90class Transformer:
91    def __init__(self, direction):
92        self.depth = 0
93        if direction == Direction.TOPDOWN:
94            self.transform = self._transform_topdown
95        elif direction == Direction.BOTTOMUP:
96            self.transform = self._transform_bottomup
97
98    def __transform_node(self, tree):
99        fn = getattr(self, tree.label, None)
100        if not fn:
101            fn = getattr(self, "default", None)
102        if fn:
103            return fn(tree)
104        else:
105            return tree
106
107    def _transform_topdown(self, tree):
108        new_tree = self.__transform_node(tree)
109        self.depth += 1
110        for i, child in enumerate(tree.children):
111            if isinstance(child, Tree):
112                tree.children[i] = self.transform(child)
113        self.depth -= 1
114        return new_tree
115
116    def _transform_bottomup(self, tree):
117        self.depth += 1
118        for i, child in enumerate(tree.children):
119            if isinstance(child, Tree):
120                tree.children[i] = self.transform(child)
121        self.depth -= 1
122        return self.__transform_node(tree)
123
124    def transform(self, tree):
125        raise NotImplementedError
126
127class Interpreter:
128    def __init__(self, context):
129        self.context = context
130
131    def interpret(self, expr):
132        assert isinstance(expr, Tree)
133        fn = getattr(self, expr.label, None)
134        if not fn:
135            fn = getattr(self, "default", None)
136        if fn:
137            return fn(expr)
138        else:
139            raise NotImplementedError(f"don't know how to interpret a tree node with label {expr.label}")
140