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.
wxString path = ResolveLibraryPath( aLibraryPath, m_project );
// May throw an exception.
std::unique_ptr<SIM_LIBRARY> library = SIM_LIBRARY::Create( path, aReporter );
std::function<std::string(const std::string&, const std::string&)> f2 =
[&]( 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();
m_libraries[path] = std::move( library );

View File

@ -27,7 +27,8 @@
#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;
@ -37,6 +38,7 @@ std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( const wxString& aFilePath, REP
library = std::make_unique<SIM_LIBRARY_SPICE>();
library->m_reporter = aReporter;
library->m_pathResolver = aResolver;
library->ReadFile( std::string( aFilePath.c_str() ) );
return library;
}

View File

@ -53,7 +53,8 @@ public:
* @return The library loaded in a newly constructed object.
*/
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.
@ -82,6 +83,8 @@ protected:
std::vector<std::string> m_modelNames;
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;
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<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.
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 );
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>() )
{
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() );
}
catch( const IO_ERROR& e )
{
DisplayErrorMessage( nullptr, e.What() );
}
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() );
}
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::unknownLine>() )
catch( const IO_ERROR& e )
{
// Do nothing.
}
else
{
wxFAIL_MSG( "Unhandled parse tree node" );
DisplayErrorMessage( nullptr, e.What() );
}
}
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 )
{

View File

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