commit
This commit is contained in:
parent
0a3830b6cd
commit
41637b3678
|
@ -400,11 +400,11 @@ DIR_LIB_SOURCE::~DIR_LIB_SOURCE()
|
||||||
void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory )
|
void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory )
|
||||||
throw( IO_ERROR )
|
throw( IO_ERROR )
|
||||||
{
|
{
|
||||||
PN_ITER limit = aCategory.size() ?
|
PN_ITER end = aCategory.size() ?
|
||||||
partnames.lower_bound( aCategory + char( '/' + 1 ) ) :
|
partnames.lower_bound( aCategory + char( '/' + 1 ) ) :
|
||||||
partnames.end();
|
partnames.end();
|
||||||
|
|
||||||
PN_ITER it = aCategory.size() ?
|
PN_ITER it = aCategory.size() ?
|
||||||
partnames.upper_bound( aCategory + "/" ) :
|
partnames.upper_bound( aCategory + "/" ) :
|
||||||
partnames.begin();
|
partnames.begin();
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& a
|
||||||
{
|
{
|
||||||
STRING partName;
|
STRING partName;
|
||||||
|
|
||||||
while( it != limit )
|
while( it != end )
|
||||||
{
|
{
|
||||||
const char* rev = endsWithRev( *it );
|
const char* rev = endsWithRev( *it );
|
||||||
|
|
||||||
|
@ -434,7 +434,32 @@ void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& a
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while( it != limit )
|
while( it != end )
|
||||||
|
aResults->push_back( *it++ );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DIR_LIB_SOURCE::GetRevisions( STRINGS* aResults, const STRING& aPartName )
|
||||||
|
throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
aResults->clear();
|
||||||
|
|
||||||
|
if( useVersioning )
|
||||||
|
{
|
||||||
|
STRING partName;
|
||||||
|
|
||||||
|
const char* rev = endsWithRev( aPartName );
|
||||||
|
if( rev )
|
||||||
|
// partName is substring which omits the rev and the separator
|
||||||
|
partName.assign( aPartName, 0, rev - aPartName.c_str() - 1 );
|
||||||
|
else
|
||||||
|
partName = aPartName;
|
||||||
|
|
||||||
|
PN_ITER it = partnames.upper_bound( partName +'/' );
|
||||||
|
PN_ITER end = partnames.lower_bound( partName + char( '/' +1 ) );
|
||||||
|
|
||||||
|
while( it != end )
|
||||||
aResults->push_back( *it++ );
|
aResults->push_back( *it++ );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,10 +174,8 @@ protected:
|
||||||
void GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory = "" )
|
void GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory = "" )
|
||||||
throw( IO_ERROR );
|
throw( IO_ERROR );
|
||||||
|
|
||||||
void GetRevisions( STRINGS* aResults, const STRING& aPartName ) throw( IO_ERROR )
|
void GetRevisions( STRINGS* aResults, const STRING& aPartName )
|
||||||
{
|
throw( IO_ERROR );
|
||||||
// @todo
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindParts( STRINGS* aResults, const STRING& aQuery ) throw( IO_ERROR )
|
void FindParts( STRINGS* aResults, const STRING& aQuery ) throw( IO_ERROR )
|
||||||
{
|
{
|
||||||
|
|
178
new/sch_lib.cpp
178
new/sch_lib.cpp
|
@ -25,19 +25,95 @@
|
||||||
#include <memory> // std::auto_ptr
|
#include <memory> // std::auto_ptr
|
||||||
#include <wx/string.h>
|
#include <wx/string.h>
|
||||||
|
|
||||||
|
|
||||||
#include <sch_lib.h>
|
#include <sch_lib.h>
|
||||||
#include <sch_lpid.h>
|
#include <sch_lpid.h>
|
||||||
#include <sch_part.h>
|
#include <sch_part.h>
|
||||||
#include <sweet_lexer.h>
|
#include <sweet_lexer.h>
|
||||||
#include <sch_lib_table.h>
|
#include <sch_lib_table.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
The LIB part cache consist of a std::map of partnames without revisions at the top level.
|
||||||
|
Each top level map entry can point to another std::map which it owns and holds all the revisions
|
||||||
|
for that part name. At any point in the tree, there can be NULL pointers which
|
||||||
|
allow for lazy loading, including the very top most root pointer itself, which
|
||||||
|
is PARTS* parts. We use the key to hold the partName at one level, and revision
|
||||||
|
at the deeper nested level, and that key information may not be present within
|
||||||
|
right hand side of the map tuple.
|
||||||
|
|
||||||
|
1) Only things which are asked for are done.
|
||||||
|
2) Anything we learn we remember.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SCH {
|
||||||
|
|
||||||
|
class PART_REVS : public std::map< STRING, PART* >
|
||||||
|
{
|
||||||
|
// @todo provide an integer sort on revN.. strings here.
|
||||||
|
|
||||||
|
public:
|
||||||
|
~PART_REVS()
|
||||||
|
{
|
||||||
|
for( iterator it = begin(); it != end(); ++it )
|
||||||
|
{
|
||||||
|
delete it->second; // second may be NULL, no problem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PARTS : public std::map< STRING, PART_REVS* >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~PARTS()
|
||||||
|
{
|
||||||
|
for( iterator it = begin(); it != end(); ++it )
|
||||||
|
{
|
||||||
|
delete it->second; // second may be NULL, no problem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace SCH
|
||||||
|
|
||||||
|
|
||||||
|
#else // was nothing but grief:
|
||||||
|
|
||||||
|
#include <boost/ptr_container/ptr_map.hpp>
|
||||||
|
|
||||||
|
namespace SCH {
|
||||||
|
|
||||||
|
/// PARTS' key is revision, like "rev12", PART pointer may be null until loaded.
|
||||||
|
typedef boost::ptr_map< STRING, boost::nullable<PART> > PARTS;
|
||||||
|
typedef PARTS::iterator PARTS_ITER;
|
||||||
|
typedef PARTS::const_iterator PARTS_CITER;
|
||||||
|
|
||||||
|
|
||||||
|
/// PART_REVS' key is part name, w/o rev, PART pointer may be null until loaded.
|
||||||
|
typedef boost::ptr_map< STRING, boost::nullable<PARTS> > PART_REVS;
|
||||||
|
typedef PART_REVS::iterator PART_REVS_ITER;
|
||||||
|
typedef PART_REVS::const_iterator PART_REVS_CITER;
|
||||||
|
|
||||||
|
} // namespace SCH
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
using namespace SCH;
|
using namespace SCH;
|
||||||
|
|
||||||
|
|
||||||
LIB::LIB( const STRING& aLogicalLibrary, LIB_SOURCE* aSource, LIB_SINK* aSink ) :
|
LIB::LIB( const STRING& aLogicalLibrary, LIB_SOURCE* aSource, LIB_SINK* aSink ) :
|
||||||
name( aLogicalLibrary ),
|
logicalName( aLogicalLibrary ),
|
||||||
source( aSource ),
|
source( aSource ),
|
||||||
sink( aSink )
|
sink( aSink ),
|
||||||
|
cachedCategories( false ),
|
||||||
|
parts( 0 )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,25 +122,99 @@ LIB::~LIB()
|
||||||
{
|
{
|
||||||
delete source;
|
delete source;
|
||||||
delete sink;
|
delete sink;
|
||||||
|
delete parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
||||||
|
{
|
||||||
|
if( !parts )
|
||||||
|
{
|
||||||
|
parts = new PARTS;
|
||||||
|
|
||||||
|
source->GetCategoricalPartNames( &vfetch );
|
||||||
|
|
||||||
|
// insert a PART_REVS for each part name
|
||||||
|
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
||||||
|
{
|
||||||
|
// D(printf("findPart:%s\n", it->c_str() );)
|
||||||
|
(*parts)[*it] = new PART_REVS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load all the revisions for this part name, only if it has any
|
||||||
|
PARTS::iterator pi = parts->find( aLPID.GetPartName() );
|
||||||
|
|
||||||
|
PART_REVS* revs = pi != parts->end() ? pi->second : NULL;
|
||||||
|
|
||||||
|
// D(printf("revs:%p partName:%s\n", revs, aLPID.GetPartName().c_str() );)
|
||||||
|
|
||||||
|
// if the key for parts has no aLPID.GetPartName() the part is not in this lib
|
||||||
|
if( revs )
|
||||||
|
{
|
||||||
|
if( revs->size() == 0 )
|
||||||
|
{
|
||||||
|
// load all the revisions for this part.
|
||||||
|
source->GetRevisions( &vfetch, aLPID.GetPartName() );
|
||||||
|
|
||||||
|
// creat a PART_REV entry for revision, but leave the PART* NULL
|
||||||
|
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
||||||
|
{
|
||||||
|
// D(printf("findPartRev:%s\n", it->c_str() );)
|
||||||
|
(*revs)[*it] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PART_REVS::iterator result = revs->find( aLPID.GetPartNameAndRev() );
|
||||||
|
|
||||||
|
if( result != revs->end() )
|
||||||
|
{
|
||||||
|
if( !result->second ) // the PART has never been loaded before
|
||||||
|
{
|
||||||
|
result->second = new PART( this, aLPID.GetPartNameAndRev() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If caller did not say what revision, find the highest numbered one and return that.
|
||||||
|
// Otherwise he knew what he wanted specifically, and we do not have it.
|
||||||
|
if( !aLPID.GetRevision().size() && revs->size() )
|
||||||
|
{
|
||||||
|
result = revs->begin(); // sort order has highest rev first
|
||||||
|
|
||||||
|
if( !result->second ) // the PART has never been loaded before
|
||||||
|
{
|
||||||
|
result->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), result->first ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // no such part name in this lib
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR )
|
PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR )
|
||||||
{
|
{
|
||||||
PART* part;
|
PART* part = (PART*) findPart( aLPID );
|
||||||
|
|
||||||
// If part not already cached
|
if( !part ) // part does not exist in this lib
|
||||||
if( 1 /* @todo test cache */ )
|
|
||||||
{
|
{
|
||||||
// load it.
|
wxString msg = wxString::Format( _("part '%s' not found in lib %s" ),
|
||||||
|
wxString::FromUTF8( aLPID.GetPartNameAndRev().c_str() ).GetData(),
|
||||||
part = new PART( this, aLPID.GetPartName(), aLPID.GetRevision() );
|
wxString::FromUTF8( logicalName.c_str() ).GetData() );
|
||||||
|
THROW_IO_ERROR( msg );
|
||||||
std::auto_ptr<PART> wrapped( part );
|
}
|
||||||
|
|
||||||
|
if( part->body.empty() )
|
||||||
|
{
|
||||||
|
// load body
|
||||||
source->ReadPart( &part->body, aLPID.GetPartName(), aLPID.GetRevision() );
|
source->ReadPart( &part->body, aLPID.GetPartName(), aLPID.GetRevision() );
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if 0 && defined(DEBUG)
|
||||||
const STRING& body = part->body;
|
const STRING& body = part->body;
|
||||||
printf( "body: %s", body.c_str() );
|
printf( "body: %s", body.c_str() );
|
||||||
if( !body.size() || body[body.size()-1] != '\n' )
|
if( !body.size() || body[body.size()-1] != '\n' )
|
||||||
|
@ -74,12 +224,6 @@ PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR
|
||||||
SWEET_LEXER sw( part->body, wxString::FromUTF8("body") /* @todo have ReadPart give better source */ );
|
SWEET_LEXER sw( part->body, wxString::FromUTF8("body") /* @todo have ReadPart give better source */ );
|
||||||
|
|
||||||
part->Parse( &sw, aLibTable );
|
part->Parse( &sw, aLibTable );
|
||||||
|
|
||||||
|
|
||||||
// stuff the part into this LIBs cache:
|
|
||||||
// @todo
|
|
||||||
|
|
||||||
wrapped.release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return part;
|
return part;
|
||||||
|
|
|
@ -105,7 +105,9 @@ protected: ///< derived classes must implement
|
||||||
/**
|
/**
|
||||||
* Function GetRevisions
|
* Function GetRevisions
|
||||||
* fetches all revisions for @a aPartName into @a aResults. Revisions are strings
|
* fetches all revisions for @a aPartName into @a aResults. Revisions are strings
|
||||||
* like "rev12", "rev279", and are library source agnostic. These
|
* like "rev12", "rev279", and are library source agnostic. These do not have to be
|
||||||
|
* in a contiguous order, but the first 3 characters must be "rev" and subsequent
|
||||||
|
* characters must consist of at least one decimal digit.
|
||||||
*/
|
*/
|
||||||
virtual void GetRevisions( STRINGS* aResults, const STRING& aPartName )
|
virtual void GetRevisions( STRINGS* aResults, const STRING& aPartName )
|
||||||
throw( IO_ERROR ) = 0;
|
throw( IO_ERROR ) = 0;
|
||||||
|
@ -183,6 +185,9 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class PARTS;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class LIB
|
* Class LIB
|
||||||
* is a cache of parts, and because the LIB_SOURCE is abstracted, there
|
* is a cache of parts, and because the LIB_SOURCE is abstracted, there
|
||||||
|
@ -318,17 +323,34 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
STR_UTF fetch; // scratch, used to fetch things, grows to worst case size.
|
STR_UTF fetch; // scratch, used to fetch things, grows to worst case size.
|
||||||
STR_UTFS vfetch; // scratch, used to fetch things.
|
STR_UTFS vfetch; // scratch, used to fetch things.
|
||||||
|
|
||||||
STRING name;
|
STRING logicalName;
|
||||||
LIB_SOURCE* source;
|
LIB_SOURCE* source;
|
||||||
LIB_SINK* sink;
|
LIB_SINK* sink;
|
||||||
// STRING libraryURI;
|
|
||||||
|
|
||||||
STRINGS categories;
|
STRINGS categories;
|
||||||
|
bool cachedCategories; /// < is true only after reading categories
|
||||||
|
|
||||||
|
|
||||||
|
/** parts are in various states of readiness:
|
||||||
|
* 1) not even loaded (if cachedParts is false)
|
||||||
|
* 2) present, but without member 'body' having been read() yet.
|
||||||
|
* 3) body has been read, but not parsed yet.
|
||||||
|
* 4) parsed and inheritance if any has been applied.
|
||||||
|
*/
|
||||||
|
PARTS* parts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function findPart
|
||||||
|
* finds a PART, returns NULL if cannot find.
|
||||||
|
* @throw IO_ERROR if there is some kind of communications error reading
|
||||||
|
* the original list of parts.
|
||||||
|
*/
|
||||||
|
const PART* findPart( const LPID& aLPID ) throw( IO_ERROR );
|
||||||
|
|
||||||
|
|
||||||
// PARTS parts;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -375,7 +375,6 @@ private:
|
||||||
typedef boost::ptr_map<STRING, ROW> ROWS;
|
typedef boost::ptr_map<STRING, ROW> ROWS;
|
||||||
typedef ROWS::iterator ROWS_ITER;
|
typedef ROWS::iterator ROWS_ITER;
|
||||||
typedef ROWS::const_iterator ROWS_CITER;
|
typedef ROWS::const_iterator ROWS_CITER;
|
||||||
// typedef std::pair<ROWS_ITER, bool> ROW_PAIR;
|
|
||||||
|
|
||||||
ROWS rows;
|
ROWS rows;
|
||||||
LIB_TABLE* fallBack;
|
LIB_TABLE* fallBack;
|
||||||
|
|
147
new/sch_lpid.cpp
147
new/sch_lpid.cpp
|
@ -186,7 +186,7 @@ LPID::LPID( const STRING& aLPID ) throw( PARSE_ERROR )
|
||||||
{
|
{
|
||||||
THROW_PARSE_ERROR(
|
THROW_PARSE_ERROR(
|
||||||
_( "Illegal character found in LPID string" ),
|
_( "Illegal character found in LPID string" ),
|
||||||
wxConvertMB2WX( aLPID.c_str() ),
|
wxString::FromUTF8( aLPID.c_str() ),
|
||||||
aLPID.c_str(),
|
aLPID.c_str(),
|
||||||
0,
|
0,
|
||||||
offset
|
offset
|
||||||
|
@ -249,6 +249,36 @@ int LPID::SetBaseName( const STRING& aBaseName )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int LPID::SetPartName( const STRING& aPartName )
|
||||||
|
{
|
||||||
|
STRING category;
|
||||||
|
STRING base;
|
||||||
|
int offset;
|
||||||
|
int separation = int( aPartName.find_first_of( "/" ) );
|
||||||
|
|
||||||
|
if( separation != -1 )
|
||||||
|
{
|
||||||
|
category = aPartName.substr( 0, separation );
|
||||||
|
base = aPartName.substr( separation+1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// leave category empty
|
||||||
|
base = aPartName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (offset = SetCategory( category )) != -1 )
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
if( (offset = SetBaseName( base )) != -1 )
|
||||||
|
{
|
||||||
|
return offset + separation + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int LPID::SetRevision( const STRING& aRevision )
|
int LPID::SetRevision( const STRING& aRevision )
|
||||||
{
|
{
|
||||||
int offset = okRevision( aRevision );
|
int offset = okRevision( aRevision );
|
||||||
|
@ -288,6 +318,121 @@ STRING LPID::Format() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STRING LPID::GetPartNameAndRev() const
|
||||||
|
{
|
||||||
|
STRING ret;
|
||||||
|
|
||||||
|
if( category.size() )
|
||||||
|
{
|
||||||
|
ret += category;
|
||||||
|
ret += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += baseName;
|
||||||
|
|
||||||
|
if( revision.size() )
|
||||||
|
{
|
||||||
|
ret += '/';
|
||||||
|
ret += revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STRING LPID::Format( const STRING& aLogicalLib, const STRING& aPartName, const STRING& aRevision )
|
||||||
|
throw( PARSE_ERROR )
|
||||||
|
{
|
||||||
|
STRING ret;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if( aLogicalLib.size() )
|
||||||
|
{
|
||||||
|
offset = okLogical( aLogicalLib );
|
||||||
|
if( offset != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR(
|
||||||
|
_( "Illegal character found in logical lib name" ),
|
||||||
|
wxString::FromUTF8( aLogicalLib.c_str() ),
|
||||||
|
aLogicalLib.c_str(),
|
||||||
|
0,
|
||||||
|
offset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret += aLogicalLib;
|
||||||
|
ret += ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
STRING category;
|
||||||
|
STRING base;
|
||||||
|
|
||||||
|
int separation = int( aPartName.find_first_of( "/" ) );
|
||||||
|
|
||||||
|
if( separation != -1 )
|
||||||
|
{
|
||||||
|
category = aPartName.substr( 0, separation );
|
||||||
|
base = aPartName.substr( separation+1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// leave category empty
|
||||||
|
base = aPartName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (offset = okCategory( category )) != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR(
|
||||||
|
_( "Illegal character found in category" ),
|
||||||
|
wxString::FromUTF8( aRevision.c_str() ),
|
||||||
|
aRevision.c_str(),
|
||||||
|
0,
|
||||||
|
offset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (offset = okBase( base )) != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR(
|
||||||
|
_( "Illegal character found in base name" ),
|
||||||
|
wxString::FromUTF8( aRevision.c_str() ),
|
||||||
|
aRevision.c_str(),
|
||||||
|
0,
|
||||||
|
offset + separation + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( category.size() )
|
||||||
|
{
|
||||||
|
ret += category;
|
||||||
|
ret += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += base;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( aRevision.size() )
|
||||||
|
{
|
||||||
|
offset = okRevision( aRevision );
|
||||||
|
if( offset != -1 )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR(
|
||||||
|
_( "Illegal character found in revision" ),
|
||||||
|
wxString::FromUTF8( aRevision.c_str() ),
|
||||||
|
aRevision.c_str(),
|
||||||
|
0,
|
||||||
|
offset
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret += '/';
|
||||||
|
ret += aRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0 && defined(DEBUG)
|
#if 0 && defined(DEBUG)
|
||||||
|
|
||||||
// build this with Debug CMAKE_BUILD_TYPE
|
// build this with Debug CMAKE_BUILD_TYPE
|
||||||
|
|
|
@ -145,6 +145,23 @@ public:
|
||||||
return partName;
|
return partName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetPartNameAndRev
|
||||||
|
* returns the part name with revision if any, i.e. [category/]baseName[/revN..]
|
||||||
|
*/
|
||||||
|
STRING GetPartNameAndRev() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SetPartName
|
||||||
|
* overrides the part name portion of the LPID to @a aPartName
|
||||||
|
* @return int - minus 1 (i.e. -1) means success, >= 0 indicates the
|
||||||
|
* character offset into the parameter at which an error was detected, usually
|
||||||
|
* because it contained more than one '/', or one or more ':', or is blank.
|
||||||
|
* A single '/' is allowed, since that is used to separate the category from the
|
||||||
|
* base name.
|
||||||
|
*/
|
||||||
|
int SetPartName( const STRING& aPartName );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetRevision
|
* Function GetRevision
|
||||||
* returns the revision portion of the LPID.
|
* returns the revision portion of the LPID.
|
||||||
|
@ -170,6 +187,16 @@ public:
|
||||||
*/
|
*/
|
||||||
STRING Format() const;
|
STRING Format() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Format
|
||||||
|
* returns a STRING in the proper format as an LPID for a combination of
|
||||||
|
* aLogicalLib, aPartName, and aRevision.
|
||||||
|
* @throw PARSE_ERROR if any of the pieces are illegal.
|
||||||
|
*/
|
||||||
|
static STRING Format( const STRING& aLogicalLib, const STRING& aPartName, const STRING& aRevision="" )
|
||||||
|
throw( PARSE_ERROR );
|
||||||
|
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
static void Test();
|
static void Test();
|
||||||
#endif
|
#endif
|
||||||
|
|
147
new/sch_part.cpp
147
new/sch_part.cpp
|
@ -31,9 +31,13 @@
|
||||||
using namespace SCH;
|
using namespace SCH;
|
||||||
|
|
||||||
|
|
||||||
//-----<temporary home for PART sub objects, move after stable>------------------
|
#define MAX_INHERITANCE_NESTING 10 // no problem going larger
|
||||||
|
|
||||||
|
|
||||||
|
//-----<temporary home for PART sub objects, move after stable>------------------
|
||||||
|
struct XY {};
|
||||||
|
struct AT {};
|
||||||
|
|
||||||
|
|
||||||
//-----</temporary home for PART sub objects, move after stable>-----------------
|
//-----</temporary home for PART sub objects, move after stable>-----------------
|
||||||
|
|
||||||
|
@ -55,7 +59,8 @@ class PART_PARSER
|
||||||
{
|
{
|
||||||
SWEET_LEXER* in;
|
SWEET_LEXER* in;
|
||||||
LIB_TABLE* libs;
|
LIB_TABLE* libs;
|
||||||
int contains;
|
int contains; // separate from PART::contains until done
|
||||||
|
// so we can see what we inherited from base PART
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PART_PARSER( PART* aPart, SWEET_LEXER* aLexer, LIB_TABLE* aTable ) :
|
PART_PARSER( PART* aPart, SWEET_LEXER* aLexer, LIB_TABLE* aTable ) :
|
||||||
|
@ -66,51 +71,98 @@ public:
|
||||||
parsePart( aPart );
|
parsePart( aPart );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parseXY( XY* me )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseAt( AT* me )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void parseExtends( PART* me )
|
||||||
|
{
|
||||||
|
PART* base;
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
if( contains & PB(EXTENDS) )
|
||||||
|
in->Duplicate( T_extends );
|
||||||
|
|
||||||
|
in->NeedSYMBOLorNUMBER();
|
||||||
|
me->setExtends( new LPID() );
|
||||||
|
|
||||||
|
offset = me->extends->Parse( in->CurText() );
|
||||||
|
if( offset > -1 ) // -1 is success
|
||||||
|
THROW_PARSE_ERROR( _("invalid extends LPID"),
|
||||||
|
in->CurSource(),
|
||||||
|
in->CurLine(),
|
||||||
|
in->CurLineNumber(),
|
||||||
|
in->CurOffset() + offset );
|
||||||
|
|
||||||
|
base = libs->LookupPart( *me->extends, me->Owner() );
|
||||||
|
|
||||||
|
// we could be going in circles here, recursively, or too deep, set limits
|
||||||
|
// and disallow extending from self (even indirectly)
|
||||||
|
int extendsDepth = 0;
|
||||||
|
for( PART* ancestor = base; ancestor && extendsDepth<MAX_INHERITANCE_NESTING;
|
||||||
|
++extendsDepth, ancestor = ancestor->base )
|
||||||
|
{
|
||||||
|
if( ancestor == me )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR( _("'extends' may not have self as any ancestor"),
|
||||||
|
in->CurSource(),
|
||||||
|
in->CurLine(),
|
||||||
|
in->CurLineNumber(),
|
||||||
|
in->CurOffset() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( extendsDepth == MAX_INHERITANCE_NESTING )
|
||||||
|
{
|
||||||
|
THROW_PARSE_ERROR( _("max allowed extends depth exceeded"),
|
||||||
|
in->CurSource(),
|
||||||
|
in->CurLine(),
|
||||||
|
in->CurLineNumber(),
|
||||||
|
in->CurOffset() );
|
||||||
|
}
|
||||||
|
|
||||||
|
me->inherit( *base );
|
||||||
|
me->base = base;
|
||||||
|
contains |= PB(EXTENDS);
|
||||||
|
}
|
||||||
|
|
||||||
/// @param me = ja mir, the object getting stuffed, from its perspective
|
/// @param me = ja mir, the object getting stuffed, from its perspective
|
||||||
void parsePart( PART* me )
|
void parsePart( PART* me )
|
||||||
{
|
{
|
||||||
PART_T tok;
|
PART_T tok = in->NextTok();
|
||||||
|
|
||||||
if( (tok = in->NextTok()) == T_LEFT )
|
|
||||||
tok = in->NextTok();
|
|
||||||
|
|
||||||
// a token "( part .." i.e. class PART
|
|
||||||
// Be flexible regarding the starting point of the stream.
|
// Be flexible regarding the starting point of the stream.
|
||||||
// Caller may not have read the first two tokens out of the
|
// Caller may not have read the first two tokens out of the
|
||||||
// stream: T_LEFT and T_part, so ignore them if seen here.
|
// stream: T_LEFT and T_part, so ignore them if seen here.
|
||||||
// The 1st two tokens T_LEFT and T_part are then optional in the grammar.
|
// The 1st two tokens T_LEFT and T_part are then optional in the grammar.
|
||||||
if( tok == T_part )
|
|
||||||
|
if( tok == T_LEFT )
|
||||||
{
|
{
|
||||||
in->NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss
|
if( ( tok = in->NextTok() ) != T_part )
|
||||||
tok = in->NextTok();
|
in->Expecting( T_part );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
in->NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss
|
||||||
|
tok = in->NextTok();
|
||||||
|
|
||||||
// extends must be _first_ thing, if it is present at all, after NAME_HINT
|
// extends must be _first_ thing, if it is present at all, after NAME_HINT
|
||||||
if( tok == T_extends )
|
if( tok == T_extends )
|
||||||
{
|
{
|
||||||
PART* base;
|
parseExtends( me );
|
||||||
int offset;
|
|
||||||
|
|
||||||
if( contains & PB(EXTENDS) )
|
|
||||||
in->Duplicate( tok );
|
|
||||||
in->NeedSYMBOLorNUMBER();
|
|
||||||
me->setExtends( new LPID() );
|
|
||||||
offset = me->extends->Parse( in->CurText() );
|
|
||||||
if( offset > -1 ) // -1 is success
|
|
||||||
THROW_PARSE_ERROR( _("invalid extends LPID"),
|
|
||||||
in->CurSource(),
|
|
||||||
in->CurLine(),
|
|
||||||
in->CurLineNumber(),
|
|
||||||
in->CurOffset() + offset );
|
|
||||||
// we could be going in circles here, recursively, @todo add a max counter or stack chain
|
|
||||||
base = libs->LookupPart( *me->extends, me->Owner() );
|
|
||||||
me->inherit( *base );
|
|
||||||
contains |= PB(EXTENDS);
|
|
||||||
tok = in->NextTok();
|
tok = in->NextTok();
|
||||||
}
|
}
|
||||||
|
|
||||||
for( ; tok!=T_RIGHT && tok!=T_EOF; tok = in->NextTok() )
|
for( ; tok!=T_RIGHT; tok = in->NextTok() )
|
||||||
{
|
{
|
||||||
|
if( tok==T_EOF )
|
||||||
|
in->Unexpected( _( "end of input" ) );
|
||||||
|
|
||||||
if( tok == T_LEFT )
|
if( tok == T_LEFT )
|
||||||
tok = in->NextTok();
|
tok = in->NextTok();
|
||||||
|
|
||||||
|
@ -212,22 +264,26 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contains |= PB(PARSED);
|
||||||
|
|
||||||
|
this->contains |= contains;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void parseAt( PART* me )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
PART::PART( LIB* aOwner, const STRING& aPartName, const STRING& aRevision ) :
|
PART::PART( LIB* aOwner, const STRING& aPartNameAndRev ) :
|
||||||
owner( aOwner ),
|
owner( aOwner ),
|
||||||
contains( 0 ),
|
contains( 0 ),
|
||||||
partName( aPartName ),
|
partNameAndRev( aPartNameAndRev ),
|
||||||
revision( aRevision ),
|
extends( 0 ),
|
||||||
extends( 0 )
|
base( 0 )
|
||||||
{}
|
{
|
||||||
|
// Our goal is to have class LIB only instantiate what is needed, so print here
|
||||||
|
// what it is doing. It is the only class where PART can be instantiated.
|
||||||
|
D(printf("PART::PART(%s)\n", aPartNameAndRev.c_str() );)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PART::~PART()
|
PART::~PART()
|
||||||
|
@ -247,19 +303,20 @@ void PART::inherit( const PART& other )
|
||||||
{
|
{
|
||||||
contains = other.contains;
|
contains = other.contains;
|
||||||
|
|
||||||
setExtends( other.extends ? new LPID( *other.extends ) : 0 );
|
// @todo copy the inherited drawables, properties, and pins here
|
||||||
|
|
||||||
body = other.body;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PART& PART::operator=( const PART& other )
|
PART& PART::operator=( const PART& other )
|
||||||
{
|
{
|
||||||
owner = other.owner;
|
owner = other.owner;
|
||||||
partName = other.partName;
|
partNameAndRev = other.partNameAndRev;
|
||||||
revision = other.revision;
|
body = other.body;
|
||||||
|
base = other.base;
|
||||||
|
|
||||||
// maintain inherit() as a partial assignment operator.
|
setExtends( other.extends ? new LPID( *other.extends ) : 0 );
|
||||||
|
|
||||||
|
// maintain in concert with inherit(), which is a partial assignment operator.
|
||||||
inherit( other );
|
inherit( other );
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
|
|
@ -43,9 +43,8 @@ class LPID;
|
||||||
*/
|
*/
|
||||||
enum PartBit
|
enum PartBit
|
||||||
{
|
{
|
||||||
BODY, ///< body has been read in.
|
|
||||||
PARSED, ///< have parsed this part already, otherwise 'body' text must be parsed
|
PARSED, ///< have parsed this part already, otherwise 'body' text must be parsed
|
||||||
EXTENDS, ///< saw and "extends" keyword, inheriting from another PART
|
EXTENDS, ///< saw "extends" keyword, inheriting from another PART
|
||||||
VALUE,
|
VALUE,
|
||||||
ANCHOR,
|
ANCHOR,
|
||||||
REFERENCE,
|
REFERENCE,
|
||||||
|
@ -55,6 +54,7 @@ enum PartBit
|
||||||
KEYWORDS,
|
KEYWORDS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Function PB
|
/// Function PB
|
||||||
/// is a PartBit shifter for PART::contains field.
|
/// is a PartBit shifter for PART::contains field.
|
||||||
static inline const int PB( PartBit oneBitOnly )
|
static inline const int PB( PartBit oneBitOnly )
|
||||||
|
@ -80,7 +80,7 @@ class PART
|
||||||
protected: // not likely to have C++ descendants, but protected none-the-less.
|
protected: // not likely to have C++ descendants, but protected none-the-less.
|
||||||
|
|
||||||
/// a protected constructor, only a LIB can instantiate a PART.
|
/// a protected constructor, only a LIB can instantiate a PART.
|
||||||
PART( LIB* aOwner, const STRING& aPartName, const STRING& aRevision );
|
PART( LIB* aOwner, const STRING& aPartNameAndRev );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function inherit
|
* Function inherit
|
||||||
|
@ -95,10 +95,10 @@ protected: // not likely to have C++ descendants, but protected none-the-le
|
||||||
LIB* owner; ///< which LIB am I a part of (pun if you want)
|
LIB* owner; ///< which LIB am I a part of (pun if you want)
|
||||||
int contains; ///< has bits from Enum PartParts
|
int contains; ///< has bits from Enum PartParts
|
||||||
|
|
||||||
STRING partName; ///< example "passives/R", immutable.
|
STRING partNameAndRev; ///< example "passives/R[/revN..]", immutable.
|
||||||
STRING revision; // @todo need a single search key, this won't do.
|
|
||||||
|
|
||||||
LPID* extends; ///< of base part, NULL if none, otherwise I own it.
|
LPID* extends; ///< of base part, NULL if none, otherwise I own it.
|
||||||
|
PART* base; ///< which PART am I extending, if any. no ownership.
|
||||||
|
|
||||||
/// encapsulate the old version deletion, take ownership of @a aLPID
|
/// encapsulate the old version deletion, take ownership of @a aLPID
|
||||||
void setExtends( LPID* aLPID );
|
void setExtends( LPID* aLPID );
|
||||||
|
@ -107,6 +107,7 @@ protected: // not likely to have C++ descendants, but protected none-the-le
|
||||||
/// actually becomes cached in RAM.
|
/// actually becomes cached in RAM.
|
||||||
STRING body;
|
STRING body;
|
||||||
|
|
||||||
|
// bool cachedRevisions; ///< allows lazy loading of revision of this same part name
|
||||||
|
|
||||||
// 3 separate lists for speed:
|
// 3 separate lists for speed:
|
||||||
|
|
||||||
|
@ -136,7 +137,6 @@ public:
|
||||||
*/
|
*/
|
||||||
LIB* Owner() { return owner; }
|
LIB* Owner() { return owner; }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Parse
|
* Function Parse
|
||||||
* translates a Sweet string into a binary form that is represented
|
* translates a Sweet string into a binary form that is represented
|
||||||
|
|
Loading…
Reference in New Issue