Add preflighting for DRC rule function calls.
This commit is contained in:
parent
a61ea1fb0c
commit
a6b6084a60
|
@ -138,6 +138,14 @@ std::string UCODE::Dump() const
|
|||
return rv;
|
||||
};
|
||||
|
||||
|
||||
void CONTEXT::ReportError( const wxString& aErrorMsg )
|
||||
{
|
||||
m_errorStatus.pendingError = true;
|
||||
m_errorStatus.message = aErrorMsg;
|
||||
}
|
||||
|
||||
|
||||
std::string TOKENIZER::GetChars( std::function<bool( int )> cond ) const
|
||||
{
|
||||
std::string rv;
|
||||
|
@ -167,7 +175,6 @@ bool TOKENIZER::MatchAhead( const std::string& match, std::function<bool( int )>
|
|||
|
||||
COMPILER::COMPILER()
|
||||
{
|
||||
m_errorStatus.pendingError = false;
|
||||
m_localeDecimalSeparator = '.';
|
||||
m_sourcePos = 0;
|
||||
m_parseFinished = false;
|
||||
|
@ -578,12 +585,7 @@ void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 )
|
|||
}
|
||||
}
|
||||
|
||||
ERROR_STATUS COMPILER::GetErrorStatus()
|
||||
{
|
||||
return m_errorStatus;
|
||||
}
|
||||
|
||||
void COMPILER::ReportError( const std::string& aErrorMsg )
|
||||
void COMPILER::ReportError( const wxString& aErrorMsg )
|
||||
{
|
||||
m_errorStatus.pendingError = true;
|
||||
m_errorStatus.message = aErrorMsg;
|
||||
|
@ -694,6 +696,28 @@ bool COMPILER::generateUCode( UCODE* aCode )
|
|||
return false;
|
||||
}
|
||||
|
||||
// Preflight the function call
|
||||
CONTEXT ctx;
|
||||
VALUE* param = ctx.AllocValue();
|
||||
param->Set( node->value.str );
|
||||
ctx.Push( param );
|
||||
|
||||
try
|
||||
{
|
||||
func( aCode, &ctx, vref );
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
}
|
||||
|
||||
if( ctx.GetErrorStatus().pendingError )
|
||||
{
|
||||
m_errorStatus = ctx.GetErrorStatus();
|
||||
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
|
||||
m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
visitedNodes.insert( node->leaf[0] );
|
||||
visitedNodes.insert( node->leaf[1]->leaf[0] );
|
||||
|
||||
|
@ -764,7 +788,7 @@ bool COMPILER::generateUCode( UCODE* aCode )
|
|||
}
|
||||
|
||||
|
||||
void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
|
||||
void UOP::Exec( CONTEXT* ctx, UCODE* ucode )
|
||||
{
|
||||
|
||||
switch( m_op )
|
||||
|
@ -772,7 +796,7 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
|
|||
case TR_UOP_PUSH_VAR:
|
||||
{
|
||||
auto value = ctx->AllocValue();
|
||||
value->Set( reinterpret_cast<VAR_REF*>( m_arg )->GetValue( ucode ) );
|
||||
value->Set( reinterpret_cast<VAR_REF*>( m_arg )->GetValue( ctx, ucode ) );
|
||||
ctx->Push( value );
|
||||
}
|
||||
break;
|
||||
|
@ -869,9 +893,4 @@ VALUE* UCODE::Run()
|
|||
}
|
||||
|
||||
|
||||
void UCODE::RuntimeError( const std::string& aErrorMsg )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace LIBEVAL
|
||||
|
|
|
@ -57,7 +57,7 @@ class COMPILER;
|
|||
|
||||
struct ERROR_STATUS
|
||||
{
|
||||
bool pendingError;
|
||||
bool pendingError = false;
|
||||
|
||||
enum STAGE
|
||||
{
|
||||
|
@ -242,63 +242,69 @@ private:
|
|||
|
||||
|
||||
class UCODE;
|
||||
class CONTEXT;
|
||||
|
||||
|
||||
class VAR_REF
|
||||
{
|
||||
public:
|
||||
virtual VAR_TYPE_T GetType() = 0;
|
||||
virtual VALUE GetValue( UCODE* aUcode ) = 0;
|
||||
virtual VALUE GetValue( CONTEXT* aCtx, UCODE* aUcode ) = 0;
|
||||
};
|
||||
|
||||
|
||||
class CONTEXT
|
||||
{
|
||||
public:
|
||||
const int c_memSize = 128;
|
||||
|
||||
CONTEXT()
|
||||
{
|
||||
m_sp = 0;
|
||||
|
||||
for( int i = 0; i < c_memSize; i++ )
|
||||
m_heap.emplace_back( VALUE() );
|
||||
}
|
||||
|
||||
VALUE* AllocValue()
|
||||
{
|
||||
assert( m_memPos < c_memSize );
|
||||
auto rv = &m_heap[ m_memPos++ ];
|
||||
return rv;
|
||||
}
|
||||
|
||||
void Push( VALUE* v )
|
||||
{
|
||||
m_stack[m_sp++] = v;
|
||||
}
|
||||
|
||||
VALUE* Pop()
|
||||
{
|
||||
m_sp--;
|
||||
return m_stack[m_sp];
|
||||
}
|
||||
|
||||
int SP() const
|
||||
{
|
||||
return m_sp;
|
||||
}
|
||||
|
||||
ERROR_STATUS GetErrorStatus() const { return m_errorStatus; }
|
||||
void ReportError( const wxString& aErrorMsg );
|
||||
|
||||
private:
|
||||
std::vector<VALUE> m_heap;
|
||||
VALUE* m_stack[128];
|
||||
int m_sp = 0;
|
||||
int m_memPos = 0;
|
||||
ERROR_STATUS m_errorStatus;
|
||||
};
|
||||
|
||||
|
||||
class UCODE
|
||||
{
|
||||
public:
|
||||
|
||||
class CONTEXT
|
||||
{
|
||||
public:
|
||||
const int c_memSize = 128;
|
||||
|
||||
CONTEXT()
|
||||
{
|
||||
m_sp = 0;
|
||||
|
||||
for( int i = 0; i < c_memSize; i++ )
|
||||
m_memory.push_back( VALUE() );
|
||||
}
|
||||
|
||||
VALUE* AllocValue()
|
||||
{
|
||||
assert( m_memPos < c_memSize );
|
||||
auto rv = &m_memory[ m_memPos++ ];
|
||||
return rv;
|
||||
}
|
||||
|
||||
void Push( VALUE* v )
|
||||
{
|
||||
m_stack[m_sp++] = v;
|
||||
}
|
||||
|
||||
VALUE* Pop()
|
||||
{
|
||||
m_sp--;
|
||||
return m_stack[m_sp];
|
||||
}
|
||||
|
||||
int SP() const
|
||||
{
|
||||
return m_sp;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<VALUE> m_memory;
|
||||
VALUE* m_stack[128];
|
||||
int m_sp = 0;
|
||||
int m_memPos = 0;
|
||||
};
|
||||
|
||||
typedef std::function<void(UCODE*, CONTEXT*, void*)> FUNC_PTR;
|
||||
typedef std::function<void( UCODE*, CONTEXT*, void* )> FUNC_PTR;
|
||||
|
||||
void AddOp( UOP* uop )
|
||||
{
|
||||
|
@ -307,9 +313,9 @@ public:
|
|||
|
||||
VALUE* Run();
|
||||
std::string Dump() const;
|
||||
void RuntimeError( const std::string& aErrorMsg );
|
||||
|
||||
virtual VAR_REF* createVarRef( COMPILER* aCompiler, const std::string& var, const std::string& field )
|
||||
virtual VAR_REF* createVarRef( COMPILER* aCompiler, const std::string& var,
|
||||
const std::string& field )
|
||||
{
|
||||
return nullptr;
|
||||
};
|
||||
|
@ -338,7 +344,7 @@ public:
|
|||
m_func( std::move( func ) )
|
||||
{};
|
||||
|
||||
void Exec( UCODE::CONTEXT* ctx, UCODE *ucode );
|
||||
void Exec( CONTEXT* ctx, UCODE *ucode );
|
||||
|
||||
std::string Format() const;
|
||||
|
||||
|
@ -423,8 +429,8 @@ public:
|
|||
void setRoot( LIBEVAL::TREE_NODE root );
|
||||
|
||||
bool Compile( const std::string& aString, UCODE* aCode );
|
||||
void ReportError( const std::string& aErrorMsg );
|
||||
ERROR_STATUS GetErrorStatus();
|
||||
void ReportError( const wxString& aErrorMsg );
|
||||
ERROR_STATUS GetErrorStatus() const { return m_errorStatus; }
|
||||
|
||||
protected:
|
||||
enum LEXER_STATE
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include <fctsys.h>
|
||||
#include <drc/drc_rule.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <class_board.h>
|
||||
#include <class_board_item.h>
|
||||
#include <pcb_expr_evaluator.h>
|
||||
|
@ -75,16 +74,6 @@
|
|||
* (rule "disallowMicrovias" (disallow micro_via))
|
||||
*
|
||||
*
|
||||
testEvalExpr( "A.type == \"Pad\" && B.type == \"Pad\" && (A.onLayer(\"F.Cu\"))",VAL(0.0), false, &trackA, &trackB );
|
||||
return 0;
|
||||
testEvalExpr( "A.Width > B.Width", VAL(0.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Width + B.Width", VAL(Mils2iu(10) + Mils2iu(20)), false, &trackA, &trackB );
|
||||
|
||||
testEvalExpr( "A.Netclass", VAL( (const char*) trackA.GetNetClassName().c_str() ), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.Netclass == \"HV\") && (B.netclass == \"otherClass\") && (B.netclass != \"F.Cu\")", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Netclass + 1.0", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.type == \"Track\" && B.type == \"Track\" && A.layer == \"F.Cu\"", VAL(0.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.type == \"Track\") && (B.type == \"Track\") && (A.layer == \"F.Cu\")", VAL(0.0), false, &trackA, &trackB );
|
||||
*/
|
||||
|
||||
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint )
|
||||
|
@ -126,7 +115,6 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM
|
|||
|
||||
m_ucode->SetItems( a, b );
|
||||
|
||||
// fixme: handle error conditions
|
||||
return m_ucode->Run()->AsDouble() != 0.0;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,33 +62,49 @@ public:
|
|||
private:
|
||||
std::map<std::string, FPTR> m_funcs;
|
||||
|
||||
static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self )
|
||||
static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::CONTEXT* aCtx, void *self )
|
||||
{
|
||||
LIBEVAL::VALUE* arg = aCtx->Pop();
|
||||
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
PCB_LAYER_ID layer = ENUM_MAP<PCB_LAYER_ID>::Instance().ToEnum( arg->AsString() );
|
||||
BOARD_ITEM* item = vref->GetObject( aUcode );
|
||||
LIBEVAL::VALUE* rv = aCtx->AllocValue();
|
||||
LIBEVAL::VALUE* arg = aCtx->Pop();
|
||||
LIBEVAL::VALUE* result = aCtx->AllocValue();
|
||||
|
||||
rv->Set( item->IsOnLayer( layer ) ? 1.0 : 0.0 );
|
||||
aCtx->Push( rv );
|
||||
}
|
||||
result->Set( 0.0 );
|
||||
aCtx->Push( result );
|
||||
|
||||
static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self )
|
||||
{
|
||||
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
BOARD_ITEM* item = vref->GetObject( aUcode );
|
||||
bool result = false;
|
||||
|
||||
if( item->Type() == PCB_PAD_T )
|
||||
if( !arg )
|
||||
{
|
||||
D_PAD* pad = static_cast<D_PAD*>( item );
|
||||
result = pad->GetAttribute() == PAD_ATTRIB_STANDARD;
|
||||
aCtx->ReportError( _( "Missing argument to 'onLayer()'" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
LIBEVAL::VALUE* rv = aCtx->AllocValue();
|
||||
rv->Set( result ? 1.0 : 0.0 );
|
||||
aCtx->Push( rv );
|
||||
wxString layerName = arg->AsString();
|
||||
PCB_LAYER_ID layer = ENUM_MAP<PCB_LAYER_ID>::Instance().ToEnum( layerName );
|
||||
|
||||
if( layer == UNDEFINED_LAYER )
|
||||
{
|
||||
aCtx->ReportError( wxString::Format( _( "Unrecognized layer '%s' " ), layerName ) );
|
||||
return;
|
||||
}
|
||||
|
||||
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
BOARD_ITEM* item = vref ? vref->GetObject( aUcode ) : nullptr;
|
||||
|
||||
if( item && item->IsOnLayer( layer ) )
|
||||
result->Set( 1.0 );
|
||||
}
|
||||
|
||||
static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::CONTEXT* aCtx, void *self )
|
||||
{
|
||||
LIBEVAL::VALUE* result = aCtx->AllocValue();
|
||||
|
||||
result->Set( 0.0 );
|
||||
aCtx->Push( result );
|
||||
|
||||
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
BOARD_ITEM* item = vref ? vref->GetObject( aUcode ) : nullptr;
|
||||
D_PAD* pad = dynamic_cast<D_PAD*>( item );
|
||||
|
||||
if( pad && pad->GetAttribute() == PAD_ATTRIB_STANDARD )
|
||||
result->Set( 1.0 );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -108,7 +124,7 @@ BOARD_ITEM* PCB_EXPR_VAR_REF::GetObject( LIBEVAL::UCODE* aUcode ) const
|
|||
}
|
||||
|
||||
|
||||
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode )
|
||||
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCODE* aUcode )
|
||||
{
|
||||
BOARD_ITEM* item = const_cast<BOARD_ITEM*>( GetObject( aUcode ) );
|
||||
auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
|
||||
|
@ -117,7 +133,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode )
|
|||
{
|
||||
wxString msg;
|
||||
msg.Printf("property not found for item of type: 0x%x!\n", TYPE_HASH( *item ) );
|
||||
aUcode->RuntimeError( (const char *) msg.c_str() );
|
||||
aCtx->ReportError( (const char *) msg.c_str() );
|
||||
return LIBEVAL::VALUE( 0.0 );
|
||||
}
|
||||
else
|
||||
|
@ -261,7 +277,6 @@ PCB_EXPR_COMPILER::PCB_EXPR_COMPILER()
|
|||
PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR()
|
||||
{
|
||||
m_result = 0;
|
||||
m_errorStatus.pendingError = false;
|
||||
}
|
||||
|
||||
PCB_EXPR_EVALUATOR::~PCB_EXPR_EVALUATOR()
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
return m_type;
|
||||
}
|
||||
|
||||
virtual LIBEVAL::VALUE GetValue( LIBEVAL::UCODE* aUcode ) override;
|
||||
virtual LIBEVAL::VALUE GetValue( LIBEVAL::CONTEXT* aCtx, LIBEVAL::UCODE* aUcode ) override;
|
||||
|
||||
|
||||
BOARD_ITEM* GetObject( LIBEVAL::UCODE* aUcode ) const;
|
||||
|
|
|
@ -23,12 +23,9 @@
|
|||
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <board_design_settings.h>
|
||||
#include <drc_proto/drc_rule.h>
|
||||
#include <class_board.h>
|
||||
#include <class_board_item.h>
|
||||
|
||||
|
||||
#include <drc_proto/drc_rule.h>
|
||||
#include <pcb_expr_evaluator.h>
|
||||
|
||||
|
||||
|
@ -56,9 +53,11 @@ test::DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
|
|||
|
||||
bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB )
|
||||
{
|
||||
m_ucode->SetItems( const_cast<BOARD_ITEM*>( aItemA ), const_cast<BOARD_ITEM*>( aItemB ) );
|
||||
BOARD_ITEM* a = const_cast<BOARD_ITEM*>( aItemA );
|
||||
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance();
|
||||
|
||||
m_ucode->SetItems( a, b );
|
||||
|
||||
// fixme: handle error conditions
|
||||
return m_ucode->Run()->AsDouble() != 0.0;
|
||||
}
|
||||
|
||||
|
@ -77,8 +76,6 @@ bool test::DRC_RULE_CONDITION::Compile()
|
|||
|
||||
m_compileError = compiler.GetErrorStatus();
|
||||
|
||||
printf( "Fail: %s", m_compileError.Format().c_str() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue