Add sim_lib callback to resolve embeded libs

Also teach parser to look for include directives in libraries

We get KiCad variable resolution in include pathnames for free.

Fixes https://gitlab.com/kicad/code/kicad/issues/13083
This commit is contained in:
Seth Hillbrand 2022-12-12 19:23:55 -08:00
parent cdcf875ec0
commit 10a3d57193
5 changed files with 93 additions and 34 deletions

View File

@ -90,8 +90,39 @@ SIM_LIBRARY& SIM_LIB_MGR::SetLibrary( const wxString& aLibraryPath, REPORTER* aR
// May throw an exception. // May throw an exception.
wxString path = ResolveLibraryPath( aLibraryPath, m_project ); wxString path = ResolveLibraryPath( aLibraryPath, m_project );
// May throw an exception. std::function<std::string(const std::string&, const std::string&)> f2 =
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, aReporter ); [&]( const std::string& aLibPath, const std::string& aRelativeLib ) -> std::string
{
wxFileName testPath( aLibPath );
wxString fullPath( aLibPath );
if( !testPath.IsAbsolute() && !aRelativeLib.empty() )
{
wxString relLib( aRelativeLib );
try
{
relLib = ResolveLibraryPath( relLib, m_project );
}
catch( ... )
{}
wxFileName fn( relLib );
fullPath = testPath.GetAbsolutePath( fn.GetPath( true ) );
}
try
{
fullPath = ResolveLibraryPath( fullPath, m_project );
}
catch( ... )
{}
return fullPath.ToStdString();
};
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, aReporter, &f2 );
Clear(); Clear();
m_libraries[path] = std::move( library ); m_libraries[path] = std::move( library );

View File

@ -27,7 +27,8 @@
#include <sim/sim_library_spice.h> #include <sim/sim_library_spice.h>
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REPORTER* aReporter ) std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString &aFilePath, REPORTER *aReporter,
std::function<std::string( const std::string&, const std::string& )> *aResolver )
{ {
std::unique_ptr<SIM_LIBRARY> library; std::unique_ptr<SIM_LIBRARY> library;
@ -37,6 +38,7 @@ std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REP
library = std::make_unique<SIM_LIBRARY_SPICE>(); library = std::make_unique<SIM_LIBRARY_SPICE>();
library->m_reporter = aReporter; library->m_reporter = aReporter;
library->m_pathResolver = aResolver;
library->ReadFile( std::string( aFilePath.c_str() ) ); library->ReadFile( std::string( aFilePath.c_str() ) );
return library; return library;
} }

View File

