[feaLib] Implement valueRecordDef statements

This commit is contained in:
Sascha Brawer 2015-08-04 11:01:04 +02:00
parent 4169e584cc
commit c06a377aa3
3 changed files with 105 additions and 3 deletions

View File

@ -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

View File

@ -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_)

View File

@ -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")