[feaLib] Parse substitute from
statements
This commit is contained in:
parent
8b77f68dec
commit
72c1f165b4
@ -28,6 +28,12 @@ class GlyphClassDefinition(object):
|
||||
self.glyphs = glyphs
|
||||
|
||||
|
||||
class AlternateSubstitution(object):
|
||||
def __init__(self, location, glyph, from_class):
|
||||
self.location = location
|
||||
self.glyph, self.from_class = (glyph, from_class)
|
||||
|
||||
|
||||
class AnchorDefinition(object):
|
||||
def __init__(self, location, name, x, y, contourpoint):
|
||||
self.location = location
|
||||
|
@ -130,7 +130,7 @@ class Parser(object):
|
||||
|
||||
def parse_glyph_pattern_(self):
|
||||
prefix, glyphs, lookups, suffix = ([], [], [], [])
|
||||
while self.next_token_ not in {"by", ";"}:
|
||||
while self.next_token_ not in {"by", "from", ";"}:
|
||||
gc = self.parse_glyphclass_(accept_glyphname=True)
|
||||
marked = False
|
||||
if self.next_token_ == "'":
|
||||
@ -218,15 +218,31 @@ class Parser(object):
|
||||
assert self.cur_token_ in {"substitute", "sub"}
|
||||
location = self.cur_token_location_
|
||||
old_prefix, old, lookups, old_suffix = self.parse_glyph_pattern_()
|
||||
|
||||
if self.next_token_ == "by":
|
||||
self.expect_keyword_("by")
|
||||
keyword = self.expect_keyword_("by")
|
||||
new = [self.parse_glyphclass_(accept_glyphname=True)]
|
||||
elif self.next_token_ == "from":
|
||||
keyword = self.expect_keyword_("from")
|
||||
new = [self.parse_glyphclass_(accept_glyphname=False)]
|
||||
else:
|
||||
keyword = None
|
||||
new = []
|
||||
self.expect_symbol_(";")
|
||||
if len(new) is 0 and not any(lookups):
|
||||
raise ParserError('Expected "by" or explicit lookup references',
|
||||
self.cur_token_location_)
|
||||
raise ParserError(
|
||||
'Expected "by", "from" or explicit lookup references',
|
||||
self.cur_token_location_)
|
||||
|
||||
if keyword == "from":
|
||||
if len(old) != 1 or len(old[0]) != 1:
|
||||
raise ParserError('Expected a single glyph before "from"',
|
||||
location)
|
||||
if len(new) != 1:
|
||||
raise ParserError('Expected a single glyphclass after "from"',
|
||||
location)
|
||||
return ast.AlternateSubstitution(location, list(old[0])[0], new[0])
|
||||
|
||||
rule = ast.SubstitutionRule(location, old, new)
|
||||
rule.old_prefix, rule.old_suffix = old_prefix, old_suffix
|
||||
rule.lookups = lookups
|
||||
|
@ -289,6 +289,25 @@ class ParserTest(unittest.TestCase):
|
||||
self.assertEqual(sub.new, [{"A.sc", "B.sc", "C.sc", "D.sc"}])
|
||||
self.assertEqual(sub.lookups, [None])
|
||||
|
||||
def test_substitute_from(self): # GSUB LookupType 3
|
||||
doc = self.parse("feature test {"
|
||||
" substitute a from [a.1 a.2 a.3];"
|
||||
"} test;")
|
||||
sub = doc.statements[0].statements[0]
|
||||
self.assertEqual(type(sub), ast.AlternateSubstitution)
|
||||
self.assertEqual(sub.glyph, "a")
|
||||
self.assertEqual(sub.from_class, {"a.1", "a.2", "a.3"})
|
||||
|
||||
def test_substitute_from_glyphclass(self): # GSUB LookupType 3
|
||||
doc = self.parse("feature test {"
|
||||
" @Ampersands = [ampersand.1 ampersand.2];"
|
||||
" substitute ampersand from @Ampersands;"
|
||||
"} test;")
|
||||
[glyphclass, sub] = doc.statements[0].statements
|
||||
self.assertEqual(type(sub), ast.AlternateSubstitution)
|
||||
self.assertEqual(sub.glyph, "ampersand")
|
||||
self.assertEqual(sub.from_class, {"ampersand.1", "ampersand.2"})
|
||||
|
||||
def test_substitute_ligature(self): # GSUB LookupType 4
|
||||
doc = self.parse("feature liga {substitute f f i by f_f_i;} liga;")
|
||||
sub = doc.statements[0].statements[0]
|
||||
@ -306,7 +325,7 @@ class ParserTest(unittest.TestCase):
|
||||
|
||||
def test_substitute_missing_by(self):
|
||||
self.assertRaisesRegex(
|
||||
ParserError, 'Expected "by" or explicit lookup references',
|
||||
ParserError, 'Expected "by", "from" or explicit lookup references',
|
||||
self.parse, "feature liga {substitute f f i;} liga;")
|
||||
|
||||
def test_subtable(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user