@ -53,7 +53,8 @@ public:
* @return The library loaded in a newly constructed object. * @return The library loaded in a newly constructed object.
*/ */
static std::unique_ptr<SIM_LIBRARY> Create( const wxString& aFilePath, static std::unique_ptr<SIM_LIBRARY> Create( const wxString& aFilePath,
REPORTER* aReporter = nullptr ); REPORTER* aReporter = nullptr,
std::function<std::string(const std::string&, const std::string&)>* aResolver = nullptr);
/** /**
* Read library from a source file. Must be in the format appropriate to the subclass, e.g. * Read library from a source file. Must be in the format appropriate to the subclass, e.g.
@ -82,6 +83,8 @@ protected:
std::vector<std::string> m_modelNames; std::vector<std::string> m_modelNames;
std::vector<std::unique_ptr<SIM_MODEL>> m_models; std::vector<std::unique_ptr<SIM_MODEL>> m_models;
std::function<std::string( const std::string&, const std::string& )>* m_pathResolver;
std::string m_filePath; std::string m_filePath;
REPORTER* m_reporter = nullptr; REPORTER* m_reporter = nullptr;

View File

@ -47,47 +47,68 @@ namespace SIM_LIBRARY_SPICE_PARSER
template <> struct librarySelector<modelUnit> : std::true_type {}; template <> struct librarySelector<modelUnit> : std::true_type {};
template <> struct librarySelector<modelName> : std::true_type {}; template <> struct librarySelector<modelName> : std::true_type {};
template <> struct librarySelector<dotInclude> : std::true_type {};
template <> struct librarySelector<dotIncludePathWithoutQuotes> : std::true_type {};
template <> struct librarySelector<dotIncludePathWithoutApostrophes> : std::true_type {};
template <> struct librarySelector<dotIncludePath> : std::true_type {};
// For debugging. // For debugging.
template <> struct librarySelector<unknownLine> : std::true_type {}; template <> struct librarySelector<unknownLine> : std::true_type {};
}; };
void SPICE_LIBRARY_PARSER::ReadFile( const std::string& aFilePath ) void SPICE_LIBRARY_PARSER::readElement( const std::string &aFilePath )
{ {
try tao::pegtl::file_input in( aFilePath );
std::unique_ptr<tao::pegtl::parse_tree::node> root =
tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
SIM_LIBRARY_SPICE_PARSER::librarySelector,
tao::pegtl::nothing,
SIM_LIBRARY_SPICE_PARSER::control>( in );
for( const auto& node : root->children )
{ {
tao::pegtl::file_input in( aFilePath ); if( node->is_type<SIM_LIBRARY_SPICE_PARSER::modelUnit>() )
auto root = tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
SIM_LIBRARY_SPICE_PARSER::librarySelector,
tao::pegtl::nothing,
SIM_LIBRARY_SPICE_PARSER::control>( in );
m_library.m_models.clear();
m_library.m_modelNames.clear();
for( const auto& node : root->children )
{ {
if( node->is_type<SIM_LIBRARY_SPICE_PARSER::modelUnit>() ) try
{ {
try m_library.m_models.push_back( SIM_MODEL_SPICE::Create( m_library, node->string() ) );
{ m_library.m_modelNames.emplace_back( node->children.at( 0 )->string() );
m_library.m_models.push_back( SIM_MODEL_SPICE::Create( m_library, node->string() ) );
m_library.m_modelNames.emplace_back( node->children.at( 0 )->string() );
}
catch( const IO_ERROR& e )
{
DisplayErrorMessage( nullptr, e.What() );
}
} }
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::unknownLine>() ) catch( const IO_ERROR& e )
{ {
// Do nothing. DisplayErrorMessage( nullptr, e.What() );
}
else
{
wxFAIL_MSG( "Unhandled parse tree node" );
} }
} }
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::dotInclude>() )
{
std::string lib = node->children.at( 0 )->string();
if( m_library.m_pathResolver )
lib = ( *m_library.m_pathResolver )( lib, aFilePath );
readElement( lib );
}
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::unknownLine>() )
{
// Do nothing.
}
else
{
wxFAIL_MSG( "Unhandled parse tree node" );
}
}
}
void SPICE_LIBRARY_PARSER::ReadFile( const std::string& aFilePath )
{
m_library.m_models.clear();
m_library.m_modelNames.clear();
try
{
readElement( aFilePath );
} }
catch( const std::filesystem::filesystem_error& e ) catch( const std::filesystem::filesystem_error& e )
{ {

View File

@ -29,11 +29,10 @@
class SIM_LIBRARY_SPICE; class SIM_LIBRARY_SPICE;
class SPICE_LIBRARY_PARSER class SPICE_LIBRARY_PARSER
{ {
public: public:
SPICE_LIBRARY_PARSER( SIM_LIBRARY_SPICE& aLibrary ) : SPICE_LIBRARY_PARSER( SIM_LIBRARY_SPICE &aLibrary ) :
m_library( aLibrary ) m_library( aLibrary )
{}; {};
@ -42,6 +41,9 @@ public:
virtual void ReadFile( const std::string& aFilePath ); virtual void ReadFile( const std::string& aFilePath );
protected:
void readElement( const std::string& aFilePath );
private: private:
SIM_LIBRARY_SPICE& m_library; SIM_LIBRARY_SPICE& m_library;
}; };