xref: /llvm-project/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/formatter.py (revision fffe8c668461e73055182f229765cb7de908e295)
1"""
2This is the llvm::Optional data formatter from llvm/utils/lldbDataFormatters.py
3with the implementation replaced by bytecode.
4"""
5
6from __future__ import annotations
7from formatter_bytecode import *
8import lldb
9
10
11def __lldb_init_module(debugger, internal_dict):
12    debugger.HandleCommand(
13        "type synthetic add -w llvm "
14        f"-l {__name__}.MyOptionalSynthProvider "
15        '-x "^MyOptional<.+>$"'
16    )
17    debugger.HandleCommand(
18        "type summary add -w llvm "
19        f"-e -F {__name__}.MyOptionalSummaryProvider "
20        '-x "^MyOptional<.+>$"'
21    )
22
23
24def stringify(bytecode: bytearray) -> str:
25    s = ""
26    in_hex = False
27    for b in bytecode:
28        if (b < 32 or b > 127 or chr(b) in ['"', "`", "'"]) or (
29            in_hex
30            and chr(b).lower()
31            in [
32                "a",
33                "b",
34                "c",
35                "d",
36                "e",
37                "f",
38                "0",
39                "1",
40                "2",
41                "3",
42                "4",
43                "5",
44                "6",
45                "7",
46                "8",
47                "9",
48            ]
49        ):
50            s += r"\x" + hex(b)[2:]
51            in_hex = True
52        else:
53            s += chr(b)
54            in_hex = False
55    return s
56
57
58def evaluate(assembler: str, data: list):
59    bytecode = compile(assembler)
60    trace = True
61    if trace:
62        print(
63            "Compiled to {0} bytes of bytecode:\n{1}".format(
64                len(bytecode), stringify(bytecode)
65            )
66        )
67    result = interpret(bytecode, [], data, False)  # trace)
68    if trace:
69        print("--> {0}".format(result))
70    return result
71
72
73# def GetOptionalValue(valobj):
74#    storage = valobj.GetChildMemberWithName("Storage")
75#    if not storage:
76#        storage = valobj
77#
78#    failure = 2
79#    hasVal = storage.GetChildMemberWithName("hasVal").GetValueAsUnsigned(failure)
80#    if hasVal == failure:
81#        return "<could not read MyOptional>"
82#
83#    if hasVal == 0:
84#        return None
85#
86#    underlying_type = storage.GetType().GetTemplateArgumentType(0)
87#    storage = storage.GetChildMemberWithName("value")
88#    return storage.Cast(underlying_type)
89
90
91def MyOptionalSummaryProvider(valobj, internal_dict):
92    #    val = GetOptionalValue(valobj)
93    #    if val is None:
94    #        return "None"
95    #    if val.summary:
96    #        return val.summary
97    #    return val.GetValue()
98    summary = ""
99    summary += ' dup "Storage" @get_child_with_name call'  # valobj storage
100    summary += " dup is_null ~ { swap } if drop"  # storage
101    summary += ' dup "hasVal" @get_child_with_name call'  # storage obj(hasVal)
102    summary += ' dup is_null { drop "<could not read MyOptional>" } {'
103    summary += "   @get_value_as_unsigned call"  # storage int(hasVal)
104    summary += '   0u = { "None" } {'
105    summary += "     dup @get_type call"
106    summary += "     0u @get_template_argument_type call"  # storage type
107    summary += "     swap"  # type storage
108    summary += '     "value" @get_child_with_name call'  # type value
109    summary += "     swap @cast call"  # type(value)
110    summary += '     dup is_null { "None" } {'
111    summary += (
112        "       dup @summary call dup @strlen call { @get_value call } { drop } ifelse"
113    )
114    summary += "     } ifelse"
115    summary += "   } ifelse"
116    summary += " } ifelse"
117    return evaluate(summary, [valobj])
118
119
120class MyOptionalSynthProvider:
121    """Provides deref support to llvm::Optional<T>"""
122
123    def __init__(self, valobj, internal_dict):
124        self.valobj = valobj
125
126    def num_children(self):
127        # return self.valobj.num_children
128        num_children = " @get_num_children call"
129        return evaluate(num_children, [self.valobj])
130
131    def get_child_index(self, name):
132        # if name == "$$dereference$$":
133        #    return self.valobj.num_children
134        # return self.valobj.GetIndexOfChildWithName(name)
135        get_child_index = ' dup "$$dereference$$" ='
136        get_child_index += " { drop @get_num_children call } {"  # obj name
137        get_child_index += "   @get_child_index call"  # index
138        get_child_index += " } ifelse"
139        return evaluate(get_child_index, [self.valobj, name])
140
141    def get_child_at_index(self, index):
142        # if index < self.valobj.num_children:
143        #    return self.valobj.GetChildAtIndex(index)
144        # return GetOptionalValue(self.valobj) or lldb.SBValue()
145        get_child_at_index = " over over swap"  # obj index index obj
146        get_child_at_index += " @get_num_children call"  # obj index index n
147        get_child_at_index += " < { @get_child_at_index call } {"  # obj index
148
149        get_opt_val = ' dup "Storage" @get_child_with_name call'  # valobj storage
150        get_opt_val += " dup { swap } if drop"  # storage
151        get_opt_val += ' dup "hasVal" @get_child_with_name call'  # storage
152        get_opt_val += " @get_value_as_unsigned call"  # storage int(hasVal)
153        get_opt_val += ' dup 2 = { drop "<could not read MyOptional>" } {'
154        get_opt_val += '   0 = { "None" } {'
155        get_opt_val += (
156            "     dup @get_type call 0 @get_template_argument_type call"  # storage type
157        )
158        get_opt_val += "     swap"  # type storage
159        get_opt_val += '     "value" @get_child_with_name call'  # type value
160        get_opt_val += "     swap @cast call"  # type(value)
161        get_opt_val += "   } ifelse"
162        get_opt_val += " } ifelse"
163
164        get_child_at_index += get_opt_val
165        get_child_at_index += " } ifelse"
166
167        return evaluate(get_child_at_index, [self.valobj, index])
168