diff --git a/Lib/fontTools/feaLib/ast.py b/Lib/fontTools/feaLib/ast.py index 7f33ca41c..06a018ef7 100644 --- a/Lib/fontTools/feaLib/ast.py +++ b/Lib/fontTools/feaLib/ast.py @@ -1115,6 +1115,9 @@ class ValueRecord(Expression): hash(self.xAdvDevice) ^ hash(self.yAdvDevice)) def makeString(self, vertical=None): + if not self: + return "" + x, y = self.xPlacement, self.yPlacement xAdvance, yAdvance = self.xAdvance, self.yAdvance xPlaDevice, yPlaDevice = self.xPlaDevice, self.yPlaDevice @@ -1140,6 +1143,23 @@ class ValueRecord(Expression): deviceToString(xPlaDevice), deviceToString(yPlaDevice), deviceToString(xAdvDevice), deviceToString(yAdvDevice)) + def __bool__(self): + return any( + getattr(self, v) is not None + for v in [ + "xPlacement", + "yPlacement", + "xAdvance", + "yAdvance", + "xPlaDevice", + "yPlaDevice", + "xAdvDevice", + "yAdvDevice", + ] + ) + + __nonzero__ = __bool__ + class ValueRecordDefinition(Statement): def __init__(self, name, value, location=None): diff --git a/Lib/fontTools/feaLib/parser.py b/Lib/fontTools/feaLib/parser.py index 304269875..61d371111 100644 --- a/Lib/fontTools/feaLib/parser.py +++ b/Lib/fontTools/feaLib/parser.py @@ -1153,7 +1153,7 @@ class Parser(object): name = self.expect_name_() if name == "NULL": self.expect_symbol_(">") - return None + return self.ast.ValueRecord() vrd = self.valuerecords_.resolve(name) if vrd is None: raise FeatureLibError("Unknown valueRecordDef \"%s\"" % name, diff --git a/Tests/feaLib/parser_test.py b/Tests/feaLib/parser_test.py index f9b1063b9..900792196 100644 --- a/Tests/feaLib/parser_test.py +++ b/Tests/feaLib/parser_test.py @@ -800,7 +800,22 @@ class ParserTest(unittest.TestCase): self.assertEqual(pos.valuerecord2.makeString(vertical=False), "<1 2 3 4>") - def test_gpos_type_2_format_a_with_null(self): + def test_gpos_type_2_format_a_with_null_first(self): + doc = self.parse("feature kern {" + " pos [T V] [a b c] <1 2 3 4>;" + "} kern;") + pos = doc.statements[0].statements[0] + self.assertEqual(type(pos), ast.PairPosStatement) + self.assertFalse(pos.enumerated) + self.assertEqual(glyphstr([pos.glyphs1]), "[T V]") + self.assertFalse(pos.valuerecord1) + self.assertEqual(pos.valuerecord1.makeString(), "") + self.assertEqual(glyphstr([pos.glyphs2]), "[a b c]") + self.assertEqual(pos.valuerecord2.makeString(vertical=False), + "<1 2 3 4>") + self.assertEqual(pos.asFea(), "pos [T V] [a b c] <1 2 3 4>;") + + def test_gpos_type_2_format_a_with_null_second(self): doc = self.parse("feature kern {" " pos [T V] <1 2 3 4> [a b c] ;" "} kern;") @@ -811,7 +826,8 @@ class ParserTest(unittest.TestCase): self.assertEqual(pos.valuerecord1.makeString(vertical=False), "<1 2 3 4>") self.assertEqual(glyphstr([pos.glyphs2]), "[a b c]") - self.assertIsNone(pos.valuerecord2) + self.assertFalse(pos.valuerecord2) + self.assertEqual(pos.asFea(), "pos [T V] [a b c] <1 2 3 4>;") def test_gpos_type_2_format_b(self): doc = self.parse("feature kern {" @@ -1523,7 +1539,8 @@ class ParserTest(unittest.TestCase): def test_valuerecord_format_d(self): doc = self.parse("feature test {valueRecordDef foo;} test;") value = doc.statements[0].statements[0].value - self.assertIsNone(value) + self.assertFalse(value) + self.assertEqual(value.makeString(), "") def test_valuerecord_named(self): doc = self.parse("valueRecordDef <1 2 3 4> foo;"