parser: Lexing and parsing OpenType feature files
Overview
The primary interface for processing .fea
files is
fontTools.feaLib.parser.Parser
. At a lower level, the
fontTools.feaLib.lexer
module implements feaLib’s lexical
analysis of the .fea
language syntax, augmented by several smaller
utility modules.
Parsing
- class fontTools.feaLib.parser.Parser(featurefile, glyphNames=(), followIncludes=True, includeDir=None, **kwargs)[source]
Bases:
object
Initializes a Parser object.
Example
from fontTools.feaLib.parser import Parser parser = Parser(file, font.getReverseGlyphMap()) parsetree = parser.parse()
Note: the
glyphNames
iterable serves a double role to help distinguish glyph names from ranges in the presence of hyphens and to ensure that glyph names referenced in a feature file are actually part of a font’s glyph set. If the iterable is left empty, no glyph name in glyph set checking takes place, and all glyph tokens containing hyphens are treated as literal glyph names, not as ranges. (Adding a space around the hyphen can, in any case, help to disambiguate ranges from glyph names containing hyphens.)By default, the parser will follow
include()
statements in the feature file. To turn this off, passfollowIncludes=False
. Pass a directory string asincludeDir
to explicitly declare a directory to search included feature files in.- extensions = {}
- ast = <module 'fontTools.feaLib.ast' from '/tmp/B.veuktzyf/BUILD/fonttools-4.58.0-build/fonttools-4.58.0/Lib/fontTools/feaLib/ast.py'>
- SS_FEATURE_TAGS = {'ss01', 'ss02', 'ss03', 'ss04', 'ss05', 'ss06', 'ss07', 'ss08', 'ss09', 'ss10', 'ss11', 'ss12', 'ss13', 'ss14', 'ss15', 'ss16', 'ss17', 'ss18', 'ss19', 'ss20'}
- CV_FEATURE_TAGS = {'cv01', 'cv02', 'cv03', 'cv04', 'cv05', 'cv06', 'cv07', 'cv08', 'cv09', 'cv10', 'cv11', 'cv12', 'cv13', 'cv14', 'cv15', 'cv16', 'cv17', 'cv18', 'cv19', 'cv20', 'cv21', 'cv22', 'cv23', 'cv24', 'cv25', 'cv26', 'cv27', 'cv28', 'cv29', 'cv30', 'cv31', 'cv32', 'cv33', 'cv34', 'cv35', 'cv36', 'cv37', 'cv38', 'cv39', 'cv40', 'cv41', 'cv42', 'cv43', 'cv44', 'cv45', 'cv46', 'cv47', 'cv48', 'cv49', 'cv50', 'cv51', 'cv52', 'cv53', 'cv54', 'cv55', 'cv56', 'cv57', 'cv58', 'cv59', 'cv60', 'cv61', 'cv62', 'cv63', 'cv64', 'cv65', 'cv66', 'cv67', 'cv68', 'cv69', 'cv70', 'cv71', 'cv72', 'cv73', 'cv74', 'cv75', 'cv76', 'cv77', 'cv78', 'cv79', 'cv80', 'cv81', 'cv82', 'cv83', 'cv84', 'cv85', 'cv86', 'cv87', 'cv88', 'cv89', 'cv90', 'cv91', 'cv92', 'cv93', 'cv94', 'cv95', 'cv96', 'cv97', 'cv98', 'cv99'}
- parse()[source]
Parse the file, and return a
fontTools.feaLib.ast.FeatureFile
object representing the root of the abstract syntax tree containing the parsed contents of the file.
- parse_name_()[source]
Parses a name record. See section 9.e.
- parse_featureNames_(tag)[source]
Parses a
featureNames
statement found in stylistic set features. See section 8.c.
- check_glyph_name_in_glyph_set(*names)[source]
Adds a glyph name (just start) or glyph names of a range (start and end) which are not in the glyph set to the “missing list” for future error reporting.
If no glyph set is present, does nothing.
Lexing
- class fontTools.feaLib.lexer.Lexer(text, filename)[source]
Bases:
object
- NUMBER = 'NUMBER'
- HEXADECIMAL = 'HEXADECIMAL'
- OCTAL = 'OCTAL'
- NUMBERS = ('NUMBER', 'HEXADECIMAL', 'OCTAL')
- FLOAT = 'FLOAT'
- STRING = 'STRING'
- NAME = 'NAME'
- FILENAME = 'FILENAME'
- GLYPHCLASS = 'GLYPHCLASS'
- CID = 'CID'
- SYMBOL = 'SYMBOL'
- COMMENT = 'COMMENT'
- NEWLINE = 'NEWLINE'
- ANONYMOUS_BLOCK = 'ANONYMOUS_BLOCK'
- CHAR_WHITESPACE_ = ' \t'
- CHAR_NEWLINE_ = '\r\n'
- CHAR_SYMBOL_ = ",;:-+'{}[]<>()="
- CHAR_DIGIT_ = '0123456789'
- CHAR_HEXDIGIT_ = '0123456789ABCDEFabcdef'
- CHAR_LETTER_ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
- CHAR_NAME_START_ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_+*:.^~!\\'
- CHAR_NAME_CONTINUATION_ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.+*:^~!/-'
- RE_GLYPHCLASS = re.compile('^[A-Za-z_0-9.\\-]+$')
- MODE_NORMAL_ = 'NORMAL'
- MODE_FILENAME_ = 'FILENAME'
- class fontTools.feaLib.lexer.IncludingLexer(featurefile, *, includeDir=None)[source]
Bases:
object
A Lexer that follows include statements.
The OpenType feature file specification states that due to historical reasons, relative imports should be resolved in this order:
If the source font is UFO format, then relative to the UFO’s font directory
relative to the top-level include file
relative to the parent include file
We only support 1 (via includeDir) and 2.
- class fontTools.feaLib.lexer.NonIncludingLexer(featurefile, *, includeDir=None)[source]
Bases:
IncludingLexer
Lexer that does not follow include statements, emits them as-is.