Change in expression parser: nil is now propagated through expressions as 'x+nil'=x, 'nil+x'=nil. This is useful for evaluating device parameter expressions.

This commit is contained in:
Matthias Koefferlein 2026-06-13 17:33:25 +02:00
parent 36f147bcc1
commit 12071e7300
2 changed files with 70 additions and 12 deletions

View File

@ -1075,7 +1075,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1131,7 +1133,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1187,7 +1191,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil () || b->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1249,7 +1255,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil () || b->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1309,7 +1317,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil () || b->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1399,7 +1409,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil () || b->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1555,7 +1567,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil () || b->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1611,7 +1625,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil () || b->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1667,7 +1683,9 @@ public:
m_c[0]->execute (v);
m_c[1]->execute (b);
if (v->is_user ()) {
if (v->is_nil () || b->is_nil ()) {
// don't change
} else if (v->is_user ()) {
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
if (! c) {
@ -1802,7 +1820,9 @@ public:
{
m_c[0]->execute (v);
if (v->is_user ()) {
if (v->is_nil ()) {
// don't change
} else if (v->is_user ()) {
throw EvalError (tl::to_string (tr ("Unary minus not implemented for objects")), m_context);
/*
@ -1859,7 +1879,9 @@ public:
{
m_c[0]->execute (v);
if (v->is_user ()) {
if (v->is_nil ()) {
// don't change
} else if (v->is_user ()) {
throw EvalError (tl::to_string (tr ("Unary tilde not implemented for objects")), m_context);
/*

View File

@ -39,6 +39,14 @@ TEST(1)
EXPECT_EQ (v.to_string (), std::string ("1"));
v = e.parse ("1+2").execute ();
EXPECT_EQ (v.to_string (), std::string ("3"));
v = e.parse ("nil+2").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("2+nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("2"));
v = e.parse ("nil-2").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("2-nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("2"));
v = e.parse ("1.2e3").execute ();
EXPECT_EQ (v.to_string (), std::string ("1200"));
v = e.parse ("-0.25e-2").execute ();
@ -49,6 +57,14 @@ TEST(1)
EXPECT_EQ (v.to_string (), std::string ("4097"));
v = e.parse ("0x1").execute ();
EXPECT_EQ (v.to_string (), std::string ("1"));
v = e.parse ("nil*2").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("2*nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("2"));
v = e.parse ("nil/2").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("2/nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("2"));
v = e.parse ("1-2+3").execute ();
EXPECT_EQ (v.to_string (), std::string ("2"));
v = e.parse ("1-4*2+3").execute ();
@ -972,8 +988,16 @@ TEST(9)
v = e.parse ("1<<2+3").execute ();
EXPECT_EQ (v.to_string (), std::string ("32"));
v = e.parse ("nil<<2").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("1<<nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("1"));
v = e.parse ("8*8>>2+3").execute ();
EXPECT_EQ (v.to_string (), std::string ("2"));
v = e.parse ("nil>>2").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("1>>nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("1"));
}
// bitwise ops
@ -986,8 +1010,16 @@ TEST(10)
EXPECT_EQ (v.to_string (), std::string ("20"));
v = e.parse ("31&63").execute ();
EXPECT_EQ (v.to_string (), std::string ("31"));
v = e.parse ("nil&63").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("31&nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("31"));
v = e.parse ("31^63").execute ();
EXPECT_EQ (v.to_string (), std::string ("32"));
v = e.parse ("nil^63").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("31^nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("31"));
}
// unary ops
@ -1000,8 +1032,12 @@ TEST(11)
EXPECT_EQ (v.to_string (), std::string ("2"));
v = e.parse ("~1").execute ();
EXPECT_EQ (v.to_string (), std::string ("-2"));
v = e.parse ("~nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("-1").execute ();
EXPECT_EQ (v.to_string (), std::string ("-1"));
v = e.parse ("-nil").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
v = e.parse ("--1").execute ();
EXPECT_EQ (v.to_string (), std::string ("1"));
}
@ -1159,7 +1195,7 @@ TEST(16)
v = e.parse ("'abc' ~ '(*)a(*)'").execute ();
EXPECT_EQ (v.to_string (), std::string ("true"));
v = e.parse ("$1+'.'+$2+'.'+$3").execute ();
EXPECT_EQ (v.to_string (), std::string (".bc.nil"));
EXPECT_EQ (v.to_string (), std::string (".bc."));
v = e.parse ("'abc' ~ 'b*'").execute ();
EXPECT_EQ (v.to_string (), std::string ("false"));
v = e.parse ("'abc' !~ '*a*'").execute ();