History

ScriptValue::repr, detailed representation of a script value for logging

Ada committed 8 months ago

Commit abd6bae1 parent cdb75078 files · +143 −8Browse files

Showing the changes to libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp (1 of 8 files). Show all

Unified · Split

libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp+115−0
@@ -628,6 +628,121 @@ QObject* ScriptValueV8Wrapper::toQObject() const { · 627 unmodified lines
628628 }
629629 }
630630
631+static QString reprImpl(
632+ v8::Isolate* isolate,
633+ v8::Local<v8::Context> context,
634+ v8::Local<v8::Value> value,
635+ int indent = 0,
636+ bool prependIndent = true
637+) {
638+ constexpr int INDENT_WIDTH = 4;
639+
640+ QString str;
641+
642+ if (prependIndent) { str = QString(INDENT_WIDTH * indent, ' '); }
643+
644+ if (value->IsUndefined()) {
645+ str += "undefined";
646+ } else if (value->IsNull()) {
647+ str += "null";
648+ } else if (value->IsFunction()) {
649+ if (auto funcString = value->ToString(context); !funcString.IsEmpty()) {
650+ // source available
651+ str += QString(*v8::String::Utf8Value(isolate, funcString.ToLocalChecked()));
652+ } else {
653+ v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(value);
654+ v8::Local<v8::Value> debugName = func->GetDebugName();
655+
656+ str += "function ";
657+ str += QString(*v8::String::Utf8Value(isolate, debugName->ToString(context).ToLocalChecked()));
658+ str += "() { [native code] }";
659+ }
660+ } else if (value->IsArray()) {
661+ v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
662+ auto length = array->Length();
663+
664+ str += "Array(";
665+ str += QString::number(length);
666+ str += ") [\n";
667+
668+ for (uint32_t i = 0; i < length; i++) {
669+ str += QString(INDENT_WIDTH * (indent + 1), ' ');
670+ str += QString::number(i);
671+ str += ": ";
672+
673+ // arrays in javascript can have unoccupied elements
674+ if (array->Has(context, i).ToChecked()) {
675+ str += reprImpl(
676+ isolate,
677+ context,
678+ array->Get(context, i).ToLocalChecked(),
679+ indent + 1,
680+ false
681+ );
682+ } else {
683+ str += "<empty slot>";
684+ }
685+
686+ str += ",\n";
687+ }
688+
689+ str += QString(INDENT_WIDTH * indent, ' ');
690+ str += ']';
691+ } else if (value->IsObject()) {
692+ v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(value);
693+ v8::Local<v8::String> constructorName = object->GetConstructorName();
694+
695+ str += QString(*v8::String::Utf8Value(isolate, constructorName->ToString(context).ToLocalChecked()));;
696+
697+ v8::Local<v8::Array> properties = object->GetPropertyNames(context).ToLocalChecked();
698+
699+ if (properties->Length() != 0) {
700+ str += " {\n";
701+
702+ for (uint32_t i = 0; i < properties->Length(); i++) {
703+ auto name = properties->Get(context, i).ToLocalChecked();
704+ auto elem = object->Get(context, name).ToLocalChecked();
705+
706+ str += QString(INDENT_WIDTH * (indent + 1), ' ');
707+ str += QString(*v8::String::Utf8Value(isolate, name->ToString(context).ToLocalChecked()));;
708+ str += ": ";
709+ str += reprImpl(
710+ isolate,
711+ context,
712+ elem,
713+ indent + 1,
714+ false
715+ );
716+ str += "\n";
717+ }
718+
719+ str += QString(INDENT_WIDTH * indent, ' ');
720+ str += "}";
721+ } else {
722+ str += " {}";
723+ }
724+ } else {
725+ // Number, String, Boolean
726+ return QString(*v8::String::Utf8Value(isolate, value->ToString(context).ToLocalChecked()));
727+ }
728+
729+ return str;
730+}
731+
732+QString ScriptValueV8Wrapper::repr() const {
733+ auto* isolate = _engine->getIsolate();
734+ Q_ASSERT(isolate->IsCurrent());
735+
736+ v8::HandleScope handleScope(isolate);
737+
738+ auto context = _engine->getContext();
739+ v8::Context::Scope contextScope(context);
740+
741+ auto value = toV8Value().constGet();
742+
743+ return reprImpl(isolate, context, value);
744+}
745+
631746 bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const {
632747 auto isolate = _engine->getIsolate();
633748 Q_ASSERT(isolate->IsCurrent());