[feaLib.ast] make location=None by default

This would make it easier to construct feaLib AST from code,
where the location is not defined and thus should be None.
Also, we can make other arguments as kwargs with a default
value, now that the first parameter is no longer 'location'.
This commit is contained in:
Cosimo Lupo 2018-02-27 18:38:15 +00:00
parent ff2144ee6a
commit e5c0bdd5df
No known key found for this signature in database
GPG Key ID: 59D54DB0C9976482
3 changed files with 224 additions and 157 deletions

View File

@ -49,7 +49,7 @@ def asFea(g):
class Element(object): class Element(object):
def __init__(self, location): def __init__(self, location=None):
self.location = location self.location = location
def build(self, builder): def build(self, builder):
@ -71,7 +71,7 @@ class Expression(Element):
class Comment(Element): class Comment(Element):
def __init__(self, location, text): def __init__(self, text, location=None):
super(Comment, self).__init__(location) super(Comment, self).__init__(location)
self.text = text self.text = text
@ -81,7 +81,7 @@ class Comment(Element):
class GlyphName(Expression): class GlyphName(Expression):
"""A single glyph name, such as cedilla.""" """A single glyph name, such as cedilla."""
def __init__(self, location, glyph): def __init__(self, glyph, location=None):
Expression.__init__(self, location) Expression.__init__(self, location)
self.glyph = glyph self.glyph = glyph
@ -94,7 +94,7 @@ class GlyphName(Expression):
class GlyphClass(Expression): class GlyphClass(Expression):
"""A glyph class, such as [acute cedilla grave].""" """A glyph class, such as [acute cedilla grave]."""
def __init__(self, location, glyphs=None): def __init__(self, glyphs=None, location=None):
Expression.__init__(self, location) Expression.__init__(self, location)
self.glyphs = glyphs if glyphs is not None else [] self.glyphs = glyphs if glyphs is not None else []
self.original = [] self.original = []
@ -142,7 +142,7 @@ class GlyphClass(Expression):
class GlyphClassName(Expression): class GlyphClassName(Expression):
"""A glyph class name, such as @FRENCH_MARKS.""" """A glyph class name, such as @FRENCH_MARKS."""
def __init__(self, location, glyphclass): def __init__(self, glyphclass, location=None):
Expression.__init__(self, location) Expression.__init__(self, location)
assert isinstance(glyphclass, GlyphClassDefinition) assert isinstance(glyphclass, GlyphClassDefinition)
self.glyphclass = glyphclass self.glyphclass = glyphclass
@ -156,7 +156,7 @@ class GlyphClassName(Expression):
class MarkClassName(Expression): class MarkClassName(Expression):
"""A mark class name, such as @FRENCH_MARKS defined with markClass.""" """A mark class name, such as @FRENCH_MARKS defined with markClass."""
def __init__(self, location, markClass): def __init__(self, markClass, location=None):
Expression.__init__(self, location) Expression.__init__(self, location)
assert isinstance(markClass, MarkClass) assert isinstance(markClass, MarkClass)
self.markClass = markClass self.markClass = markClass
@ -169,7 +169,7 @@ class MarkClassName(Expression):
class AnonymousBlock(Statement): class AnonymousBlock(Statement):
def __init__(self, tag, content, location): def __init__(self, tag, content, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.tag, self.content = tag, content self.tag, self.content = tag, content
@ -181,7 +181,7 @@ class AnonymousBlock(Statement):
class Block(Statement): class Block(Statement):
def __init__(self, location): def __init__(self, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.statements = [] self.statements = []
@ -205,7 +205,7 @@ class FeatureFile(Block):
class FeatureBlock(Block): class FeatureBlock(Block):
def __init__(self, location, name, use_extension): def __init__(self, name, use_extension=False, location=None):
Block.__init__(self, location) Block.__init__(self, location)
self.name, self.use_extension = name, use_extension self.name, self.use_extension = name, use_extension
@ -230,7 +230,7 @@ class FeatureBlock(Block):
class FeatureNamesBlock(Block): class FeatureNamesBlock(Block):
def __init__(self, location): def __init__(self, location=None):
Block.__init__(self, location) Block.__init__(self, location)
def asFea(self, indent=""): def asFea(self, indent=""):
@ -241,7 +241,7 @@ class FeatureNamesBlock(Block):
class LookupBlock(Block): class LookupBlock(Block):
def __init__(self, location, name, use_extension): def __init__(self, name, use_extension=False, location=None):
Block.__init__(self, location) Block.__init__(self, location)
self.name, self.use_extension = name, use_extension self.name, self.use_extension = name, use_extension
@ -259,7 +259,7 @@ class LookupBlock(Block):
class TableBlock(Block): class TableBlock(Block):
def __init__(self, location, name): def __init__(self, name, location=None):
Block.__init__(self, location) Block.__init__(self, location)
self.name = name self.name = name
@ -272,7 +272,7 @@ class TableBlock(Block):
class GlyphClassDefinition(Statement): class GlyphClassDefinition(Statement):
"""Example: @UPPERCASE = [A-Z];""" """Example: @UPPERCASE = [A-Z];"""
def __init__(self, location, name, glyphs): def __init__(self, name, glyphs, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.name = name self.name = name
self.glyphs = glyphs self.glyphs = glyphs
@ -286,8 +286,8 @@ class GlyphClassDefinition(Statement):
class GlyphClassDefStatement(Statement): class GlyphClassDefStatement(Statement):
"""Example: GlyphClassDef @UPPERCASE, [B], [C], [D];""" """Example: GlyphClassDef @UPPERCASE, [B], [C], [D];"""
def __init__(self, location, baseGlyphs, markGlyphs, def __init__(self, baseGlyphs, markGlyphs, ligatureGlyphs,
ligatureGlyphs, componentGlyphs): componentGlyphs, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.baseGlyphs, self.markGlyphs = (baseGlyphs, markGlyphs) self.baseGlyphs, self.markGlyphs = (baseGlyphs, markGlyphs)
self.ligatureGlyphs = ligatureGlyphs self.ligatureGlyphs = ligatureGlyphs
@ -328,9 +328,13 @@ class MarkClass(object):
for glyph in definition.glyphSet(): for glyph in definition.glyphSet():
if glyph in self.glyphs: if glyph in self.glyphs:
otherLoc = self.glyphs[glyph].location otherLoc = self.glyphs[glyph].location
if otherLoc is None:
end = ""
else:
end = " at %s:%d:%d" % (
otherLoc[0], otherLoc[1], otherLoc[2])
raise FeatureLibError( raise FeatureLibError(
"Glyph %s already defined at %s:%d:%d" % ( "Glyph %s already defined%s" % (glyph, end),
glyph, otherLoc[0], otherLoc[1], otherLoc[2]),
definition.location) definition.location)
self.glyphs[glyph] = definition self.glyphs[glyph] = definition
@ -343,7 +347,7 @@ class MarkClass(object):
class MarkClassDefinition(Statement): class MarkClassDefinition(Statement):
def __init__(self, location, markClass, anchor, glyphs): def __init__(self, markClass, anchor, glyphs, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
assert isinstance(markClass, MarkClass) assert isinstance(markClass, MarkClass)
assert isinstance(anchor, Anchor) and isinstance(glyphs, Expression) assert isinstance(anchor, Anchor) and isinstance(glyphs, Expression)
@ -359,7 +363,7 @@ class MarkClassDefinition(Statement):
class AlternateSubstStatement(Statement): class AlternateSubstStatement(Statement):
def __init__(self, location, prefix, glyph, suffix, replacement): def __init__(self, prefix, glyph, suffix, replacement, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.prefix, self.glyph, self.suffix = (prefix, glyph, suffix) self.prefix, self.glyph, self.suffix = (prefix, glyph, suffix)
self.replacement = replacement self.replacement = replacement
@ -391,8 +395,8 @@ class AlternateSubstStatement(Statement):
class Anchor(Expression): class Anchor(Expression):
def __init__(self, location, name, x, y, contourpoint, def __init__(self, x, y, name=None, contourpoint=None,
xDeviceTable, yDeviceTable): xDeviceTable=None, yDeviceTable=None, location=None):
Expression.__init__(self, location) Expression.__init__(self, location)
self.name = name self.name = name
self.x, self.y, self.contourpoint = x, y, contourpoint self.x, self.y, self.contourpoint = x, y, contourpoint
@ -414,7 +418,7 @@ class Anchor(Expression):
class AnchorDefinition(Statement): class AnchorDefinition(Statement):
def __init__(self, location, name, x, y, contourpoint): def __init__(self, name, x, y, contourpoint=None, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.name, self.x, self.y, self.contourpoint = name, x, y, contourpoint self.name, self.x, self.y, self.contourpoint = name, x, y, contourpoint
@ -427,7 +431,7 @@ class AnchorDefinition(Statement):
class AttachStatement(Statement): class AttachStatement(Statement):
def __init__(self, location, glyphs, contourPoints): def __init__(self, glyphs, contourPoints, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.glyphs, self.contourPoints = (glyphs, contourPoints) self.glyphs, self.contourPoints = (glyphs, contourPoints)
@ -441,7 +445,7 @@ class AttachStatement(Statement):
class ChainContextPosStatement(Statement): class ChainContextPosStatement(Statement):
def __init__(self, location, prefix, glyphs, suffix, lookups): def __init__(self, prefix, glyphs, suffix, lookups, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix
self.lookups = lookups self.lookups = lookups
@ -473,7 +477,7 @@ class ChainContextPosStatement(Statement):
class ChainContextSubstStatement(Statement): class ChainContextSubstStatement(Statement):
def __init__(self, location, prefix, glyphs, suffix, lookups): def __init__(self, prefix, glyphs, suffix, lookups, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix
self.lookups = lookups self.lookups = lookups
@ -505,7 +509,7 @@ class ChainContextSubstStatement(Statement):
class CursivePosStatement(Statement): class CursivePosStatement(Statement):
def __init__(self, location, glyphclass, entryAnchor, exitAnchor): def __init__(self, glyphclass, entryAnchor, exitAnchor, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.glyphclass = glyphclass self.glyphclass = glyphclass
self.entryAnchor, self.exitAnchor = entryAnchor, exitAnchor self.entryAnchor, self.exitAnchor = entryAnchor, exitAnchor
@ -522,7 +526,7 @@ class CursivePosStatement(Statement):
class FeatureReferenceStatement(Statement): class FeatureReferenceStatement(Statement):
"""Example: feature salt;""" """Example: feature salt;"""
def __init__(self, location, featureName): def __init__(self, featureName, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.location, self.featureName = (location, featureName) self.location, self.featureName = (location, featureName)
@ -534,7 +538,7 @@ class FeatureReferenceStatement(Statement):
class IgnorePosStatement(Statement): class IgnorePosStatement(Statement):
def __init__(self, location, chainContexts): def __init__(self, chainContexts, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.chainContexts = chainContexts self.chainContexts = chainContexts
@ -563,7 +567,7 @@ class IgnorePosStatement(Statement):
class IgnoreSubstStatement(Statement): class IgnoreSubstStatement(Statement):
def __init__(self, location, chainContexts): def __init__(self, chainContexts, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.chainContexts = chainContexts self.chainContexts = chainContexts
@ -592,7 +596,7 @@ class IgnoreSubstStatement(Statement):
class IncludeStatement(Statement): class IncludeStatement(Statement):
def __init__(self, location, filename): def __init__(self, filename, location=None):
super(IncludeStatement, self).__init__(location) super(IncludeStatement, self).__init__(location)
self.filename = filename self.filename = filename
@ -608,7 +612,8 @@ class IncludeStatement(Statement):
class LanguageStatement(Statement): class LanguageStatement(Statement):
def __init__(self, location, language, include_default, required): def __init__(self, language, include_default=True, required=False,
location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
assert(len(language) == 4) assert(len(language) == 4)
self.language = language self.language = language
@ -631,7 +636,7 @@ class LanguageStatement(Statement):
class LanguageSystemStatement(Statement): class LanguageSystemStatement(Statement):
def __init__(self, location, script, language): def __init__(self, script, language, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.script, self.language = (script, language) self.script, self.language = (script, language)
@ -643,7 +648,7 @@ class LanguageSystemStatement(Statement):
class FontRevisionStatement(Statement): class FontRevisionStatement(Statement):
def __init__(self, location, revision): def __init__(self, revision, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.revision = revision self.revision = revision
@ -655,7 +660,7 @@ class FontRevisionStatement(Statement):
class LigatureCaretByIndexStatement(Statement): class LigatureCaretByIndexStatement(Statement):
def __init__(self, location, glyphs, carets): def __init__(self, glyphs, carets, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.glyphs, self.carets = (glyphs, carets) self.glyphs, self.carets = (glyphs, carets)
@ -669,7 +674,7 @@ class LigatureCaretByIndexStatement(Statement):
class LigatureCaretByPosStatement(Statement): class LigatureCaretByPosStatement(Statement):
def __init__(self, location, glyphs, carets): def __init__(self, glyphs, carets, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.glyphs, self.carets = (glyphs, carets) self.glyphs, self.carets = (glyphs, carets)
@ -683,8 +688,8 @@ class LigatureCaretByPosStatement(Statement):
class LigatureSubstStatement(Statement): class LigatureSubstStatement(Statement):
def __init__(self, location, prefix, glyphs, suffix, replacement, def __init__(self, prefix, glyphs, suffix, replacement,
forceChain): forceChain, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.prefix, self.glyphs, self.suffix = (prefix, glyphs, suffix) self.prefix, self.glyphs, self.suffix = (prefix, glyphs, suffix)
self.replacement, self.forceChain = replacement, forceChain self.replacement, self.forceChain = replacement, forceChain
@ -714,7 +719,8 @@ class LigatureSubstStatement(Statement):
class LookupFlagStatement(Statement): class LookupFlagStatement(Statement):
def __init__(self, location, value, markAttachment, markFilteringSet): def __init__(self, value=0, markAttachment=None, markFilteringSet=None,
location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.value = value self.value = value
self.markAttachment = markAttachment self.markAttachment = markAttachment
@ -747,7 +753,7 @@ class LookupFlagStatement(Statement):
class LookupReferenceStatement(Statement): class LookupReferenceStatement(Statement):
def __init__(self, location, lookup): def __init__(self, lookup, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.location, self.lookup = (location, lookup) self.location, self.lookup = (location, lookup)
@ -759,7 +765,7 @@ class LookupReferenceStatement(Statement):
class MarkBasePosStatement(Statement): class MarkBasePosStatement(Statement):
def __init__(self, location, base, marks): def __init__(self, base, marks, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.base, self.marks = base, marks self.base, self.marks = base, marks
@ -775,7 +781,7 @@ class MarkBasePosStatement(Statement):
class MarkLigPosStatement(Statement): class MarkLigPosStatement(Statement):
def __init__(self, location, ligatures, marks): def __init__(self, ligatures, marks, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.ligatures, self.marks = ligatures, marks self.ligatures, self.marks = ligatures, marks
@ -799,7 +805,7 @@ class MarkLigPosStatement(Statement):
class MarkMarkPosStatement(Statement): class MarkMarkPosStatement(Statement):
def __init__(self, location, baseMarks, marks): def __init__(self, baseMarks, marks, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.baseMarks, self.marks = baseMarks, marks self.baseMarks, self.marks = baseMarks, marks
@ -815,7 +821,7 @@ class MarkMarkPosStatement(Statement):
class MultipleSubstStatement(Statement): class MultipleSubstStatement(Statement):
def __init__(self, location, prefix, glyph, suffix, replacement): def __init__(self, prefix, glyph, suffix, replacement, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.prefix, self.glyph, self.suffix = prefix, glyph, suffix self.prefix, self.glyph, self.suffix = prefix, glyph, suffix
self.replacement = replacement self.replacement = replacement
@ -843,8 +849,9 @@ class MultipleSubstStatement(Statement):
class PairPosStatement(Statement): class PairPosStatement(Statement):
def __init__(self, location, enumerated, def __init__(self, enumerated,
glyphs1, valuerecord1, glyphs2, valuerecord2): glyphs1, valuerecord1, glyphs2, valuerecord2,
location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.enumerated = enumerated self.enumerated = enumerated
self.glyphs1, self.valuerecord1 = glyphs1, valuerecord1 self.glyphs1, self.valuerecord1 = glyphs1, valuerecord1
@ -884,7 +891,8 @@ class PairPosStatement(Statement):
class ReverseChainSingleSubstStatement(Statement): class ReverseChainSingleSubstStatement(Statement):
def __init__(self, location, old_prefix, old_suffix, glyphs, replacements): def __init__(self, old_prefix, old_suffix, glyphs, replacements,
location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.old_prefix, self.old_suffix = old_prefix, old_suffix self.old_prefix, self.old_suffix = old_prefix, old_suffix
self.glyphs = glyphs self.glyphs = glyphs
@ -915,7 +923,8 @@ class ReverseChainSingleSubstStatement(Statement):
class SingleSubstStatement(Statement): class SingleSubstStatement(Statement):
def __init__(self, location, glyphs, replace, prefix, suffix, forceChain): def __init__(self, glyphs, replace, prefix, suffix, forceChain,
location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.prefix, self.suffix = prefix, suffix self.prefix, self.suffix = prefix, suffix
self.forceChain = forceChain self.forceChain = forceChain
@ -948,7 +957,7 @@ class SingleSubstStatement(Statement):
class ScriptStatement(Statement): class ScriptStatement(Statement):
def __init__(self, location, script): def __init__(self, script, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.script = script self.script = script
@ -960,7 +969,7 @@ class ScriptStatement(Statement):
class SinglePosStatement(Statement): class SinglePosStatement(Statement):
def __init__(self, location, pos, prefix, suffix, forceChain): def __init__(self, pos, prefix, suffix, forceChain, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.pos, self.prefix, self.suffix = pos, prefix, suffix self.pos, self.prefix, self.suffix = pos, prefix, suffix
self.forceChain = forceChain self.forceChain = forceChain
@ -989,14 +998,16 @@ class SinglePosStatement(Statement):
class SubtableStatement(Statement): class SubtableStatement(Statement):
def __init__(self, location): def __init__(self, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
class ValueRecord(Expression): class ValueRecord(Expression):
def __init__(self, location, vertical, def __init__(self, xPlacement=None, yPlacement=None,
xPlacement, yPlacement, xAdvance, yAdvance, xAdvance=None, yAdvance=None,
xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice): xPlaDevice=None, yPlaDevice=None,
xAdvDevice=None, yAdvDevice=None,
vertical=False, location=None):
Expression.__init__(self, location) Expression.__init__(self, location)
self.xPlacement, self.yPlacement = (xPlacement, yPlacement) self.xPlacement, self.yPlacement = (xPlacement, yPlacement)
self.xAdvance, self.yAdvance = (xAdvance, yAdvance) self.xAdvance, self.yAdvance = (xAdvance, yAdvance)
@ -1049,7 +1060,7 @@ class ValueRecord(Expression):
class ValueRecordDefinition(Statement): class ValueRecordDefinition(Statement):
def __init__(self, location, name, value): def __init__(self, name, value, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.name = name self.name = name
self.value = value self.value = value
@ -1068,8 +1079,8 @@ def simplify_name_attributes(pid, eid, lid):
class NameRecord(Statement): class NameRecord(Statement):
def __init__(self, location, nameID, platformID, def __init__(self, nameID, platformID, platEncID, langID, string,
platEncID, langID, string): location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.nameID = nameID self.nameID = nameID
self.platformID = platformID self.platformID = platformID
@ -1123,8 +1134,8 @@ class FeatureNameStatement(NameRecord):
class SizeParameters(Statement): class SizeParameters(Statement):
def __init__(self, location, DesignSize, SubfamilyID, RangeStart, def __init__(self, DesignSize, SubfamilyID, RangeStart, RangeEnd,
RangeEnd): location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.DesignSize = DesignSize self.DesignSize = DesignSize
self.SubfamilyID = SubfamilyID self.SubfamilyID = SubfamilyID
@ -1143,7 +1154,7 @@ class SizeParameters(Statement):
class BaseAxis(Statement): class BaseAxis(Statement):
def __init__(self, location, bases, scripts, vertical): def __init__(self, bases, scripts, vertical, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.bases = bases self.bases = bases
self.scripts = scripts self.scripts = scripts
@ -1160,7 +1171,7 @@ class BaseAxis(Statement):
class OS2Field(Statement): class OS2Field(Statement):
def __init__(self, location, key, value): def __init__(self, key, value, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.key = key self.key = key
self.value = value self.value = value
@ -1185,7 +1196,7 @@ class OS2Field(Statement):
class HheaField(Statement): class HheaField(Statement):
def __init__(self, location, key, value): def __init__(self, key, value, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.key = key self.key = key
self.value = value self.value = value
@ -1200,7 +1211,7 @@ class HheaField(Statement):
class VheaField(Statement): class VheaField(Statement):
def __init__(self, location, key, value): def __init__(self, key, value, location=None):
Statement.__init__(self, location) Statement.__init__(self, location)
self.key = key self.key = key
self.value = value self.value = value

View File

@ -52,7 +52,9 @@ class Parser(object):
while self.next_token_type_ is not None or self.cur_comments_: while self.next_token_type_ is not None or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(
self.ast.Comment(self.cur_token_,
location=self.cur_token_location_))
elif self.is_cur_keyword_("include"): elif self.is_cur_keyword_("include"):
statements.append(self.parse_include_()) statements.append(self.parse_include_())
elif self.cur_token_type_ is Lexer.GLYPHCLASS: elif self.cur_token_type_ is Lexer.GLYPHCLASS:
@ -103,9 +105,11 @@ class Parser(object):
'Unknown anchor "%s"' % name, 'Unknown anchor "%s"' % name,
self.cur_token_location_) self.cur_token_location_)
self.expect_symbol_(">") self.expect_symbol_(">")
return self.ast.Anchor(location, name, anchordef.x, anchordef.y, return self.ast.Anchor(anchordef.x, anchordef.y,
anchordef.contourpoint, name=name,
xDeviceTable=None, yDeviceTable=None) contourpoint=anchordef.contourpoint,
xDeviceTable=None, yDeviceTable=None,
location=location)
x, y = self.expect_number_(), self.expect_number_() x, y = self.expect_number_(), self.expect_number_()
@ -121,8 +125,11 @@ class Parser(object):
xDeviceTable, yDeviceTable = None, None xDeviceTable, yDeviceTable = None, None
self.expect_symbol_(">") self.expect_symbol_(">")
return self.ast.Anchor(location, None, x, y, contourpoint, return self.ast.Anchor(x, y, name=None,
xDeviceTable, yDeviceTable) contourpoint=contourpoint,
xDeviceTable=xDeviceTable,
yDeviceTable=yDeviceTable,
location=location)
def parse_anchor_marks_(self): def parse_anchor_marks_(self):
"""Parses a sequence of [<anchor> mark @MARKCLASS]*.""" """Parses a sequence of [<anchor> mark @MARKCLASS]*."""
@ -146,7 +153,9 @@ class Parser(object):
contourpoint = self.expect_number_() contourpoint = self.expect_number_()
name = self.expect_name_() name = self.expect_name_()
self.expect_symbol_(";") self.expect_symbol_(";")
anchordef = self.ast.AnchorDefinition(location, name, x, y, contourpoint) anchordef = self.ast.AnchorDefinition(name, x, y,
contourpoint=contourpoint,
location=location)
self.anchors_.define(name, anchordef) self.anchors_.define(name, anchordef)
return anchordef return anchordef
@ -159,7 +168,7 @@ class Parser(object):
end_tag = self.expect_tag_() end_tag = self.expect_tag_()
assert tag == end_tag, "bad splitting in Lexer.scan_anonymous_block()" assert tag == end_tag, "bad splitting in Lexer.scan_anonymous_block()"
self.expect_symbol_(';') self.expect_symbol_(';')
return self.ast.AnonymousBlock(tag, content, location) return self.ast.AnonymousBlock(tag, content, location=location)
def parse_attach_(self): def parse_attach_(self):
assert self.is_cur_keyword_("Attach") assert self.is_cur_keyword_("Attach")
@ -169,7 +178,8 @@ class Parser(object):
while self.next_token_ != ";": while self.next_token_ != ";":
contourPoints.add(self.expect_number_()) contourPoints.add(self.expect_number_())
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.AttachStatement(location, glyphs, contourPoints) return self.ast.AttachStatement(glyphs, contourPoints,
location=location)
def parse_enumerate_(self, vertical): def parse_enumerate_(self, vertical):
assert self.cur_token_ in {"enumerate", "enum"} assert self.cur_token_ in {"enumerate", "enum"}
@ -200,8 +210,9 @@ class Parser(object):
else: else:
componentGlyphs = None componentGlyphs = None
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.GlyphClassDefStatement(location, baseGlyphs, markGlyphs, return self.ast.GlyphClassDefStatement(baseGlyphs, markGlyphs,
ligatureGlyphs, componentGlyphs) ligatureGlyphs, componentGlyphs,
location=location)
def parse_glyphclass_definition_(self): def parse_glyphclass_definition_(self):
"""Parses glyph class definitions such as '@UPPERCASE = [A-Z];'""" """Parses glyph class definitions such as '@UPPERCASE = [A-Z];'"""
@ -209,7 +220,8 @@ class Parser(object):
self.expect_symbol_("=") self.expect_symbol_("=")
glyphs = self.parse_glyphclass_(accept_glyphname=False) glyphs = self.parse_glyphclass_(accept_glyphname=False)
self.expect_symbol_(";") self.expect_symbol_(";")
glyphclass = self.ast.GlyphClassDefinition(location, name, glyphs) glyphclass = self.ast.GlyphClassDefinition(name, glyphs,
location=location)
self.glyphclasses_.define(name, glyphclass) self.glyphclasses_.define(name, glyphclass)
return glyphclass return glyphclass
@ -256,7 +268,7 @@ class Parser(object):
if (accept_glyphname and if (accept_glyphname and
self.next_token_type_ in (Lexer.NAME, Lexer.CID)): self.next_token_type_ in (Lexer.NAME, Lexer.CID)):
glyph = self.expect_glyph_() glyph = self.expect_glyph_()
return self.ast.GlyphName(self.cur_token_location_, glyph) return self.ast.GlyphName(glyph, location=self.cur_token_location_)
if self.next_token_type_ is Lexer.GLYPHCLASS: if self.next_token_type_ is Lexer.GLYPHCLASS:
self.advance_lexer_() self.advance_lexer_()
gc = self.glyphclasses_.resolve(self.cur_token_) gc = self.glyphclasses_.resolve(self.cur_token_)
@ -265,13 +277,15 @@ class Parser(object):
"Unknown glyph class @%s" % self.cur_token_, "Unknown glyph class @%s" % self.cur_token_,
self.cur_token_location_) self.cur_token_location_)
if isinstance(gc, self.ast.MarkClass): if isinstance(gc, self.ast.MarkClass):
return self.ast.MarkClassName(self.cur_token_location_, gc) return self.ast.MarkClassName(
gc, location=self.cur_token_location_)
else: else:
return self.ast.GlyphClassName(self.cur_token_location_, gc) return self.ast.GlyphClassName(
gc, location=self.cur_token_location_)
self.expect_symbol_("[") self.expect_symbol_("[")
location = self.cur_token_location_ location = self.cur_token_location_
glyphs = self.ast.GlyphClass(location) glyphs = self.ast.GlyphClass(location=location)
while self.next_token_ != "]": while self.next_token_ != "]":
if self.next_token_type_ is Lexer.NAME: if self.next_token_type_ is Lexer.NAME:
glyph = self.expect_glyph_() glyph = self.expect_glyph_()
@ -310,9 +324,11 @@ class Parser(object):
"Unknown glyph class @%s" % self.cur_token_, "Unknown glyph class @%s" % self.cur_token_,
self.cur_token_location_) self.cur_token_location_)
if isinstance(gc, self.ast.MarkClass): if isinstance(gc, self.ast.MarkClass):
gc = self.ast.MarkClassName(self.cur_token_location_, gc) gc = self.ast.MarkClassName(
gc, location=self.cur_token_location_)
else: else:
gc = self.ast.GlyphClassName(self.cur_token_location_, gc) gc = self.ast.GlyphClassName(
gc, location=self.cur_token_location_)
glyphs.add_class(gc) glyphs.add_class(gc)
else: else:
raise FeatureLibError( raise FeatureLibError(
@ -330,9 +346,11 @@ class Parser(object):
"Unknown glyph class @%s" % name, "Unknown glyph class @%s" % name,
self.cur_token_location_) self.cur_token_location_)
if isinstance(gc, self.ast.MarkClass): if isinstance(gc, self.ast.MarkClass):
return self.ast.MarkClassName(self.cur_token_location_, gc) return self.ast.MarkClassName(
gc, location=self.cur_token_location_)
else: else:
return self.ast.GlyphClassName(self.cur_token_location_, gc) return self.ast.GlyphClassName(
gc, location=self.cur_token_location_)
def parse_glyph_pattern_(self, vertical): def parse_glyph_pattern_(self, vertical):
prefix, glyphs, lookups, values, suffix = ([], [], [], [], []) prefix, glyphs, lookups, values, suffix = ([], [], [], [], [])
@ -412,14 +430,16 @@ class Parser(object):
raise FeatureLibError( raise FeatureLibError(
"No lookups can be specified for \"ignore sub\"", "No lookups can be specified for \"ignore sub\"",
location) location)
return self.ast.IgnoreSubstStatement(location, chainContext) return self.ast.IgnoreSubstStatement(chainContext,
location=location)
if self.cur_token_ in ["position", "pos"]: if self.cur_token_ in ["position", "pos"]:
chainContext, hasLookups = self.parse_chain_context_() chainContext, hasLookups = self.parse_chain_context_()
if hasLookups: if hasLookups:
raise FeatureLibError( raise FeatureLibError(
"No lookups can be specified for \"ignore pos\"", "No lookups can be specified for \"ignore pos\"",
location) location)
return self.ast.IgnorePosStatement(location, chainContext) return self.ast.IgnorePosStatement(chainContext,
location=location)
raise FeatureLibError( raise FeatureLibError(
"Expected \"substitute\" or \"position\"", "Expected \"substitute\" or \"position\"",
self.cur_token_location_) self.cur_token_location_)
@ -429,7 +449,7 @@ class Parser(object):
location = self.cur_token_location_ location = self.cur_token_location_
filename = self.expect_filename_() filename = self.expect_filename_()
# self.expect_symbol_(";") # self.expect_symbol_(";")
return ast.IncludeStatement(location, filename) return ast.IncludeStatement(filename, location=location)
def parse_language_(self): def parse_language_(self):
assert self.is_cur_keyword_("language") assert self.is_cur_keyword_("language")
@ -442,8 +462,9 @@ class Parser(object):
self.expect_keyword_("required") self.expect_keyword_("required")
required = True required = True
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.LanguageStatement(location, language, return self.ast.LanguageStatement(language,
include_default, required) include_default, required,
location=location)
def parse_ligatureCaretByIndex_(self): def parse_ligatureCaretByIndex_(self):
assert self.is_cur_keyword_("LigatureCaretByIndex") assert self.is_cur_keyword_("LigatureCaretByIndex")
@ -453,7 +474,8 @@ class Parser(object):
while self.next_token_ != ";": while self.next_token_ != ";":
carets.append(self.expect_number_()) carets.append(self.expect_number_())
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.LigatureCaretByIndexStatement(location, glyphs, carets) return self.ast.LigatureCaretByIndexStatement(glyphs, carets,
location=location)
def parse_ligatureCaretByPos_(self): def parse_ligatureCaretByPos_(self):
assert self.is_cur_keyword_("LigatureCaretByPos") assert self.is_cur_keyword_("LigatureCaretByPos")
@ -463,7 +485,8 @@ class Parser(object):
while self.next_token_ != ";": while self.next_token_ != ";":
carets.append(self.expect_number_()) carets.append(self.expect_number_())
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.LigatureCaretByPosStatement(location, glyphs, carets) return self.ast.LigatureCaretByPosStatement(glyphs, carets,
location=location)
def parse_lookup_(self, vertical): def parse_lookup_(self, vertical):
assert self.is_cur_keyword_("lookup") assert self.is_cur_keyword_("lookup")
@ -475,14 +498,15 @@ class Parser(object):
raise FeatureLibError("Unknown lookup \"%s\"" % name, raise FeatureLibError("Unknown lookup \"%s\"" % name,
self.cur_token_location_) self.cur_token_location_)
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.LookupReferenceStatement(location, lookup) return self.ast.LookupReferenceStatement(lookup,
location=location)
use_extension = False use_extension = False
if self.next_token_ == "useExtension": if self.next_token_ == "useExtension":
self.expect_keyword_("useExtension") self.expect_keyword_("useExtension")
use_extension = True use_extension = True
block = self.ast.LookupBlock(location, name, use_extension) block = self.ast.LookupBlock(name, use_extension, location=location)
self.parse_block_(block, vertical) self.parse_block_(block, vertical)
self.lookups_.define(name, block) self.lookups_.define(name, block)
return block return block
@ -495,7 +519,7 @@ class Parser(object):
if self.next_token_type_ == Lexer.NUMBER: if self.next_token_type_ == Lexer.NUMBER:
value = self.expect_number_() value = self.expect_number_()
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.LookupFlagStatement(location, value, None, None) return self.ast.LookupFlagStatement(value, location=location)
# format A: "lookupflag RightToLeft MarkAttachmentType @M;" # format A: "lookupflag RightToLeft MarkAttachmentType @M;"
value, markAttachment, markFilteringSet = 0, None, None value, markAttachment, markFilteringSet = 0, None, None
@ -523,8 +547,10 @@ class Parser(object):
'"%s" is not a recognized lookupflag' % self.next_token_, '"%s" is not a recognized lookupflag' % self.next_token_,
self.next_token_location_) self.next_token_location_)
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.LookupFlagStatement(location, value, return self.ast.LookupFlagStatement(value,
markAttachment, markFilteringSet) markAttachment=markAttachment,
markFilteringSet=markFilteringSet,
location=location)
def parse_markClass_(self): def parse_markClass_(self):
assert self.is_cur_keyword_("markClass") assert self.is_cur_keyword_("markClass")
@ -538,7 +564,8 @@ class Parser(object):
markClass = self.ast.MarkClass(name) markClass = self.ast.MarkClass(name)
self.doc_.markClasses[name] = markClass self.doc_.markClasses[name] = markClass
self.glyphclasses_.define(name, markClass) self.glyphclasses_.define(name, markClass)
mcdef = self.ast.MarkClassDefinition(location, markClass, anchor, glyphs) mcdef = self.ast.MarkClassDefinition(markClass, anchor, glyphs,
location=location)
markClass.addDefinition(mcdef) markClass.addDefinition(mcdef)
return mcdef return mcdef
@ -565,7 +592,7 @@ class Parser(object):
"If \"lookup\" is present, no values must be specified", "If \"lookup\" is present, no values must be specified",
location) location)
return self.ast.ChainContextPosStatement( return self.ast.ChainContextPosStatement(
location, prefix, glyphs, suffix, lookups) prefix, glyphs, suffix, lookups, location=location)
# Pair positioning, format A: "pos V 10 A -10;" # Pair positioning, format A: "pos V 10 A -10;"
# Pair positioning, format B: "pos V A -20;" # Pair positioning, format B: "pos V A -20;"
@ -573,14 +600,16 @@ class Parser(object):
if values[0] is None: # Format B: "pos V A -20;" if values[0] is None: # Format B: "pos V A -20;"
values.reverse() values.reverse()
return self.ast.PairPosStatement( return self.ast.PairPosStatement(
location, enumerated, enumerated,
glyphs[0], values[0], glyphs[1], values[1]) glyphs[0], values[0], glyphs[1], values[1],
location=location)
if enumerated: if enumerated:
raise FeatureLibError( raise FeatureLibError(
'"enumerate" is only allowed with pair positionings', location) '"enumerate" is only allowed with pair positionings', location)
return self.ast.SinglePosStatement(location, list(zip(glyphs, values)), return self.ast.SinglePosStatement(list(zip(glyphs, values)),
prefix, suffix, forceChain=hasMarks) prefix, suffix, forceChain=hasMarks,
location=location)
def parse_position_cursive_(self, enumerated, vertical): def parse_position_cursive_(self, enumerated, vertical):
location = self.cur_token_location_ location = self.cur_token_location_
@ -595,7 +624,7 @@ class Parser(object):
exitAnchor = self.parse_anchor_() exitAnchor = self.parse_anchor_()
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.CursivePosStatement( return self.ast.CursivePosStatement(
location, glyphclass, entryAnchor, exitAnchor) glyphclass, entryAnchor, exitAnchor, location=location)
def parse_position_base_(self, enumerated, vertical): def parse_position_base_(self, enumerated, vertical):
location = self.cur_token_location_ location = self.cur_token_location_
@ -608,7 +637,7 @@ class Parser(object):
base = self.parse_glyphclass_(accept_glyphname=True) base = self.parse_glyphclass_(accept_glyphname=True)
marks = self.parse_anchor_marks_() marks = self.parse_anchor_marks_()
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.MarkBasePosStatement(location, base, marks) return self.ast.MarkBasePosStatement(base, marks, location=location)
def parse_position_ligature_(self, enumerated, vertical): def parse_position_ligature_(self, enumerated, vertical):
location = self.cur_token_location_ location = self.cur_token_location_
@ -624,7 +653,7 @@ class Parser(object):
self.expect_keyword_("ligComponent") self.expect_keyword_("ligComponent")
marks.append(self.parse_anchor_marks_()) marks.append(self.parse_anchor_marks_())
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.MarkLigPosStatement(location, ligatures, marks) return self.ast.MarkLigPosStatement(ligatures, marks, location=location)
def parse_position_mark_(self, enumerated, vertical): def parse_position_mark_(self, enumerated, vertical):
location = self.cur_token_location_ location = self.cur_token_location_
@ -637,13 +666,14 @@ class Parser(object):
baseMarks = self.parse_glyphclass_(accept_glyphname=True) baseMarks = self.parse_glyphclass_(accept_glyphname=True)
marks = self.parse_anchor_marks_() marks = self.parse_anchor_marks_()
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.MarkMarkPosStatement(location, baseMarks, marks) return self.ast.MarkMarkPosStatement(baseMarks, marks,
location=location)
def parse_script_(self): def parse_script_(self):
assert self.is_cur_keyword_("script") assert self.is_cur_keyword_("script")
location, script = self.cur_token_location_, self.expect_script_tag_() location, script = self.cur_token_location_, self.expect_script_tag_()
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.ScriptStatement(location, script) return self.ast.ScriptStatement(script, location=location)
def parse_substitute_(self): def parse_substitute_(self):
assert self.cur_token_ in {"substitute", "sub", "reversesub", "rsub"} assert self.cur_token_ in {"substitute", "sub", "reversesub", "rsub"}
@ -687,7 +717,7 @@ class Parser(object):
'Expected a single glyphclass after "from"', 'Expected a single glyphclass after "from"',
location) location)
return self.ast.AlternateSubstStatement( return self.ast.AlternateSubstStatement(
location, old_prefix, old[0], old_suffix, new[0]) old_prefix, old[0], old_suffix, new[0], location=location)
num_lookups = len([l for l in lookups if l is not None]) num_lookups = len([l for l in lookups if l is not None])
@ -707,9 +737,10 @@ class Parser(object):
'but found a glyph class with %d elements' % 'but found a glyph class with %d elements' %
(len(glyphs), len(replacements)), location) (len(glyphs), len(replacements)), location)
return self.ast.SingleSubstStatement( return self.ast.SingleSubstStatement(
location, old, new, old, new,
old_prefix, old_suffix, old_prefix, old_suffix,
forceChain=hasMarks forceChain=hasMarks,
location=location
) )
# GSUB lookup type 2: Multiple substitution. # GSUB lookup type 2: Multiple substitution.
@ -719,8 +750,8 @@ class Parser(object):
len(new) > 1 and max([len(n.glyphSet()) for n in new]) == 1 and len(new) > 1 and max([len(n.glyphSet()) for n in new]) == 1 and
num_lookups == 0): num_lookups == 0):
return self.ast.MultipleSubstStatement( return self.ast.MultipleSubstStatement(
location, old_prefix, tuple(old[0].glyphSet())[0], old_suffix, old_prefix, tuple(old[0].glyphSet())[0], old_suffix,
tuple([list(n.glyphSet())[0] for n in new])) tuple([list(n.glyphSet())[0] for n in new]), location=location)
# GSUB lookup type 4: Ligature substitution. # GSUB lookup type 4: Ligature substitution.
# Format: "substitute f f i by f_f_i;" # Format: "substitute f f i by f_f_i;"
@ -729,8 +760,9 @@ class Parser(object):
len(new[0].glyphSet()) == 1 and len(new[0].glyphSet()) == 1 and
num_lookups == 0): num_lookups == 0):
return self.ast.LigatureSubstStatement( return self.ast.LigatureSubstStatement(
location, old_prefix, old, old_suffix, old_prefix, old, old_suffix,
list(new[0].glyphSet())[0], forceChain=hasMarks) list(new[0].glyphSet())[0], forceChain=hasMarks,
location=location)
# GSUB lookup type 8: Reverse chaining substitution. # GSUB lookup type 8: Reverse chaining substitution.
if reverse: if reverse:
@ -758,7 +790,7 @@ class Parser(object):
'but found a glyph class with %d elements' % 'but found a glyph class with %d elements' %
(len(glyphs), len(replacements)), location) (len(glyphs), len(replacements)), location)
return self.ast.ReverseChainSingleSubstStatement( return self.ast.ReverseChainSingleSubstStatement(
location, old_prefix, old_suffix, old, new) old_prefix, old_suffix, old, new, location=location)
if len(old) > 1 and len(new) > 1: if len(old) > 1 and len(new) > 1:
raise FeatureLibError( raise FeatureLibError(
@ -769,14 +801,14 @@ class Parser(object):
# GSUB lookup type 6: Chaining contextual substitution. # GSUB lookup type 6: Chaining contextual substitution.
assert len(new) == 0, new assert len(new) == 0, new
rule = self.ast.ChainContextSubstStatement( rule = self.ast.ChainContextSubstStatement(
location, old_prefix, old, old_suffix, lookups) old_prefix, old, old_suffix, lookups, location=location)
return rule return rule
def parse_subtable_(self): def parse_subtable_(self):
assert self.is_cur_keyword_("subtable") assert self.is_cur_keyword_("subtable")
location = self.cur_token_location_ location = self.cur_token_location_
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.SubtableStatement(location) return self.ast.SubtableStatement(location=location)
def parse_size_parameters_(self): def parse_size_parameters_(self):
assert self.is_cur_keyword_("parameters") assert self.is_cur_keyword_("parameters")
@ -791,20 +823,22 @@ class Parser(object):
RangeEnd = self.expect_decipoint_() RangeEnd = self.expect_decipoint_()
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.SizeParameters(location, DesignSize, SubfamilyID, return self.ast.SizeParameters(DesignSize, SubfamilyID,
RangeStart, RangeEnd) RangeStart, RangeEnd,
location=location)
def parse_size_menuname_(self): def parse_size_menuname_(self):
assert self.is_cur_keyword_("sizemenuname") assert self.is_cur_keyword_("sizemenuname")
location = self.cur_token_location_ location = self.cur_token_location_
platformID, platEncID, langID, string = self.parse_name_() platformID, platEncID, langID, string = self.parse_name_()
return self.ast.FeatureNameStatement(location, "size", platformID, return self.ast.FeatureNameStatement("size", platformID,
platEncID, langID, string) platEncID, langID, string,
location=location)
def parse_table_(self): def parse_table_(self):
assert self.is_cur_keyword_("table") assert self.is_cur_keyword_("table")
location, name = self.cur_token_location_, self.expect_tag_() location, name = self.cur_token_location_, self.expect_tag_()
table = self.ast.TableBlock(location, name) table = self.ast.TableBlock(name, location=location)
self.expect_symbol_("{") self.expect_symbol_("{")
handler = { handler = {
"GDEF": self.parse_table_GDEF_, "GDEF": self.parse_table_GDEF_,
@ -833,7 +867,8 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.is_cur_keyword_("Attach"): elif self.is_cur_keyword_("Attach"):
statements.append(self.parse_attach_()) statements.append(self.parse_attach_())
elif self.is_cur_keyword_("GlyphClassDef"): elif self.is_cur_keyword_("GlyphClassDef"):
@ -855,7 +890,8 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.is_cur_keyword_("FontRevision"): elif self.is_cur_keyword_("FontRevision"):
statements.append(self.parse_FontRevision_()) statements.append(self.parse_FontRevision_())
elif self.cur_token_ == ";": elif self.cur_token_ == ";":
@ -870,12 +906,14 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in fields: elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in fields:
key = self.cur_token_.lower() key = self.cur_token_.lower()
value = self.expect_number_() value = self.expect_number_()
statements.append( statements.append(
self.ast.HheaField(self.cur_token_location_, key, value)) self.ast.HheaField(key, value,
location=self.cur_token_location_))
if self.next_token_ != ";": if self.next_token_ != ";":
raise FeatureLibError("Incomplete statement", self.next_token_location_) raise FeatureLibError("Incomplete statement", self.next_token_location_)
elif self.cur_token_ == ";": elif self.cur_token_ == ";":
@ -891,12 +929,14 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in fields: elif self.cur_token_type_ is Lexer.NAME and self.cur_token_ in fields:
key = self.cur_token_.lower() key = self.cur_token_.lower()
value = self.expect_number_() value = self.expect_number_()
statements.append( statements.append(
self.ast.VheaField(self.cur_token_location_, key, value)) self.ast.VheaField(key, value,
location=self.cur_token_location_))
if self.next_token_ != ";": if self.next_token_ != ";":
raise FeatureLibError("Incomplete statement", self.next_token_location_) raise FeatureLibError("Incomplete statement", self.next_token_location_)
elif self.cur_token_ == ";": elif self.cur_token_ == ";":
@ -911,7 +951,8 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.is_cur_keyword_("nameid"): elif self.is_cur_keyword_("nameid"):
statement = self.parse_nameid_() statement = self.parse_nameid_()
if statement: if statement:
@ -966,8 +1007,8 @@ class Parser(object):
return None return None
platformID, platEncID, langID, string = self.parse_name_() platformID, platEncID, langID, string = self.parse_name_()
return self.ast.NameRecord(location, nameID, platformID, platEncID, return self.ast.NameRecord(nameID, platformID, platEncID,
langID, string) langID, string, location=location)
def unescape_string_(self, string, encoding): def unescape_string_(self, string, encoding):
if encoding == "utf_16_be": if encoding == "utf_16_be":
@ -996,21 +1037,24 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.is_cur_keyword_("HorizAxis.BaseTagList"): elif self.is_cur_keyword_("HorizAxis.BaseTagList"):
horiz_bases = self.parse_base_tag_list_() horiz_bases = self.parse_base_tag_list_()
elif self.is_cur_keyword_("HorizAxis.BaseScriptList"): elif self.is_cur_keyword_("HorizAxis.BaseScriptList"):
horiz_scripts = self.parse_base_script_list_(len(horiz_bases)) horiz_scripts = self.parse_base_script_list_(len(horiz_bases))
statements.append( statements.append(
self.ast.BaseAxis(self.cur_token_location_, horiz_bases, self.ast.BaseAxis(horiz_bases,
horiz_scripts, False)) horiz_scripts, False,
location=self.cur_token_location_))
elif self.is_cur_keyword_("VertAxis.BaseTagList"): elif self.is_cur_keyword_("VertAxis.BaseTagList"):
vert_bases = self.parse_base_tag_list_() vert_bases = self.parse_base_tag_list_()
elif self.is_cur_keyword_("VertAxis.BaseScriptList"): elif self.is_cur_keyword_("VertAxis.BaseScriptList"):
vert_scripts = self.parse_base_script_list_(len(vert_bases)) vert_scripts = self.parse_base_script_list_(len(vert_bases))
statements.append( statements.append(
self.ast.BaseAxis(self.cur_token_location_, vert_bases, self.ast.BaseAxis(vert_bases,
vert_scripts, True)) vert_scripts, True,
location=self.cur_token_location_))
elif self.cur_token_ == ";": elif self.cur_token_ == ";":
continue continue
@ -1023,7 +1067,8 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.cur_token_type_ is Lexer.NAME: elif self.cur_token_type_ is Lexer.NAME:
key = self.cur_token_.lower() key = self.cur_token_.lower()
value = None value = None
@ -1040,7 +1085,8 @@ class Parser(object):
elif self.is_cur_keyword_("Vendor"): elif self.is_cur_keyword_("Vendor"):
value = self.expect_string_() value = self.expect_string_()
statements.append( statements.append(
self.ast.OS2Field(self.cur_token_location_, key, value)) self.ast.OS2Field(key, value,
location=self.cur_token_location_))
elif self.cur_token_ == ";": elif self.cur_token_ == ";":
continue continue
@ -1091,13 +1137,13 @@ class Parser(object):
if self.next_token_type_ is Lexer.NUMBER: if self.next_token_type_ is Lexer.NUMBER:
number, location = self.expect_number_(), self.cur_token_location_ number, location = self.expect_number_(), self.cur_token_location_
if vertical: if vertical:
val = self.ast.ValueRecord(location, vertical, val = self.ast.ValueRecord(yAdvance=number,
None, None, None, number, vertical=vertical,
None, None, None, None) location=location)
else: else:
val = self.ast.ValueRecord(location, vertical, val = self.ast.ValueRecord(xAdvance=number,
None, None, number, None, vertical=vertical,
None, None, None, None) location=location)
return val return val
self.expect_symbol_("<") self.expect_symbol_("<")
location = self.cur_token_location_ location = self.cur_token_location_
@ -1139,8 +1185,9 @@ class Parser(object):
self.expect_symbol_(">") self.expect_symbol_(">")
return self.ast.ValueRecord( return self.ast.ValueRecord(
location, vertical, xPlacement, yPlacement, xAdvance, yAdvance, xPlacement, yPlacement, xAdvance, yAdvance,
xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice) xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice,
vertical=vertical, location=location)
def parse_valuerecord_definition_(self, vertical): def parse_valuerecord_definition_(self, vertical):
assert self.is_cur_keyword_("valueRecordDef") assert self.is_cur_keyword_("valueRecordDef")
@ -1148,7 +1195,7 @@ class Parser(object):
value = self.parse_valuerecord_(vertical) value = self.parse_valuerecord_(vertical)
name = self.expect_name_() name = self.expect_name_()
self.expect_symbol_(";") self.expect_symbol_(";")
vrd = self.ast.ValueRecordDefinition(location, name, value) vrd = self.ast.ValueRecordDefinition(name, value, location=location)
self.valuerecords_.define(name, vrd) self.valuerecords_.define(name, vrd)
return vrd return vrd
@ -1162,7 +1209,8 @@ class Parser(object):
raise FeatureLibError( raise FeatureLibError(
'For script "DFLT", the language must be "dflt"', 'For script "DFLT", the language must be "dflt"',
self.cur_token_location_) self.cur_token_location_)
return self.ast.LanguageSystemStatement(location, script, language) return self.ast.LanguageSystemStatement(script, language,
location=location)
def parse_feature_block_(self): def parse_feature_block_(self):
assert self.cur_token_ == "feature" assert self.cur_token_ == "feature"
@ -1180,7 +1228,8 @@ class Parser(object):
self.expect_keyword_("useExtension") self.expect_keyword_("useExtension")
use_extension = True use_extension = True
block = self.ast.FeatureBlock(location, tag, use_extension) block = self.ast.FeatureBlock(tag, use_extension=use_extension,
location=location)
self.parse_block_(block, vertical, stylisticset, size_feature) self.parse_block_(block, vertical, stylisticset, size_feature)
return block return block
@ -1189,7 +1238,8 @@ class Parser(object):
location = self.cur_token_location_ location = self.cur_token_location_
featureName = self.expect_tag_() featureName = self.expect_tag_()
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.FeatureReferenceStatement(location, featureName) return self.ast.FeatureReferenceStatement(featureName,
location=location)
def parse_featureNames_(self, tag): def parse_featureNames_(self, tag):
assert self.cur_token_ == "featureNames", self.cur_token_ assert self.cur_token_ == "featureNames", self.cur_token_
@ -1200,13 +1250,15 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
block.statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) block.statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.is_cur_keyword_("name"): elif self.is_cur_keyword_("name"):
location = self.cur_token_location_ location = self.cur_token_location_
platformID, platEncID, langID, string = self.parse_name_() platformID, platEncID, langID, string = self.parse_name_()
block.statements.append( block.statements.append(
self.ast.FeatureNameStatement(location, tag, platformID, self.ast.FeatureNameStatement(tag, platformID,
platEncID, langID, string)) platEncID, langID, string,
location=location))
elif self.cur_token_ == ";": elif self.cur_token_ == ";":
continue continue
else: else:
@ -1225,7 +1277,7 @@ class Parser(object):
if version <= 0: if version <= 0:
raise FeatureLibError("Font revision numbers must be positive", raise FeatureLibError("Font revision numbers must be positive",
location) location)
return self.ast.FontRevisionStatement(location, version) return self.ast.FontRevisionStatement(version, location=location)
def parse_block_(self, block, vertical, stylisticset=None, def parse_block_(self, block, vertical, stylisticset=None,
size_feature=False): size_feature=False):
@ -1237,7 +1289,8 @@ class Parser(object):
while self.next_token_ != "}" or self.cur_comments_: while self.next_token_ != "}" or self.cur_comments_:
self.advance_lexer_(comments=True) self.advance_lexer_(comments=True)
if self.cur_token_type_ is Lexer.COMMENT: if self.cur_token_type_ is Lexer.COMMENT:
statements.append(self.ast.Comment(self.cur_token_location_, self.cur_token_)) statements.append(self.ast.Comment(
self.cur_token_, location=self.cur_token_location_))
elif self.cur_token_type_ is Lexer.GLYPHCLASS: elif self.cur_token_type_ is Lexer.GLYPHCLASS:
statements.append(self.parse_glyphclass_definition_()) statements.append(self.parse_glyphclass_definition_())
elif self.is_cur_keyword_("anchorDef"): elif self.is_cur_keyword_("anchorDef"):
@ -1311,9 +1364,10 @@ class Parser(object):
if has_single and has_multiple: if has_single and has_multiple:
for i, s in enumerate(statements): for i, s in enumerate(statements):
if isinstance(s, self.ast.SingleSubstStatement): if isinstance(s, self.ast.SingleSubstStatement):
statements[i] = self.ast.MultipleSubstStatement(s.location, statements[i] = self.ast.MultipleSubstStatement(
s.prefix, s.glyphs[0].glyphSet()[0], s.suffix, s.prefix, s.glyphs[0].glyphSet()[0], s.suffix,
[r.glyphSet()[0] for r in s.replacements]) [r.glyphSet()[0] for r in s.replacements],
location=s.location)
def is_cur_keyword_(self, k): def is_cur_keyword_(self, k):
if self.cur_token_type_ is Lexer.NAME: if self.cur_token_type_ is Lexer.NAME:

View File

@ -438,7 +438,8 @@ class BuilderTest(unittest.TestCase):
m = self.expect_markClass_reference_() m = self.expect_markClass_reference_()
marks.append(m) marks.append(m)
self.expect_symbol_(";") self.expect_symbol_(";")
return self.ast.MarkBasePosStatement(location, base, marks) return self.ast.MarkBasePosStatement(base, marks,
location=location)
def parseBaseClass(self): def parseBaseClass(self):
if not hasattr(self.doc_, 'baseClasses'): if not hasattr(self.doc_, 'baseClasses'):
@ -453,7 +454,8 @@ class BuilderTest(unittest.TestCase):
baseClass = ast_BaseClass(name) baseClass = ast_BaseClass(name)
self.doc_.baseClasses[name] = baseClass self.doc_.baseClasses[name] = baseClass
self.glyphclasses_.define(name, baseClass) self.glyphclasses_.define(name, baseClass)
bcdef = ast_BaseClassDefinition(location, baseClass, anchor, glyphs) bcdef = ast_BaseClassDefinition(baseClass, anchor, glyphs,
location=location)
baseClass.addDefinition(bcdef) baseClass.addDefinition(bcdef)
return bcdef return bcdef