Result OnTypeCount(Index count) override;
Result OnFuncType(Index index,
Index param_count,
Type* param_types,
Index result_count,
Type* result_types) override;
Result OnStructType(Index index, Index field_count, TypeMut* fields) override;
Result OnArrayType(Index index, TypeMut field) override;
Result OnImportCount(Index count) override;
Result OnImportFunc(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index func_index,
Index sig_index) override;
Result OnImportTable(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index table_index,
Type elem_type, const Limits* elem_limits) override;
Result OnImportMemory(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index memory_index, const Limits* page_limits,
uint32_t page_size) override;
Result OnImportGlobal(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index global_index,
Type type, bool mutable_) override;
Result OnImportTag(Index import_index,
std::string_view module_name,
std::string_view field_name,
Index tag_index,
Index sig_index) override;
Result OnFunctionCount(Index count) override;
Result OnFunction(Index index, Index sig_index) override;
Result OnTableCount(Index count) override;
Result OnTable(Index index,
Type elem_type, const Limits* elem_limits) override;
Result OnMemoryCount(Index count) override;
Result OnMemory(Index index, const Limits* limits,
uint32_t page_size) override;
Result OnGlobalCount(Index count) override;
Result BeginGlobal(Index index, Type type, bool mutable_) override;
Result BeginGlobalInitExpr(Index index) override;
Result EndGlobalInitExpr(Index index) override;
Result OnExportCount(Index count) override;
Result OnExport(Index index,
ExternalKind kind,
Index item_index,
std::string_view name) override;
Result OnStartFunction(Index func_index) override;
Result OnFunctionBodyCount(Index count) override;
Result BeginFunctionBody(Index index, Offset size) override;
Result OnLocalDecl(Index decl_index, Index count, Type type) override;
Result OnOpcode(Opcode opcode) override;
Result OnAtomicLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicRmwExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicRmwCmpxchgExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicWaitExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnAtomicFenceExpr(uint32_t consistency_model) override;
Result OnAtomicNotifyExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnBinaryExpr(Opcode opcode) override;
Result OnBlockExpr(Type sig_type) override;
Result OnBrExpr(Index depth) override;
Result OnBrIfExpr(Index depth) override;
Result OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) override;
Result OnCallExpr(Index func_index) override;
Result OnCatchExpr(Index tag_index) override;
Result OnCatchAllExpr() override;
Result OnCallIndirectExpr(Index sig_index, Index table_index) override;
Result OnCallRefExpr() override;
Result OnReturnCallExpr(Index func_index) override;
Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override;
Result OnCompareExpr(Opcode opcode) override;
Result OnConvertExpr(Opcode opcode) override;
Result OnDelegateExpr(Index depth) override;
Result OnDropExpr() override;
Result OnElseExpr() override;
Result OnEndExpr() override;
Result OnF32ConstExpr(uint32_t value_bits) override;
Result OnF64ConstExpr(uint64_t value_bits) override;
Result OnV128ConstExpr(v128 value_bits) override;
Result OnGlobalGetExpr(Index global_index) override;
Result OnGlobalSetExpr(Index global_index) override;
Result OnI32ConstExpr(uint32_t value) override;
Result OnI64ConstExpr(uint64_t value) override;
Result OnIfExpr(Type sig_type) override;
Result OnLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnLocalGetExpr(Index local_index) override;
Result OnLocalSetExpr(Index local_index) override;
Result OnLocalTeeExpr(Index local_index) override;
Result OnLoopExpr(Type sig_type) override;
Result OnMemoryCopyExpr(Index destmemidx, Index srcmemidx) override;
Result OnDataDropExpr(Index segment_index) override;
Result OnMemoryFillExpr(Index memidx) override;
Result OnMemoryGrowExpr(Index memidx) override;
Result OnMemoryInitExpr(Index segment_index, Index memidx) override;
Result OnMemorySizeExpr(Index memidx) override;
Result OnTableCopyExpr(Index dst_index, Index src_index) override;
Result OnElemDropExpr(Index segment_index) override;
Result OnTableInitExpr(Index segment_index, Index table_index) override;
Result OnTableGetExpr(Index table_index) override;
Result OnTableSetExpr(Index table_index) override;
Result OnTableGrowExpr(Index table_index) override;
Result OnTableSizeExpr(Index table_index) override;
Result OnTableFillExpr(Index table_index) override;
Result OnRefFuncExpr(Index func_index) override;
Result OnRefNullExpr(Type type) override;
Result OnRefIsNullExpr() override;
Result OnNopExpr() override;
Result OnRethrowExpr(Index depth) override;
Result OnReturnExpr() override;
Result OnSelectExpr(Index result_count, Type* result_types) override;
Result OnStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnThrowExpr(Index tag_index) override;
Result OnTryExpr(Type sig_type) override;
Result OnUnaryExpr(Opcode opcode) override;
Result OnTernaryExpr(Opcode opcode) override;
Result OnUnreachableExpr() override;
Result EndFunctionBody(Index index) override;
Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override;
Result OnSimdLoadLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) override;
Result OnSimdStoreLaneExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset,
uint64_t value) override;
Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override;
Result OnLoadSplatExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnLoadZeroExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) override;
Result OnElemSegmentCount(Index count) override;
Result BeginElemSegment(Index index,
Index table_index,
uint8_t flags) override;
Result BeginElemSegmentInitExpr(Index index) override;
Result EndElemSegmentInitExpr(Index index) override;
Result OnElemSegmentElemType(Index index, Type elem_type) override;
Result OnElemSegmentElemExprCount(Index index, Index count) override;
Result BeginElemExpr(Index elem_index, Index expr_index) override;
Result EndElemExpr(Index elem_index, Index expr_index) override;
Result OnDataSegmentCount(Index count) override;
Result BeginDataSegment(Index index,
Index memory_index,
uint8_t flags) override;
Result BeginDataSegmentInitExpr(Index index) override;
Result EndDataSegmentInitExpr(Index index) override;
Result OnDataSegmentData(Index index, constvoid* data,
Address size) override;
Result OnModuleName(std::string_view module_name) override;
Result OnFunctionNamesCount(Index num_functions) override;
Result OnFunctionName(Index function_index,
std::string_view function_name) override;
Result OnLocalNameLocalCount(Index function_index, Index num_locals) override;
Result OnLocalName(Index function_index,
Index local_index,
std::string_view local_name) override;
Result OnNameEntry(NameSectionSubsection type,
Index index,
std::string_view name) override;
Result OnGenericCustomSection(std::string_view name, constvoid* data,
Offset size) override;
Result BeginTagSection(Offset size) override { return Result::Ok; }
Result OnTagCount(Index count) override { return Result::Ok; }
Result OnTagType(Index index, Index sig_index) override;
Result EndTagSection() override { return Result::Ok; }
Result OnDataSymbol(Index index,
uint32_t flags,
std::string_view name,
Index segment,
uint32_t offset,
uint32_t size) override;
Result OnFunctionSymbol(Index index,
uint32_t flags,
std::string_view name,
Index func_index) override;
Result OnGlobalSymbol(Index index,
uint32_t flags,
std::string_view name,
Index global_index) override;
Result OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) override; /* Code Metadata sections */
Result BeginCodeMetadataSection(std::string_view name, Offset size) override;
Result OnCodeMetadataFuncCount(Index count) override;
Result OnCodeMetadataCount(Index function_index, Index count) override;
Result OnCodeMetadata(Offset offset, constvoid* data, Address size) override;
Result OnTagSymbol(Index index,
uint32_t flags,
std::string_view name,
Index tag_index) override;
Result OnTableSymbol(Index index,
uint32_t flags,
std::string_view name,
Index table_index) override;
private:
Location GetLocation() const; void PrintError(constchar* format, ...);
Result PushLabel(LabelType label_type,
ExprList* first,
Expr* context = nullptr);
Result BeginInitExpr(ExprList* init_expr);
Result EndInitExpr();
Result PopLabel();
Result GetLabelAt(LabelNode** label, Index depth);
Result TopLabel(LabelNode** label);
Result TopLabelExpr(LabelNode** label, Expr** expr);
Result AppendExpr(std::unique_ptr<Expr> expr);
Result AppendCatch(Catch&& catch_); void SetFuncDeclaration(FuncDeclaration* decl, Var var); void SetBlockDeclaration(BlockDeclaration* decl, Type sig_type);
Result SetMemoryName(Index index, std::string_view name);
Result SetTableName(Index index, std::string_view name);
Result SetFunctionName(Index index, std::string_view name);
Result SetTypeName(Index index, std::string_view name);
Result SetGlobalName(Index index, std::string_view name);
Result SetDataSegmentName(Index index, std::string_view name);
Result SetElemSegmentName(Index index, std::string_view name);
Result SetTagName(Index index, std::string_view name);
Result BinaryReaderIR::BeginGlobal(Index index, Type type, bool mutable_) { auto field = std::make_unique<GlobalModuleField>(GetLocation());
Global& global = field->global;
global.type = type;
global.mutable_ = mutable_;
module_->AppendField(std::move(field));
module_->features_used.simd |= (type == Type::V128);
module_->features_used.exceptions |= (type == Type::ExnRef); return Result::Ok;
}
Result BinaryReaderIR::BeginGlobalInitExpr(Index index) {
assert(index == module_->globals.size() - 1);
Global* global = module_->globals[index]; return BeginInitExpr(&global->init_expr);
}
Result BinaryReaderIR::EndGlobalInitExpr(Index index) { return EndInitExpr();
}
Result BinaryReaderIR::OnExportCount(Index count) {
WABT_TRY
module_->exports.reserve(count);
WABT_CATCH_BAD_ALLOC return Result::Ok;
}
Result BinaryReaderIR::OnExport(Index index,
ExternalKind kind,
Index item_index,
std::string_view name) { auto field = std::make_unique<ExportModuleField>(GetLocation());
Export& export_ = field->export_;
export_.name = name;
export_.var = Var(item_index, GetLocation());
export_.kind = kind;
module_->AppendField(std::move(field)); return Result::Ok;
}
Result BinaryReaderIR::OnStartFunction(Index func_index) {
Var start(func_index, GetLocation());
module_->AppendField(
std::make_unique<StartModuleField>(start, GetLocation())); return Result::Ok;
}
Result BinaryReaderIR::OnFunctionBodyCount(Index count) { // Can hit this case on a malformed module if we don't stop on first error. if (module_->num_func_imports + count != module_->funcs.size()) {
PrintError( "number of imported func + func count in code section does not match " "actual number of funcs in module"); return Result::Error;
} return Result::Ok;
}
Result BinaryReaderIR::OnAtomicLoadExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) { return AppendExpr(std::make_unique<AtomicLoadExpr>(
opcode, Var(memidx, GetLocation()), 1ull << alignment_log2, offset));
}
Result BinaryReaderIR::OnAtomicStoreExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) { return AppendExpr(std::make_unique<AtomicStoreExpr>(
opcode, Var(memidx, GetLocation()), 1ull << alignment_log2, offset));
}
Result BinaryReaderIR::OnAtomicRmwExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) { return AppendExpr(std::make_unique<AtomicRmwExpr>(
opcode, Var(memidx, GetLocation()), 1ull << alignment_log2, offset));
}
Result BinaryReaderIR::OnAtomicRmwCmpxchgExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) { return AppendExpr(std::make_unique<AtomicRmwCmpxchgExpr>(
opcode, Var(memidx, GetLocation()), 1ull << alignment_log2, offset));
}
Result BinaryReaderIR::OnAtomicWaitExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) { return AppendExpr(std::make_unique<AtomicWaitExpr>(
opcode, Var(memidx, GetLocation()), 1ull << alignment_log2, offset));
}
Result BinaryReaderIR::OnAtomicFenceExpr(uint32_t consistency_model) { return AppendExpr(std::make_unique<AtomicFenceExpr>(consistency_model));
}
Result BinaryReaderIR::OnAtomicNotifyExpr(Opcode opcode,
Index memidx,
Address alignment_log2,
Address offset) { return AppendExpr(std::make_unique<AtomicNotifyExpr>(
opcode, Var(memidx, GetLocation()), 1ull << alignment_log2, offset));
}
Result BinaryReaderIR::OnBinaryExpr(Opcode opcode) { return AppendExpr(std::make_unique<BinaryExpr>(opcode));
}
Result BinaryReaderIR::OnBlockExpr(Type sig_type) { auto expr = std::make_unique<BlockExpr>();
SetBlockDeclaration(&expr->block.decl, sig_type);
ExprList* expr_list = &expr->block.exprs;
CHECK_RESULT(AppendExpr(std::move(expr))); return PushLabel(LabelType::Block, expr_list);
}
Result BinaryReaderIR::OnBrExpr(Index depth) { return AppendExpr(std::make_unique<BrExpr>(Var(depth, GetLocation())));
}
Result BinaryReaderIR::OnBrIfExpr(Index depth) { return AppendExpr(std::make_unique<BrIfExpr>(Var(depth, GetLocation())));
}
Result BinaryReaderIR::OnBrTableExpr(Index num_targets,
Index* target_depths,
Index default_target_depth) { auto expr = std::make_unique<BrTableExpr>();
expr->default_target = Var(default_target_depth, GetLocation());
expr->targets.resize(num_targets); for (Index i = 0; i < num_targets; ++i) {
expr->targets[i] = Var(target_depths[i], GetLocation());
} return AppendExpr(std::move(expr));
}
Result BinaryReaderIR::OnCallExpr(Index func_index) { return AppendExpr(std::make_unique<CallExpr>(Var(func_index, GetLocation())));
}
Result BinaryReaderIR::OnCallIndirectExpr(Index sig_index, Index table_index) { auto expr = std::make_unique<CallIndirectExpr>();
SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation()));
expr->table = Var(table_index, GetLocation()); return AppendExpr(std::move(expr));
}
Result BinaryReaderIR::OnCallRefExpr() { return AppendExpr(std::make_unique<CallRefExpr>());
}
Result BinaryReaderIR::OnReturnCallExpr(Index func_index) { if (current_func_) { // syntactically, a return_call expr can occur in an init expression // (outside a function)
current_func_->features_used.tailcall = true;
} return AppendExpr(
std::make_unique<ReturnCallExpr>(Var(func_index, GetLocation())));
}
Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index,
Index table_index) { if (current_func_) { // syntactically, a return_call_indirect expr can occur in an init // expression (outside a function)
current_func_->features_used.tailcall = true;
} auto expr = std::make_unique<ReturnCallIndirectExpr>();
SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation()));
expr->table = Var(table_index, GetLocation());
FuncType* type = module_->GetFuncType(Var(sig_index, GetLocation())); if (type) {
type->features_used.tailcall = true;
} return AppendExpr(std::move(expr));
}
Result BinaryReaderIR::OnCompareExpr(Opcode opcode) { return AppendExpr(std::make_unique<CompareExpr>(opcode));
}
Result BinaryReaderIR::OnConvertExpr(Opcode opcode) { return AppendExpr(std::make_unique<ConvertExpr>(opcode));
}
Result BinaryReaderIR::OnDropExpr() { return AppendExpr(std::make_unique<DropExpr>());
}
Result BinaryReaderIR::OnElseExpr() {
LabelNode* label;
Expr* expr;
CHECK_RESULT(TopLabelExpr(&label, &expr));
Result BinaryReaderIR::OnLocalTeeExpr(Index local_index) { return AppendExpr(
std::make_unique<LocalTeeExpr>(Var(local_index, GetLocation())));
}
Result BinaryReaderIR::OnTryExpr(Type sig_type) { auto expr_ptr = std::make_unique<TryExpr>(); // Save expr so it can be used below, after expr_ptr has been moved.
TryExpr* expr = expr_ptr.get();
ExprList* expr_list = &expr->block.exprs;
SetBlockDeclaration(&expr->block.decl, sig_type);
CHECK_RESULT(AppendExpr(std::move(expr_ptr)));
module_->features_used.exceptions = true; return PushLabel(LabelType::Try, expr_list, expr);
}
Result BinaryReaderIR::AppendCatch(Catch&& catch_) {
LabelNode* label = nullptr;
CHECK_RESULT(TopLabel(&label));
if (label->label_type != LabelType::Try) {
PrintError("catch not inside try block"); return Result::Error;
}
auto* try_ = cast<TryExpr>(label->context);
if (catch_.IsCatchAll() && !try_->catches.empty() &&
try_->catches.back().IsCatchAll()) {
PrintError("only one catch_all allowed in try block"); return Result::Error;
}
if (try_->kind == TryKind::Plain) {
try_->kind = TryKind::Catch;
} elseif (try_->kind != TryKind::Catch) {
PrintError("catch not allowed in try-delegate"); return Result::Error;
}
Result BinaryReaderIR::SetTagName(Index index, std::string_view name) { if (name.empty()) { return Result::Ok;
} if (index >= module_->tags.size()) {
PrintError("invalid tag index: %" PRIindex, index); return Result::Error;
}
Tag* tag = module_->tags[index];
std::string dollar_name =
GetUniqueName(&module_->tag_bindings, MakeDollarName(name));
tag->name = dollar_name;
module_->tag_bindings.emplace(dollar_name, Binding(index)); return Result::Ok;
}
Result BinaryReaderIR::OnFunctionName(Index index, std::string_view name) { return SetFunctionName(index, name);
}
Result BinaryReaderIR::OnNameEntry(NameSectionSubsection type,
Index index,
std::string_view name) { switch (type) { // TODO(sbc): remove OnFunctionName in favor of just using // OnNameEntry so that this works case NameSectionSubsection::Function: case NameSectionSubsection::Local: case NameSectionSubsection::Module: case NameSectionSubsection::Label: case NameSectionSubsection::Field: break; case NameSectionSubsection::Type:
SetTypeName(index, name); break; case NameSectionSubsection::Tag:
SetTagName(index, name); break; case NameSectionSubsection::Global:
SetGlobalName(index, name); break; case NameSectionSubsection::Table:
SetTableName(index, name); break; case NameSectionSubsection::DataSegment:
SetDataSegmentName(index, name); break; case NameSectionSubsection::Memory:
SetMemoryName(index, name); break; case NameSectionSubsection::ElemSegment:
SetElemSegmentName(index, name); break;
} return Result::Ok;
}
Result BinaryReaderIR::OnLocalNameLocalCount(Index index, Index count) {
assert(index < module_->funcs.size());
Func* func = module_->funcs[index];
Index num_params_and_locals = func->GetNumParamsAndLocals(); if (count > num_params_and_locals) {
PrintError("expected local name count (%" PRIindex ") <= local count (%" PRIindex ")",
count, num_params_and_locals); return Result::Error;
} return Result::Ok;
}
Result BinaryReaderIR::OnCodeMetadataFuncCount(Index count) { return Result::Ok;
}
Result BinaryReaderIR::OnCodeMetadataCount(Index function_index, Index count) {
code_metadata_queue_.push_func(module_->funcs[function_index]); return Result::Ok;
}
Result BinaryReaderIR::OnCodeMetadata(Offset offset, constvoid* data,
Address size) {
std::vector<uint8_t> data_(static_cast<const uint8_t*>(data), static_cast<const uint8_t*>(data) + size); auto meta = std::make_unique<CodeMetadataExpr>(current_metadata_name_,
std::move(data_));
meta->loc.offset = offset;
code_metadata_queue_.push_metadata(std::move(meta)); return Result::Ok;
}
Result BinaryReaderIR::OnLocalName(Index func_index,
Index local_index,
std::string_view name) { if (name.empty()) { return Result::Ok;
}
Result BinaryReaderIR::OnTagType(Index index, Index sig_index) { auto field = std::make_unique<TagModuleField>(GetLocation());
Tag& tag = field->tag;
SetFuncDeclaration(&tag.decl, Var(sig_index, GetLocation()));
module_->AppendField(std::move(field));
module_->features_used.exceptions = true; return Result::Ok;
}
Result BinaryReaderIR::OnDataSymbol(Index index,
uint32_t flags,
std::string_view name,
Index segment,
uint32_t offset,
uint32_t size) { if (name.empty()) { return Result::Ok;
} if (flags & WABT_SYMBOL_FLAG_UNDEFINED) { // Refers to data in another file, `segment` not valid. return Result::Ok;
} if (offset) { // If it is pointing into the data segment, then it's not really naming // the whole segment. return Result::Ok;
} if (segment >= module_->data_segments.size()) {
PrintError("invalid data segment index: %" PRIindex, segment); return Result::Error;
}
DataSegment* seg = module_->data_segments[segment];
std::string dollar_name =
GetUniqueName(&module_->data_segment_bindings, MakeDollarName(name));
seg->name = dollar_name;
module_->data_segment_bindings.emplace(dollar_name, Binding(segment)); return Result::Ok;
}
Result BinaryReaderIR::OnFunctionSymbol(Index index,
uint32_t flags,
std::string_view name,
Index func_index) { if (name.empty()) { return Result::Ok;
} if (func_index >= module_->funcs.size()) {
PrintError("invalid function index: %" PRIindex, func_index); return Result::Error;
}
Func* func = module_->funcs[func_index]; if (!func->name.empty()) { // The name section has already named this function. return Result::Ok;
}
std::string dollar_name =
GetUniqueName(&module_->func_bindings, MakeDollarName(name));
func->name = dollar_name;
module_->func_bindings.emplace(dollar_name, Binding(func_index)); return Result::Ok;
}
Result BinaryReaderIR::OnGlobalSymbol(Index index,
uint32_t flags,
std::string_view name,
Index global_index) { return SetGlobalName(global_index, name);
}
Result BinaryReaderIR::OnSectionSymbol(Index index,
uint32_t flags,
Index section_index) { return Result::Ok;
}
Result BinaryReaderIR::OnTagSymbol(Index index,
uint32_t flags,
std::string_view name,
Index tag_index) { if (name.empty()) { return Result::Ok;
} if (tag_index >= module_->tags.size()) {
PrintError("invalid tag index: %" PRIindex, tag_index); return Result::Error;
}
Tag* tag = module_->tags[tag_index];
std::string dollar_name =
GetUniqueName(&module_->tag_bindings, MakeDollarName(name));
tag->name = dollar_name;
module_->tag_bindings.emplace(dollar_name, Binding(tag_index)); return Result::Ok;
}
Result BinaryReaderIR::OnTableSymbol(Index index,
uint32_t flags,
std::string_view name,
Index table_index) { return SetTableName(table_index, name);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.