fonttools 4.55.6__cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fonttools might be problematic. Click here for more details.

Files changed (329) hide show
  1. fontTools/__init__.py +8 -0
  2. fontTools/__main__.py +35 -0
  3. fontTools/afmLib.py +439 -0
  4. fontTools/agl.py +5233 -0
  5. fontTools/cffLib/CFF2ToCFF.py +203 -0
  6. fontTools/cffLib/CFFToCFF2.py +305 -0
  7. fontTools/cffLib/__init__.py +3659 -0
  8. fontTools/cffLib/specializer.py +924 -0
  9. fontTools/cffLib/transforms.py +490 -0
  10. fontTools/cffLib/width.py +210 -0
  11. fontTools/colorLib/__init__.py +0 -0
  12. fontTools/colorLib/builder.py +664 -0
  13. fontTools/colorLib/errors.py +2 -0
  14. fontTools/colorLib/geometry.py +143 -0
  15. fontTools/colorLib/table_builder.py +223 -0
  16. fontTools/colorLib/unbuilder.py +81 -0
  17. fontTools/config/__init__.py +75 -0
  18. fontTools/cu2qu/__init__.py +15 -0
  19. fontTools/cu2qu/__main__.py +6 -0
  20. fontTools/cu2qu/benchmark.py +54 -0
  21. fontTools/cu2qu/cli.py +198 -0
  22. fontTools/cu2qu/cu2qu.c +14829 -0
  23. fontTools/cu2qu/cu2qu.cpython-39-x86_64-linux-gnu.so +0 -0
  24. fontTools/cu2qu/cu2qu.py +531 -0
  25. fontTools/cu2qu/errors.py +77 -0
  26. fontTools/cu2qu/ufo.py +349 -0
  27. fontTools/designspaceLib/__init__.py +3338 -0
  28. fontTools/designspaceLib/__main__.py +6 -0
  29. fontTools/designspaceLib/split.py +475 -0
  30. fontTools/designspaceLib/statNames.py +253 -0
  31. fontTools/designspaceLib/types.py +147 -0
  32. fontTools/encodings/MacRoman.py +258 -0
  33. fontTools/encodings/StandardEncoding.py +258 -0
  34. fontTools/encodings/__init__.py +1 -0
  35. fontTools/encodings/codecs.py +135 -0
  36. fontTools/feaLib/__init__.py +4 -0
  37. fontTools/feaLib/__main__.py +78 -0
  38. fontTools/feaLib/ast.py +2134 -0
  39. fontTools/feaLib/builder.py +1747 -0
  40. fontTools/feaLib/error.py +22 -0
  41. fontTools/feaLib/lexer.c +17986 -0
  42. fontTools/feaLib/lexer.cpython-39-x86_64-linux-gnu.so +0 -0
  43. fontTools/feaLib/lexer.py +287 -0
  44. fontTools/feaLib/location.py +12 -0
  45. fontTools/feaLib/lookupDebugInfo.py +12 -0
  46. fontTools/feaLib/parser.py +2359 -0
  47. fontTools/feaLib/variableScalar.py +113 -0
  48. fontTools/fontBuilder.py +1008 -0
  49. fontTools/help.py +36 -0
  50. fontTools/merge/__init__.py +248 -0
  51. fontTools/merge/__main__.py +6 -0
  52. fontTools/merge/base.py +81 -0
  53. fontTools/merge/cmap.py +141 -0
  54. fontTools/merge/layout.py +526 -0
  55. fontTools/merge/options.py +85 -0
  56. fontTools/merge/tables.py +341 -0
  57. fontTools/merge/unicode.py +78 -0
  58. fontTools/merge/util.py +143 -0
  59. fontTools/misc/__init__.py +1 -0
  60. fontTools/misc/arrayTools.py +424 -0
  61. fontTools/misc/bezierTools.c +41831 -0
  62. fontTools/misc/bezierTools.cpython-39-x86_64-linux-gnu.so +0 -0
  63. fontTools/misc/bezierTools.py +1497 -0
  64. fontTools/misc/classifyTools.py +170 -0
  65. fontTools/misc/cliTools.py +53 -0
  66. fontTools/misc/configTools.py +349 -0
  67. fontTools/misc/cython.py +27 -0
  68. fontTools/misc/dictTools.py +83 -0
  69. fontTools/misc/eexec.py +119 -0
  70. fontTools/misc/encodingTools.py +72 -0
  71. fontTools/misc/etree.py +479 -0
  72. fontTools/misc/filenames.py +245 -0
  73. fontTools/misc/fixedTools.py +253 -0
  74. fontTools/misc/intTools.py +25 -0
  75. fontTools/misc/iterTools.py +12 -0
  76. fontTools/misc/lazyTools.py +42 -0
  77. fontTools/misc/loggingTools.py +543 -0
  78. fontTools/misc/macCreatorType.py +56 -0
  79. fontTools/misc/macRes.py +261 -0
  80. fontTools/misc/plistlib/__init__.py +681 -0
  81. fontTools/misc/plistlib/py.typed +0 -0
  82. fontTools/misc/psCharStrings.py +1496 -0
  83. fontTools/misc/psLib.py +398 -0
  84. fontTools/misc/psOperators.py +572 -0
  85. fontTools/misc/py23.py +96 -0
  86. fontTools/misc/roundTools.py +110 -0
  87. fontTools/misc/sstruct.py +231 -0
  88. fontTools/misc/symfont.py +244 -0
  89. fontTools/misc/testTools.py +229 -0
  90. fontTools/misc/textTools.py +154 -0
  91. fontTools/misc/timeTools.py +88 -0
  92. fontTools/misc/transform.py +516 -0
  93. fontTools/misc/treeTools.py +45 -0
  94. fontTools/misc/vector.py +147 -0
  95. fontTools/misc/visitor.py +142 -0
  96. fontTools/misc/xmlReader.py +188 -0
  97. fontTools/misc/xmlWriter.py +204 -0
  98. fontTools/mtiLib/__init__.py +1402 -0
  99. fontTools/mtiLib/__main__.py +5 -0
  100. fontTools/otlLib/__init__.py +1 -0
  101. fontTools/otlLib/builder.py +3221 -0
  102. fontTools/otlLib/error.py +11 -0
  103. fontTools/otlLib/maxContextCalc.py +96 -0
  104. fontTools/otlLib/optimize/__init__.py +53 -0
  105. fontTools/otlLib/optimize/__main__.py +6 -0
  106. fontTools/otlLib/optimize/gpos.py +453 -0
  107. fontTools/pens/__init__.py +1 -0
  108. fontTools/pens/areaPen.py +52 -0
  109. fontTools/pens/basePen.py +475 -0
  110. fontTools/pens/boundsPen.py +98 -0
  111. fontTools/pens/cairoPen.py +26 -0
  112. fontTools/pens/cocoaPen.py +26 -0
  113. fontTools/pens/cu2quPen.py +325 -0
  114. fontTools/pens/explicitClosingLinePen.py +101 -0
  115. fontTools/pens/filterPen.py +241 -0
  116. fontTools/pens/freetypePen.py +462 -0
  117. fontTools/pens/hashPointPen.py +89 -0
  118. fontTools/pens/momentsPen.c +13448 -0
  119. fontTools/pens/momentsPen.cpython-39-x86_64-linux-gnu.so +0 -0
  120. fontTools/pens/momentsPen.py +879 -0
  121. fontTools/pens/perimeterPen.py +69 -0
  122. fontTools/pens/pointInsidePen.py +192 -0
  123. fontTools/pens/pointPen.py +600 -0
  124. fontTools/pens/qtPen.py +29 -0
  125. fontTools/pens/qu2cuPen.py +105 -0
  126. fontTools/pens/quartzPen.py +43 -0
  127. fontTools/pens/recordingPen.py +335 -0
  128. fontTools/pens/reportLabPen.py +79 -0
  129. fontTools/pens/reverseContourPen.py +96 -0
  130. fontTools/pens/roundingPen.py +130 -0
  131. fontTools/pens/statisticsPen.py +312 -0
  132. fontTools/pens/svgPathPen.py +310 -0
  133. fontTools/pens/t2CharStringPen.py +68 -0
  134. fontTools/pens/teePen.py +55 -0
  135. fontTools/pens/transformPen.py +115 -0
  136. fontTools/pens/ttGlyphPen.py +335 -0
  137. fontTools/pens/wxPen.py +29 -0
  138. fontTools/qu2cu/__init__.py +15 -0
  139. fontTools/qu2cu/__main__.py +7 -0
  140. fontTools/qu2cu/benchmark.py +56 -0
  141. fontTools/qu2cu/cli.py +125 -0
  142. fontTools/qu2cu/qu2cu.c +16269 -0
  143. fontTools/qu2cu/qu2cu.cpython-39-x86_64-linux-gnu.so +0 -0
  144. fontTools/qu2cu/qu2cu.py +405 -0
  145. fontTools/subset/__init__.py +3838 -0
  146. fontTools/subset/__main__.py +6 -0
  147. fontTools/subset/cff.py +184 -0
  148. fontTools/subset/svg.py +253 -0
  149. fontTools/subset/util.py +25 -0
  150. fontTools/svgLib/__init__.py +3 -0
  151. fontTools/svgLib/path/__init__.py +65 -0
  152. fontTools/svgLib/path/arc.py +154 -0
  153. fontTools/svgLib/path/parser.py +322 -0
  154. fontTools/svgLib/path/shapes.py +183 -0
  155. fontTools/t1Lib/__init__.py +648 -0
  156. fontTools/tfmLib.py +460 -0
  157. fontTools/ttLib/__init__.py +26 -0
  158. fontTools/ttLib/__main__.py +109 -0
  159. fontTools/ttLib/macUtils.py +54 -0
  160. fontTools/ttLib/removeOverlaps.py +393 -0
  161. fontTools/ttLib/reorderGlyphs.py +284 -0
  162. fontTools/ttLib/scaleUpem.py +436 -0
  163. fontTools/ttLib/sfnt.py +662 -0
  164. fontTools/ttLib/standardGlyphOrder.py +271 -0
  165. fontTools/ttLib/tables/B_A_S_E_.py +14 -0
  166. fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
  167. fontTools/ttLib/tables/C_B_D_T_.py +113 -0
  168. fontTools/ttLib/tables/C_B_L_C_.py +19 -0
  169. fontTools/ttLib/tables/C_F_F_.py +61 -0
  170. fontTools/ttLib/tables/C_F_F__2.py +26 -0
  171. fontTools/ttLib/tables/C_O_L_R_.py +165 -0
  172. fontTools/ttLib/tables/C_P_A_L_.py +305 -0
  173. fontTools/ttLib/tables/D_S_I_G_.py +158 -0
  174. fontTools/ttLib/tables/D__e_b_g.py +17 -0
  175. fontTools/ttLib/tables/DefaultTable.py +49 -0
  176. fontTools/ttLib/tables/E_B_D_T_.py +835 -0
  177. fontTools/ttLib/tables/E_B_L_C_.py +718 -0
  178. fontTools/ttLib/tables/F_F_T_M_.py +52 -0
  179. fontTools/ttLib/tables/F__e_a_t.py +149 -0
  180. fontTools/ttLib/tables/G_D_E_F_.py +13 -0
  181. fontTools/ttLib/tables/G_M_A_P_.py +148 -0
  182. fontTools/ttLib/tables/G_P_K_G_.py +133 -0
  183. fontTools/ttLib/tables/G_P_O_S_.py +14 -0
  184. fontTools/ttLib/tables/G_S_U_B_.py +13 -0
  185. fontTools/ttLib/tables/G__l_a_t.py +235 -0
  186. fontTools/ttLib/tables/G__l_o_c.py +85 -0
  187. fontTools/ttLib/tables/H_V_A_R_.py +13 -0
  188. fontTools/ttLib/tables/J_S_T_F_.py +13 -0
  189. fontTools/ttLib/tables/L_T_S_H_.py +58 -0
  190. fontTools/ttLib/tables/M_A_T_H_.py +13 -0
  191. fontTools/ttLib/tables/M_E_T_A_.py +352 -0
  192. fontTools/ttLib/tables/M_V_A_R_.py +13 -0
  193. fontTools/ttLib/tables/O_S_2f_2.py +752 -0
  194. fontTools/ttLib/tables/S_I_N_G_.py +99 -0
  195. fontTools/ttLib/tables/S_T_A_T_.py +15 -0
  196. fontTools/ttLib/tables/S_V_G_.py +223 -0
  197. fontTools/ttLib/tables/S__i_l_f.py +1040 -0
  198. fontTools/ttLib/tables/S__i_l_l.py +92 -0
  199. fontTools/ttLib/tables/T_S_I_B_.py +13 -0
  200. fontTools/ttLib/tables/T_S_I_C_.py +14 -0
  201. fontTools/ttLib/tables/T_S_I_D_.py +13 -0
  202. fontTools/ttLib/tables/T_S_I_J_.py +13 -0
  203. fontTools/ttLib/tables/T_S_I_P_.py +13 -0
  204. fontTools/ttLib/tables/T_S_I_S_.py +13 -0
  205. fontTools/ttLib/tables/T_S_I_V_.py +26 -0
  206. fontTools/ttLib/tables/T_S_I__0.py +59 -0
  207. fontTools/ttLib/tables/T_S_I__1.py +166 -0
  208. fontTools/ttLib/tables/T_S_I__2.py +17 -0
  209. fontTools/ttLib/tables/T_S_I__3.py +22 -0
  210. fontTools/ttLib/tables/T_S_I__5.py +49 -0
  211. fontTools/ttLib/tables/T_T_F_A_.py +14 -0
  212. fontTools/ttLib/tables/TupleVariation.py +884 -0
  213. fontTools/ttLib/tables/V_A_R_C_.py +12 -0
  214. fontTools/ttLib/tables/V_D_M_X_.py +249 -0
  215. fontTools/ttLib/tables/V_O_R_G_.py +165 -0
  216. fontTools/ttLib/tables/V_V_A_R_.py +13 -0
  217. fontTools/ttLib/tables/__init__.py +97 -0
  218. fontTools/ttLib/tables/_a_n_k_r.py +15 -0
  219. fontTools/ttLib/tables/_a_v_a_r.py +191 -0
  220. fontTools/ttLib/tables/_b_s_l_n.py +15 -0
  221. fontTools/ttLib/tables/_c_i_d_g.py +24 -0
  222. fontTools/ttLib/tables/_c_m_a_p.py +1578 -0
  223. fontTools/ttLib/tables/_c_v_a_r.py +94 -0
  224. fontTools/ttLib/tables/_c_v_t.py +55 -0
  225. fontTools/ttLib/tables/_f_e_a_t.py +15 -0
  226. fontTools/ttLib/tables/_f_p_g_m.py +60 -0
  227. fontTools/ttLib/tables/_f_v_a_r.py +261 -0
  228. fontTools/ttLib/tables/_g_a_s_p.py +63 -0
  229. fontTools/ttLib/tables/_g_c_i_d.py +13 -0
  230. fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
  231. fontTools/ttLib/tables/_g_v_a_r.py +292 -0
  232. fontTools/ttLib/tables/_h_d_m_x.py +127 -0
  233. fontTools/ttLib/tables/_h_e_a_d.py +130 -0
  234. fontTools/ttLib/tables/_h_h_e_a.py +147 -0
  235. fontTools/ttLib/tables/_h_m_t_x.py +160 -0
  236. fontTools/ttLib/tables/_k_e_r_n.py +289 -0
  237. fontTools/ttLib/tables/_l_c_a_r.py +13 -0
  238. fontTools/ttLib/tables/_l_o_c_a.py +70 -0
  239. fontTools/ttLib/tables/_l_t_a_g.py +72 -0
  240. fontTools/ttLib/tables/_m_a_x_p.py +147 -0
  241. fontTools/ttLib/tables/_m_e_t_a.py +112 -0
  242. fontTools/ttLib/tables/_m_o_r_t.py +14 -0
  243. fontTools/ttLib/tables/_m_o_r_x.py +15 -0
  244. fontTools/ttLib/tables/_n_a_m_e.py +1237 -0
  245. fontTools/ttLib/tables/_o_p_b_d.py +14 -0
  246. fontTools/ttLib/tables/_p_o_s_t.py +317 -0
  247. fontTools/ttLib/tables/_p_r_e_p.py +16 -0
  248. fontTools/ttLib/tables/_p_r_o_p.py +12 -0
  249. fontTools/ttLib/tables/_s_b_i_x.py +129 -0
  250. fontTools/ttLib/tables/_t_r_a_k.py +332 -0
  251. fontTools/ttLib/tables/_v_h_e_a.py +139 -0
  252. fontTools/ttLib/tables/_v_m_t_x.py +19 -0
  253. fontTools/ttLib/tables/asciiTable.py +20 -0
  254. fontTools/ttLib/tables/grUtils.py +92 -0
  255. fontTools/ttLib/tables/otBase.py +1465 -0
  256. fontTools/ttLib/tables/otConverters.py +2065 -0
  257. fontTools/ttLib/tables/otData.py +6400 -0
  258. fontTools/ttLib/tables/otTables.py +2700 -0
  259. fontTools/ttLib/tables/otTraverse.py +162 -0
  260. fontTools/ttLib/tables/sbixGlyph.py +149 -0
  261. fontTools/ttLib/tables/sbixStrike.py +177 -0
  262. fontTools/ttLib/tables/table_API_readme.txt +91 -0
  263. fontTools/ttLib/tables/ttProgram.py +594 -0
  264. fontTools/ttLib/ttCollection.py +125 -0
  265. fontTools/ttLib/ttFont.py +1155 -0
  266. fontTools/ttLib/ttGlyphSet.py +500 -0
  267. fontTools/ttLib/ttVisitor.py +32 -0
  268. fontTools/ttLib/woff2.py +1683 -0
  269. fontTools/ttx.py +467 -0
  270. fontTools/ufoLib/__init__.py +2477 -0
  271. fontTools/ufoLib/converters.py +334 -0
  272. fontTools/ufoLib/errors.py +22 -0
  273. fontTools/ufoLib/etree.py +6 -0
  274. fontTools/ufoLib/filenames.py +291 -0
  275. fontTools/ufoLib/glifLib.py +2022 -0
  276. fontTools/ufoLib/kerning.py +91 -0
  277. fontTools/ufoLib/plistlib.py +47 -0
  278. fontTools/ufoLib/pointPen.py +6 -0
  279. fontTools/ufoLib/utils.py +76 -0
  280. fontTools/ufoLib/validators.py +1186 -0
  281. fontTools/unicode.py +50 -0
  282. fontTools/unicodedata/Blocks.py +802 -0
  283. fontTools/unicodedata/OTTags.py +50 -0
  284. fontTools/unicodedata/ScriptExtensions.py +806 -0
  285. fontTools/unicodedata/Scripts.py +3618 -0
  286. fontTools/unicodedata/__init__.py +298 -0
  287. fontTools/varLib/__init__.py +1511 -0
  288. fontTools/varLib/__main__.py +6 -0
  289. fontTools/varLib/avar.py +260 -0
  290. fontTools/varLib/avarPlanner.py +1004 -0
  291. fontTools/varLib/builder.py +215 -0
  292. fontTools/varLib/cff.py +631 -0
  293. fontTools/varLib/errors.py +219 -0
  294. fontTools/varLib/featureVars.py +689 -0
  295. fontTools/varLib/instancer/__init__.py +1937 -0
  296. fontTools/varLib/instancer/__main__.py +5 -0
  297. fontTools/varLib/instancer/featureVars.py +190 -0
  298. fontTools/varLib/instancer/names.py +388 -0
  299. fontTools/varLib/instancer/solver.py +309 -0
  300. fontTools/varLib/interpolatable.py +1209 -0
  301. fontTools/varLib/interpolatableHelpers.py +396 -0
  302. fontTools/varLib/interpolatablePlot.py +1269 -0
  303. fontTools/varLib/interpolatableTestContourOrder.py +82 -0
  304. fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
  305. fontTools/varLib/interpolate_layout.py +124 -0
  306. fontTools/varLib/iup.c +19154 -0
  307. fontTools/varLib/iup.cpython-39-x86_64-linux-gnu.so +0 -0
  308. fontTools/varLib/iup.py +490 -0
  309. fontTools/varLib/merger.py +1717 -0
  310. fontTools/varLib/models.py +642 -0
  311. fontTools/varLib/multiVarStore.py +253 -0
  312. fontTools/varLib/mutator.py +518 -0
  313. fontTools/varLib/mvar.py +40 -0
  314. fontTools/varLib/plot.py +238 -0
  315. fontTools/varLib/stat.py +149 -0
  316. fontTools/varLib/varStore.py +767 -0
  317. fontTools/voltLib/__init__.py +5 -0
  318. fontTools/voltLib/ast.py +448 -0
  319. fontTools/voltLib/error.py +12 -0
  320. fontTools/voltLib/lexer.py +99 -0
  321. fontTools/voltLib/parser.py +656 -0
  322. fontTools/voltLib/voltToFea.py +730 -0
  323. fonttools-4.55.6.data/data/share/man/man1/ttx.1 +225 -0
  324. fonttools-4.55.6.dist-info/LICENSE +21 -0
  325. fonttools-4.55.6.dist-info/METADATA +3413 -0
  326. fonttools-4.55.6.dist-info/RECORD +329 -0
  327. fonttools-4.55.6.dist-info/WHEEL +6 -0
  328. fonttools-4.55.6.dist-info/entry_points.txt +5 -0
  329. fonttools-4.55.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,656 @@
