[feaLib] Implement valueRecordDef statements
This commit is contained in:
parent
4169e584cc
commit
c06a377aa3
@ -48,3 +48,17 @@ class LanguageSystemStatement(object):
|
||||
def write(self, out, linesep):
|
||||
write(out, "languagesystem %s %s;%s" %
|
||||
(self.script.strip(), self.language.strip(), linesep))
|
||||
|
||||
|
||||
class ValueRecord(object):
|
||||
def __init__(self, location, xPlacement, yPlacement, xAdvance, yAdvance):
|
||||
self.location = location
|
||||
self.xPlacement, self.yPlacement = (xPlacement, yPlacement)
|
||||
self.xAdvance, self.yAdvance = (xAdvance, yAdvance)
|
||||
|
||||
|
||||
class ValueRecordDefinition(object):
|
||||
def __init__(self, location, name, value):
|
||||
self.location = location
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
@ -32,11 +32,14 @@ class Parser(object):
|
||||
self.advance_lexer_()
|
||||
|
||||
def parse(self):
|
||||
statements = self.doc_.statements
|
||||
while self.next_token_type_ is not None:
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ is Lexer.GLYPHCLASS:
|
||||
glyphclass = self.parse_glyphclass_definition_()
|
||||
self.doc_.statements.append(glyphclass)
|
||||
statements.append(self.parse_glyphclass_definition_())
|
||||
elif self.is_cur_keyword_("valueRecordDef"):
|
||||
statements.append(
|
||||
self.parse_valuerecord_definition_(vertical=False))
|
||||
elif self.is_cur_keyword_("languagesystem"):
|
||||
self.parse_languagesystem_()
|
||||
elif self.is_cur_keyword_("feature"):
|
||||
@ -99,6 +102,43 @@ class Parser(object):
|
||||
self.expect_symbol_("]")
|
||||
return result
|
||||
|
||||
def parse_valuerecord_(self, vertical):
|
||||
if self.next_token_type_ is Lexer.NUMBER:
|
||||
number, location = self.expect_number_(), self.cur_token_location_
|
||||
if vertical:
|
||||
val = ast.ValueRecord(location, 0, 0, 0, number)
|
||||
else:
|
||||
val = ast.ValueRecord(location, 0, 0, number, 0)
|
||||
return val
|
||||
self.expect_symbol_("<")
|
||||
location = self.cur_token_location_
|
||||
if self.next_token_type_ is Lexer.NAME:
|
||||
name = self.expect_name_()
|
||||
vrd = self.valuerecords_.resolve(name)
|
||||
if vrd is None:
|
||||
raise ParserError("Unknown valueRecordDef \"%s\"" % name,
|
||||
self.cur_token_location_)
|
||||
value = vrd.value
|
||||
xPlacement, yPlacement = (value.xPlacement, value.yPlacement)
|
||||
xAdvance, yAdvance = (value.xAdvance, value.yAdvance)
|
||||
else:
|
||||
xPlacement, yPlacement, xAdvance, yAdvance = (
|
||||
self.expect_number_(), self.expect_number_(),
|
||||
self.expect_number_(), self.expect_number_())
|
||||
self.expect_symbol_(">")
|
||||
return ast.ValueRecord(
|
||||
location, xPlacement, yPlacement, xAdvance, yAdvance)
|
||||
|
||||
def parse_valuerecord_definition_(self, vertical):
|
||||
assert self.is_cur_keyword_("valueRecordDef")
|
||||
location = self.cur_token_location_
|
||||
value = self.parse_valuerecord_(vertical)
|
||||
name = self.expect_name_()
|
||||
self.expect_symbol_(";")
|
||||
vrd = ast.ValueRecordDefinition(location, name, value)
|
||||
self.valuerecords_.define(name, vrd)
|
||||
return vrd
|
||||
|
||||
def parse_languagesystem_(self):
|
||||
assert self.cur_token_ == "languagesystem"
|
||||
location = self.cur_token_location_
|
||||
@ -111,6 +151,7 @@ class Parser(object):
|
||||
assert self.cur_token_ == "feature"
|
||||
location = self.cur_token_location_
|
||||
tag = self.expect_tag_()
|
||||
vertical = (tag == "vkrn")
|
||||
|
||||
self.expect_symbol_("{")
|
||||
for symtab in self.symbol_tables_:
|
||||
@ -118,11 +159,14 @@ class Parser(object):
|
||||
|
||||
block = ast.FeatureBlock(location, tag)
|
||||
self.doc_.statements.append(block)
|
||||
statements = block.statements
|
||||
|
||||
while self.next_token_ != "}":
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ is Lexer.GLYPHCLASS:
|
||||
block.statements.append(self.parse_glyphclass_definition_())
|
||||
statements.append(self.parse_glyphclass_definition_())
|
||||
elif self.is_cur_keyword_("valueRecordDef"):
|
||||
statements.append(self.parse_valuerecord_definition_(vertical))
|
||||
else:
|
||||
raise ParserError("Expected glyph class definition",
|
||||
self.cur_token_location_)
|
||||
@ -161,6 +205,12 @@ class Parser(object):
|
||||
return self.cur_token_
|
||||
raise ParserError("Expected a name", self.cur_token_location_)
|
||||
|
||||
def expect_number_(self):
|
||||
self.advance_lexer_()
|
||||
if self.cur_token_type_ is Lexer.NUMBER:
|
||||
return self.cur_token_
|
||||
raise ParserError("Expected a number", self.cur_token_location_)
|
||||
|
||||
def advance_lexer_(self):
|
||||
self.cur_token_type_, self.cur_token_, self.cur_token_location_ = (
|
||||
self.next_token_type_, self.next_token_, self.next_token_location_)
|
||||
|
@ -109,6 +109,44 @@ class ParserTest(unittest.TestCase):
|
||||
self.assertEqual(liga.statements[0].glyphs, {"a", "b", "l"})
|
||||
self.assertEqual(smcp.statements[0].glyphs, {"a", "b", "s"})
|
||||
|
||||
def test_valuerecord_format_a_horizontal(self):
|
||||
doc = self.parse("feature liga {valueRecordDef 123 foo;} liga;")
|
||||
value = doc.statements[0].statements[0].value
|
||||
self.assertEqual(value.xPlacement, 0)
|
||||
self.assertEqual(value.yPlacement, 0)
|
||||
self.assertEqual(value.xAdvance, 123)
|
||||
self.assertEqual(value.yAdvance, 0)
|
||||
|
||||
def test_valuerecord_format_a_vertical(self):
|
||||
doc = self.parse("feature vkrn {valueRecordDef 123 foo;} vkrn;")
|
||||
value = doc.statements[0].statements[0].value
|
||||
self.assertEqual(value.xPlacement, 0)
|
||||
self.assertEqual(value.yPlacement, 0)
|
||||
self.assertEqual(value.xAdvance, 0)
|
||||
self.assertEqual(value.yAdvance, 123)
|
||||
|
||||
def test_valuerecord_format_b(self):
|
||||
doc = self.parse("feature liga {valueRecordDef <1 2 3 4> foo;} liga;")
|
||||
value = doc.statements[0].statements[0].value
|
||||
self.assertEqual(value.xPlacement, 1)
|
||||
self.assertEqual(value.yPlacement, 2)
|
||||
self.assertEqual(value.xAdvance, 3)
|
||||
self.assertEqual(value.yAdvance, 4)
|
||||
|
||||
def test_valuerecord_named(self):
|
||||
doc = self.parse("valueRecordDef <1 2 3 4> foo;"
|
||||
"feature liga {valueRecordDef <foo> bar;} liga;")
|
||||
value = doc.statements[1].statements[0].value
|
||||
self.assertEqual(value.xPlacement, 1)
|
||||
self.assertEqual(value.yPlacement, 2)
|
||||
self.assertEqual(value.xAdvance, 3)
|
||||
self.assertEqual(value.yAdvance, 4)
|
||||
|
||||
def test_valuerecord_named_unknown(self):
|
||||
self.assertRaisesRegex(
|
||||
ParserError, "Unknown valueRecordDef \"unknown\"",
|
||||
self.parse, "valueRecordDef <unknown> foo;")
|
||||
|
||||
def test_languagesystem(self):
|
||||
[langsys] = self.parse("languagesystem latn DEU;").statements
|
||||
self.assertEqual(langsys.script, "latn")
|
||||
|
Loading…
x
Reference in New Issue
Block a user