]> git.lizzy.rs Git - rust.git/blob - src/etc/lldb_rust_formatters.py
cleanup: s/impl Copy/#[derive(Copy)]/g
[rust.git] / src / etc / lldb_rust_formatters.py
1 # Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 # file at the top-level directory of this distribution and at
3 # http://rust-lang.org/COPYRIGHT.
4 #
5 # Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 # http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 # <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 # option. This file may not be copied, modified, or distributed
9 # except according to those terms.
10
11 import lldb
12
13 def print_val(val, internal_dict):
14   '''Prints the given value with Rust syntax'''
15   type_class = val.GetType().GetTypeClass()
16
17   if type_class == lldb.eTypeClassStruct:
18     return print_struct_val(val, internal_dict)
19
20   if type_class == lldb.eTypeClassUnion:
21     return print_enum_val(val, internal_dict)
22
23   if type_class == lldb.eTypeClassPointer:
24     return print_pointer_val(val, internal_dict)
25
26   if type_class == lldb.eTypeClassArray:
27     return print_fixed_size_vec_val(val, internal_dict)
28
29   return val.GetValue()
30
31
32 #=--------------------------------------------------------------------------------------------------
33 # Type-Specialized Printing Functions
34 #=--------------------------------------------------------------------------------------------------
35
36 def print_struct_val(val, internal_dict):
37   '''Prints a struct, tuple, or tuple struct value with Rust syntax'''
38   assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
39
40   if is_vec_slice(val):
41     return print_vec_slice_val(val, internal_dict)
42   else:
43     return print_struct_val_starting_from(0, val, internal_dict)
44
45 def print_vec_slice_val(val, internal_dict):
46   length = val.GetChildAtIndex(1).GetValueAsUnsigned()
47
48   data_ptr_val = val.GetChildAtIndex(0)
49   data_ptr_type = data_ptr_val.GetType()
50   assert data_ptr_type.IsPointerType()
51
52   element_type = data_ptr_type.GetPointeeType()
53   element_type_size = element_type.GetByteSize()
54
55   start_address = data_ptr_val.GetValueAsUnsigned()
56
57   def render_element(i):
58     address = start_address + i * element_type_size
59     element_val = val.CreateValueFromAddress( val.GetName() + ("[%s]" % i), address, element_type)
60     return print_val(element_val, internal_dict)
61
62   return "&[%s]" % (', '.join([render_element(i) for i in range(length)]))
63
64 def print_struct_val_starting_from(field_start_index, val, internal_dict):
65   '''
66   Prints a struct, tuple, or tuple struct value with Rust syntax.
67   Ignores any fields before field_start_index.
68   '''
69   assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
70
71   t = val.GetType()
72   type_name = extract_type_name(t.GetName())
73   num_children = val.num_children
74
75   if (num_children - field_start_index) == 0:
76     # The only field of this struct is the enum discriminant
77     return type_name
78
79   has_field_names = type_has_field_names(t)
80
81   if has_field_names:
82     template = "%(type_name)s {\n%(body)s\n}"
83     separator = ", \n"
84   else:
85     template = "%(type_name)s(%(body)s)"
86     separator = ", "
87
88   if type_name.startswith("("):
89     # this is a tuple, so don't print the type name
90     type_name = ""
91
92   def render_child(child_index):
93     this = ""
94     if has_field_names:
95       field_name = t.GetFieldAtIndex(child_index).GetName()
96       this += field_name + ": "
97
98     field_val = val.GetChildAtIndex(child_index)
99     return this + print_val(field_val, internal_dict)
100
101   body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
102
103   return template % {"type_name": type_name,
104                      "body": body}
105
106
107 def print_enum_val(val, internal_dict):
108   '''Prints an enum value with Rust syntax'''
109
110   assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion
111
112   if val.num_children == 1:
113     # This is either an enum with just one variant, or it is an Option-like enum
114     # where the discriminant is encoded in a non-nullable pointer field. We find
115     # out which one it is by looking at the member name of the sole union
116     # variant. If it starts with "RUST$ENCODED$ENUM$" then we have an
117     # Option-like enum.
118     first_variant_name = val.GetChildAtIndex(0).GetName()
119     if first_variant_name and first_variant_name.startswith("RUST$ENCODED$ENUM$"):
120
121       # This is an Option-like enum. The position of the discriminator field is
122       # encoded in the name which has the format:
123       #  RUST$ENCODED$ENUM$<index of discriminator field>$<name of null variant>
124       last_separator_index = first_variant_name.rfind("$")
125       if last_separator_index == -1:
126         return "<invalid enum encoding: %s>" % first_variant_name
127
128       start_index = len("RUST$ENCODED$ENUM$")
129
130       # Extract indices of the discriminator field
131       try:
132         disr_field_indices = first_variant_name[start_index :
133                                               last_separator_index].split("$")
134         disr_field_indices = [int(index) for index in disr_field_indices]
135       except:
136         return "<invalid enum encoding: %s>" % first_variant_name
137
138       # Read the discriminant
139       disr_val = val.GetChildAtIndex(0)
140       for index in disr_field_indices:
141         disr_val = disr_val.GetChildAtIndex(index)
142
143       # If the discriminant field is a fat pointer we have to consider the
144       # first word as the true discriminant
145       if disr_val.GetType().GetTypeClass() == lldb.eTypeClassStruct:
146         disr_val = disr_val.GetChildAtIndex(0)
147
148       if disr_val.GetValueAsUnsigned() == 0:
149         # Null case: Print the name of the null-variant
150         null_variant_name = first_variant_name[last_separator_index + 1:]
151         return null_variant_name
152       else:
153         # Non-null case: Interpret the data as a value of the non-null variant type
154         return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
155     else:
156       # This is just a regular uni-variant enum without discriminator field
157       return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
158
159   # If we are here, this is a regular enum with more than one variant
160   disr_val = val.GetChildAtIndex(0).GetChildMemberWithName("RUST$ENUM$DISR")
161   disr_type = disr_val.GetType()
162
163   if disr_type.GetTypeClass() != lldb.eTypeClassEnumeration:
164     return "<Invalid enum value encountered: Discriminator is not an enum>"
165
166   variant_index = disr_val.GetValueAsUnsigned()
167   return print_struct_val_starting_from(1, val.GetChildAtIndex(variant_index), internal_dict)
168
169
170 def print_pointer_val(val, internal_dict):
171   '''Prints a pointer value with Rust syntax'''
172   assert val.GetType().IsPointerType()
173   sigil = "&"
174   type_name = extract_type_name(val.GetType().GetName())
175   if type_name and type_name[0:1] in ["&", "~", "*"]:
176     sigil = type_name[0:1]
177
178   return sigil + hex(val.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict)
179
180
181 def print_fixed_size_vec_val(val, internal_dict):
182   assert val.GetType().GetTypeClass() == lldb.eTypeClassArray
183
184   output = "["
185
186   for i in range(val.num_children):
187     output += print_val(val.GetChildAtIndex(i), internal_dict)
188     if i != val.num_children - 1:
189       output += ", "
190
191   output += "]"
192   return output
193
194
195 #=--------------------------------------------------------------------------------------------------
196 # Helper Functions
197 #=--------------------------------------------------------------------------------------------------
198
199 unqualified_type_markers = frozenset(["(", "[", "&", "*"])
200
201 def extract_type_name(qualified_type_name):
202   '''Extracts the type name from a fully qualified path'''
203   if qualified_type_name[0] in unqualified_type_markers:
204     return qualified_type_name
205
206   end_of_search = qualified_type_name.find("<")
207   if end_of_search < 0:
208     end_of_search = len(qualified_type_name)
209
210   index = qualified_type_name.rfind("::", 0, end_of_search)
211   if index < 0:
212     return qualified_type_name
213   else:
214     return qualified_type_name[index + 2:]
215
216
217 def type_has_field_names(ty):
218   '''Returns true of this is a type with field names (struct, struct-like enum variant)'''
219   # This may also be an enum variant where the first field doesn't have a name but the rest has
220   if ty.GetNumberOfFields() > 1:
221     return ty.GetFieldAtIndex(1).GetName() != None
222   else:
223     return ty.GetFieldAtIndex(0).GetName() != None
224
225
226 def is_vec_slice(val):
227   ty = val.GetType()
228   if ty.GetTypeClass() != lldb.eTypeClassStruct:
229     return False
230
231   if ty.GetNumberOfFields() != 2:
232     return False
233
234   if ty.GetFieldAtIndex(0).GetName() != "data_ptr":
235     return False
236
237   if ty.GetFieldAtIndex(1).GetName() != "length":
238     return False
239
240   type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
241   return type_name.startswith("&[") and type_name.endswith("]")
242
243 # vi: sw=2:ts=2