static void describe_internal( VMachine *vm, String &tgt, const Item *elem, int32 level, int32 maxLevel, int32 maxSize ) { uint32 count; // return if we reached the maximum level. if ( maxLevel >= 0 && level > maxLevel ) { tgt += "..."; return; } switch( elem->type() ) { case FLC_ITEM_NIL: tgt += "Nil"; break; case FLC_ITEM_UNB: tgt += "_"; break; case FLC_ITEM_BOOL: tgt += elem->asBoolean() ? "true" : "false"; break; case FLC_ITEM_INT: tgt.writeNumber( elem->asInteger() ); break; case FLC_ITEM_NUM: tgt.writeNumber( elem->asNumeric(), "%g" ); break; case FLC_ITEM_RANGE: elem->toString(tgt); break; case FLC_ITEM_STRING: tgt += "\""; if ( maxSize < 0 || elem->asString()->length() < (uint32) maxSize ) { tgt += *elem->asString(); tgt += "\""; } else { tgt += elem->asString()->subString(0, maxSize ); tgt += " ... \""; } break; case FLC_ITEM_LBIND: tgt += "&"; tgt += *elem->asLBind(); if (elem->isFutureBind()) { tgt +="|"; describe_internal( vm, tgt, &elem->asFutureBind(), level+1, maxLevel, maxSize ); } break; case FLC_ITEM_MEMBUF: { MemBuf *mb = elem->asMemBuf(); tgt += "MB("; tgt.writeNumber( (int64) mb->length() ); tgt += ","; tgt.writeNumber( (int64) mb->wordSize() ); tgt += ")"; tgt += " ["; String fmt; int limit = 0; switch ( mb->wordSize() ) { case 1: fmt = "%02" LLFMT "X"; limit = 24; break; case 2: fmt = "%04" LLFMT "X"; limit = 12; break; case 3: fmt = "%06" LLFMT "X"; limit = 9; break; case 4: fmt = "%08" LLFMT "X"; limit = 6; break; } uint32 max = maxSize < 0 || mb->length() < (uint32) maxSize ? mb->length() : (uint32) maxSize; for( count = 0; count < max; count++ ) { tgt.writeNumber( (int64) mb->get( count ), fmt ); tgt += " "; } if ( count == (uint32) maxSize ) tgt += " ..."; tgt += "]"; } break; case FLC_ITEM_ARRAY: { CoreArray *arr = elem->asArray(); tgt += "["; if ( level == maxLevel ) { tgt += "...]"; break; } for( count = 0; count < arr->length(); count++ ) { if ( count == 0 ) tgt += " "; describe_internal( vm, tgt, & ((*arr)[count]), level + 1, maxLevel, maxSize ); if ( count + 1 < arr->length() ) tgt += ", "; } tgt +="]"; } break; case FLC_ITEM_DICT: { CoreDict *dict = elem->asDict(); if( dict->isBlessed() ) tgt += "*"; tgt += "["; if ( level == maxLevel ) { tgt += "...=>...]"; break; } if ( dict->length() == 0 ) { tgt += "=>]"; break; } Item key, value; Iterator iter( &dict->items() ); // separate the first loop to be able to add ", " describe_internal( vm, tgt, &iter.getCurrentKey(), level + 1, maxLevel, maxSize ); tgt += " => "; describe_internal( vm, tgt, &iter.getCurrent(), level + 1, maxLevel, maxSize ); iter.next(); while( iter.hasCurrent() ) { tgt += ", "; describe_internal( vm, tgt, &iter.getCurrentKey(), level + 1, maxLevel, maxSize ); tgt += " => "; describe_internal( vm, tgt, &iter.getCurrent(), level + 1, maxLevel, maxSize ); iter.next(); } tgt += "]"; } break; case FLC_ITEM_OBJECT: { CoreObject *arr = elem->asObjectSafe(); tgt += arr->generator()->symbol()->name() + "(){ "; if ( level == maxLevel ) { tgt += "...}"; break; } const PropertyTable &pt = arr->generator()->properties(); for( count = 0; count < pt.added() ; count++ ) { const String &propName = *pt.getKey( count ); // write only? if ( pt.getEntry( count ).isWriteOnly() ) { tgt.A( "(" ).A( propName ).A(")"); } else { Item dummy; arr->getProperty( propName, dummy ); // in describe skip methods. if ( dummy.isFunction() || dummy.isMethod() ) continue; tgt += propName + " = "; describe_internal( vm, tgt, &dummy, level + 1, maxLevel, maxSize ); } if (count+1 < pt.added()) { tgt += ", "; } } tgt += "}"; } break; case FLC_ITEM_CLASS: tgt += "Class " + elem->asClass()->symbol()->name(); break; case FLC_ITEM_METHOD: { tgt += "("; Item itemp; elem->getMethodItem( itemp ); describe_internal( vm, tgt, &itemp, level + 1, maxLevel, maxSize ); tgt += ")."; tgt += elem->asMethodFunc()->name() + "()"; } break; case FLC_ITEM_CLSMETHOD: tgt += "Class "; tgt += elem->asMethodClassOwner()->generator()->symbol()->name(); tgt += "." + elem->asMethodClass()->symbol()->name() + "()"; break; case FLC_ITEM_FUNC: { const Symbol *funcSym = elem->asFunction()->symbol(); tgt += funcSym->name() + "()"; } break; case FLC_ITEM_REFERENCE: tgt += "->"; describe_internal( vm, tgt, elem->dereference(), level + 1, maxLevel, maxSize ); break; default: tgt += "?"; } }
void inspect_internal( VMachine *vm, const Item *elem, int32 level, int32 maxLevel, int32 maxSize, Item* i_stream, bool add, bool addline ) { uint32 count; int32 i; Stream *stream = i_stream != 0 ? dyncast<Stream*>(i_stream->asObjectSafe()->getFalconData()) : vm->stdErr(); // return if we reached the maximum level. if ( maxLevel >= 0 && level > maxLevel ) { stream->writeString( "..." ); if ( addline ) stream->writeString( "\n" ); return; } if ( stream == 0 ) { stream = vm->stdOut(); if ( stream == 0 ) return; } if ( add ) for ( i = 0; i < level*3; i ++ ) { stream->put( 0x20 ); // space } if ( elem == 0 ) { stream->writeString( "Nothing" ); if ( addline ) stream->writeString( "\n" ); return; } String temp; switch( elem->type() ) { case FLC_ITEM_NIL: stream->writeString( "Nil" ); break; case FLC_ITEM_UNB: stream->writeString( "_" ); break; case FLC_ITEM_BOOL: stream->writeString( elem->asBoolean() ? "true" : "false" ); break; case FLC_ITEM_INT: temp.writeNumber( elem->asInteger() ); stream->writeString( "int(" ); stream->writeString( temp ); stream->writeString( ")" ); break; case FLC_ITEM_NUM: temp.writeNumber( elem->asNumeric(), "%g" ); stream->writeString( "num(" ); stream->writeString( temp ); stream->writeString( ")" ); break; case FLC_ITEM_RANGE: elem->toString(temp); stream->writeString( temp ); break; case FLC_ITEM_STRING: stream->writeString( "\"" ); if ( maxSize < 0 || elem->asString()->length() < (uint32) maxSize ) { stream->writeString( *elem->asString() ); stream->writeString( "\"" ); } else { stream->writeString( elem->asString()->subString(0, maxSize ) ); stream->writeString( " ... \"" ); } break; case FLC_ITEM_LBIND: stream->writeString( "&" ); stream->writeString( *elem->asLBind() ); break; case FLC_ITEM_MEMBUF: { MemBuf *mb = elem->asMemBuf(); temp = "MemBuf("; temp.writeNumber( (int64) mb->length() ); temp += ","; temp.writeNumber( (int64) mb->wordSize() ); temp += ")"; if ( maxSize == 0 ) stream->writeString( temp ); else { temp += " [\n"; String fmt; int limit = 0; switch ( mb->wordSize() ) { case 1: fmt = "%02" LLFMT "X"; limit = 24; break; case 2: fmt = "%04" LLFMT "X"; limit = 12; break; case 3: fmt = "%06" LLFMT "X"; limit = 9; break; case 4: fmt = "%08" LLFMT "X"; limit = 6; break; } int written = 0; uint32 max = maxSize < 0 || mb->length() < (uint32) maxSize ? mb->length() : (uint32) maxSize; for( count = 0; count < max; count++ ) { temp.writeNumber( (int64) mb->get( count ), fmt ); temp += " "; written ++; if ( written == limit ) { temp += "\n"; written = 0; } stream->writeString( temp ); temp = ""; } if ( count == (uint32) maxSize ) stream->writeString( " ... " ); stream->writeString( "]" ); } } break; case FLC_ITEM_ARRAY: { CoreArray *arr = elem->asArray(); temp = "Array["; temp.writeNumber( (int64) arr->length() ); temp += "]"; stream->writeString( temp ); if ( level == maxLevel ) { stream->writeString( "{...}" ); break; } stream->writeString( "{\n" ); for( count = 0; count < arr->length(); count++ ) { inspect_internal( vm, & ((*arr)[count]), level + 1, maxLevel, maxSize, i_stream, true, true ); } for ( i = 0; i < level; i ++ ) { stream->writeString( " " ); } stream->writeString( "}" ); } break; case FLC_ITEM_DICT: { CoreDict *dict = elem->asDict(); temp = "Dict["; temp.writeNumber( (int64) dict->length() ); temp += "]"; stream->writeString( temp ); if ( level == maxLevel ) { stream->writeString( "{...}" ); break; } stream->writeString( "{\n" ); Iterator iter( &dict->items() ); while( iter.hasCurrent() ) { inspect_internal( vm, &iter.getCurrentKey(), level + 1, maxLevel, maxSize, i_stream, true, false ); stream->writeString( " => " ); inspect_internal( vm, &iter.getCurrent(), level + 1, maxLevel, maxSize, i_stream, false, true ); iter.next(); } for ( i = 0; i < level; i ++ ) { stream->writeString(" "); } stream->writeString( "}" ); } break; case FLC_ITEM_OBJECT: { CoreObject *arr = elem->asObjectSafe(); stream->writeString( "Object of class " + arr->generator()->symbol()->name() ); if ( level == maxLevel ) { stream->writeString( "{...}" ); break; } stream->writeString( " {\n" ); const PropertyTable &pt = arr->generator()->properties(); for( count = 0; count < pt.added() ; count++ ) { for ( i = 0; i < (level+1); i ++ ) { stream->writeString(" "); } const String &propName = *pt.getKey( count ); if ( pt.getEntry(count).isWriteOnly() ) { stream->writeString( "(" ); stream->writeString( propName + ")\n" ); } else { stream->writeString( propName + " => " ); Item dummy; arr->getProperty( propName, dummy); inspect_internal( vm, &dummy, level + 1, maxLevel, maxSize, i_stream, false, true ); } } for ( i = 0; i < level; i ++ ) { stream->writeString(" "); } stream->writeString( "}" ); } break; case FLC_ITEM_CLASS: stream->writeString( "Class " + elem->asClass()->symbol()->name() ); break; case FLC_ITEM_METHOD: { temp = "Method "; temp += "->" + elem->asMethodFunc()->name(); stream->writeString( temp ); Item itemp; elem->getMethodItem( itemp ); inspect_internal( vm, &itemp, level + 1, maxLevel, maxSize, i_stream, true, true ); for ( i = 0; i < level; i ++ ) { stream->writeString(" "); } stream->writeString( "}" ); } break; case FLC_ITEM_CLSMETHOD: temp = "Cls.Method 0x"; temp.writeNumberHex( (uint64) elem->asMethodClassOwner() ); temp += "->" + elem->asMethodClass()->symbol()->name(); stream->writeString( temp ); break; case FLC_ITEM_FUNC: { const Symbol *funcSym = elem->asFunction()->symbol(); if ( funcSym->isExtFunc() ) { stream->writeString( "Ext. Function " + funcSym->name() ); } else { stream->writeString( "Function " + funcSym->name() ); FuncDef *def = funcSym->getFuncDef(); uint32 itemId = def->onceItemId(); if ( itemId != FuncDef::NO_STATE ) { if ( elem->asFunction()->liveModule()->globals()[ itemId ].isNil() ) stream->writeString( "{ not called }"); else stream->writeString( "{ called }"); } } } break; case FLC_ITEM_REFERENCE: stream->writeString( "Ref to " ); inspect_internal( vm, elem->dereference(), level + 1, maxLevel, maxSize, i_stream, false, true ); break; default: stream->writeString( "Invalid type"); } if ( addline ) stream->writeString( "\n" ); stream->flush(); }