1
+ import fontTools.voltLib.ast as ast
2
+ from fontTools.voltLib.lexer import Lexer
3
+ from fontTools.voltLib.error import VoltLibError
4
+ from io import open
5
+
6
+ PARSE_FUNCS = {
7
+ "DEF_GLYPH": "parse_def_glyph_",
8
+ "DEF_GROUP": "parse_def_group_",
9
+ "DEF_SCRIPT": "parse_def_script_",
10
+ "DEF_LOOKUP": "parse_def_lookup_",
11
+ "DEF_ANCHOR": "parse_def_anchor_",
12
+ "GRID_PPEM": "parse_ppem_",
13
+ "PRESENTATION_PPEM": "parse_ppem_",
14
+ "PPOSITIONING_PPEM": "parse_ppem_",
15
+ "COMPILER_USEEXTENSIONLOOKUPS": "parse_noarg_option_",
16
+ "COMPILER_USEPAIRPOSFORMAT2": "parse_noarg_option_",
17
+ "CMAP_FORMAT": "parse_cmap_format",
18
+ "DO_NOT_TOUCH_CMAP": "parse_noarg_option_",
19
+ }
20
+
21
+
22
+ class Parser(object):
23
+ def __init__(self, path):
24
+ self.doc_ = ast.VoltFile()
25
+ self.glyphs_ = OrderedSymbolTable()
26
+ self.groups_ = SymbolTable()
27
+ self.anchors_ = {} # dictionary of SymbolTable() keyed by glyph
28
+ self.scripts_ = SymbolTable()
29
+ self.langs_ = SymbolTable()
30
+ self.lookups_ = SymbolTable()
31
+ self.next_token_type_, self.next_token_ = (None, None)
32
+ self.next_token_location_ = None
33
+ self.make_lexer_(path)
34
+ self.advance_lexer_()
35
+
36
+ def make_lexer_(self, file_or_path):
37
+ if hasattr(file_or_path, "read"):
38
+ filename = getattr(file_or_path, "name", None)
39
+ data = file_or_path.read()
40
+ else:
41
+ filename = file_or_path
42
+ with open(file_or_path, "r") as f:
43
+ data = f.read()
44
+ self.lexer_ = Lexer(data, filename)
45
+
46
+ def parse(self):
47
+ statements = self.doc_.statements
48
+ while self.next_token_type_ is not None:
49
+ self.advance_lexer_()
50
+ if self.cur_token_ in PARSE_FUNCS.keys():
51
+ func = getattr(self, PARSE_FUNCS[self.cur_token_])
52
+ statements.append(func())
53
+ elif self.is_cur_keyword_("END"):
54
+ break
55
+ else:
56
+ raise VoltLibError(
57
+ "Expected " + ", ".join(sorted(PARSE_FUNCS.keys())),
58
+ self.cur_token_location_,
59
+ )
60
+ return self.doc_
61
+
62
+ def parse_def_glyph_(self):
63
+ assert self.is_cur_keyword_("DEF_GLYPH")
64
+ location = self.cur_token_location_
65
+ name = self.expect_string_()
66
+ self.expect_keyword_("ID")
67
+ gid = self.expect_number_()
68
+ if gid < 0:
69
+ raise VoltLibError("Invalid glyph ID", self.cur_token_location_)
70
+ gunicode = None
71
+ if self.next_token_ == "UNICODE":
72
+ self.expect_keyword_("UNICODE")
73
+ gunicode = [self.expect_number_()]
74
+ if gunicode[0] < 0:
75
+ raise VoltLibError("Invalid glyph UNICODE", self.cur_token_location_)
76
+ elif self.next_token_ == "UNICODEVALUES":
77
+ self.expect_keyword_("UNICODEVALUES")
78
+ gunicode = self.parse_unicode_values_()
79
+ gtype = None
80
+ if self.next_token_ == "TYPE":
81
+ self.expect_keyword_("TYPE")
82
+ gtype = self.expect_name_()
83
+ assert gtype in ("BASE", "LIGATURE", "MARK", "COMPONENT")
84
+ components = None
85
+ if self.next_token_ == "COMPONENTS":
86
+ self.expect_keyword_("COMPONENTS")
87
+ components = self.expect_number_()
88
+ self.expect_keyword_("END_GLYPH")
89
+ if self.glyphs_.resolve(name) is not None:
90
+ raise VoltLibError(
91
+ 'Glyph "%s" (gid %i) already defined' % (name, gid), location
92
+ )
93
+ def_glyph = ast.GlyphDefinition(
94
+ name, gid, gunicode, gtype, components, location=location
95
+ )
96
+ self.glyphs_.define(name, def_glyph)
97
+ return def_glyph
98
+
99
+ def parse_def_group_(self):
100
+ assert self.is_cur_keyword_("DEF_GROUP")
101
+ location = self.cur_token_location_
102
+ name = self.expect_string_()
103
+ enum = None
104
+ if self.next_token_ == "ENUM":
105
+ enum = self.parse_enum_()
106
+ self.expect_keyword_("END_GROUP")
107
+ if self.groups_.resolve(name) is not None:
108
+ raise VoltLibError(
109
+ 'Glyph group "%s" already defined, '
110
+ "group names are case insensitive" % name,
111
+ location,
112
+ )
113
+ def_group = ast.GroupDefinition(name, enum, location=location)
114
+ self.groups_.define(name, def_group)
115
+ return def_group
116
+
117
+ def parse_def_script_(self):
118
+ assert self.is_cur_keyword_("DEF_SCRIPT")
119
+ location = self.cur_token_location_
120
+ name = None
121
+ if self.next_token_ == "NAME":
122
+ self.expect_keyword_("NAME")
123
+ name = self.expect_string_()
124
+ self.expect_keyword_("TAG")
125
+ tag = self.expect_string_()
126
+ if self.scripts_.resolve(tag) is not None:
127
+ raise VoltLibError(
128
+ 'Script "%s" already defined, '
129
+ "script tags are case insensitive" % tag,
130
+ location,
131
+ )
132
+ self.langs_.enter_scope()
133
+ langs = []
134
+ while self.next_token_ != "END_SCRIPT":
135
+ self.advance_lexer_()
136
+ lang = self.parse_langsys_()
137
+ self.expect_keyword_("END_LANGSYS")
138
+ if self.langs_.resolve(lang.tag) is not None:
139
+ raise VoltLibError(
140
+ 'Language "%s" already defined in script "%s", '
141
+ "language tags are case insensitive" % (lang.tag, tag),
142
+ location,
143
+ )
144
+ self.langs_.define(lang.tag, lang)
145
+ langs.append(lang)
146
+ self.expect_keyword_("END_SCRIPT")
147
+ self.langs_.exit_scope()
148
+ def_script = ast.ScriptDefinition(name, tag, langs, location=location)
149
+ self.scripts_.define(tag, def_script)
150
+ return def_script
151
+
152
+ def parse_langsys_(self):
153
+ assert self.is_cur_keyword_("DEF_LANGSYS")
154
+ location = self.cur_token_location_
155
+ name = None
156
+ if self.next_token_ == "NAME":
157
+ self.expect_keyword_("NAME")
158
+ name = self.expect_string_()
159
+ self.expect_keyword_("TAG")
160
+ tag = self.expect_string_()
161
+ features = []
162
+ while self.next_token_ != "END_LANGSYS":
163
+ self.advance_lexer_()
164
+ feature = self.parse_feature_()
165
+ self.expect_keyword_("END_FEATURE")
166
+ features.append(feature)
167
+ def_langsys = ast.LangSysDefinition(name, tag, features, location=location)
168
+ return def_langsys
169
+
170
+ def parse_feature_(self):
171
+ assert self.is_cur_keyword_("DEF_FEATURE")
172
+ location = self.cur_token_location_
173
+ self.expect_keyword_("NAME")
174
+ name = self.expect_string_()
175
+ self.expect_keyword_("TAG")
176
+ tag = self.expect_string_()
177
+ lookups = []
178
+ while self.next_token_ != "END_FEATURE":
179
+ # self.advance_lexer_()
180
+ self.expect_keyword_("LOOKUP")
181
+ lookup = self.expect_string_()
182
+ lookups.append(lookup)
183
+ feature = ast.FeatureDefinition(name, tag, lookups, location=location)
184
+ return feature
185
+
186
+ def parse_def_lookup_(self):
187
+ assert self.is_cur_keyword_("DEF_LOOKUP")
188
+ location = self.cur_token_location_
189
+ name = self.expect_string_()
190
+ if not name[0].isalpha():
191
+ raise VoltLibError(
192
+ 'Lookup name "%s" must start with a letter' % name, location
193
+ )
194
+ if self.lookups_.resolve(name) is not None:
195
+ raise VoltLibError(
196
+ 'Lookup "%s" already defined, '
197
+ "lookup names are case insensitive" % name,
198
+ location,
199
+ )
200
+ process_base = True
201
+ if self.next_token_ == "PROCESS_BASE":
202
+ self.advance_lexer_()
203
+ elif self.next_token_ == "SKIP_BASE":
204
+ self.advance_lexer_()
205
+ process_base = False
206
+ process_marks = True
207
+ mark_glyph_set = None
208
+ if self.next_token_ == "PROCESS_MARKS":
209
+ self.advance_lexer_()
210
+ if self.next_token_ == "MARK_GLYPH_SET":
211
+ self.advance_lexer_()
212
+ mark_glyph_set = self.expect_string_()
213
+ elif self.next_token_ == "ALL":
214
+ self.advance_lexer_()
215
+ elif self.next_token_ == "NONE":
216
+ self.advance_lexer_()
217
+ process_marks = False
218
+ elif self.next_token_type_ == Lexer.STRING:
219
+ process_marks = self.expect_string_()
220
+ else:
221
+ raise VoltLibError(
222
+ "Expected ALL, NONE, MARK_GLYPH_SET or an ID. "
223
+ "Got %s" % (self.next_token_type_),
224
+ location,
225
+ )
226
+ elif self.next_token_ == "SKIP_MARKS":
227
+ self.advance_lexer_()
228
+ process_marks = False
229
+ direction = None
230
+ if self.next_token_ == "DIRECTION":
231
+ self.expect_keyword_("DIRECTION")
232
+ direction = self.expect_name_()
233
+ assert direction in ("LTR", "RTL")
234
+ reversal = None
235
+ if self.next_token_ == "REVERSAL":
236
+ self.expect_keyword_("REVERSAL")
237
+ reversal = True
238
+ comments = None
239
+ if self.next_token_ == "COMMENTS":
240
+ self.expect_keyword_("COMMENTS")
241
+ comments = self.expect_string_().replace(r"\n", "\n")
242
+ context = []
243
+ while self.next_token_ in ("EXCEPT_CONTEXT", "IN_CONTEXT"):
244
+ context = self.parse_context_()
245
+ as_pos_or_sub = self.expect_name_()
246
+ sub = None
247
+ pos = None
248
+ if as_pos_or_sub == "AS_SUBSTITUTION":
249
+ sub = self.parse_substitution_(reversal)
250
+ elif as_pos_or_sub == "AS_POSITION":
251
+ pos = self.parse_position_()
252
+ else:
253
+ raise VoltLibError(
254
+ "Expected AS_SUBSTITUTION or AS_POSITION. " "Got %s" % (as_pos_or_sub),
255
+ location,
256
+ )
257
+ def_lookup = ast.LookupDefinition(
258
+ name,
259
+ process_base,
260
+ process_marks,
261
+ mark_glyph_set,
262
+ direction,
263
+ reversal,
264
+ comments,
265
+ context,
266
+ sub,
267
+ pos,
268
+ location=location,
269
+ )
270
+ self.lookups_.define(name, def_lookup)
271
+ return def_lookup
272
+
273
+ def parse_context_(self):
274
+ location = self.cur_token_location_
275
+ contexts = []
276
+ while self.next_token_ in ("EXCEPT_CONTEXT", "IN_CONTEXT"):
277
+ side = None
278
+ coverage = None
279
+ ex_or_in = self.expect_name_()
280
+ # side_contexts = [] # XXX
281
+ if self.next_token_ != "END_CONTEXT":
282
+ left = []
283
+ right = []
284
+ while self.next_token_ in ("LEFT", "RIGHT"):
285
+ side = self.expect_name_()
286
+ coverage = self.parse_coverage_()
287
+ if side == "LEFT":
288
+ left.append(coverage)
289
+ else:
290
+ right.append(coverage)
291
+ self.expect_keyword_("END_CONTEXT")
292
+ context = ast.ContextDefinition(
293
+ ex_or_in, left, right, location=location
294
+ )
295
+ contexts.append(context)
296
+ else:
297
+ self.expect_keyword_("END_CONTEXT")
298
+ return contexts
299
+
300
+ def parse_substitution_(self, reversal):
301
+ assert self.is_cur_keyword_("AS_SUBSTITUTION")
302
+ location = self.cur_token_location_
303
+ src = []
304
+ dest = []
305
+ if self.next_token_ != "SUB":
306
+ raise VoltLibError("Expected SUB", location)
307
+ while self.next_token_ == "SUB":
308
+ self.expect_keyword_("SUB")
309
+ src.append(self.parse_coverage_())
310
+ self.expect_keyword_("WITH")
311
+ dest.append(self.parse_coverage_())
312
+ self.expect_keyword_("END_SUB")
313
+ self.expect_keyword_("END_SUBSTITUTION")
314
+ max_src = max([len(cov) for cov in src])
315
+ max_dest = max([len(cov) for cov in dest])
316
+ # many to many or mixed is invalid
317
+ if (max_src > 1 and max_dest > 1) or (
318
+ reversal and (max_src > 1 or max_dest > 1)
319
+ ):
320
+ raise VoltLibError("Invalid substitution type", location)
321
+ mapping = dict(zip(tuple(src), tuple(dest)))
322
+ if max_src == 1 and max_dest == 1:
323
+ if reversal:
324
+ sub = ast.SubstitutionReverseChainingSingleDefinition(
325
+ mapping, location=location
326
+ )
327
+ else:
328
+ sub = ast.SubstitutionSingleDefinition(mapping, location=location)
329
+ elif max_src == 1 and max_dest > 1:
330
+ sub = ast.SubstitutionMultipleDefinition(mapping, location=location)
331
+ elif max_src > 1 and max_dest == 1:
332
+ sub = ast.SubstitutionLigatureDefinition(mapping, location=location)
333
+ return sub
334
+
335
+ def parse_position_(self):
336
+ assert self.is_cur_keyword_("AS_POSITION")
337
+ location = self.cur_token_location_
338
+ pos_type = self.expect_name_()
339
+ if pos_type not in ("ATTACH", "ATTACH_CURSIVE", "ADJUST_PAIR", "ADJUST_SINGLE"):
340
+ raise VoltLibError(
341
+ "Expected ATTACH, ATTACH_CURSIVE, ADJUST_PAIR, ADJUST_SINGLE", location
342
+ )
343
+ if pos_type == "ATTACH":
344
+ position = self.parse_attach_()
345
+ elif pos_type == "ATTACH_CURSIVE":
346
+ position = self.parse_attach_cursive_()
347
+ elif pos_type == "ADJUST_PAIR":
348
+ position = self.parse_adjust_pair_()
349
+ elif pos_type == "ADJUST_SINGLE":
350
+ position = self.parse_adjust_single_()
351
+ self.expect_keyword_("END_POSITION")
352
+ return position
353
+
354
+ def parse_attach_(self):
355
+ assert self.is_cur_keyword_("ATTACH")
356
+ location = self.cur_token_location_
357
+ coverage = self.parse_coverage_()
358
+ coverage_to = []
359
+ self.expect_keyword_("TO")
360
+ while self.next_token_ != "END_ATTACH":
361
+ cov = self.parse_coverage_()
362
+ self.expect_keyword_("AT")
363
+ self.expect_keyword_("ANCHOR")
364
+ anchor_name = self.expect_string_()
365
+ coverage_to.append((cov, anchor_name))
366
+ self.expect_keyword_("END_ATTACH")
367
+ position = ast.PositionAttachDefinition(
368
+ coverage, coverage_to, location=location
369
+ )
370
+ return position
371
+
372
+ def parse_attach_cursive_(self):
373
+ assert self.is_cur_keyword_("ATTACH_CURSIVE")
374
+ location = self.cur_token_location_
375
+ coverages_exit = []
376
+ coverages_enter = []
377
+ while self.next_token_ != "ENTER":
378
+ self.expect_keyword_("EXIT")
379
+ coverages_exit.append(self.parse_coverage_())
380
+ while self.next_token_ != "END_ATTACH":
381
+ self.expect_keyword_("ENTER")
382
+ coverages_enter.append(self.parse_coverage_())
383
+ self.expect_keyword_("END_ATTACH")
384
+ position = ast.PositionAttachCursiveDefinition(
385
+ coverages_exit, coverages_enter, location=location
386
+ )
387
+ return position
388
+
389
+ def parse_adjust_pair_(self):
390
+ assert self.is_cur_keyword_("ADJUST_PAIR")
391
+ location = self.cur_token_location_
392
+ coverages_1 = []
393
+ coverages_2 = []
394
+ adjust_pair = {}
395
+ while self.next_token_ == "FIRST":
396
+ self.advance_lexer_()
397
+ coverage_1 = self.parse_coverage_()
398
+ coverages_1.append(coverage_1)
399
+ while self.next_token_ == "SECOND":
400
+ self.advance_lexer_()
401
+ coverage_2 = self.parse_coverage_()
402
+ coverages_2.append(coverage_2)
403
+ while self.next_token_ != "END_ADJUST":
404
+ id_1 = self.expect_number_()
405
+ id_2 = self.expect_number_()
406
+ self.expect_keyword_("BY")
407
+ pos_1 = self.parse_pos_()
408
+ pos_2 = self.parse_pos_()
409
+ adjust_pair[(id_1, id_2)] = (pos_1, pos_2)
410
+ self.expect_keyword_("END_ADJUST")
411
+ position = ast.PositionAdjustPairDefinition(
412
+ coverages_1, coverages_2, adjust_pair, location=location
413
+ )
414
+ return position
415
+
416
+ def parse_adjust_single_(self):
417
+ assert self.is_cur_keyword_("ADJUST_SINGLE")
418
+ location = self.cur_token_location_
419
+ adjust_single = []
420
+ while self.next_token_ != "END_ADJUST":
421
+ coverages = self.parse_coverage_()
422
+ self.expect_keyword_("BY")
423
+ pos = self.parse_pos_()
424
+ adjust_single.append((coverages, pos))
425
+ self.expect_keyword_("END_ADJUST")
426
+ position = ast.PositionAdjustSingleDefinition(adjust_single, location=location)
427
+ return position
428
+
429
+ def parse_def_anchor_(self):
430
+ assert self.is_cur_keyword_("DEF_ANCHOR")
431
+ location = self.cur_token_location_
432
+ name = self.expect_string_()
433
+ self.expect_keyword_("ON")
434
+ gid = self.expect_number_()
435
+ self.expect_keyword_("GLYPH")
436
+ glyph_name = self.expect_name_()
437
+ self.expect_keyword_("COMPONENT")
438
+ component = self.expect_number_()
439
+ # check for duplicate anchor names on this glyph
440
+ if glyph_name in self.anchors_:
441
+ anchor = self.anchors_[glyph_name].resolve(name)
442
+ if anchor is not None and anchor.component == component:
443
+ raise VoltLibError(
444
+ 'Anchor "%s" already defined, '
445
+ "anchor names are case insensitive" % name,
446
+ location,
447
+ )
448
+ if self.next_token_ == "LOCKED":
449
+ locked = True
450
+ self.advance_lexer_()
451
+ else:
452
+ locked = False
453
+ self.expect_keyword_("AT")
454
+ pos = self.parse_pos_()
455
+ self.expect_keyword_("END_ANCHOR")
456
+ anchor = ast.AnchorDefinition(
457
+ name, gid, glyph_name, component, locked, pos, location=location
458
+ )
459
+ if glyph_name not in self.anchors_:
460
+ self.anchors_[glyph_name] = SymbolTable()
461
+ self.anchors_[glyph_name].define(name, anchor)
462
+ return anchor
463
+
464
+ def parse_adjust_by_(self):
465
+ self.advance_lexer_()
466
+ assert self.is_cur_keyword_("ADJUST_BY")
467
+ adjustment = self.expect_number_()
468
+ self.expect_keyword_("AT")
469
+ size = self.expect_number_()
470
+ return adjustment, size
471
+
472
+ def parse_pos_(self):
473
+ # VOLT syntax doesn't seem to take device Y advance
474
+ self.advance_lexer_()
475
+ location = self.cur_token_location_
476
+ assert self.is_cur_keyword_("POS"), location
477
+ adv = None
478
+ dx = None
479
+ dy = None
480
+ adv_adjust_by = {}
481
+ dx_adjust_by = {}
482
+ dy_adjust_by = {}
483
+ if self.next_token_ == "ADV":
484
+ self.advance_lexer_()
485
+ adv = self.expect_number_()
486
+ while self.next_token_ == "ADJUST_BY":
487
+ adjustment, size = self.parse_adjust_by_()
488
+ adv_adjust_by[size] = adjustment
489
+ if self.next_token_ == "DX":
490
+ self.advance_lexer_()
491
+ dx = self.expect_number_()
492
+ while self.next_token_ == "ADJUST_BY":
493
+ adjustment, size = self.parse_adjust_by_()
494
+ dx_adjust_by[size] = adjustment
495
+ if self.next_token_ == "DY":
496
+ self.advance_lexer_()
497
+ dy = self.expect_number_()
498
+ while self.next_token_ == "ADJUST_BY":
499
+ adjustment, size = self.parse_adjust_by_()
500
+ dy_adjust_by[size] = adjustment
501
+ self.expect_keyword_("END_POS")
502
+ return ast.Pos(adv, dx, dy, adv_adjust_by, dx_adjust_by, dy_adjust_by)
503
+
504
+ def parse_unicode_values_(self):
505
+ location = self.cur_token_location_
506
+ try:
507
+ unicode_values = self.expect_string_().split(",")
508
+ unicode_values = [int(uni[2:], 16) for uni in unicode_values if uni != ""]
509
+ except ValueError as err:
510
+ raise VoltLibError(str(err), location)
511
+ return unicode_values if unicode_values != [] else None
512
+
513
+ def parse_enum_(self):
514
+ self.expect_keyword_("ENUM")
515
+ location = self.cur_token_location_
516
+ enum = ast.Enum(self.parse_coverage_(), location=location)
517
+ self.expect_keyword_("END_ENUM")
518
+ return enum
519
+
520
+ def parse_coverage_(self):
521
+ coverage = []
522
+ location = self.cur_token_location_
523
+ while self.next_token_ in ("GLYPH", "GROUP", "RANGE", "ENUM"):
524
+ if self.next_token_ == "ENUM":
525
+ enum = self.parse_enum_()
526
+ coverage.append(enum)
527
+ elif self.next_token_ == "GLYPH":
528
+ self.expect_keyword_("GLYPH")
529
+ name = self.expect_string_()
530
+ coverage.append(ast.GlyphName(name, location=location))
531
+ elif self.next_token_ == "GROUP":
532
+ self.expect_keyword_("GROUP")
533
+ name = self.expect_string_()
534
+ coverage.append(ast.GroupName(name, self, location=location))
535
+ elif self.next_token_ == "RANGE":
536
+ self.expect_keyword_("RANGE")
537
+ start = self.expect_string_()
538
+ self.expect_keyword_("TO")
539
+ end = self.expect_string_()
540
+ coverage.append(ast.Range(start, end, self, location=location))
541
+ return tuple(coverage)
542
+
543
+ def resolve_group(self, group_name):
544
+ return self.groups_.resolve(group_name)
545
+
546
+ def glyph_range(self, start, end):
547
+ return self.glyphs_.range(start, end)
548
+
549
+ def parse_ppem_(self):
550
+ location = self.cur_token_location_
551
+ ppem_name = self.cur_token_
552
+ value = self.expect_number_()
553
+ setting = ast.SettingDefinition(ppem_name, value, location=location)
554
+ return setting
555
+
556
+ def parse_noarg_option_(self):
557
+ location = self.cur_token_location_
558
+ name = self.cur_token_
559
+ value = True
560
+ setting = ast.SettingDefinition(name, value, location=location)
561
+ return setting
562
+
563
+ def parse_cmap_format(self):
564
+ location = self.cur_token_location_
565
+ name = self.cur_token_
566
+ value = (self.expect_number_(), self.expect_number_(), self.expect_number_())
567
+ setting = ast.SettingDefinition(name, value, location=location)
568
+ return setting
569
+
570
+ def is_cur_keyword_(self, k):
571
+ return (self.cur_token_type_ is Lexer.NAME) and (self.cur_token_ == k)
572
+
573
+ def expect_string_(self):
574
+ self.advance_lexer_()
575
+ if self.cur_token_type_ is not Lexer.STRING:
576
+ raise VoltLibError("Expected a string", self.cur_token_location_)
577
+ return self.cur_token_
578
+
579
+ def expect_keyword_(self, keyword):
580
+ self.advance_lexer_()
581
+ if self.cur_token_type_ is Lexer.NAME and self.cur_token_ == keyword:
582
+ return self.cur_token_
583
+ raise VoltLibError('Expected "%s"' % keyword, self.cur_token_location_)
584
+
585
+ def expect_name_(self):
586
+ self.advance_lexer_()
587
+ if self.cur_token_type_ is Lexer.NAME:
588
+ return self.cur_token_
589
+ raise VoltLibError("Expected a name", self.cur_token_location_)
590
+
591
+ def expect_number_(self):
592
+ self.advance_lexer_()
593
+ if self.cur_token_type_ is not Lexer.NUMBER:
594
+ raise VoltLibError("Expected a number", self.cur_token_location_)
595
+ return self.cur_token_
596
+
597
+ def advance_lexer_(self):
598
+ self.cur_token_type_, self.cur_token_, self.cur_token_location_ = (
599
+ self.next_token_type_,
600
+ self.next_token_,
601
+ self.next_token_location_,
602
+ )
603
+ try:
604
+ if self.is_cur_keyword_("END"):
605
+ raise StopIteration
606
+ (
607
+ self.next_token_type_,
608
+ self.next_token_,
609
+ self.next_token_location_,
610
+ ) = self.lexer_.next()
611
+ except StopIteration:
612
+ self.next_token_type_, self.next_token_ = (None, None)
613
+
614
+
615
+ class SymbolTable(object):
616
+ def __init__(self):
617
+ self.scopes_ = [{}]
618
+
619
+ def enter_scope(self):
620
+ self.scopes_.append({})
621
+
622
+ def exit_scope(self):
623
+ self.scopes_.pop()
624
+
625
+ def define(self, name, item):
626
+ self.scopes_[-1][name] = item
627
+
628
+ def resolve(self, name, case_insensitive=True):
629
+ for scope in reversed(self.scopes_):
630
+ item = scope.get(name)
631
+ if item:
632
+ return item
633
+ if case_insensitive:
634
+ for key in scope:
635
+ if key.lower() == name.lower():
636
+ return scope[key]
637
+ return None
638
+
639
+
640
+ class OrderedSymbolTable(SymbolTable):
641
+ def __init__(self):
642
+ self.scopes_ = [{}]
643
+
644
+ def enter_scope(self):
645
+ self.scopes_.append({})
646
+
647
+ def resolve(self, name, case_insensitive=False):
648
+ SymbolTable.resolve(self, name, case_insensitive=case_insensitive)
649
+
650
+ def range(self, start, end):
651
+ for scope in reversed(self.scopes_):
652
+ if start in scope and end in scope:
653
+ start_idx = list(scope.keys()).index(start)
654
+ end_idx = list(scope.keys()).index(end)
655
+ return list(scope.keys())[start_idx : end_idx + 1]
656
+ return None