xref: /llvm-project/lldb/examples/python/formatter_bytecode.py (revision ee1adc5aab4fb517314358ce03cfda426da9c4ce)
1fffe8c66SAdrian Prantl"""
2fffe8c66SAdrian PrantlSpecification, compiler, disassembler, and interpreter
3fffe8c66SAdrian Prantlfor LLDB dataformatter bytecode.
4fffe8c66SAdrian Prantl
5fffe8c66SAdrian PrantlSee https://lldb.llvm.org/resources/formatterbytecode.html for more details.
6fffe8c66SAdrian Prantl"""
7fffe8c66SAdrian Prantl
8fffe8c66SAdrian Prantlfrom __future__ import annotations
9fffe8c66SAdrian Prantl
10fffe8c66SAdrian Prantl# Types
11fffe8c66SAdrian Prantltype_String = 1
12fffe8c66SAdrian Prantltype_Int = 2
13fffe8c66SAdrian Prantltype_UInt = 3
14fffe8c66SAdrian Prantltype_Object = 4
15fffe8c66SAdrian Prantltype_Type = 5
16fffe8c66SAdrian Prantl
17fffe8c66SAdrian Prantl# Opcodes
18fffe8c66SAdrian Prantlopcode = dict()
19fffe8c66SAdrian Prantl
20fffe8c66SAdrian Prantl
21fffe8c66SAdrian Prantldef define_opcode(n, mnemonic, name):
22fffe8c66SAdrian Prantl    globals()["op_" + name] = n
23fffe8c66SAdrian Prantl    if mnemonic:
24fffe8c66SAdrian Prantl        opcode[mnemonic] = n
25fffe8c66SAdrian Prantl    opcode[n] = mnemonic
26fffe8c66SAdrian Prantl
27fffe8c66SAdrian Prantl
28fffe8c66SAdrian Prantldefine_opcode(1, "dup", "dup")
29fffe8c66SAdrian Prantldefine_opcode(2, "drop", "drop")
30fffe8c66SAdrian Prantldefine_opcode(3, "pick", "pick")
31fffe8c66SAdrian Prantldefine_opcode(4, "over", "over")
32fffe8c66SAdrian Prantldefine_opcode(5, "swap", "swap")
33fffe8c66SAdrian Prantldefine_opcode(6, "rot", "rot")
34fffe8c66SAdrian Prantl
35fffe8c66SAdrian Prantldefine_opcode(0x10, "{", "begin")
36fffe8c66SAdrian Prantldefine_opcode(0x11, "if", "if")
37fffe8c66SAdrian Prantldefine_opcode(0x12, "ifelse", "ifelse")
38*ee1adc5aSAdrian Prantldefine_opcode(0x13, "return", "return")
39fffe8c66SAdrian Prantl
40fffe8c66SAdrian Prantldefine_opcode(0x20, None, "lit_uint")
41fffe8c66SAdrian Prantldefine_opcode(0x21, None, "lit_int")
42fffe8c66SAdrian Prantldefine_opcode(0x22, None, "lit_string")
43fffe8c66SAdrian Prantldefine_opcode(0x23, None, "lit_selector")
44fffe8c66SAdrian Prantl
45fffe8c66SAdrian Prantldefine_opcode(0x2A, "as_int", "as_int")
46fffe8c66SAdrian Prantldefine_opcode(0x2B, "as_uint", "as_uint")
47fffe8c66SAdrian Prantldefine_opcode(0x2C, "is_null", "is_null")
48fffe8c66SAdrian Prantl
49fffe8c66SAdrian Prantldefine_opcode(0x30, "+", "plus")
50fffe8c66SAdrian Prantldefine_opcode(0x31, "-", "minus")
51fffe8c66SAdrian Prantldefine_opcode(0x32, "*", "mul")
52fffe8c66SAdrian Prantldefine_opcode(0x33, "/", "div")
53fffe8c66SAdrian Prantldefine_opcode(0x34, "%", "mod")
54fffe8c66SAdrian Prantldefine_opcode(0x35, "<<", "shl")
55fffe8c66SAdrian Prantldefine_opcode(0x36, ">>", "shr")
56fffe8c66SAdrian Prantl
57fffe8c66SAdrian Prantldefine_opcode(0x40, "&", "and")
58fffe8c66SAdrian Prantldefine_opcode(0x41, "|", "or")
59fffe8c66SAdrian Prantldefine_opcode(0x42, "^", "xor")
60fffe8c66SAdrian Prantldefine_opcode(0x43, "~", "not")
61fffe8c66SAdrian Prantl
62fffe8c66SAdrian Prantldefine_opcode(0x50, "=", "eq")
63fffe8c66SAdrian Prantldefine_opcode(0x51, "!=", "neq")
64fffe8c66SAdrian Prantldefine_opcode(0x52, "<", "lt")
65fffe8c66SAdrian Prantldefine_opcode(0x53, ">", "gt")
66fffe8c66SAdrian Prantldefine_opcode(0x54, "=<", "le")
67fffe8c66SAdrian Prantldefine_opcode(0x55, ">=", "ge")
68fffe8c66SAdrian Prantl
69fffe8c66SAdrian Prantldefine_opcode(0x60, "call", "call")
70fffe8c66SAdrian Prantl
71fffe8c66SAdrian Prantl# Function signatures
72fffe8c66SAdrian Prantlsig_summary = 0
73fffe8c66SAdrian Prantlsig_init = 1
74fffe8c66SAdrian Prantlsig_get_num_children = 2
75fffe8c66SAdrian Prantlsig_get_child_index = 3
76fffe8c66SAdrian Prantlsig_get_child_at_index = 4
77fffe8c66SAdrian Prantl
78fffe8c66SAdrian Prantl# Selectors
79fffe8c66SAdrian Prantlselector = dict()
80fffe8c66SAdrian Prantl
81fffe8c66SAdrian Prantl
82fffe8c66SAdrian Prantldef define_selector(n, name):
83fffe8c66SAdrian Prantl    globals()["sel_" + name] = n
84fffe8c66SAdrian Prantl    selector["@" + name] = n
85fffe8c66SAdrian Prantl    selector[n] = "@" + name
86fffe8c66SAdrian Prantl
87fffe8c66SAdrian Prantl
88fffe8c66SAdrian Prantldefine_selector(0, "summary")
89fffe8c66SAdrian Prantldefine_selector(1, "type_summary")
90fffe8c66SAdrian Prantl
91fffe8c66SAdrian Prantldefine_selector(0x10, "get_num_children")
92fffe8c66SAdrian Prantldefine_selector(0x11, "get_child_at_index")
93fffe8c66SAdrian Prantldefine_selector(0x12, "get_child_with_name")
94fffe8c66SAdrian Prantldefine_selector(0x13, "get_child_index")
95fffe8c66SAdrian Prantldefine_selector(0x15, "get_type")
96fffe8c66SAdrian Prantldefine_selector(0x16, "get_template_argument_type")
97fffe8c66SAdrian Prantldefine_selector(0x17, "cast")
98fffe8c66SAdrian Prantldefine_selector(0x20, "get_value")
99fffe8c66SAdrian Prantldefine_selector(0x21, "get_value_as_unsigned")
100fffe8c66SAdrian Prantldefine_selector(0x22, "get_value_as_signed")
101fffe8c66SAdrian Prantldefine_selector(0x23, "get_value_as_address")
102fffe8c66SAdrian Prantl
103fffe8c66SAdrian Prantldefine_selector(0x40, "read_memory_byte")
104fffe8c66SAdrian Prantldefine_selector(0x41, "read_memory_uint32")
105fffe8c66SAdrian Prantldefine_selector(0x42, "read_memory_int32")
106fffe8c66SAdrian Prantldefine_selector(0x43, "read_memory_unsigned")
107fffe8c66SAdrian Prantldefine_selector(0x44, "read_memory_signed")
108fffe8c66SAdrian Prantldefine_selector(0x45, "read_memory_address")
109fffe8c66SAdrian Prantldefine_selector(0x46, "read_memory")
110fffe8c66SAdrian Prantl
111fffe8c66SAdrian Prantldefine_selector(0x50, "fmt")
112fffe8c66SAdrian Prantldefine_selector(0x51, "sprintf")
113fffe8c66SAdrian Prantldefine_selector(0x52, "strlen")
114fffe8c66SAdrian Prantl
115fffe8c66SAdrian Prantl
116fffe8c66SAdrian Prantl################################################################################
117fffe8c66SAdrian Prantl# Compiler.
118fffe8c66SAdrian Prantl################################################################################
119fffe8c66SAdrian Prantl
120fffe8c66SAdrian Prantl
121fffe8c66SAdrian Prantldef compile(assembler: str) -> bytearray:
122fffe8c66SAdrian Prantl    """Compile assembler into bytecode"""
123fffe8c66SAdrian Prantl    # This is a stack of all in-flight/unterminated blocks.
124fffe8c66SAdrian Prantl    bytecode = [bytearray()]
125fffe8c66SAdrian Prantl
126fffe8c66SAdrian Prantl    def emit(byte):
127fffe8c66SAdrian Prantl        bytecode[-1].append(byte)
128fffe8c66SAdrian Prantl
129fffe8c66SAdrian Prantl    tokens = list(assembler.split(" "))
130fffe8c66SAdrian Prantl    tokens.reverse()
131fffe8c66SAdrian Prantl    while tokens:
132fffe8c66SAdrian Prantl        tok = tokens.pop()
133fffe8c66SAdrian Prantl        if tok == "":
134fffe8c66SAdrian Prantl            pass
135fffe8c66SAdrian Prantl        elif tok == "{":
136fffe8c66SAdrian Prantl            bytecode.append(bytearray())
137fffe8c66SAdrian Prantl        elif tok == "}":
138fffe8c66SAdrian Prantl            block = bytecode.pop()
139fffe8c66SAdrian Prantl            emit(op_begin)
140fffe8c66SAdrian Prantl            emit(len(block))  # FIXME: uleb
141fffe8c66SAdrian Prantl            bytecode[-1].extend(block)
142fffe8c66SAdrian Prantl        elif tok[0].isdigit():
143fffe8c66SAdrian Prantl            if tok[-1] == "u":
144fffe8c66SAdrian Prantl                emit(op_lit_uint)
145fffe8c66SAdrian Prantl                emit(int(tok[:-1]))  # FIXME
146fffe8c66SAdrian Prantl            else:
147fffe8c66SAdrian Prantl                emit(op_lit_int)
148fffe8c66SAdrian Prantl                emit(int(tok))  # FIXME
149fffe8c66SAdrian Prantl        elif tok[0] == "@":
150fffe8c66SAdrian Prantl            emit(op_lit_selector)
151fffe8c66SAdrian Prantl            emit(selector[tok])
152fffe8c66SAdrian Prantl        elif tok[0] == '"':
153fffe8c66SAdrian Prantl            s = bytearray()
154fffe8c66SAdrian Prantl            done = False
155fffe8c66SAdrian Prantl            chrs = tok[1:]
156fffe8c66SAdrian Prantl            while not done:
157fffe8c66SAdrian Prantl                quoted = False
158fffe8c66SAdrian Prantl                for c in chrs:
159fffe8c66SAdrian Prantl                    if quoted:
160fffe8c66SAdrian Prantl                        s.append(ord(c))  # FIXME
161fffe8c66SAdrian Prantl                        quoted = False
162fffe8c66SAdrian Prantl                    elif c == "\\":
163fffe8c66SAdrian Prantl                        quoted = True
164fffe8c66SAdrian Prantl                    elif c == '"':
165fffe8c66SAdrian Prantl                        done = True
166fffe8c66SAdrian Prantl                        break
167fffe8c66SAdrian Prantl                        # FIXME assert this is last in token
168fffe8c66SAdrian Prantl                    else:
169fffe8c66SAdrian Prantl                        s.append(ord(c))
170fffe8c66SAdrian Prantl                if not done:
171fffe8c66SAdrian Prantl                    s.append(ord(" "))
172fffe8c66SAdrian Prantl                    chrs = tokens.pop()
173fffe8c66SAdrian Prantl
174fffe8c66SAdrian Prantl            emit(op_lit_string)
175fffe8c66SAdrian Prantl            emit(len(s))
176fffe8c66SAdrian Prantl            bytecode[-1].extend(s)
177fffe8c66SAdrian Prantl        else:
178fffe8c66SAdrian Prantl            emit(opcode[tok])
179fffe8c66SAdrian Prantl    assert len(bytecode) == 1  # unterminated {
180fffe8c66SAdrian Prantl    return bytecode[0]
181fffe8c66SAdrian Prantl
182fffe8c66SAdrian Prantl
183fffe8c66SAdrian Prantl################################################################################
184fffe8c66SAdrian Prantl# Disassembler.
185fffe8c66SAdrian Prantl################################################################################
186fffe8c66SAdrian Prantl
187fffe8c66SAdrian Prantl
188fffe8c66SAdrian Prantldef disassemble(bytecode: bytearray) -> (str, int):
189fffe8c66SAdrian Prantl    """Disassemble bytecode into (assembler, token starts)"""
190fffe8c66SAdrian Prantl    asm = ""
191fffe8c66SAdrian Prantl    all_bytes = list(bytecode)
192fffe8c66SAdrian Prantl    all_bytes.reverse()
193fffe8c66SAdrian Prantl    blocks = []
194fffe8c66SAdrian Prantl    tokens = [0]
195fffe8c66SAdrian Prantl
196fffe8c66SAdrian Prantl    def next_byte():
197fffe8c66SAdrian Prantl        """Fetch the next byte in the bytecode and keep track of all
198fffe8c66SAdrian Prantl        in-flight blocks"""
199fffe8c66SAdrian Prantl        for i in range(len(blocks)):
200fffe8c66SAdrian Prantl            blocks[i] -= 1
201fffe8c66SAdrian Prantl        tokens.append(len(asm))
202fffe8c66SAdrian Prantl        return all_bytes.pop()
203fffe8c66SAdrian Prantl
204fffe8c66SAdrian Prantl    while all_bytes:
205fffe8c66SAdrian Prantl        b = next_byte()
206fffe8c66SAdrian Prantl        if b == op_begin:
207fffe8c66SAdrian Prantl            asm += "{"
208fffe8c66SAdrian Prantl            length = next_byte()
209fffe8c66SAdrian Prantl            blocks.append(length)
210fffe8c66SAdrian Prantl        elif b == op_lit_uint:
211fffe8c66SAdrian Prantl            b = next_byte()
212fffe8c66SAdrian Prantl            asm += str(b)  # FIXME uleb
213fffe8c66SAdrian Prantl            asm += "u"
214fffe8c66SAdrian Prantl        elif b == op_lit_int:
215fffe8c66SAdrian Prantl            b = next_byte()
216fffe8c66SAdrian Prantl            asm += str(b)
217fffe8c66SAdrian Prantl        elif b == op_lit_selector:
218fffe8c66SAdrian Prantl            b = next_byte()
219fffe8c66SAdrian Prantl            asm += selector[b]
220fffe8c66SAdrian Prantl        elif b == op_lit_string:
221fffe8c66SAdrian Prantl            length = next_byte()
222fffe8c66SAdrian Prantl            s = "'"
223fffe8c66SAdrian Prantl            while length:
224fffe8c66SAdrian Prantl                s += chr(next_byte())
225fffe8c66SAdrian Prantl                length -= 1
226fffe8c66SAdrian Prantl            asm += '"' + repr(s)[2:]
227fffe8c66SAdrian Prantl        else:
228fffe8c66SAdrian Prantl            asm += opcode[b]
229fffe8c66SAdrian Prantl
230fffe8c66SAdrian Prantl        while blocks and blocks[-1] == 0:
231fffe8c66SAdrian Prantl            asm += " }"
232fffe8c66SAdrian Prantl            blocks.pop()
233fffe8c66SAdrian Prantl
234fffe8c66SAdrian Prantl        if all_bytes:
235fffe8c66SAdrian Prantl            asm += " "
236fffe8c66SAdrian Prantl
237fffe8c66SAdrian Prantl    if blocks:
238fffe8c66SAdrian Prantl        asm += "ERROR"
239fffe8c66SAdrian Prantl    return asm, tokens
240fffe8c66SAdrian Prantl
241fffe8c66SAdrian Prantl
242fffe8c66SAdrian Prantl################################################################################
243fffe8c66SAdrian Prantl# Interpreter.
244fffe8c66SAdrian Prantl################################################################################
245fffe8c66SAdrian Prantl
246fffe8c66SAdrian Prantl
247fffe8c66SAdrian Prantldef count_fmt_params(fmt: str) -> int:
248fffe8c66SAdrian Prantl    """Count the number of parameters in a format string"""
249fffe8c66SAdrian Prantl    from string import Formatter
250fffe8c66SAdrian Prantl
251fffe8c66SAdrian Prantl    f = Formatter()
252fffe8c66SAdrian Prantl    n = 0
253fffe8c66SAdrian Prantl    for _, name, _, _ in f.parse(fmt):
254fffe8c66SAdrian Prantl        if name > n:
255fffe8c66SAdrian Prantl            n = name
256fffe8c66SAdrian Prantl    return n
257fffe8c66SAdrian Prantl
258fffe8c66SAdrian Prantl
259fffe8c66SAdrian Prantldef interpret(bytecode: bytearray, control: list, data: list, tracing: bool = False):
260fffe8c66SAdrian Prantl    """Interpret bytecode"""
261fffe8c66SAdrian Prantl    frame = []
262fffe8c66SAdrian Prantl    frame.append((0, len(bytecode)))
263fffe8c66SAdrian Prantl
264fffe8c66SAdrian Prantl    def trace():
265fffe8c66SAdrian Prantl        """print a trace of the execution for debugging purposes"""
266fffe8c66SAdrian Prantl
267fffe8c66SAdrian Prantl        def fmt(d):
268fffe8c66SAdrian Prantl            if isinstance(d, int):
269fffe8c66SAdrian Prantl                return str(d)
270fffe8c66SAdrian Prantl            if isinstance(d, str):
271fffe8c66SAdrian Prantl                return d
272fffe8c66SAdrian Prantl            return repr(type(d))
273fffe8c66SAdrian Prantl
274fffe8c66SAdrian Prantl        pc, end = frame[-1]
275fffe8c66SAdrian Prantl        asm, tokens = disassemble(bytecode)
276fffe8c66SAdrian Prantl        print(
277fffe8c66SAdrian Prantl            "=== frame = {1}, data = {2}, opcode = {0}".format(
278fffe8c66SAdrian Prantl                opcode[b], frame, [fmt(d) for d in data]
279fffe8c66SAdrian Prantl            )
280fffe8c66SAdrian Prantl        )
281fffe8c66SAdrian Prantl        print(asm)
282fffe8c66SAdrian Prantl        print(" " * (tokens[pc]) + "^")
283fffe8c66SAdrian Prantl
284fffe8c66SAdrian Prantl    def next_byte():
285fffe8c66SAdrian Prantl        """Fetch the next byte and update the PC"""
286fffe8c66SAdrian Prantl        pc, end = frame[-1]
287fffe8c66SAdrian Prantl        assert pc < len(bytecode)
288fffe8c66SAdrian Prantl        b = bytecode[pc]
289fffe8c66SAdrian Prantl        frame[-1] = pc + 1, end
290fffe8c66SAdrian Prantl        # At the end of a block?
291fffe8c66SAdrian Prantl        while pc >= end:
292fffe8c66SAdrian Prantl            frame.pop()
293fffe8c66SAdrian Prantl            if not frame:
294fffe8c66SAdrian Prantl                return None
295fffe8c66SAdrian Prantl            pc, end = frame[-1]
296fffe8c66SAdrian Prantl            if pc >= end:
297fffe8c66SAdrian Prantl                return None
298fffe8c66SAdrian Prantl            b = bytecode[pc]
299fffe8c66SAdrian Prantl            frame[-1] = pc + 1, end
300fffe8c66SAdrian Prantl        return b
301fffe8c66SAdrian Prantl
302fffe8c66SAdrian Prantl    while frame[-1][0] < len(bytecode):
303fffe8c66SAdrian Prantl        b = next_byte()
304fffe8c66SAdrian Prantl        if b == None:
305fffe8c66SAdrian Prantl            break
306fffe8c66SAdrian Prantl        if tracing:
307fffe8c66SAdrian Prantl            trace()
308fffe8c66SAdrian Prantl        # Data stack manipulation.
309fffe8c66SAdrian Prantl        if b == op_dup:
310fffe8c66SAdrian Prantl            data.append(data[-1])
311fffe8c66SAdrian Prantl        elif b == op_drop:
312fffe8c66SAdrian Prantl            data.pop()
313fffe8c66SAdrian Prantl        elif b == op_pick:
314fffe8c66SAdrian Prantl            data.append(data[data.pop()])
315fffe8c66SAdrian Prantl        elif b == op_over:
316fffe8c66SAdrian Prantl            data.append(data[-2])
317fffe8c66SAdrian Prantl        elif b == op_swap:
318fffe8c66SAdrian Prantl            x = data.pop()
319fffe8c66SAdrian Prantl            y = data.pop()
320fffe8c66SAdrian Prantl            data.append(x)
321fffe8c66SAdrian Prantl            data.append(y)
322fffe8c66SAdrian Prantl        elif b == op_rot:
323fffe8c66SAdrian Prantl            z = data.pop()
324fffe8c66SAdrian Prantl            y = data.pop()
325fffe8c66SAdrian Prantl            x = data.pop()
326fffe8c66SAdrian Prantl            data.append(z)
327fffe8c66SAdrian Prantl            data.append(x)
328fffe8c66SAdrian Prantl            data.append(y)
329fffe8c66SAdrian Prantl
330fffe8c66SAdrian Prantl        # Control stack manipulation.
331fffe8c66SAdrian Prantl        elif b == op_begin:
332fffe8c66SAdrian Prantl            length = next_byte()
333fffe8c66SAdrian Prantl            pc, end = frame[-1]
334fffe8c66SAdrian Prantl            control.append((pc, pc + length))
335fffe8c66SAdrian Prantl            frame[-1] = pc + length, end
336fffe8c66SAdrian Prantl        elif b == op_if:
337fffe8c66SAdrian Prantl            if data.pop():
338fffe8c66SAdrian Prantl                frame.append(control.pop())
339fffe8c66SAdrian Prantl        elif b == op_ifelse:
340fffe8c66SAdrian Prantl            if data.pop():
341fffe8c66SAdrian Prantl                control.pop()
342fffe8c66SAdrian Prantl                frame.append(control.pop())
343fffe8c66SAdrian Prantl            else:
344fffe8c66SAdrian Prantl                frame.append(control.pop())
345fffe8c66SAdrian Prantl                control.pop()
346*ee1adc5aSAdrian Prantl        elif b == op_return:
347*ee1adc5aSAdrian Prantl            control.clear()
348*ee1adc5aSAdrian Prantl            return data[-1]
349fffe8c66SAdrian Prantl
350fffe8c66SAdrian Prantl        # Literals.
351fffe8c66SAdrian Prantl        elif b == op_lit_uint:
352fffe8c66SAdrian Prantl            b = next_byte()  # FIXME uleb
353fffe8c66SAdrian Prantl            data.append(int(b))
354fffe8c66SAdrian Prantl        elif b == op_lit_int:
355fffe8c66SAdrian Prantl            b = next_byte()  # FIXME uleb
356fffe8c66SAdrian Prantl            data.append(int(b))
357fffe8c66SAdrian Prantl        elif b == op_lit_selector:
358fffe8c66SAdrian Prantl            b = next_byte()
359fffe8c66SAdrian Prantl            data.append(b)
360fffe8c66SAdrian Prantl        elif b == op_lit_string:
361fffe8c66SAdrian Prantl            length = next_byte()
362fffe8c66SAdrian Prantl            s = ""
363fffe8c66SAdrian Prantl            while length:
364fffe8c66SAdrian Prantl                s += chr(next_byte())
365fffe8c66SAdrian Prantl                length -= 1
366fffe8c66SAdrian Prantl            data.append(s)
367fffe8c66SAdrian Prantl
368fffe8c66SAdrian Prantl        elif b == op_as_uint:
369fffe8c66SAdrian Prantl            pass
370fffe8c66SAdrian Prantl        elif b == op_as_int:
371fffe8c66SAdrian Prantl            pass
372fffe8c66SAdrian Prantl        elif b == op_is_null:
373fffe8c66SAdrian Prantl            data.append(1 if data.pop() == None else 0)
374fffe8c66SAdrian Prantl
375fffe8c66SAdrian Prantl        # Arithmetic, logic, etc.
376fffe8c66SAdrian Prantl        elif b == op_plus:
377fffe8c66SAdrian Prantl            data.append(data.pop() + data.pop())
378fffe8c66SAdrian Prantl        elif b == op_minus:
379fffe8c66SAdrian Prantl            data.append(-data.pop() + data.pop())
380fffe8c66SAdrian Prantl        elif b == op_mul:
381fffe8c66SAdrian Prantl            data.append(data.pop() * data.pop())
382fffe8c66SAdrian Prantl        elif b == op_div:
383fffe8c66SAdrian Prantl            y = data.pop()
384fffe8c66SAdrian Prantl            data.append(data.pop() / y)
385fffe8c66SAdrian Prantl        elif b == op_mod:
386fffe8c66SAdrian Prantl            y = data.pop()
387fffe8c66SAdrian Prantl            data.append(data.pop() % y)
388fffe8c66SAdrian Prantl        elif b == op_shl:
389fffe8c66SAdrian Prantl            y = data.pop()
390fffe8c66SAdrian Prantl            data.append(data.pop() << y)
391fffe8c66SAdrian Prantl        elif b == op_shr:
392fffe8c66SAdrian Prantl            y = data.pop()
393fffe8c66SAdrian Prantl            data.append(data.pop() >> y)
394fffe8c66SAdrian Prantl        elif b == op_and:
395fffe8c66SAdrian Prantl            data.append(data.pop() & data.pop())
396fffe8c66SAdrian Prantl        elif b == op_or:
397fffe8c66SAdrian Prantl            data.append(data.pop() | data.pop())
398fffe8c66SAdrian Prantl        elif b == op_xor:
399fffe8c66SAdrian Prantl            data.append(data.pop() ^ data.pop())
400fffe8c66SAdrian Prantl        elif b == op_not:
401fffe8c66SAdrian Prantl            data.append(not data.pop())
402fffe8c66SAdrian Prantl        elif b == op_eq:
403fffe8c66SAdrian Prantl            data.append(data.pop() == data.pop())
404fffe8c66SAdrian Prantl        elif b == op_neq:
405fffe8c66SAdrian Prantl            data.append(data.pop() != data.pop())
406fffe8c66SAdrian Prantl        elif b == op_lt:
407fffe8c66SAdrian Prantl            data.append(data.pop() > data.pop())
408fffe8c66SAdrian Prantl        elif b == op_gt:
409fffe8c66SAdrian Prantl            data.append(data.pop() < data.pop())
410fffe8c66SAdrian Prantl        elif b == op_le:
411fffe8c66SAdrian Prantl            data.append(data.pop() >= data.pop())
412fffe8c66SAdrian Prantl        elif b == op_ge:
413fffe8c66SAdrian Prantl            data.append(data.pop() <= data.pop())
414fffe8c66SAdrian Prantl
415fffe8c66SAdrian Prantl        # Function calls.
416fffe8c66SAdrian Prantl        elif b == op_call:
417fffe8c66SAdrian Prantl            sel = data.pop()
418fffe8c66SAdrian Prantl            if sel == sel_summary:
419fffe8c66SAdrian Prantl                data.append(data.pop().GetSummary())
420fffe8c66SAdrian Prantl            elif sel == sel_get_num_children:
421fffe8c66SAdrian Prantl                data.append(data.pop().GetNumChildren())
422fffe8c66SAdrian Prantl            elif sel == sel_get_child_at_index:
423fffe8c66SAdrian Prantl                index = data.pop()
424fffe8c66SAdrian Prantl                valobj = data.pop()
425fffe8c66SAdrian Prantl                data.append(valobj.GetChildAtIndex(index))
426fffe8c66SAdrian Prantl            elif sel == sel_get_child_with_name:
427fffe8c66SAdrian Prantl                name = data.pop()
428fffe8c66SAdrian Prantl                valobj = data.pop()
429fffe8c66SAdrian Prantl                data.append(valobj.GetChildMemberWithName(name))
430fffe8c66SAdrian Prantl            elif sel == sel_get_child_index:
431fffe8c66SAdrian Prantl                name = data.pop()
432fffe8c66SAdrian Prantl                valobj = data.pop()
433fffe8c66SAdrian Prantl                data.append(valobj.GetIndexOfChildWithName(name))
434fffe8c66SAdrian Prantl            elif sel == sel_get_type:
435fffe8c66SAdrian Prantl                data.append(data.pop().GetType())
436fffe8c66SAdrian Prantl            elif sel == sel_get_template_argument_type:
437fffe8c66SAdrian Prantl                n = data.pop()
438fffe8c66SAdrian Prantl                valobj = data.pop()
439fffe8c66SAdrian Prantl                data.append(valobj.GetTemplateArgumentType(n))
440fffe8c66SAdrian Prantl            elif sel == sel_get_value:
441fffe8c66SAdrian Prantl                data.append(data.pop().GetValue())
442fffe8c66SAdrian Prantl            elif sel == sel_get_value_as_unsigned:
443fffe8c66SAdrian Prantl                data.append(data.pop().GetValueAsUnsigned())
444fffe8c66SAdrian Prantl            elif sel == sel_get_value_as_signed:
445fffe8c66SAdrian Prantl                data.append(data.pop().GetValueAsSigned())
446fffe8c66SAdrian Prantl            elif sel == sel_get_value_as_address:
447fffe8c66SAdrian Prantl                data.append(data.pop().GetValueAsAddress())
448fffe8c66SAdrian Prantl            elif sel == sel_cast:
449fffe8c66SAdrian Prantl                sbtype = data.pop()
450fffe8c66SAdrian Prantl                valobj = data.pop()
451fffe8c66SAdrian Prantl                data.append(valobj.Cast(sbtype))
452fffe8c66SAdrian Prantl            elif sel == sel_strlen:
453fffe8c66SAdrian Prantl                s = data.pop()
454fffe8c66SAdrian Prantl                data.append(len(s) if s else 0)
455fffe8c66SAdrian Prantl            elif sel == sel_fmt:
456fffe8c66SAdrian Prantl                fmt = data.pop()
457fffe8c66SAdrian Prantl                n = count_fmt_params(fmt)
458fffe8c66SAdrian Prantl                args = []
459fffe8c66SAdrian Prantl                for i in range(n):
460fffe8c66SAdrian Prantl                    args.append(data.pop())
461fffe8c66SAdrian Prantl                data.append(fmt.format(*args))
462fffe8c66SAdrian Prantl            else:
463fffe8c66SAdrian Prantl                print("not implemented: " + selector[sel])
464fffe8c66SAdrian Prantl                assert False
465fffe8c66SAdrian Prantl                pass
466fffe8c66SAdrian Prantl    return data[-1]
467fffe8c66SAdrian Prantl
468fffe8c66SAdrian Prantl
469fffe8c66SAdrian Prantlif __name__ == "__main__":
4709f98949cSAdrian Prantl    # Work around the fact that one of the local files is called
4719f98949cSAdrian Prantl    # types.py, which breaks some versions of python.
4729f98949cSAdrian Prantl    import os, sys
4739f98949cSAdrian Prantl
4749f98949cSAdrian Prantl    path = os.path.abspath(os.path.dirname(__file__))
4759f98949cSAdrian Prantl    sys.path.remove(path)
476fffe8c66SAdrian Prantl    import argparse
477fffe8c66SAdrian Prantl
478fffe8c66SAdrian Prantl    parser = argparse.ArgumentParser(
479fffe8c66SAdrian Prantl        description="""
480fffe8c66SAdrian Prantl    Compiler, disassembler, and interpreter for LLDB dataformatter bytecode.
481fffe8c66SAdrian Prantl    See https://lldb.llvm.org/resources/formatterbytecode.html for more details.
482fffe8c66SAdrian Prantl    """
483fffe8c66SAdrian Prantl    )
484fffe8c66SAdrian Prantl    parser.add_argument(
485fffe8c66SAdrian Prantl        "-c", "--compile", type=str, help="compile assembler into bytecode"
486fffe8c66SAdrian Prantl    )
487fffe8c66SAdrian Prantl    parser.add_argument("-d", "--disassemble", type=str, help="disassemble bytecode")
488fffe8c66SAdrian Prantl    parser.add_argument("-t", "--test", action="store_true", help="run unit tests")
489fffe8c66SAdrian Prantl    args = parser.parse_args()
490fffe8c66SAdrian Prantl    if args.compile:
491fffe8c66SAdrian Prantl        print(compile(str(args.compile)).hex())
492fffe8c66SAdrian Prantl
493fffe8c66SAdrian Prantl    if args.disassemble:
494fffe8c66SAdrian Prantl        print(disassemble(bytearray.fromhex(str(args.disassemble))))
495fffe8c66SAdrian Prantl
496fffe8c66SAdrian Prantl    ############################################################################
497fffe8c66SAdrian Prantl    # Tests.
498fffe8c66SAdrian Prantl    ############################################################################
499fffe8c66SAdrian Prantl    if args.test:
500fffe8c66SAdrian Prantl        import unittest
501fffe8c66SAdrian Prantl
502fffe8c66SAdrian Prantl        class TestCompiler(unittest.TestCase):
503fffe8c66SAdrian Prantl            def test(self):
504fffe8c66SAdrian Prantl                self.assertEqual(compile("1u dup").hex(), "200101")
505fffe8c66SAdrian Prantl                self.assertEqual(compile('"1u dup"').hex(), "2206317520647570")
506fffe8c66SAdrian Prantl                self.assertEqual(compile("16 < { dup } if").hex(), "21105210010111")
507fffe8c66SAdrian Prantl                self.assertEqual(compile('{ { " } " } }').hex(), "100710052203207d20")
508fffe8c66SAdrian Prantl
509fffe8c66SAdrian Prantl                def roundtrip(asm):
510fffe8c66SAdrian Prantl                    self.assertEqual(disassemble(compile(asm))[0], asm)
511fffe8c66SAdrian Prantl
512fffe8c66SAdrian Prantl                roundtrip("1u dup")
513fffe8c66SAdrian Prantl                roundtrip('1u dup "1u dup"')
514fffe8c66SAdrian Prantl                roundtrip("16 < { dup } if")
515fffe8c66SAdrian Prantl                roundtrip('{ { " } " } }')
516fffe8c66SAdrian Prantl
517fffe8c66SAdrian Prantl                self.assertEqual(interpret(compile("1 1 +"), [], []), 2)
518fffe8c66SAdrian Prantl                self.assertEqual(interpret(compile("2 1 1 + *"), [], []), 4)
519fffe8c66SAdrian Prantl                self.assertEqual(
520fffe8c66SAdrian Prantl                    interpret(compile('2 1 > { "yes" } { "no" } ifelse'), [], []), "yes"
521fffe8c66SAdrian Prantl                )
522fffe8c66SAdrian Prantl
523fffe8c66SAdrian Prantl                import sys
524fffe8c66SAdrian Prantl
525fffe8c66SAdrian Prantl                sys.argv.pop()
526fffe8c66SAdrian Prantl                path = os.path.dirname(__file__)
527fffe8c66SAdrian Prantl                sys.path.remove
528fffe8c66SAdrian Prantl                unittest.main()
529