more PART parser work
This commit is contained in:
parent
b942ebdc69
commit
0af1004f5c
|
@ -459,8 +459,12 @@ void DIR_LIB_SOURCE::GetRevisions( STRINGS* aResults, const STRING& aPartName )
|
||||||
PN_ITER it = partnames.upper_bound( partName +'/' );
|
PN_ITER it = partnames.upper_bound( partName +'/' );
|
||||||
PN_ITER end = partnames.lower_bound( partName + char( '/' +1 ) );
|
PN_ITER end = partnames.lower_bound( partName + char( '/' +1 ) );
|
||||||
|
|
||||||
while( it != end )
|
for( ; it != end; ++it )
|
||||||
aResults->push_back( *it++ );
|
{
|
||||||
|
const char* rev = endsWithRev( *it );
|
||||||
|
assert( rev );
|
||||||
|
aResults->push_back( it->substr( rev - it->c_str() ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
100
new/sch_lib.cpp
100
new/sch_lib.cpp
|
@ -39,13 +39,12 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
The LIB part cache consist of a std::map of partnames without revisions at the top level.
|
The LIB part cache consists of a std::map of partnames without revisions at the
|
||||||
Each top level map entry can point to another std::map which it owns and holds all the revisions
|
top level. Each top level map entry can point to another std::map which it owns
|
||||||
for that part name. At any point in the tree, there can be NULL pointers which
|
and which holds all the revisions for that part name. At any point in the tree,
|
||||||
allow for lazy loading, including the very top most root pointer itself, which
|
there can be NULL pointers which allow for lazy loading, including the very top
|
||||||
is PARTS* parts. We use the key to hold the partName at one level, and revision
|
most root pointer itself, which is PARTS* parts. We use the key to hold the
|
||||||
at the deeper nested level, and that key information may not be present within
|
partName at one level, and revision at the deeper nested level.
|
||||||
right hand side of the map tuple.
|
|
||||||
|
|
||||||
1) Only things which are asked for are done.
|
1) Only things which are asked for are done.
|
||||||
2) Anything we learn we remember.
|
2) Anything we learn we remember.
|
||||||
|
@ -54,10 +53,31 @@ right hand side of the map tuple.
|
||||||
|
|
||||||
namespace SCH {
|
namespace SCH {
|
||||||
|
|
||||||
class PART_REVS : public std::map< STRING, PART* >
|
|
||||||
{
|
|
||||||
// @todo provide an integer sort on revN.. strings here.
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct LTREV
|
||||||
|
* is for PART_REVS, and provides a custom way to compare rev STRINGs.
|
||||||
|
* Namely, the revN[N..] string if present, is collated according to a
|
||||||
|
* 'higher revision first'.
|
||||||
|
*/
|
||||||
|
struct LTREV
|
||||||
|
{
|
||||||
|
bool operator() ( const STRING& s1, const STRING& s2 ) const
|
||||||
|
{
|
||||||
|
return RevCmp( s1.c_str(), s2.c_str() ) < 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PART_REVS
|
||||||
|
* contains the collection of revisions for a particular part name, in the
|
||||||
|
* form of cached PARTs. The tuple consists of a rev string and a PART pointer.
|
||||||
|
* The rev string is like "rev1", the PART pointer will be NULL until the PART
|
||||||
|
* gets loaded, lazily.
|
||||||
|
*/
|
||||||
|
class PART_REVS : public std::map< STRING, PART*, LTREV >
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
~PART_REVS()
|
~PART_REVS()
|
||||||
{
|
{
|
||||||
|
@ -68,6 +88,15 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class PARTS
|
||||||
|
* contains the collection of PART_REVS for all PARTs in the lib.
|
||||||
|
* The tuple consists of a part name and a PART_REVS pointer.
|
||||||
|
* The part name does not have the revision attached (of course this is understood
|
||||||
|
* by definition of "part name"). The PART_REVS pointer will be NULL until a client
|
||||||
|
* askes about the revisions for a part name, so the loading is done lazily.
|
||||||
|
*/
|
||||||
class PARTS : public std::map< STRING, PART_REVS* >
|
class PARTS : public std::map< STRING, PART_REVS* >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -126,7 +155,7 @@ LIB::~LIB()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
const PART* LIB::lookupPart( const LPID& aLPID ) throw( IO_ERROR )
|
||||||
{
|
{
|
||||||
if( !parts )
|
if( !parts )
|
||||||
{
|
{
|
||||||
|
@ -137,7 +166,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
||||||
// insert a PART_REVS for each part name
|
// insert a PART_REVS for each part name
|
||||||
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
||||||
{
|
{
|
||||||
// D(printf("findPart:%s\n", it->c_str() );)
|
D(printf("lookupPart:%s\n", it->c_str() );)
|
||||||
(*parts)[*it] = new PART_REVS;
|
(*parts)[*it] = new PART_REVS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,44 +181,46 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
||||||
// if the key for parts has no aLPID.GetPartName() the part is not in this lib
|
// if the key for parts has no aLPID.GetPartName() the part is not in this lib
|
||||||
if( revs )
|
if( revs )
|
||||||
{
|
{
|
||||||
if( revs->size() == 0 )
|
if( revs->size() == 0 ) // assume rev list has not been loaded yet
|
||||||
{
|
{
|
||||||
// load all the revisions for this part.
|
// load all the revisions for this part.
|
||||||
source->GetRevisions( &vfetch, aLPID.GetPartName() );
|
source->GetRevisions( &vfetch, aLPID.GetPartName() );
|
||||||
|
|
||||||
// creat a PART_REV entry for revision, but leave the PART* NULL
|
// create a PART_REV entry for each revision, but leave the PART* NULL
|
||||||
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
||||||
{
|
{
|
||||||
// D(printf("findPartRev:%s\n", it->c_str() );)
|
D(printf("lookupPartRev:%s\n", it->c_str() );)
|
||||||
(*revs)[*it] = 0;
|
(*revs)[*it] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PART_REVS::iterator result = revs->find( aLPID.GetPartNameAndRev() );
|
PART_REVS::iterator rev;
|
||||||
|
|
||||||
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.
|
// 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() )
|
if( !aLPID.GetRevision().size() && revs->size() )
|
||||||
{
|
{
|
||||||
result = revs->begin(); // sort order has highest rev first
|
rev = revs->begin(); // sort order has highest rev first
|
||||||
|
|
||||||
if( !result->second ) // the PART has never been loaded before
|
if( !rev->second ) // the PART has never been instantiated before
|
||||||
{
|
{
|
||||||
result->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), result->first ) );
|
rev->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), rev->first ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return result->second;
|
D(printf("lookupPartLatestRev:%s\n", rev->second->partNameAndRev.c_str() );)
|
||||||
|
return rev->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rev = revs->find( aLPID.GetRevision() );
|
||||||
|
|
||||||
|
if( rev != revs->end() )
|
||||||
|
{
|
||||||
|
if( !rev->second ) // the PART has never been instantiated before
|
||||||
|
{
|
||||||
|
rev->second = new PART( this, aLPID.GetPartNameAndRev() );
|
||||||
|
}
|
||||||
|
return rev->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +230,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
||||||
|
|
||||||
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*) findPart( aLPID );
|
PART* part = (PART*) lookupPart( aLPID );
|
||||||
|
|
||||||
if( !part ) // part does not exist in this lib
|
if( !part ) // part does not exist in this lib
|
||||||
{
|
{
|
||||||
|
@ -221,7 +252,8 @@ PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR
|
||||||
printf( "\n" );
|
printf( "\n" );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SWEET_LEXER sw( part->body, wxString::FromUTF8("body") /* @todo have ReadPart give better source */ );
|
// @todo consider changing ReadPart to return a "source"
|
||||||
|
SWEET_LEXER sw( part->body, wxString::FromUTF8( aLPID.Format().c_str() ) );
|
||||||
|
|
||||||
part->Parse( &sw, aLibTable );
|
part->Parse( &sw, aLibTable );
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,14 +343,17 @@ protected:
|
||||||
PARTS* parts;
|
PARTS* parts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function findPart
|
* Function lookupPart
|
||||||
* finds a PART, returns NULL if cannot find.
|
* looks up a PART, returns NULL if cannot find in source. Does not parse
|
||||||
|
* the part. Does not even load the part's Sweet string. No ownership
|
||||||
|
* is given to the PART, it stays in the cache that is this LIB.
|
||||||
|
*
|
||||||
* @throw IO_ERROR if there is some kind of communications error reading
|
* @throw IO_ERROR if there is some kind of communications error reading
|
||||||
* the original list of parts.
|
* the original list of parts.
|
||||||
|
*
|
||||||
|
* @return PART* - the cached PART, or NULL if not found. No ownership transferred.
|
||||||
*/
|
*/
|
||||||
const PART* findPart( const LPID& aLPID ) throw( IO_ERROR );
|
const PART* lookupPart( const LPID& aLPID ) throw( IO_ERROR );
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,20 @@ const char* EndsWithRev( const char* start, const char* tail, char separator )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RevCmp( const char* s1, const char* s2 )
|
||||||
|
{
|
||||||
|
int r = strncmp( s1, s2, 3 );
|
||||||
|
|
||||||
|
if( r || strlen(s1)<4 || strlen(s2)<4 )
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rnum1 = atoi( s1+3 );
|
||||||
|
int rnum2 = atoi( s2+3 );
|
||||||
|
|
||||||
|
return -(rnum1 - rnum2); // swap the sign, higher revs first
|
||||||
|
}
|
||||||
|
|
||||||
//----<Policy and field test functions>-------------------------------------
|
//----<Policy and field test functions>-------------------------------------
|
||||||
|
|
||||||
|
@ -94,7 +108,7 @@ static int okRevision( const STRING& aField )
|
||||||
{
|
{
|
||||||
char rev[32]; // C string for speed
|
char rev[32]; // C string for speed
|
||||||
|
|
||||||
if( aField.size() >= 4 && aField.size() <= sizeof(rev)-3 )
|
if( aField.size() >= 4 )
|
||||||
{
|
{
|
||||||
strcpy( rev, "x/" );
|
strcpy( rev, "x/" );
|
||||||
strcat( rev, aField.c_str() );
|
strcat( rev, aField.c_str() );
|
||||||
|
|
|
@ -228,4 +228,16 @@ static inline const char* EndsWithRev( const STRING& aPartName, char separator =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function RevCmp
|
||||||
|
* compares two rev strings in a way like strcmp() except that the highest numbered
|
||||||
|
* revision is considered first in the sort order. The function probably won't work
|
||||||
|
* unless you give it two rev strings.
|
||||||
|
* @param s1 is a rev string like "rev10"
|
||||||
|
* @param s2 is a rev string like "rev1".
|
||||||
|
* @return int - either negative, zero, or positive depending on whether the revision
|
||||||
|
* is greater, equal, or less on the left hand side.
|
||||||
|
*/
|
||||||
|
int RevCmp( const char* s1, const char* s2 );
|
||||||
|
|
||||||
#endif // SCH_LPID_H_
|
#endif // SCH_LPID_H_
|
||||||
|
|
|
@ -135,19 +135,28 @@ public:
|
||||||
/// @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 = in->NextTok();
|
PART_T tok;
|
||||||
|
|
||||||
|
#if 0
|
||||||
// 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_LEFT )
|
if( (tok = in->NextTok() ) == T_LEFT )
|
||||||
{
|
{
|
||||||
if( ( tok = in->NextTok() ) != T_part )
|
if( ( tok = in->NextTok() ) != T_part )
|
||||||
in->Expecting( T_part );
|
in->Expecting( T_part );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
// "( part" are not optional
|
||||||
|
in->NeedLEFT();
|
||||||
|
|
||||||
|
if( ( tok = in->NextTok() ) != T_part )
|
||||||
|
in->Expecting( T_part );
|
||||||
|
#endif
|
||||||
|
|
||||||
in->NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss
|
in->NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss
|
||||||
tok = in->NextTok();
|
tok = in->NextTok();
|
||||||
|
|
||||||
|
@ -267,7 +276,7 @@ public:
|
||||||
|
|
||||||
contains |= PB(PARSED);
|
contains |= PB(PARSED);
|
||||||
|
|
||||||
this->contains |= contains;
|
me->contains |= contains;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue