diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc index 17f6c5c52..cad1fdee1 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc @@ -1928,9 +1928,9 @@ TEST(205_extended_props) TempPropertiesRepository temp_pr; db::SaveLayoutOptions options; - EXPECT_EQ (options.get_option_by_name ("extended_features").to_bool (), true); - options.set_option_by_name ("extended_features", false); - EXPECT_EQ (options.get_option_by_name ("extended_features").to_bool (), false); + EXPECT_EQ (options.get_option_by_name ("gds2_extended_features").to_bool (), true); + options.set_option_by_name ("gds2_extended_features", false); + EXPECT_EQ (options.get_option_by_name ("gds2_extended_features").to_bool (), false); db::PropertiesSet ps1; ps1.insert (tl::Variant ("prop_name"), db::DBox (0, 0, 1.5, 2.5)); diff --git a/src/tl/tl/tlExpression.cc b/src/tl/tl/tlExpression.cc index a888c5bbf..8a9b997ee 100644 --- a/src/tl/tl/tlExpression.cc +++ b/src/tl/tl/tlExpression.cc @@ -3722,12 +3722,96 @@ get_variable_name (tl::Extractor &ex, std::string &name) } } +bool +Eval::read_number (ExpressionParserContext &ex, tl::Variant &t) +{ + ExpressionParserContext exl = ex, exd = ex, ex1 = ex; + + long long l = 0; + double d = 0.0; + bool is_long = exl.try_read (l); + bool is_double = exd.try_read (d); + + if (! is_long && ! is_double) { + + return false; + + } else if ((is_long && ! is_double) || (is_long && is_double && exl.get () >= exd.get ())) { + + ex = exl; + + if (l <= (long long) std::numeric_limits::max () && l >= (long long) std::numeric_limits::min ()) { + t = tl::Variant (long (l)); + } else { + t = tl::Variant (l); + } + + } else { + + ex = exd; + t = tl::Variant (d); + + } + + double f = 0.0; + double dbu = ctx_handler () ? ctx_handler ()->dbu () : 1.0; + + if (ex.test ("um2") || ex.test("micron2") || ex.test ("mic2")) { + f = 1.0 / (dbu * dbu); + } else if (ex.test ("nm2")) { + f = 1e-6 / (dbu * dbu); + } else if (ex.test ("mm2")) { + f = 1e6 / (dbu * dbu); + } else if (ex.test ("m2")) { + f = 1e12 / (dbu * dbu); + } else if (ex.test ("bs")) { + f = 0.005 / dbu; + } else if (ex.test ("nm")) { + f = 1e-3 / dbu; + } else if (ex.test ("um") || ex.test("micron") || ex.test ("mic")) { + f = 1.0 / dbu; + } else if (ex.test ("mm")) { + f = 1e3 / dbu; + } else if (ex.test ("m")) { + f = 1e6 / dbu; + } + + // DBU conversion + if (f != 0.0) { + + if (! ctx_handler ()) { + + if (m_sloppy) { + t = tl::Variant (); + } else { + throw EvalError (tl::to_string (tr ("Length or area value with unit requires a layout context")), ex1); + } + + } else { + + if (m_sloppy) { + t = tl::Variant (t.to_double () * f); + } else { + double gg = t.to_double (); + double g = floor (0.5 + t.to_double ()); + if (fabs (g) < 1e12 && fabs (g - gg) > 1e-3) { + throw EvalError (tl::to_string (tr ("Value is not a multiple of the database unit")), ex1); + } + } + + } + + } + + return true; +} + void Eval::eval_atomic (ExpressionParserContext &ex, std::unique_ptr &n, int am) { - double g = 0.0; int match_group = 0; std::string t; + tl::Variant g; ExpressionParserContext ex1 = ex; if (ex.test ("(")) { @@ -3881,97 +3965,9 @@ Eval::eval_atomic (ExpressionParserContext &ex, std::unique_ptr n.reset (new ConstantExpressionNode (ex1, tl::Variant (x))); - } else if (ex.try_read (g)) { + } else if (read_number (ex, g)) { - bool dbu_units = false; - - if (ex.test ("um2") || ex.test("micron2") || ex.test ("mic2")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1.0 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ()); - } - } else if (ex.test ("nm2")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1e-6 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ()); - } - } else if (ex.test ("mm2")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1e6 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ()); - } - } else if (ex.test ("m2")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1e12 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ()); - } - } else if (ex.test ("bs")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 0.005 / ctx_handler ()->dbu (); - } - } else if (ex.test ("nm")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1e-3 / ctx_handler ()->dbu (); - } - } else if (ex.test ("um") || ex.test("micron") || ex.test ("mic")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1.0 / ctx_handler ()->dbu (); - } - } else if (ex.test ("mm")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1e3 / ctx_handler ()->dbu (); - } - } else if (ex.test ("m")) { - dbu_units = true; - if (ctx_handler ()) { - g *= 1e6 / ctx_handler ()->dbu (); - } - } - - if (m_sloppy) { - - if (dbu_units && ! ctx_handler ()) { - n.reset (new ConstantExpressionNode (ex1, tl::Variant ())); - } else { - n.reset (new ConstantExpressionNode (ex1, tl::Variant (g))); - } - - } else { - - if (dbu_units && ! ctx_handler ()) { - throw EvalError (tl::to_string (tr ("Length or area value with unit requires a layout context")), ex1); - } - - if (dbu_units) { - - // round to integers and check whether that is possible - double gg = g; - g = floor (0.5 + g); - if (fabs (g) < 1e12 && fabs (g - gg) > 1e-3) { - throw EvalError (tl::to_string (tr ("Value is not a multiple of the database unit")), ex1); - } - - n.reset (new ConstantExpressionNode (ex1, tl::Variant (g))); - - } else { - - tl::Variant v (g); - - // prefer integers - if (g - floor (g) == 0.0 && v.can_convert_to_long ()) { - n.reset (new ConstantExpressionNode (ex1, tl::Variant (v.to_long ()))); - } else { - n.reset (new ConstantExpressionNode (ex1, v)); - } - - } - - - } + n.reset (new ConstantExpressionNode (ex1, g)); } else if (ex.try_read_quoted (t)) { diff --git a/src/tl/tl/tlExpression.h b/src/tl/tl/tlExpression.h index 63a941397..fe3947772 100644 --- a/src/tl/tl/tlExpression.h +++ b/src/tl/tl/tlExpression.h @@ -616,6 +616,7 @@ private: void eval_unary (ExpressionParserContext &context, std::unique_ptr &v); void eval_atomic (ExpressionParserContext &context, std::unique_ptr &v, int am); void eval_suffix (ExpressionParserContext &context, std::unique_ptr &v); + bool read_number (ExpressionParserContext &ex, tl::Variant &t); static Eval m_global; }; diff --git a/src/tl/unit_tests/tlExpressionTests.cc b/src/tl/unit_tests/tlExpressionTests.cc index 98e64a69c..d60cf118c 100644 --- a/src/tl/unit_tests/tlExpressionTests.cc +++ b/src/tl/unit_tests/tlExpressionTests.cc @@ -60,6 +60,8 @@ TEST(1) v = e.parse ("7%4").execute (); EXPECT_EQ (v.to_string (), std::string ("3")); v = e.parse ("2+3/2").execute (); + EXPECT_EQ (v.to_string (), std::string ("3")); + v = e.parse ("2+3/2.0").execute (); EXPECT_EQ (v.to_string (), std::string ("3.5")); v = e.parse ("to_i(1)*to_i(2)").execute (); @@ -650,13 +652,57 @@ TEST(2) EXPECT_EQ (v.to_string (), std::string ("2")); } -// to_double +// numerical constants TEST(3) { tl::Eval e; tl::Variant v; - v = e.parse ("[1,2,3]/2").execute (); + v = e.parse ("2.5+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##3.5")); + v = e.parse ("-2.5+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##-1.5")); + v = e.parse ("2+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("#3")); + v = e.parse ("-2+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("#-1")); + v = e.parse ("2.0+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##3")); + v = e.parse ("-2.0+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##-1")); + v = e.parse ("2.+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##3")); + v = e.parse ("-2.+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##-1")); + v = e.parse ("2.e1+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##21")); + v = e.parse ("-2.e1+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##-19")); + v = e.parse ("2e-1+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##1.2")); + v = e.parse ("-2e-1+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##0.8")); + v = e.parse (".2e+1+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##3")); + v = e.parse ("-.2e+1+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##-1")); + v = e.parse (".2+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##1.2")); + v = e.parse ("-.2+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##0.8")); + v = e.parse ("0.2+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##1.2")); + v = e.parse ("-0.2+1 ").execute (); + EXPECT_EQ (v.to_parsable_string (), std::string ("##0.8")); +} + +// to_double +TEST(4) +{ + tl::Eval e; + tl::Variant v; + + v = e.parse ("[1,2,3]/2.0").execute (); EXPECT_EQ (v.to_string (), std::string ("1.5")); } diff --git a/testdata/algo/net_proc_au1.gds b/testdata/algo/net_proc_au1.gds index be6e15498..c493c17ec 100644 Binary files a/testdata/algo/net_proc_au1.gds and b/testdata/algo/net_proc_au1.gds differ diff --git a/testdata/algo/net_proc_au2.gds b/testdata/algo/net_proc_au2.gds index fd53350d7..5c1a5be3e 100644 Binary files a/testdata/algo/net_proc_au2.gds and b/testdata/algo/net_proc_au2.gds differ diff --git a/testdata/algo/net_proc_au3.gds b/testdata/algo/net_proc_au3.gds index b84c44b2c..0b4bfe50b 100644 Binary files a/testdata/algo/net_proc_au3.gds and b/testdata/algo/net_proc_au3.gds differ diff --git a/testdata/drc/drcSimpleTests_au71.gds b/testdata/drc/drcSimpleTests_au71.gds index f89a29fa4..af9805450 100644 Binary files a/testdata/drc/drcSimpleTests_au71.gds and b/testdata/drc/drcSimpleTests_au71.gds differ diff --git a/testdata/python/dbLayoutTest.py b/testdata/python/dbLayoutTest.py index d7a7282bc..80f1e17bf 100644 --- a/testdata/python/dbLayoutTest.py +++ b/testdata/python/dbLayoutTest.py @@ -1146,8 +1146,8 @@ class DBLayoutTest(unittest.TestCase): self.assertEqual(shape.property("2"), None) self.assertEqual(shape.property(2.0), None) self.assertEqual(shape.property(22), None) - self.assertEqual(shape.property(42), "the answer") - self.assertEqual(shape.property("42"), None) + self.assertEqual(shape.property("42"), "the answer") + self.assertEqual(shape.property(42), None) self.assertEqual(shape.property(42.0), None) ly2 = pya.Layout() diff --git a/testdata/python/tlTest.py b/testdata/python/tlTest.py index 764864e88..2e6f710f0 100644 --- a/testdata/python/tlTest.py +++ b/testdata/python/tlTest.py @@ -40,12 +40,12 @@ class TLTest(unittest.TestCase): self.assertEqual(str(type(res)).replace("class", "type"), "") self.assertEqual(repr(res), "None") - expr = pya.Expression.eval("1+2") + expr = pya.Expression.eval("1+2.0") self.assertEqual(str(type(expr)).replace("class", "type"), "") self.assertEqual(repr(expr), "3.0") expr = pya.Expression() - expr.text = "1+2" + expr.text = "1+2.0" res = expr.eval() self.assertEqual(str(type(res)).replace("class", "type"), "") self.assertEqual(str(res), "3.0") diff --git a/testdata/ruby/tlTest.rb b/testdata/ruby/tlTest.rb index 76b04f60e..c2f43d112 100644 --- a/testdata/ruby/tlTest.rb +++ b/testdata/ruby/tlTest.rb @@ -40,14 +40,18 @@ class Tl_TestClass < TestBase assert_equal(res.to_s, "") expr = RBA::Expression.eval("1+2") + assert_equal(expr.class.to_s, "Integer") + assert_equal(expr.to_s, "3") + + expr = RBA::Expression.eval("1+2.0") assert_equal(expr.class.to_s, "Float") assert_equal(expr.to_s, "3.0") expr = RBA::Expression::new expr.text = "1+2" res = expr.eval - assert_equal(res.class.to_s, "Float") - assert_equal(res.to_s, "3.0") + assert_equal(res.class.to_s, "Integer") + assert_equal(res.to_s, "3") expr = RBA::Expression::new expr.var("a", 5)