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