[feaLib] Clean up syntax tree for FeatureNames
The syntax tree representation now reflects the syntax of feature files. Before this change, FeatureNames did not have their own `ast.Block`, which had made the code quite messy.
This commit is contained in:
parent
4210c9d2d6
commit
189c722626
@ -225,25 +225,20 @@ class FeatureBlock(Block):
|
||||
builder.end_feature()
|
||||
|
||||
def asFea(self, indent=""):
|
||||
res = indent + "feature {} {{\n".format(self.name.strip())
|
||||
indent += SHIFT
|
||||
if len(self.statements) and isinstance(self.statements[0], FeatureNameStatement):
|
||||
res += indent + "featureNames {\n"
|
||||
res += indent + SHIFT
|
||||
res += ("\n" + indent + SHIFT).join(
|
||||
[s.asFea(indent=indent + SHIFT * 2)
|
||||
for s in self.statements if isinstance(s, FeatureNameStatement)])
|
||||
res += "\n"
|
||||
res += indent + "};\n" + indent
|
||||
res += ("\n" + indent).join(
|
||||
[s.asFea(indent=indent)
|
||||
for s in self.statements if not isinstance(s, FeatureNameStatement)])
|
||||
res += "\n"
|
||||
else:
|
||||
res += indent
|
||||
res += ("\n" + indent).join([s.asFea(indent=indent) for s in self.statements])
|
||||
res += "\n"
|
||||
res += "{}}} {};\n".format(indent[:-len(SHIFT)], self.name.strip())
|
||||
res = indent + "feature %s {\n" % self.name.strip()
|
||||
res += Block.asFea(self, indent=indent)
|
||||
res += indent + "} %s;\n" % self.name.strip()
|
||||
return res
|
||||
|
||||
|
||||
class FeatureNamesBlock(Block):
|
||||
def __init__(self, location):
|
||||
Block.__init__(self, location)
|
||||
|
||||
def asFea(self, indent=""):
|
||||
res = indent + "featureNames {\n"
|
||||
res += Block.asFea(self, indent=indent)
|
||||
res += indent + "};\n"
|
||||
return res
|
||||
|
||||
|
||||
|
@ -1152,27 +1152,30 @@ class Parser(object):
|
||||
|
||||
def parse_featureNames_(self, tag):
|
||||
assert self.cur_token_ == "featureNames", self.cur_token_
|
||||
block = self.ast.FeatureNamesBlock(self.cur_token_location_)
|
||||
self.expect_symbol_("{")
|
||||
for symtab in self.symbol_tables_:
|
||||
symtab.enter_scope()
|
||||
|
||||
statements = []
|
||||
while self.next_token_ != "}":
|
||||
self.expect_keyword_("name")
|
||||
location = self.cur_token_location_
|
||||
platformID, platEncID, langID, string = self.parse_name_()
|
||||
statements.append(
|
||||
while self.next_token_ != "}" or self.cur_comments_:
|
||||
self.advance_lexer_(comments=True)
|
||||
if self.cur_token_type_ is Lexer.COMMENT:
|
||||
block.statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_))
|
||||
elif self.is_cur_keyword_("name"):
|
||||
location = self.cur_token_location_
|
||||
platformID, platEncID, langID, string = self.parse_name_()
|
||||
block.statements.append(
|
||||
self.ast.FeatureNameStatement(location, tag, platformID,
|
||||
platEncID, langID, string))
|
||||
|
||||
elif self.cur_token_ == ";":
|
||||
continue
|
||||
else:
|
||||
raise FeatureLibError('Expected "name"',
|
||||
self.cur_token_location_)
|
||||
self.expect_symbol_("}")
|
||||
|
||||
for symtab in self.symbol_tables_:
|
||||
symtab.exit_scope()
|
||||
|
||||
self.expect_symbol_(";")
|
||||
|
||||
return statements
|
||||
return block
|
||||
|
||||
def parse_FontRevision_(self):
|
||||
assert self.cur_token_ == "FontRevision", self.cur_token_
|
||||
@ -1225,7 +1228,7 @@ class Parser(object):
|
||||
elif self.is_cur_keyword_("valueRecordDef"):
|
||||
statements.append(self.parse_valuerecord_definition_(vertical))
|
||||
elif stylisticset and self.is_cur_keyword_("featureNames"):
|
||||
statements.extend(self.parse_featureNames_(stylisticset))
|
||||
statements.append(self.parse_featureNames_(stylisticset))
|
||||
elif size_feature and self.is_cur_keyword_("parameters"):
|
||||
statements.append(self.parse_size_parameters_())
|
||||
elif size_feature and self.is_cur_keyword_("sizemenuname"):
|
||||
|
1
NEWS.rst
1
NEWS.rst
@ -1,5 +1,6 @@
|
||||
- [feaLib] Added (partial) support for parsing feature file comments ``# ...``
|
||||
appearing in between statements (#879).
|
||||
- [feaLib] Cleaned up syntax tree for FeatureNames.
|
||||
- [ttLib] Added support for reading/writing ``CFF2`` table (thanks to
|
||||
@readroberts at Adobe), and ``TTFA`` (ttfautohint) table.
|
||||
|
||||
|
@ -202,6 +202,27 @@ class ParserTest(unittest.TestCase):
|
||||
self.assertIsInstance(ref, ast.FeatureReferenceStatement)
|
||||
self.assertEqual(ref.featureName, "salt")
|
||||
|
||||
def test_FeatureNames_bad(self):
|
||||
self.assertRaisesRegex(
|
||||
FeatureLibError, 'Expected "name"',
|
||||
self.parse, "feature ss01 { featureNames { feature test; } ss01;")
|
||||
|
||||
def test_FeatureNames_comment(self):
|
||||
[feature] = self.parse(
|
||||
"feature ss01 { featureNames { # Comment\n }; } ss01;").statements
|
||||
[featureNames] = feature.statements
|
||||
self.assertIsInstance(featureNames, ast.FeatureNamesBlock)
|
||||
[comment] = featureNames.statements
|
||||
self.assertIsInstance(comment, ast.Comment)
|
||||
self.assertEqual(comment.text, "# Comment")
|
||||
|
||||
def test_FeatureNames_emptyStatements(self):
|
||||
[feature] = self.parse(
|
||||
"feature ss01 { featureNames { ;;; }; } ss01;").statements
|
||||
[featureNames] = feature.statements
|
||||
self.assertIsInstance(featureNames, ast.FeatureNamesBlock)
|
||||
self.assertEqual(featureNames.statements, [])
|
||||
|
||||
def test_FontRevision(self):
|
||||
doc = self.parse("table head {FontRevision 2.5;} head;")
|
||||
s = doc.statements[0].statements[0]
|
||||
|
Loading…
x
Reference in New Issue
Block a user