[feaLib] Parse lookupflag
statements
They do not have any impact yet, this change is just for the parsing.
This commit is contained in:
parent
ef03a3be47
commit
0dbb2fdcc0
@ -26,6 +26,13 @@ class Expression(object):
|
||||
pass
|
||||
|
||||
|
||||
class GlyphClassName(Expression):
|
||||
def __init__(self, location, glyphclass):
|
||||
Expression.__init__(self, location)
|
||||
assert isinstance(glyphclass, GlyphClassDefinition)
|
||||
self.glyphclass = glyphclass
|
||||
|
||||
|
||||
class Block(Statement):
|
||||
def __init__(self, location):
|
||||
Statement.__init__(self, location)
|
||||
@ -181,6 +188,17 @@ class LigatureSubstStatement(Statement):
|
||||
builder.add_ligature_subst(self.location, glyphs, self.replacement)
|
||||
|
||||
|
||||
class LookupFlagStatement(Statement):
|
||||
def __init__(self, location, value, markAttachment, markFilteringSet):
|
||||
Statement.__init__(self, location)
|
||||
self.value = value
|
||||
self.markAttachment = markAttachment
|
||||
self.markFilteringSet = markFilteringSet
|
||||
|
||||
def build(self, builder):
|
||||
pass # TODO: Implement.
|
||||
|
||||
|
||||
class LookupReferenceStatement(Statement):
|
||||
def __init__(self, location, lookup):
|
||||
Statement.__init__(self, location)
|
||||
|
@ -175,6 +175,15 @@ class Parser(object):
|
||||
self.expect_symbol_("]")
|
||||
return result
|
||||
|
||||
def parse_glyphclass_name_(self):
|
||||
name = self.expect_class_name_()
|
||||
gc = self.glyphclasses_.resolve(name)
|
||||
if gc is None:
|
||||
raise FeatureLibError(
|
||||
"Unknown glyph class @%s" % name,
|
||||
self.cur_token_location_)
|
||||
return ast.GlyphClassName(self.cur_token_location_, gc)
|
||||
|
||||
def parse_glyph_pattern_(self):
|
||||
prefix, glyphs, lookups, suffix = ([], [], [], [])
|
||||
while (self.next_token_ not in {"by", "from", ";", "<"} and
|
||||
@ -260,6 +269,45 @@ class Parser(object):
|
||||
self.lookups_.define(name, block)
|
||||
return block
|
||||
|
||||
def parse_lookupflag_(self):
|
||||
assert self.is_cur_keyword_("lookupflag")
|
||||
location = self.cur_token_location_
|
||||
|
||||
# format B: "lookupflag 6;"
|
||||
if self.next_token_type_ == Lexer.NUMBER:
|
||||
value = self.expect_number_()
|
||||
self.expect_symbol_(";")
|
||||
return ast.LookupFlagStatement(location, value, None, None)
|
||||
|
||||
# format A: "lookupflag RightToLeft MarkAttachmentType @M;"
|
||||
value, markAttachment, markFilteringSet = 0, None, None
|
||||
flags = {
|
||||
"RightToLeft": 1, "IgnoreBaseGlyphs": 2,
|
||||
"IgnoreLigatures": 4, "IgnoreMarks": 8
|
||||
}
|
||||
seen = set()
|
||||
while self.next_token_ != ";":
|
||||
if self.next_token_ in seen:
|
||||
raise FeatureLibError(
|
||||
"%s can be specified only once" % self.next_token_,
|
||||
self.next_token_location_)
|
||||
seen.add(self.next_token_)
|
||||
if self.next_token_ == "MarkAttachmentType":
|
||||
self.expect_keyword_("MarkAttachmentType")
|
||||
markAttachment = self.parse_glyphclass_name_()
|
||||
if self.next_token_ == "UseMarkFilteringSet":
|
||||
self.expect_keyword_("UseMarkFilteringSet")
|
||||
markFilteringSet = self.parse_glyphclass_name_()
|
||||
elif self.next_token_ in flags:
|
||||
value = value | flags[self.expect_name_()]
|
||||
else:
|
||||
raise FeatureLibError(
|
||||
'"%s" is not a recognized lookupflag' % self.next_token_,
|
||||
self.next_token_location_)
|
||||
self.expect_symbol_(";")
|
||||
return ast.LookupFlagStatement(location, value,
|
||||
markAttachment, markFilteringSet)
|
||||
|
||||
def parse_markClass_(self):
|
||||
assert self.is_cur_keyword_("markClass")
|
||||
location = self.cur_token_location_
|
||||
@ -628,6 +676,8 @@ class Parser(object):
|
||||
statements.append(self.parse_language_())
|
||||
elif self.is_cur_keyword_("lookup"):
|
||||
statements.append(self.parse_lookup_(vertical))
|
||||
elif self.is_cur_keyword_("lookupflag"):
|
||||
statements.append(self.parse_lookupflag_())
|
||||
elif self.is_cur_keyword_("markClass"):
|
||||
self.parse_markClass_()
|
||||
elif self.is_cur_keyword_({"pos", "position"}):
|
||||
|
@ -335,6 +335,58 @@ class ParserTest(unittest.TestCase):
|
||||
FeatureLibError, 'Unknown lookup "Huh"',
|
||||
self.parse, "feature liga {lookup Huh;} liga;")
|
||||
|
||||
def parse_lookupflag_(self, s):
|
||||
return self.parse("lookup L {%s} L;" % s).statements[0].statements[-1]
|
||||
|
||||
def test_lookupflag_format_A(self):
|
||||
flag = self.parse_lookupflag_("lookupflag RightToLeft IgnoreMarks;")
|
||||
self.assertIsInstance(flag, ast.LookupFlagStatement)
|
||||
self.assertEqual(flag.value, 9)
|
||||
self.assertIsNone(flag.markAttachment)
|
||||
self.assertIsNone(flag.markFilteringSet)
|
||||
|
||||
def test_lookupflag_format_A_MarkAttachmentType(self):
|
||||
flag = self.parse_lookupflag_(
|
||||
"@TOP_MARKS = [acute grave macron];"
|
||||
"lookupflag MarkAttachmentType @TOP_MARKS RightToLeft;")
|
||||
self.assertIsInstance(flag, ast.LookupFlagStatement)
|
||||
self.assertEqual(flag.value, 1)
|
||||
self.assertIsInstance(flag.markAttachment, ast.GlyphClassName)
|
||||
self.assertEqual(flag.markAttachment.glyphclass.glyphs,
|
||||
{"acute", "grave", "macron"})
|
||||
self.assertIsNone(flag.markFilteringSet)
|
||||
|
||||
def test_lookupflag_format_A_UseMarkFilteringSet(self):
|
||||
flag = self.parse_lookupflag_(
|
||||
"@BOTTOM_MARKS = [cedilla ogonek];"
|
||||
"lookupflag UseMarkFilteringSet @BOTTOM_MARKS IgnoreLigatures;")
|
||||
self.assertIsInstance(flag, ast.LookupFlagStatement)
|
||||
self.assertEqual(flag.value, 4)
|
||||
self.assertIsNone(flag.markAttachment)
|
||||
self.assertIsInstance(flag.markFilteringSet, ast.GlyphClassName)
|
||||
self.assertEqual(flag.markFilteringSet.glyphclass.glyphs,
|
||||
{"cedilla", "ogonek"})
|
||||
|
||||
def test_lookupflag_format_B(self):
|
||||
flag = self.parse_lookupflag_("lookupflag 7;")
|
||||
self.assertIsInstance(flag, ast.LookupFlagStatement)
|
||||
self.assertEqual(flag.value, 7)
|
||||
self.assertIsNone(flag.markAttachment)
|
||||
self.assertIsNone(flag.markFilteringSet)
|
||||
|
||||
def test_lookupflag_repeated(self):
|
||||
self.assertRaisesRegex(
|
||||
FeatureLibError,
|
||||
'RightToLeft can be specified only once',
|
||||
self.parse,
|
||||
"feature test {lookupflag RightToLeft RightToLeft;} test;")
|
||||
|
||||
def test_lookupflag_unrecognized(self):
|
||||
self.assertRaisesRegex(
|
||||
FeatureLibError,
|
||||
'"IgnoreCookies" is not a recognized lookupflag',
|
||||
self.parse, "feature test {lookupflag IgnoreCookies;} test;")
|
||||
|
||||
def test_gpos_type_1_glyph(self):
|
||||
doc = self.parse("feature kern {pos one <1 2 3 4>;} kern;")
|
||||
pos = doc.statements[0].statements[0]
|
||||
|
Loading…
x
Reference in New Issue
Block a user