/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2022 Mikolaj Wielgus * Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * * 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, you may find one here: * https://www.gnu.org/licenses/gpl-3.0.html * or you may search the http://www.gnu.org website for the version 3 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #define CALL_INSTANCE( ValueType, Notation, func, ... ) \ switch( ValueType ) \ { \ case SIM_VALUE::TYPE_INT: \ switch( Notation ) \ { \ case NOTATION::SI: \ func( __VA_ARGS__ ); \ break; \ \ case NOTATION::SPICE: \ func( __VA_ARGS__ ); \ break; \ } \ break; \ \ case SIM_VALUE::TYPE_FLOAT: \ switch( Notation ) \ { \ case NOTATION::SI: \ func( __VA_ARGS__ ); \ break; \ \ case NOTATION::SPICE: \ func( __VA_ARGS__ ); \ break; \ } \ break; \ \ case SIM_VALUE::TYPE_BOOL: \ case SIM_VALUE::TYPE_COMPLEX: \ case SIM_VALUE::TYPE_STRING: \ case SIM_VALUE::TYPE_BOOL_VECTOR: \ case SIM_VALUE::TYPE_INT_VECTOR: \ case SIM_VALUE::TYPE_FLOAT_VECTOR: \ case SIM_VALUE::TYPE_COMPLEX_VECTOR: \ wxFAIL_MSG( "Unhandled SIM_VALUE type" ); \ break; \ } namespace SIM_VALUE_PARSER { using namespace SIM_VALUE_GRAMMAR; template struct numberSelector : std::false_type {}; // TODO: Reorder. NOTATION should be before TYPE. template <> struct numberSelector> : std::true_type {}; template <> struct numberSelector> : std::true_type {}; template <> struct numberSelector : std::true_type {}; template <> struct numberSelector : std::true_type {}; template <> struct numberSelector : std::true_type {}; template <> struct numberSelector> : std::true_type {}; template <> struct numberSelector> : std::true_type {}; template <> struct numberSelector> : std::true_type {}; template <> struct numberSelector> : std::true_type {}; struct PARSE_RESULT { bool isOk = true; bool isEmpty = true; std::string significand; std::optional intPart; std::optional fracPart; std::optional exponent; std::optional metricSuffixExponent; }; PARSE_RESULT Parse( const std::string& aString, NOTATION aNotation = NOTATION::SI, SIM_VALUE::TYPE aValueType = SIM_VALUE::TYPE_FLOAT ); int MetricSuffixToExponent( std::string aMetricSuffix, NOTATION aNotation = NOTATION::SI ); std::string ExponentToMetricSuffix( double aExponent, int& aReductionExponent, NOTATION aNotation = NOTATION::SI ); } template static inline void doIsValid( tao::pegtl::string_input<>& aIn ) { tao::pegtl::parse>( aIn ); } bool SIM_VALUE_GRAMMAR::IsValid( const std::string& aString, SIM_VALUE::TYPE aValueType, NOTATION aNotation ) { tao::pegtl::string_input<> in( aString, "from_content" ); try { CALL_INSTANCE( aValueType, aNotation, doIsValid, in ); } catch( const tao::pegtl::parse_error& ) { return false; } return true; } template static inline std::unique_ptr doParse( tao::pegtl::string_input<>& aIn ) { return tao::pegtl::parse_tree::parse, SIM_VALUE_PARSER::numberSelector> ( aIn ); } template static inline void handleNodeForParse( tao::pegtl::parse_tree::node& aNode, SIM_VALUE_PARSER::PARSE_RESULT& aParseResult ) { if( aNode.is_type>() ) { aParseResult.significand = aNode.string(); aParseResult.isEmpty = false; for( const auto& subnode : aNode.children ) { if( subnode->is_type() ) aParseResult.intPart = std::stol( subnode->string() ); else if( subnode->is_type() ) aParseResult.fracPart = std::stol( subnode->string() ); } } else if( aNode.is_type() ) { aParseResult.exponent = std::stoi( aNode.string() ); aParseResult.isEmpty = false; } else if( aNode.is_type>() ) { aParseResult.metricSuffixExponent = SIM_VALUE_PARSER::MetricSuffixToExponent( aNode.string(), Notation ); aParseResult.isEmpty = false; } else wxFAIL_MSG( "Unhandled parse tree node" ); } SIM_VALUE_PARSER::PARSE_RESULT SIM_VALUE_PARSER::Parse( const std::string& aString, NOTATION aNotation, SIM_VALUE::TYPE aValueType ) { LOCALE_IO toggle; tao::pegtl::string_input<> in( aString, "from_content" ); std::unique_ptr root; PARSE_RESULT result; try { CALL_INSTANCE( aValueType, aNotation, root = doParse, in ); } catch( tao::pegtl::parse_error& ) { result.isOk = false; return result; } wxASSERT( root ); try { for( const auto& node : root->children ) { CALL_INSTANCE( aValueType, aNotation, handleNodeForParse, *node, result ); } } catch( const std::invalid_argument& e ) { wxFAIL_MSG( fmt::format( "Parsing simulator value failed: {:s}", e.what() ) ); result.isOk = false; } return result; } int SIM_VALUE_PARSER::MetricSuffixToExponent( std::string aMetricSuffix, NOTATION aNotation ) { switch( aNotation ) { case NOTATION::SI: if( aMetricSuffix.empty() ) return 0; switch( aMetricSuffix[0] ) { case 'a': return -18; case 'f': return -15; case 'p': return -12; case 'n': return -9; case 'u': return -6; case 'm': return -3; case 'k': case 'K': return 3; case 'M': return 6; case 'G': return 9; case 'T': return 12; case 'P': return 15; case 'E': return 18; } break; case NOTATION::SPICE: std::transform( aMetricSuffix.begin(), aMetricSuffix.end(), aMetricSuffix.begin(), ::tolower ); if( aMetricSuffix == "f" ) return -15; else if( aMetricSuffix == "p" ) return -12; else if( aMetricSuffix == "n" ) return -9; else if( aMetricSuffix == "u" ) return -6; else if( aMetricSuffix == "m" ) return -3; else if( aMetricSuffix == "" ) return 0; else if( aMetricSuffix == "k" ) return 3; else if( aMetricSuffix == "meg" ) return 6; else if( aMetricSuffix == "g" ) return 9; else if( aMetricSuffix == "t" ) return 12; break; } wxFAIL_MSG( fmt::format( "Unknown simulator value suffix: '{:s}'", aMetricSuffix ) ); return 0; } std::string SIM_VALUE_PARSER::ExponentToMetricSuffix( double aExponent, int& aReductionExponent, NOTATION aNotation ) { if( aNotation == NOTATION::SI && aExponent >= -18 && aExponent <= -15 ) { aReductionExponent = -18; return "a"; } else if( aExponent >= -15 && aExponent < -12 ) { aReductionExponent = -15; return "f"; } else if( aExponent >= -12 && aExponent < -9 ) { aReductionExponent = -12; return "p"; } else if( aExponent >= -9 && aExponent < -6 ) { aReductionExponent = -9; return "n"; } else if( aExponent >= -6 && aExponent < -3 ) { aReductionExponent = -6; return "u"; } else if( aExponent >= -3 && aExponent < 0 ) { aReductionExponent = -3; return "m"; } else if( aExponent >= 0 && aExponent < 3 ) { aReductionExponent = 0; return ""; } else if( aExponent >= 3 && aExponent < 6 ) { aReductionExponent = 3; return "k"; } else if( aExponent >= 6 && aExponent < 9 ) { aReductionExponent = 6; return ( aNotation == NOTATION::SI ) ? "M" : "Meg"; } else if( aExponent >= 9 && aExponent < 12 ) { aReductionExponent = 9; return "G"; } else if( aExponent >= 12 && aExponent < 15 ) { aReductionExponent = 12; return "T"; } else if( aNotation == NOTATION::SI && aExponent >= 15 && aExponent < 18 ) { aReductionExponent = 15; return "P"; } else if( aNotation == NOTATION::SI && aExponent >= 18 && aExponent <= 21 ) { aReductionExponent = 18; return "E"; } aReductionExponent = 0; return ""; } std::unique_ptr SIM_VALUE::Create( TYPE aType, std::string aString, NOTATION aNotation ) { std::unique_ptr value = SIM_VALUE::Create( aType ); value->FromString( aString, aNotation ); return value; } std::unique_ptr SIM_VALUE::Create( TYPE aType ) { switch( aType ) { case TYPE_BOOL: return std::make_unique(); case TYPE_INT: return std::make_unique(); case TYPE_FLOAT: return std::make_unique(); case TYPE_COMPLEX: return std::make_unique(); case TYPE_STRING: return std::make_unique(); case TYPE_BOOL_VECTOR: return std::make_unique(); case TYPE_INT_VECTOR: return std::make_unique(); case TYPE_FLOAT_VECTOR: return std::make_unique(); case TYPE_COMPLEX_VECTOR: return std::make_unique(); } wxFAIL_MSG( _( "Unknown SIM_VALUE type" ) ); return nullptr; } void SIM_VALUE::operator=( const std::string& aString ) { FromString( aString ); } bool SIM_VALUE::operator!=( const SIM_VALUE& aOther ) const { return !( *this == aOther ); } template SIM_VALUE_INST::SIM_VALUE_INST( const T& aValue ) : m_value( aValue ) { } template SIM_VALUE_BOOL::SIM_VALUE_INST( const bool& aValue ); template SIM_VALUE_INT::SIM_VALUE_INST( const int& aValue ); template SIM_VALUE_FLOAT::SIM_VALUE_INST( const double& aValue ); template SIM_VALUE_COMPLEX::SIM_VALUE_INST( const std::complex& aValue ); template SIM_VALUE_STRING::SIM_VALUE_INST( const std::string& aValue ); template <> SIM_VALUE::TYPE SIM_VALUE_BOOL::GetType() const { return TYPE_BOOL; } template <> SIM_VALUE::TYPE SIM_VALUE_INT::GetType() const { return TYPE_INT; } template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT::GetType() const { return TYPE_FLOAT; } template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX::GetType() const { return TYPE_FLOAT; } template <> SIM_VALUE::TYPE SIM_VALUE_STRING::GetType() const { return TYPE_STRING; } // TODO /*template <> SIM_VALUE::TYPE SIM_VALUE_BOOL_VECTOR::GetType() const { return TYPE_BOOL; } template <> SIM_VALUE::TYPE SIM_VALUE_INT_VECTOR::GetType() const { return TYPE_INT; } template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT_VECTOR::GetType() const { return TYPE_FLOAT; } template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX_VECTOR::GetType() const { return TYPE_COMPLEX; }*/ template bool SIM_VALUE_INST::HasValue() const { return m_value.has_value(); } template <> bool SIM_VALUE_BOOL::FromString( const std::string& aString, NOTATION aNotation ) { SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString, aNotation ); m_value = std::nullopt; if( !parseResult.isOk ) return false; if( parseResult.isEmpty ) return true; if( !parseResult.intPart || ( *parseResult.intPart != 0 && *parseResult.intPart != 1 ) || parseResult.fracPart || parseResult.exponent || parseResult.metricSuffixExponent ) { return false; } m_value = *parseResult.intPart; return true; } template <> bool SIM_VALUE_INT::FromString( const std::string& aString, NOTATION aNotation ) { SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString, aNotation ); m_value = std::nullopt; if( !parseResult.isOk ) return false; if( parseResult.isEmpty ) return true; if( !parseResult.intPart || ( parseResult.fracPart && *parseResult.fracPart != 0 ) ) return false; int exponent = parseResult.exponent ? *parseResult.exponent : 0; exponent += parseResult.metricSuffixExponent ? *parseResult.metricSuffixExponent : 0; m_value = static_cast( *parseResult.intPart ) * std::pow( 10, exponent ); return true; } template <> bool SIM_VALUE_FLOAT::FromString( const std::string& aString, NOTATION aNotation ) { wxString buf( aString ); // Convert any entered decimal point separators to the one our PEGTL grammar expects buf.Replace( wxT( "," ), wxT( "." ) ); SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( buf.ToStdString(), aNotation ); m_value = std::nullopt; if( !parseResult.isOk ) return false; if( parseResult.isEmpty ) return true; // Single dot should be allowed in fields. // TODO: disallow single dot in models. if( parseResult.significand.empty() || parseResult.significand == "." ) return false; int exponent = parseResult.exponent ? *parseResult.exponent : 0; exponent += parseResult.metricSuffixExponent ? *parseResult.metricSuffixExponent : 0; try { m_value = std::stod( parseResult.significand ) * std::pow( 10, exponent ); } catch( const std::invalid_argument& ) { return false; } return true; } template <> bool SIM_VALUE_COMPLEX::FromString( const std::string& aString, NOTATION aNotation ) { // TODO /*LOCALE_IO toggle; double value = 0; if( !aString.ToDouble( &value ) ) throw KI_PARAM_ERROR( _( "Invalid complex sim value string" ) ); m_value = value;*/ return true; } template <> bool SIM_VALUE_STRING::FromString( const std::string& aString, NOTATION aNotation ) { m_value = aString; return true; } template std::string SIM_VALUE_INST::ToString( NOTATION aNotation ) const { static_assert( std::is_same>::value ); std::string string = ""; for( auto it = m_value.cbegin(); it != m_value.cend(); it++ ) { string += SIM_VALUE_INST( *it ).ToString(); string += ","; } return string; } template <> std::string SIM_VALUE_BOOL::ToString( NOTATION aNotation ) const { if( m_value ) return fmt::format( "{:d}", *m_value ); return ""; } template <> std::string SIM_VALUE_INT::ToString( NOTATION aNotation ) const { if( m_value ) { int value = std::abs( *m_value ); int exponent = 0; while( value != 0 && value % 1000 == 0 ) { exponent += 3; value /= 1000; } int dummy = 0; std::string metricSuffix = SIM_VALUE_PARSER::ExponentToMetricSuffix( static_cast( exponent ), dummy, aNotation ); return fmt::format( "{:d}{:s}", value, metricSuffix ); } return ""; } template <> std::string SIM_VALUE_FLOAT::ToString( NOTATION aNotation ) const { if( m_value ) { double exponent = std::log10( std::abs( *m_value ) ); int reductionExponent = 0; std::string metricSuffix = SIM_VALUE_PARSER::ExponentToMetricSuffix( exponent, reductionExponent, aNotation ); double reducedValue = *m_value / std::pow( 10, reductionExponent ); return fmt::format( "{:g}{}", reducedValue, metricSuffix ); } else return ""; } template <> std::string SIM_VALUE_COMPLEX::ToString( NOTATION aNotation ) const { if( m_value ) return fmt::format( "{:g}+{:g}i", m_value->real(), m_value->imag() ); return ""; } template <> std::string SIM_VALUE_STRING::ToString( NOTATION aNotation ) const { if( m_value ) return *m_value; return ""; // Empty string is completely equivalent to null string. } template std::string SIM_VALUE_INST::ToSimpleString() const { if( m_value ) return fmt::format( "{}", *m_value ); return ""; } template <> std::string SIM_VALUE_COMPLEX::ToSimpleString() const { // TODO /*std::string result = ""; result << *m_value; return result;*/ return ""; } template void SIM_VALUE_INST::operator=( const SIM_VALUE& aOther ) { auto other = dynamic_cast*>( &aOther ); m_value = other->m_value; } template bool SIM_VALUE_INST::operator==( const T& aOther ) const { return m_value == aOther; } template <> bool SIM_VALUE_BOOL::operator==( const bool& aOther ) const { // Note that we take nullopt as the same as false here. if( !m_value ) return false == aOther; return m_value == aOther; } template bool SIM_VALUE_INT::operator==( const int& aOther ) const; template bool SIM_VALUE_FLOAT::operator==( const double& aOther ) const; template bool SIM_VALUE_COMPLEX::operator==( const std::complex& aOther ) const; template bool SIM_VALUE_STRING::operator==( const std::string& aOther ) const; template bool SIM_VALUE_INST::operator==( const SIM_VALUE& aOther ) const { const SIM_VALUE_INST* otherValue = dynamic_cast*>( &aOther ); if( otherValue ) return m_value == otherValue->m_value; return false; } template SIM_VALUE_INST operator+( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& aRight ) { return SIM_VALUE_INST( aLeft.m_value.value() + aRight.m_value.value() ); } template SIM_VALUE_INT operator+( const SIM_VALUE_INT& aLeft, const SIM_VALUE_INT& aRight ); template SIM_VALUE_FLOAT operator+( const SIM_VALUE_FLOAT& aLeft, const SIM_VALUE_FLOAT& aRight ); template SIM_VALUE_INST operator-( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& aRight ) { return SIM_VALUE_INST( aLeft.m_value.value() - aRight.m_value.value() ); } template SIM_VALUE_INT operator-( const SIM_VALUE_INT& aLeft, const SIM_VALUE_INT& aRight ); template SIM_VALUE_FLOAT operator-( const SIM_VALUE_FLOAT& aLeft, const SIM_VALUE_FLOAT& aRight ); template SIM_VALUE_INST operator*( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& aRight ) { return SIM_VALUE_INST( aLeft.m_value.value() * aRight.m_value.value() ); } template SIM_VALUE_INT operator*( const SIM_VALUE_INT& aLeft, const SIM_VALUE_INT& aRight ); template SIM_VALUE_FLOAT operator*( const SIM_VALUE_FLOAT& aLeft, const SIM_VALUE_FLOAT& aRight ); template SIM_VALUE_INST operator/( const SIM_VALUE_INST& aLeft, const SIM_VALUE_INST& aRight ) { return SIM_VALUE_INST( aLeft.m_value.value() / aRight.m_value.value() ); } template SIM_VALUE_INT operator/( const SIM_VALUE_INT& aLeft, const SIM_VALUE_INT& aRight ); template SIM_VALUE_FLOAT operator/( const SIM_VALUE_FLOAT& aLeft, const SIM_VALUE_FLOAT& aRight );