Add preflighting for DRC rule function calls.

This commit is contained in:
Jeff Young 2020-07-22 14:08:57 +01:00
parent a61ea1fb0c
commit a6b6084a60
6 changed files with 136 additions and 111 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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()

View File

@ -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;

View File

@ -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;
}