You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

686 lines
21 KiB

10 months ago
10 months ago
10 months ago
10 months ago
2 years ago
10 months ago
2 years ago
8 months ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <cstdio>
  24. #include <memory>
  25. #include <mutex>
  26. #include <board.h>
  27. #include <footprint.h>
  28. #include <lset.h>
  29. #include <board_connected_item.h>
  30. #include <pcbexpr_evaluator.h>
  31. #include <drc/drc_engine.h>
  32. #include <component_classes/component_class.h>
  33. /* --------------------------------------------------------------------------------------------
  34. * Specialized Expression References
  35. */
  36. BOARD_ITEM* PCBEXPR_VAR_REF::GetObject( const LIBEVAL::CONTEXT* aCtx ) const
  37. {
  38. wxASSERT( dynamic_cast<const PCBEXPR_CONTEXT*>( aCtx ) );
  39. const PCBEXPR_CONTEXT* ctx = static_cast<const PCBEXPR_CONTEXT*>( aCtx );
  40. BOARD_ITEM* item = ctx->GetItem( m_itemIndex );
  41. return item;
  42. }
  43. class PCBEXPR_LAYER_VALUE : public LIBEVAL::VALUE
  44. {
  45. public:
  46. PCBEXPR_LAYER_VALUE( PCB_LAYER_ID aLayer ) :
  47. LIBEVAL::VALUE( LayerName( aLayer ) ),
  48. m_layer( aLayer )
  49. {};
  50. virtual bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
  51. {
  52. // For boards with user-defined layer names there will be 2 entries for each layer
  53. // in the ENUM_MAP: one for the canonical layer name and one for the user layer name.
  54. // We need to check against both.
  55. wxPGChoices& layerMap = ENUM_MAP<PCB_LAYER_ID>::Instance().Choices();
  56. const wxString& layerName = b->AsString();
  57. BOARD* board = static_cast<PCBEXPR_CONTEXT*>( aCtx )->GetBoard();
  58. {
  59. std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
  60. auto i = board->m_LayerExpressionCache.find( layerName );
  61. if( i != board->m_LayerExpressionCache.end() )
  62. return i->second.Contains( m_layer );
  63. }
  64. LSET mask;
  65. for( unsigned ii = 0; ii < layerMap.GetCount(); ++ii )
  66. {
  67. wxPGChoiceEntry& entry = layerMap[ii];
  68. if( entry.GetText().Matches( layerName ) )
  69. mask.set( ToLAYER_ID( entry.GetValue() ) );
  70. }
  71. {
  72. std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
  73. board->m_LayerExpressionCache[ layerName ] = mask;
  74. }
  75. return mask.Contains( m_layer );
  76. }
  77. protected:
  78. PCB_LAYER_ID m_layer;
  79. };
  80. class PCBEXPR_PINTYPE_VALUE : public LIBEVAL::VALUE
  81. {
  82. public:
  83. PCBEXPR_PINTYPE_VALUE( const wxString& aPinTypeName ) :
  84. LIBEVAL::VALUE( aPinTypeName )
  85. {};
  86. bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
  87. {
  88. const wxString& thisStr = AsString();
  89. const wxString& otherStr = b->AsString();
  90. // Case insensitive
  91. if( thisStr.IsSameAs( otherStr, false ) )
  92. return true;
  93. // Wildcards
  94. if( thisStr.Matches( otherStr ) )
  95. return true;
  96. // Handle cases where the netlist token is different from the EEschema token
  97. wxString altStr;
  98. if( thisStr == wxT( "tri_state" ) )
  99. altStr = wxT( "Tri-state" );
  100. else if( thisStr == wxT( "power_in" ) )
  101. altStr = wxT( "Power input" );
  102. else if( thisStr == wxT( "power_out" ) )
  103. altStr = wxT( "Power output" );
  104. else if( thisStr == wxT( "no_connect" ) )
  105. altStr = wxT( "Unconnected" );
  106. if( !altStr.IsEmpty() )
  107. {
  108. // Case insensitive
  109. if( altStr.IsSameAs( otherStr, false ) )
  110. return true;
  111. // Wildcards
  112. if( altStr.Matches( otherStr ) )
  113. return true;
  114. }
  115. return false;
  116. }
  117. };
  118. class PCBEXPR_NETCLASS_VALUE : public LIBEVAL::VALUE
  119. {
  120. public:
  121. PCBEXPR_NETCLASS_VALUE( BOARD_CONNECTED_ITEM* aItem ) :
  122. LIBEVAL::VALUE( wxEmptyString ),
  123. m_item( aItem )
  124. {};
  125. const wxString& AsString() const override
  126. {
  127. const_cast<PCBEXPR_NETCLASS_VALUE*>( this )->Set(
  128. m_item->GetEffectiveNetClass()->GetName() );
  129. return LIBEVAL::VALUE::AsString();
  130. }
  131. bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
  132. {
  133. if( const PCBEXPR_NETCLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_NETCLASS_VALUE*>( b ) )
  134. {
  135. return *( m_item->GetEffectiveNetClass() )
  136. == *( bValue->m_item->GetEffectiveNetClass() );
  137. }
  138. if( b->GetType() == LIBEVAL::VT_STRING )
  139. {
  140. if( m_item->GetEffectiveNetClass()->ContainsNetclassWithName( b->AsString() ) )
  141. return true;
  142. return m_item->GetEffectiveNetClass()->GetName() == b->AsString();
  143. }
  144. return LIBEVAL::VALUE::EqualTo( aCtx, b );
  145. }
  146. bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
  147. {
  148. if( const PCBEXPR_NETCLASS_VALUE* bValue = dynamic_cast<const PCBEXPR_NETCLASS_VALUE*>( b ) )
  149. {
  150. return *( m_item->GetEffectiveNetClass() )
  151. != *( bValue->m_item->GetEffectiveNetClass() );
  152. }
  153. if( b->GetType() == LIBEVAL::VT_STRING )
  154. {
  155. const bool isInConstituents =
  156. m_item->GetEffectiveNetClass()->ContainsNetclassWithName( b->AsString() );
  157. const bool isFullName = m_item->GetEffectiveNetClass()->GetName() == b->AsString();
  158. return !isInConstituents && !isFullName;
  159. }
  160. return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
  161. }
  162. protected:
  163. BOARD_CONNECTED_ITEM* m_item;
  164. };
  165. class PCBEXPR_COMPONENT_CLASS_VALUE : public LIBEVAL::VALUE
  166. {
  167. public:
  168. PCBEXPR_COMPONENT_CLASS_VALUE( BOARD_ITEM* aItem ) :
  169. LIBEVAL::VALUE( wxEmptyString ), m_item( dynamic_cast<FOOTPRINT*>( aItem ) )
  170. {};
  171. const wxString& AsString() const override
  172. {
  173. if( !m_item )
  174. return LIBEVAL::VALUE::AsString();
  175. if( const COMPONENT_CLASS* compClass = m_item->GetComponentClass() )
  176. const_cast<PCBEXPR_COMPONENT_CLASS_VALUE*>( this )->Set( compClass->GetName() );
  177. return LIBEVAL::VALUE::AsString();
  178. }
  179. bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
  180. {
  181. if( const PCBEXPR_COMPONENT_CLASS_VALUE* bValue =
  182. dynamic_cast<const PCBEXPR_COMPONENT_CLASS_VALUE*>( b ) )
  183. {
  184. if( !m_item || !bValue->m_item )
  185. return LIBEVAL::VALUE::EqualTo( aCtx, b );
  186. const COMPONENT_CLASS* aClass = m_item->GetComponentClass();
  187. const COMPONENT_CLASS* bClass = bValue->m_item->GetComponentClass();
  188. return *aClass == *bClass;
  189. }
  190. if( b->GetType() == LIBEVAL::VT_STRING )
  191. {
  192. if( m_item->GetComponentClass()->ContainsClassName( b->AsString() ) )
  193. return true;
  194. return m_item->GetComponentClass()->GetName() == b->AsString();
  195. }
  196. return LIBEVAL::VALUE::EqualTo( aCtx, b );
  197. }
  198. bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
  199. {
  200. if( const PCBEXPR_COMPONENT_CLASS_VALUE* bValue =
  201. dynamic_cast<const PCBEXPR_COMPONENT_CLASS_VALUE*>( b ) )
  202. {
  203. if( !m_item || !bValue->m_item )
  204. return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
  205. const COMPONENT_CLASS* aClass = m_item->GetComponentClass();
  206. const COMPONENT_CLASS* bClass = bValue->m_item->GetComponentClass();
  207. return *aClass != *bClass;
  208. }
  209. if( b->GetType() == LIBEVAL::VT_STRING )
  210. {
  211. const bool isInConstituents =
  212. m_item->GetComponentClass()->ContainsClassName( b->AsString() );
  213. const bool isFullName = m_item->GetComponentClass()->GetName() == b->AsString();
  214. return !isInConstituents && !isFullName;
  215. }
  216. return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
  217. }
  218. protected:
  219. FOOTPRINT* m_item;
  220. };
  221. class PCBEXPR_NET_VALUE : public LIBEVAL::VALUE
  222. {
  223. public:
  224. PCBEXPR_NET_VALUE( BOARD_CONNECTED_ITEM* aItem ) :
  225. LIBEVAL::VALUE( wxEmptyString ),
  226. m_item( aItem )
  227. {};
  228. const wxString& AsString() const override
  229. {
  230. const_cast<PCBEXPR_NET_VALUE*>( this )->Set( m_item->GetNetname() );
  231. return LIBEVAL::VALUE::AsString();
  232. }
  233. bool EqualTo( LIBEVAL::CONTEXT* aCtx, const VALUE* b ) const override
  234. {
  235. if( const PCBEXPR_NET_VALUE* bValue = dynamic_cast<const PCBEXPR_NET_VALUE*>( b ) )
  236. return m_item->GetNetCode() == bValue->m_item->GetNetCode();
  237. else
  238. return LIBEVAL::VALUE::EqualTo( aCtx, b );
  239. }
  240. bool NotEqualTo( LIBEVAL::CONTEXT* aCtx, const LIBEVAL::VALUE* b ) const override
  241. {
  242. if( const PCBEXPR_NET_VALUE* bValue = dynamic_cast<const PCBEXPR_NET_VALUE*>( b ) )
  243. return m_item->GetNetCode() != bValue->m_item->GetNetCode();
  244. else
  245. return LIBEVAL::VALUE::NotEqualTo( aCtx, b );
  246. }
  247. protected:
  248. BOARD_CONNECTED_ITEM* m_item;
  249. };
  250. LIBEVAL::VALUE* PCBEXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
  251. {
  252. PCBEXPR_CONTEXT* context = static_cast<PCBEXPR_CONTEXT*>( aCtx );
  253. if( m_type == LIBEVAL::VT_NULL )
  254. return LIBEVAL::VALUE::MakeNullValue();
  255. if( m_itemIndex == 2 )
  256. return new PCBEXPR_LAYER_VALUE( context->GetLayer() );
  257. BOARD_ITEM* item = GetObject( aCtx );
  258. if( !item )
  259. return new LIBEVAL::VALUE();
  260. auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
  261. if( it == m_matchingTypes.end() )
  262. {
  263. // Don't force user to type "A.Type == 'via' && A.Via_Type == 'buried'" when the
  264. // simpler "A.Via_Type == 'buried'" is perfectly clear. Instead, return an undefined
  265. // value when the property doesn't appear on a particular object.
  266. return new LIBEVAL::VALUE();
  267. }
  268. else
  269. {
  270. if( m_type == LIBEVAL::VT_NUMERIC )
  271. {
  272. if( m_isOptional )
  273. {
  274. auto val = item->Get<std::optional<int>>( it->second );
  275. if( val.has_value() )
  276. return new LIBEVAL::VALUE( static_cast<double>( val.value() ) );
  277. return LIBEVAL::VALUE::MakeNullValue();
  278. }
  279. return new LIBEVAL::VALUE( static_cast<double>( item->Get<int>( it->second ) ) );
  280. }
  281. else if( m_type == LIBEVAL::VT_NUMERIC_DOUBLE )
  282. {
  283. if( m_isOptional )
  284. {
  285. auto val = item->Get<std::optional<double>>( it->second );
  286. if( val.has_value() )
  287. return new LIBEVAL::VALUE( val.value() );
  288. return LIBEVAL::VALUE::MakeNullValue();
  289. }
  290. return new LIBEVAL::VALUE( item->Get<double>( it->second ) );
  291. }
  292. else
  293. {
  294. wxString str;
  295. if( !m_isEnum )
  296. {
  297. str = item->Get<wxString>( it->second );
  298. if( it->second->Name() == wxT( "Pin Type" ) )
  299. return new PCBEXPR_PINTYPE_VALUE( str );
  300. else
  301. return new LIBEVAL::VALUE( str );
  302. }
  303. else
  304. {
  305. const wxAny& any = item->Get( it->second );
  306. PCB_LAYER_ID layer;
  307. if( it->second->Name() == wxT( "Layer" )
  308. || it->second->Name() == wxT( "Layer Top" )
  309. || it->second->Name() == wxT( "Layer Bottom" ) )
  310. {
  311. if( any.GetAs<PCB_LAYER_ID>( &layer ) )
  312. return new PCBEXPR_LAYER_VALUE( layer );
  313. else if( any.GetAs<wxString>( &str ) )
  314. return new PCBEXPR_LAYER_VALUE( context->GetBoard()->GetLayerID( str ) );
  315. }
  316. else
  317. {
  318. if( any.GetAs<wxString>( &str ) )
  319. return new LIBEVAL::VALUE( str );
  320. }
  321. }
  322. return new LIBEVAL::VALUE();
  323. }
  324. }
  325. }
  326. LIBEVAL::VALUE* PCBEXPR_NETCLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
  327. {
  328. BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
  329. if( !item )
  330. return new LIBEVAL::VALUE();
  331. return new PCBEXPR_NETCLASS_VALUE( item );
  332. }
  333. LIBEVAL::VALUE* PCBEXPR_COMPONENT_CLASS_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
  334. {
  335. BOARD_ITEM* item = dynamic_cast<BOARD_ITEM*>( GetObject( aCtx ) );
  336. if( !item || item->Type() != PCB_FOOTPRINT_T )
  337. return new LIBEVAL::VALUE();
  338. return new PCBEXPR_COMPONENT_CLASS_VALUE( item );
  339. }
  340. LIBEVAL::VALUE* PCBEXPR_NETNAME_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
  341. {
  342. BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( GetObject( aCtx ) );
  343. if( !item )
  344. return new LIBEVAL::VALUE();
  345. return new PCBEXPR_NET_VALUE( item );
  346. }
  347. LIBEVAL::VALUE* PCBEXPR_TYPE_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
  348. {
  349. BOARD_ITEM* item = GetObject( aCtx );
  350. if( !item )
  351. return new LIBEVAL::VALUE();
  352. return new LIBEVAL::VALUE( ENUM_MAP<KICAD_T>::Instance().ToString( item->Type() ) );
  353. }
  354. LIBEVAL::FUNC_CALL_REF PCBEXPR_UCODE::CreateFuncCall( const wxString& aName )
  355. {
  356. PCBEXPR_BUILTIN_FUNCTIONS& registry = PCBEXPR_BUILTIN_FUNCTIONS::Instance();
  357. return registry.Get( aName.Lower() );
  358. }
  359. std::unique_ptr<LIBEVAL::VAR_REF> PCBEXPR_UCODE::CreateVarRef( const wxString& aVar,
  360. const wxString& aField )
  361. {
  362. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  363. std::unique_ptr<PCBEXPR_VAR_REF> vref;
  364. if( aVar.IsSameAs( wxT( "null" ), false ) )
  365. {
  366. vref = std::make_unique<PCBEXPR_VAR_REF>( 0 );
  367. vref->SetType( LIBEVAL::VT_NULL );
  368. return vref;
  369. }
  370. // Check for a couple of very common cases and compile them straight to "object code".
  371. if( aField.CmpNoCase( wxT( "NetClass" ) ) == 0 )
  372. {
  373. if( aVar == wxT( "A" ) )
  374. return std::make_unique<PCBEXPR_NETCLASS_REF>( 0 );
  375. else if( aVar == wxT( "B" ) )
  376. return std::make_unique<PCBEXPR_NETCLASS_REF>( 1 );
  377. else
  378. return nullptr;
  379. }
  380. else if( aField.CmpNoCase( wxT( "ComponentClass" ) ) == 0 )
  381. {
  382. if( aVar == wxT( "A" ) )
  383. return std::make_unique<PCBEXPR_COMPONENT_CLASS_REF>( 0 );
  384. else if( aVar == wxT( "B" ) )
  385. return std::make_unique<PCBEXPR_COMPONENT_CLASS_REF>( 1 );
  386. else
  387. return nullptr;
  388. }
  389. else if( aField.CmpNoCase( wxT( "NetName" ) ) == 0 )
  390. {
  391. if( aVar == wxT( "A" ) )
  392. return std::make_unique<PCBEXPR_NETNAME_REF>( 0 );
  393. else if( aVar == wxT( "B" ) )
  394. return std::make_unique<PCBEXPR_NETNAME_REF>( 1 );
  395. else
  396. return nullptr;
  397. }
  398. else if( aField.CmpNoCase( wxT( "Type" ) ) == 0 )
  399. {
  400. if( aVar == wxT( "A" ) )
  401. return std::make_unique<PCBEXPR_TYPE_REF>( 0 );
  402. else if( aVar == wxT( "B" ) )
  403. return std::make_unique<PCBEXPR_TYPE_REF>( 1 );
  404. else
  405. return nullptr;
  406. }
  407. if( aVar == wxT( "A" ) || aVar == wxT( "AB" ) )
  408. vref = std::make_unique<PCBEXPR_VAR_REF>( 0 );
  409. else if( aVar == wxT( "B" ) )
  410. vref = std::make_unique<PCBEXPR_VAR_REF>( 1 );
  411. else if( aVar == wxT( "L" ) )
  412. vref = std::make_unique<PCBEXPR_VAR_REF>( 2 );
  413. else
  414. return nullptr;
  415. if( aField.length() == 0 ) // return reference to base object
  416. return vref;
  417. wxString field( aField );
  418. field.Replace( wxT( "_" ), wxT( " " ) );
  419. for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() )
  420. {
  421. if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) )
  422. {
  423. PROPERTY_BASE* prop = propMgr.GetProperty( cls.type, field );
  424. if( prop )
  425. {
  426. vref->AddAllowedClass( cls.type, prop );
  427. if( prop->TypeHash() == TYPE_HASH( int ) )
  428. {
  429. vref->SetType( LIBEVAL::VT_NUMERIC );
  430. }
  431. else if( prop->TypeHash() == TYPE_HASH( std::optional<int> ) )
  432. {
  433. vref->SetType( LIBEVAL::VT_NUMERIC );
  434. vref->SetIsOptional();
  435. }
  436. else if( prop->TypeHash() == TYPE_HASH( double ) )
  437. {
  438. vref->SetType( LIBEVAL::VT_NUMERIC_DOUBLE );
  439. }
  440. else if( prop->TypeHash() == TYPE_HASH( std::optional<double> ) )
  441. {
  442. vref->SetType( LIBEVAL::VT_NUMERIC_DOUBLE );
  443. vref->SetIsOptional();
  444. }
  445. else if( prop->TypeHash() == TYPE_HASH( bool ) )
  446. {
  447. vref->SetType( LIBEVAL::VT_NUMERIC );
  448. }
  449. else if( prop->TypeHash() == TYPE_HASH( wxString ) )
  450. {
  451. vref->SetType( LIBEVAL::VT_STRING );
  452. }
  453. else if ( prop->HasChoices() )
  454. { // it's an enum, we treat it as string
  455. vref->SetType( LIBEVAL::VT_STRING );
  456. vref->SetIsEnum( true );
  457. }
  458. else
  459. {
  460. wxString msg = wxString::Format( wxT( "PCBEXPR_UCODE::createVarRef: Unknown "
  461. "property type %s from %s." ),
  462. cls.name,
  463. field );
  464. wxFAIL_MSG( msg );
  465. }
  466. }
  467. }
  468. }
  469. if( vref->GetType() == LIBEVAL::VT_UNDEFINED )
  470. vref->SetType( LIBEVAL::VT_PARSE_ERROR );
  471. return vref;
  472. }
  473. BOARD* PCBEXPR_CONTEXT::GetBoard() const
  474. {
  475. if( m_items[0] )
  476. return m_items[0]->GetBoard();
  477. return nullptr;
  478. }
  479. /* --------------------------------------------------------------------------------------------
  480. * Unit Resolvers
  481. */
  482. const std::vector<wxString>& PCBEXPR_UNIT_RESOLVER::GetSupportedUnits() const
  483. {
  484. static const std::vector<wxString> pcbUnits = { wxT( "mil" ), wxT( "mm" ), wxT( "in" ),
  485. wxT( "deg" ) };
  486. return pcbUnits;
  487. }
  488. wxString PCBEXPR_UNIT_RESOLVER::GetSupportedUnitsMessage() const
  489. {
  490. return _( "must be mm, in, mil, or deg" );
  491. }
  492. double PCBEXPR_UNIT_RESOLVER::Convert( const wxString& aString, int unitId ) const
  493. {
  494. double v = wxAtof( aString );
  495. switch( unitId )
  496. {
  497. case 0: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::MILS, aString );
  498. case 1: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::MM, aString );
  499. case 2: return EDA_UNIT_UTILS::UI::DoubleValueFromString( pcbIUScale, EDA_UNITS::INCH, aString );
  500. default: return v;
  501. }
  502. };
  503. const std::vector<wxString>& PCBEXPR_UNITLESS_RESOLVER::GetSupportedUnits() const
  504. {
  505. static const std::vector<wxString> emptyUnits;
  506. return emptyUnits;
  507. }
  508. double PCBEXPR_UNITLESS_RESOLVER::Convert( const wxString& aString, int unitId ) const
  509. {
  510. return wxAtof( aString );
  511. };
  512. PCBEXPR_COMPILER::PCBEXPR_COMPILER( LIBEVAL::UNIT_RESOLVER* aUnitResolver )
  513. {
  514. m_unitResolver.reset( aUnitResolver );
  515. }
  516. /* --------------------------------------------------------------------------------------------
  517. * PCB Expression Evaluator
  518. */
  519. PCBEXPR_EVALUATOR::PCBEXPR_EVALUATOR( LIBEVAL::UNIT_RESOLVER* aUnitResolver ) :
  520. m_result( 0 ),
  521. m_compiler( aUnitResolver ),
  522. m_ucode(),
  523. m_errorStatus()
  524. {
  525. }
  526. PCBEXPR_EVALUATOR::~PCBEXPR_EVALUATOR()
  527. {
  528. }
  529. bool PCBEXPR_EVALUATOR::Evaluate( const wxString& aExpr )
  530. {
  531. PCBEXPR_UCODE ucode;
  532. PCBEXPR_CONTEXT preflightContext( NULL_CONSTRAINT, F_Cu );
  533. if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) )
  534. return false;
  535. PCBEXPR_CONTEXT evaluationContext( NULL_CONSTRAINT, F_Cu );
  536. LIBEVAL::VALUE* result = ucode.Run( &evaluationContext );
  537. if( result->GetType() == LIBEVAL::VT_NUMERIC )
  538. m_result = KiROUND( result->AsDouble() );
  539. return true;
  540. }