/new Miracles
This commit is contained in:
parent
784c04203e
commit
b942ebdc69
|
@ -400,11 +400,11 @@ DIR_LIB_SOURCE::~DIR_LIB_SOURCE()
|
|||
void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory )
|
||||
throw( IO_ERROR )
|
||||
{
|
||||
PN_ITER limit = aCategory.size() ?
|
||||
PN_ITER end = aCategory.size() ?
|
||||
partnames.lower_bound( aCategory + char( '/' + 1 ) ) :
|
||||
partnames.end();
|
||||
|
||||
PN_ITER it = aCategory.size() ?
|
||||
PN_ITER it = aCategory.size() ?
|
||||
partnames.upper_bound( aCategory + "/" ) :
|
||||
partnames.begin();
|
||||
|
||||
|
@ -414,7 +414,7 @@ void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& a
|
|||
{
|
||||
STRING partName;
|
||||
|
||||
while( it != limit )
|
||||
while( it != end )
|
||||
{
|
||||
const char* rev = endsWithRev( *it );
|
||||
|
||||
|
@ -434,7 +434,32 @@ void DIR_LIB_SOURCE::GetCategoricalPartNames( STRINGS* aResults, const STRING& a
|
|||
|
||||
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++ );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,10 +174,8 @@ protected:
|
|||
void GetCategoricalPartNames( STRINGS* aResults, const STRING& aCategory = "" )
|
||||
throw( IO_ERROR );
|
||||
|
||||
void GetRevisions( STRINGS* aResults, const STRING& aPartName ) throw( IO_ERROR )
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
void GetRevisions( STRINGS* aResults, const STRING& aPartName )
|
||||
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 <wx/string.h>
|
||||
|
||||
|
||||
#include <sch_lib.h>
|
||||
#include <sch_lpid.h>
|
||||
#include <sch_part.h>
|
||||
#include <sweet_lexer.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;
|
||||
|
||||
|
||||
LIB::LIB( const STRING& aLogicalLibrary, LIB_SOURCE* aSource, LIB_SINK* aSink ) :
|
||||
name( aLogicalLibrary ),
|
||||
logicalName( aLogicalLibrary ),
|
||||
source( aSource ),
|
||||
sink( aSink )
|
||||
sink( aSink ),
|
||||
cachedCategories( false ),
|
||||
parts( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -46,25 +122,99 @@ LIB::~LIB()
|
|||
{
|
||||
delete source;
|
||||
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
|
||||
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* part;
|
||||
PART* part = (PART*) findPart( aLPID );
|
||||
|
||||
// If part not already cached
|
||||
if( 1 /* @todo test cache */ )
|
||||
if( !part ) // part does not exist in this lib
|
||||
{
|
||||
// load it.
|
||||
|
||||
part = new PART( this, aLPID.GetPartName(), aLPID.GetRevision() );
|
||||
|
||||
std::auto_ptr<PART> wrapped( part );
|
||||
wxString msg = wxString::Format( _("part '%s' not found in lib %s" ),
|
||||
wxString::FromUTF8( aLPID.GetPartNameAndRev().c_str() ).GetData(),
|
||||
wxString::FromUTF8( logicalName.c_str() ).GetData() );
|
||||
THROW_IO_ERROR( msg );
|
||||
}
|
||||
|
||||
if( part->body.empty() )
|
||||
{
|
||||
// load body
|
||||
source->ReadPart( &part->body, aLPID.GetPartName(), aLPID.GetRevision() );
|
||||
|
||||
#if defined(DEBUG)
|
||||
#if 0 && defined(DEBUG)
|
||||
const STRING& body = part->body;
|
||||
printf( "body: %s", body.c_str() );
|
||||
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 */ );
|
||||
|
||||
part->Parse( &sw, aLibTable );
|
||||
|
||||
|
||||
// stuff the part into this LIBs cache:
|
||||
// @todo
|
||||
|
||||
wrapped.release();
|
||||
}
|
||||
|
||||
return part;
|
||||
|
|
|
@ -105,7 +105,9 @@ protected: ///< derived classes must implement
|
|||
/**
|
||||
* Function GetRevisions
|
||||
* 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 )
|
||||
throw( IO_ERROR ) = 0;
|
||||
|
@ -183,6 +185,9 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
class PARTS;
|
||||
|
||||
|
||||
/**
|
||||
* Class LIB
|
||||
* is a cache of parts, and because the LIB_SOURCE is abstracted, there
|
||||
|
@ -318,17 +323,34 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
STR_UTF fetch; // scratch, used to fetch things, grows to worst case size.
|
||||
STR_UTFS vfetch; // scratch, used to fetch things.
|
||||
STR_UTF fetch; // scratch, used to fetch things, grows to worst case size.
|
||||
STR_UTFS vfetch; // scratch, used to fetch things.
|
||||
|
||||
STRING name;
|
||||
STRING logicalName;
|
||||
LIB_SOURCE* source;
|
||||
LIB_SINK* sink;
|
||||
// STRING libraryURI;
|
||||
|
||||
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 ROWS::iterator ROWS_ITER;
|
||||
typedef ROWS::const_iterator ROWS_CITER;
|
||||
// typedef std::pair<ROWS_ITER, bool> ROW_PAIR;
|
||||
|
||||
ROWS rows;
|
||||
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(
|
||||
_( "Illegal character found in LPID string" ),
|
||||
wxConvertMB2WX( aLPID.c_str() ),
|
||||
wxString::FromUTF8( aLPID.c_str() ),
|
||||
aLPID.c_str(),
|
||||
0,
|
||||
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 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)
|
||||
|
||||
// build this with Debug CMAKE_BUILD_TYPE
|
||||
|
|
|
@ -145,6 +145,23 @@ public:
|
|||
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
|
||||
* returns the revision portion of the LPID.
|
||||
|
@ -170,6 +187,16 @@ public:
|
|||
*/
|
||||
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)
|
||||
static void Test();
|
||||
#endif
|
||||
|
|
140
new/sch_part.cpp
140
new/sch_part.cpp
|
@ -31,9 +31,13 @@
|
|||
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>-----------------
|
||||
|
||||
|
@ -55,7 +59,8 @@ class PART_PARSER
|
|||
{
|
||||
SWEET_LEXER* in;
|
||||
LIB_TABLE* libs;
|
||||
int contains;
|
||||
int contains; // separate from PART::contains until done
|
||||
// so we can see what we inherited from base PART
|
||||
|
||||
public:
|
||||
PART_PARSER( PART* aPart, SWEET_LEXER* aLexer, LIB_TABLE* aTable ) :
|
||||
|
@ -66,51 +71,98 @@ public:
|
|||
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
|
||||
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.
|
||||
// Caller may not have read the first two tokens out of the
|
||||
// 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.
|
||||
if( tok == T_part )
|
||||
|
||||
if( tok == T_LEFT )
|
||||
{
|
||||
in->NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss
|
||||
tok = in->NextTok();
|
||||
if( ( tok = in->NextTok() ) != T_part )
|
||||
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
|
||||
if( tok == T_extends )
|
||||
{
|
||||
PART* base;
|
||||
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);
|
||||
parseExtends( me );
|
||||
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 )
|
||||
tok = in->NextTok();
|
||||
|
||||
|
@ -212,22 +264,26 @@ public:
|
|||
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 ),
|
||||
contains( 0 ),
|
||||
partName( aPartName ),
|
||||
revision( aRevision ),
|
||||
extends( 0 )
|
||||
{}
|
||||
partNameAndRev( aPartNameAndRev ),
|
||||
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()
|
||||
|
@ -253,10 +309,10 @@ void PART::inherit( const PART& other )
|
|||
|
||||
PART& PART::operator=( const PART& other )
|
||||
{
|
||||
owner = other.owner;
|
||||
partName = other.partName;
|
||||
revision = other.revision;
|
||||
body = other.body;
|
||||
owner = other.owner;
|
||||
partNameAndRev = other.partNameAndRev;
|
||||
body = other.body;
|
||||
base = other.base;
|
||||
|
||||
setExtends( other.extends ? new LPID( *other.extends ) : 0 );
|
||||
|
||||
|
|
|
@ -43,9 +43,8 @@ class LPID;
|
|||
*/
|
||||
enum PartBit
|
||||
{
|
||||
BODY, ///< body has been read in.
|
||||
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,
|
||||
ANCHOR,
|
||||
REFERENCE,
|
||||
|
@ -55,6 +54,7 @@ enum PartBit
|
|||
KEYWORDS,
|
||||
};
|
||||
|
||||
|
||||
/// Function PB
|
||||
/// is a PartBit shifter for PART::contains field.
|
||||
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.
|
||||
|
||||
/// 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
|
||||
|
@ -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)
|
||||
int contains; ///< has bits from Enum PartParts
|
||||
|
||||
STRING partName; ///< example "passives/R", immutable.
|
||||
STRING revision; // @todo need a single search key, this won't do.
|
||||
STRING partNameAndRev; ///< example "passives/R[/revN..]", immutable.
|
||||
|
||||
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
|
||||
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.
|
||||
STRING body;
|
||||
|
||||
// bool cachedRevisions; ///< allows lazy loading of revision of this same part name
|
||||
|
||||
// 3 separate lists for speed:
|
||||
|
||||
|
@ -136,7 +137,6 @@ public:
|
|||
*/
|
||||
LIB* Owner() { return owner; }
|
||||
|
||||
|
||||
/**
|
||||
* Function Parse
|
||||
* translates a Sweet string into a binary form that is represented
|
||||
|
|
Loading…
Reference in New Issue