Skip to content

Commit 98ee309

Browse files
authored
OCaml Value Printing Improvements (#19)
1 parent 788ad7b commit 98ee309

File tree

2 files changed

+93
-29
lines changed

2 files changed

+93
-29
lines changed

lldb/source/Core/DumpDataExtractor.cpp

Lines changed: 88 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,53 @@ static void DumpCharacter(Stream &s, const char c) {
215215
s.Printf("\\x%2.2x", c);
216216
}
217217

218+
/// Dump the character to a stream using OCaml string literal format.
219+
/// This matches OCaml's unsafe_escape function from bytes.ml in the standard library.
220+
static void DumpEscapedCharacterOCaml(Stream &s, const char c) {
221+
switch (c) {
222+
case '"':
223+
s.Printf("\\\"");
224+
return;
225+
case '\\':
226+
s.Printf("\\\\");
227+
return;
228+
case '\n':
229+
s.Printf("\\n");
230+
return;
231+
case '\t':
232+
s.Printf("\\t");
233+
return;
234+
case '\r':
235+
s.Printf("\\r");
236+
return;
237+
case '\b':
238+
s.Printf("\\b");
239+
return;
240+
default:
241+
break;
242+
}
243+
244+
// Handle printable ASCII range ' ' to '~' (32 to 126)
245+
if (c >= ' ' && c <= '~') {
246+
s.PutChar(c);
247+
return;
248+
}
249+
250+
// Use OCaml's 3-digit decimal escape format for non-printable characters
251+
// This matches the logic in bytes.ml unsafe_escape function
252+
unsigned char a = (unsigned char)c;
253+
s.Printf("\\%03d", a);
254+
}
255+
256+
/// Dump a C string as an OCaml string literal with proper escaping and quotes.
257+
static void DumpStringOCaml(Stream *s, const char *data, uint64_t string_length) {
258+
s->Printf("\"");
259+
for (uint64_t i = 0; i < string_length; ++i) {
260+
DumpEscapedCharacterOCaml(*s, data[i]);
261+
}
262+
s->Printf("\"");
263+
}
264+
218265
/// Dump a floating point type.
219266
template <typename FloatT>
220267
void DumpFloatingPoint(std::ostringstream &ss, FloatT f) {
@@ -386,13 +433,21 @@ void PrintAPIntAsFloat(Stream *s, llvm::APInt apint,
386433
else
387434
apfloat.toPossiblyShortString(sv);
388435

389-
s->AsRawOstream() << prefix;
390-
s->AsRawOstream() << sv;
391436
// OCaml Specific:
392-
// Following OCaml conventions, print the trailing "." to
437+
// Handle negative sign placement for OCaml format
438+
if (sv.size() > 0 && sv[0] == '-') {
439+
s->AsRawOstream() << "-";
440+
s->AsRawOstream() << prefix;
441+
s->AsRawOstream() << llvm::StringRef(sv.data() + 1, sv.size() - 1);
442+
} else {
443+
s->AsRawOstream() << prefix;
444+
s->AsRawOstream() << sv;
445+
}
446+
447+
// Following OCaml conventions, print the trailing ".0" to
393448
// identify that the integer is in fact a float, but don't
394-
// print any trailing zeros.
395-
bool print_trailing_dot = true;
449+
// print any trailing zeros beyond that.
450+
bool print_trailing_dot_zero = true;
396451
for (char c : sv) {
397452
switch (c) {
398453
case '-':
@@ -409,14 +464,14 @@ void PrintAPIntAsFloat(Stream *s, llvm::APInt apint,
409464
continue;
410465
default:
411466
// if we find something that is not a number such as 'e' or 'E' or '.'
412-
// there is no need to print the trailing ".".
413-
print_trailing_dot = false;
467+
// there is no need to print the trailing ".0".
468+
print_trailing_dot_zero = false;
414469
}
415470
break; // we found something that is not a number, so we will not print
416-
// the trailing "."
471+
// the trailing ".0"
417472
}
418-
if (print_trailing_dot){
419-
s->AsRawOstream() << ".";
473+
if (print_trailing_dot_zero){
474+
s->AsRawOstream() << ".0";
420475
}
421476

422477
s->AsRawOstream() << suffix;
@@ -574,19 +629,8 @@ static offset_t FormatOCamlValue(const DataExtractor &DE, Stream *s,
574629
if (error.Fail() || bytes_read < string_length) {
575630
s->Printf("<could not read string>@");
576631
} else {
577-
const char *c_str = (const char *)&str.front();
578-
if (strlen(c_str) == string_length) {
579-
/* String does not contain NUL characters */
580-
s->Printf("\"%s\"", c_str);
581-
} else {
582-
s->Printf("\"");
583-
DataExtractor cstr_data(&str.front(), str.size(),
584-
process->GetByteOrder(), 8);
585-
DumpDataExtractor(cstr_data, s, 0, lldb::eFormatChar, 1,
586-
string_length, UINT32_MAX,
587-
LLDB_INVALID_ADDRESS, 0, 0);
588-
s->Printf("\"");
589-
}
632+
const char *data = (const char *)&str.front();
633+
DumpStringOCaml(s, data, string_length);
590634
print_default = false;
591635
}
592636
}
@@ -681,7 +725,7 @@ static offset_t FormatOCamlValue(const DataExtractor &DE, Stream *s,
681725
if (int_size == 32)
682726
s->Printf("%ld", (long)i);
683727
else
684-
s->Printf("%lld", (int64_t)i);
728+
s->Printf("%" PRIi64, (int64_t)i);
685729
s->Printf("%s", suffix.c_str());
686730
print_default = false;
687731
}
@@ -927,11 +971,26 @@ lldb::offset_t lldb_private::DumpDataExtractor(
927971
case eFormatEnum: // Print enum value as a signed integer when we don't get
928972
// the enum type
929973
case eFormatDecimal:
930-
if (item_byte_size <= 8)
931-
s->Printf("%" PRId64,
932-
DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
933-
item_bit_offset));
934-
else {
974+
if (item_byte_size <= 8) {
975+
int64_t value = DE.GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size,
976+
item_bit_offset);
977+
// CR sspies: This is special cases for OCaml values. Consider wrapping
978+
// it in a guard.
979+
// Format as unboxed OCaml integer
980+
std::string suffix = "";
981+
if (item_byte_size == 4) suffix = "l";
982+
else if (item_byte_size == 8) suffix = "L";
983+
else if (item_byte_size == 2) suffix = ""; // int16 - no specific suffix
984+
else if (item_byte_size == 1) suffix = ""; // int8 - no specific suffix
985+
// Add "n" suffix for nativeint when it's pointer-sized (could be 4 or 8 bytes)
986+
987+
988+
if (value < 0) {
989+
s->Printf("-#%" PRId64 "%s", -value, suffix.c_str());
990+
} else {
991+
s->Printf("#%" PRId64 "%s", value, suffix.c_str());
992+
}
993+
} else {
935994
const bool is_signed = true;
936995
const unsigned radix = 10;
937996
offset = DumpAPInt(s, DE, offset, item_byte_size, is_signed, radix);

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5264,6 +5264,11 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) {
52645264
return lldb::eFormatBoolean;
52655265
case clang::BuiltinType::Char_S:
52665266
case clang::BuiltinType::SChar:
5267+
// For OCaml, treat signed 8-bit integers as decimal numbers (like int16, int32, int64)
5268+
// rather than characters to ensure consistent SIMD vector display
5269+
if (isLanguageOCaml())
5270+
return lldb::eFormatDecimal;
5271+
return lldb::eFormatChar;
52675272
case clang::BuiltinType::WChar_S:
52685273
case clang::BuiltinType::Char_U:
52695274
case clang::BuiltinType::UChar:

0 commit comments

Comments
 (0)