Files
kicad-source-mirror/common/libraries/library_table_parser.cpp
T
Jeff Young 386cd19975 Formatting.
2025-11-05 17:30:23 +00:00

242 lines
8.7 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
* @author Jon Evans <jon@craftyjon.com>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fmt/format.h>
#include <pegtl/contrib/parse_tree.hpp>
#include <wx/log.h>
#include <libraries/library_table_parser.h>
#include <libraries/library_table_grammar.h>
#include <trace_helpers.h>
#include <boost/locale/boundary/types.hpp>
using namespace LIBRARY_TABLE_GRAMMAR;
struct LIBRARY_TABLE_PARSER_STATE
{
LIBRARY_TABLE_PARSER_STATE() :
target_string( nullptr ),
current_row_model( {} ),
model( {} )
{}
std::string* target_string;
LIBRARY_TABLE_ROW_IR current_row_model;
LIBRARY_TABLE_IR model;
};
template <typename Rule>
struct LIBRARY_TABLE_PARSER_ACTION : tao::pegtl::nothing<Rule>
{
};
template <>
struct LIBRARY_TABLE_PARSER_ACTION<KEYWORDS::SYM_LIB_TABLE>
{
static void apply0( LIBRARY_TABLE_PARSER_STATE& s )
{
s.model.type = LIBRARY_TABLE_TYPE::SYMBOL;
}
};
template <>
struct LIBRARY_TABLE_PARSER_ACTION<KEYWORDS::FP_LIB_TABLE>
{
static void apply0( LIBRARY_TABLE_PARSER_STATE& s )
{
s.model.type = LIBRARY_TABLE_TYPE::FOOTPRINT;
}
};
template <>
struct LIBRARY_TABLE_PARSER_ACTION<KEYWORDS::DESIGN_BLOCK_LIB_TABLE>
{
static void apply0( LIBRARY_TABLE_PARSER_STATE& s )
{
s.model.type = LIBRARY_TABLE_TYPE::DESIGN_BLOCK;
}
};
template <>
struct LIBRARY_TABLE_PARSER_ACTION<TOKEN>
{
template <typename ActionInput>
static void apply( const ActionInput& in, LIBRARY_TABLE_PARSER_STATE& s )
{
wxCHECK2( s.target_string, return );
*s.target_string = in.string();
}
};
template <>
struct LIBRARY_TABLE_PARSER_ACTION<QUOTED_TEXT>
{
template <typename ActionInput>
static void apply( const ActionInput& in, LIBRARY_TABLE_PARSER_STATE& s )
{
wxCHECK2( s.target_string, return );
wxCHECK2( in.string().size() >= 2, return );
*s.target_string = in.string().substr( 1, in.string().size() - 2 );
}
};
#define DEFINE_STRING_ACTION( Rule, StateVariable ) \
template <> \
struct LIBRARY_TABLE_PARSER_ACTION<Rule> \
{ \
static void apply0( LIBRARY_TABLE_PARSER_STATE& s ) \
{ \
s.target_string = &s.StateVariable; \
} \
} \
DEFINE_STRING_ACTION( KEYWORDS::VERSION, model.version );
DEFINE_STRING_ACTION( KEYWORDS::NAME, current_row_model.nickname );
DEFINE_STRING_ACTION( KEYWORDS::TYPE, current_row_model.type );
DEFINE_STRING_ACTION( KEYWORDS::URI, current_row_model.uri );
DEFINE_STRING_ACTION( KEYWORDS::OPTIONS, current_row_model.options );
DEFINE_STRING_ACTION( KEYWORDS::DESCR, current_row_model.description );
// Handle (hidden), (disabled)
#define DEFINE_FLAG_ACTION( Rule, StateVariable ) \
template <> \
struct LIBRARY_TABLE_PARSER_ACTION<Rule> \
{ \
static void apply0( LIBRARY_TABLE_PARSER_STATE& s ) \
{ \
s.StateVariable = true; \
} \
} \
DEFINE_FLAG_ACTION( HIDDEN_MARKER, current_row_model.hidden );
DEFINE_FLAG_ACTION( DISABLED_MARKER, current_row_model.disabled );
template <>
struct LIBRARY_TABLE_PARSER_ACTION<LIB_ROW>
{
static void apply0( LIBRARY_TABLE_PARSER_STATE& s )
{
s.model.rows.emplace_back( s.current_row_model );
s.current_row_model = LIBRARY_TABLE_ROW_IR();
}
};
LIBRARY_TABLE_PARSER::LIBRARY_TABLE_PARSER()
{
}
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> LIBRARY_TABLE_PARSER::Parse(
const std::filesystem::path& aPath )
{
try
{
file_input in( aPath );
LIBRARY_TABLE_PARSER_STATE state;
wxLogTrace( traceLibraries, "LIBRARY_TABLE_PARSER::Parse %s", aPath.string().c_str() );
try
{
if( !parse<LIB_TABLE_FILE, LIBRARY_TABLE_PARSER_ACTION>( in, state ) )
{
wxLogTrace( traceLibraries, "Parsing failed without throwing" );
wxString msg = wxString::Format( _( "An unexpected error occurred while reading library table %s "),
aPath.string().c_str() );
return tl::unexpected( LIBRARY_PARSE_ERROR( { .description = msg } ) );
}
}
catch( const parse_error& e )
{
const auto& p = e.positions().front();
std::string msg = fmt::format( "Error at line {}, column {}:\n{}\n{:>{}}\n{}",
p.line, p.column, in.line_at( p ), "^", p.column,
e.message() );
wxLogTrace( traceLibraries, "%s", msg.c_str() );
return tl::unexpected( LIBRARY_PARSE_ERROR( {
.description = wxString::Format( _( "Syntax error at line %zu, column %zu" ),
p.line, p.column ),
.line = p.line,
.column = p.column
} ) );
}
return state.model;
}
catch( std::filesystem::filesystem_error& e )
{
wxLogTrace( traceLibraries, "LIBRARY_TABLE_PARSER::Parse loading '%s' error: %s", aPath.string(), e.what() );
return tl::unexpected( LIBRARY_PARSE_ERROR( {
.description = e.what()
} ) );
}
}
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> LIBRARY_TABLE_PARSER::ParseBuffer( const std::string& aBuffer )
{
memory_input in( aBuffer, "" );
LIBRARY_TABLE_PARSER_STATE state;
wxLogTrace( traceLibraries, "LIBRARY_TABLE_PARSER::Parse from string buffer" );
try
{
if( !parse<LIB_TABLE_FILE, LIBRARY_TABLE_PARSER_ACTION>( in, state ) )
{
wxLogTrace( traceLibraries, "Parsing failed without throwing" );
return tl::unexpected( LIBRARY_PARSE_ERROR( {
.description = _( "An unexpected error occurred while reading library table" )
} ) );
}
}
catch( const parse_error& e )
{
const auto& p = e.positions().front();
std::string msg = fmt::format( "Error at line {}, column {}:\n{}\n{:>{}}\n{}",
p.line, p.column, in.line_at( p ), "^", p.column,
e.message() );
wxLogTrace( traceLibraries, "%s", msg.c_str() );
return tl::unexpected( LIBRARY_PARSE_ERROR( {
.description = wxString::Format( _( "Syntax error at line %zu, column %zu" ),
p.line, p.column ),
.line = p.line,
.column = p.column
} ) );
}
return state.model;
}