aboutsummaryrefslogtreecommitdiff
path: root/Tests/voltLib/parser_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/voltLib/parser_test.py')
-rw-r--r--Tests/voltLib/parser_test.py345
1 files changed, 228 insertions, 117 deletions
diff --git a/Tests/voltLib/parser_test.py b/Tests/voltLib/parser_test.py
index 3bfa17c8..0e0191fc 100644
--- a/Tests/voltLib/parser_test.py
+++ b/Tests/voltLib/parser_test.py
@@ -1,9 +1,7 @@
-from __future__ import print_function, division, absolute_import
-from __future__ import unicode_literals
-from fontTools.misc.py23 import *
from fontTools.voltLib import ast
from fontTools.voltLib.error import VoltLibError
from fontTools.voltLib.parser import Parser
+from io import StringIO
import unittest
@@ -39,7 +37,7 @@ class ParserTest(unittest.TestCase):
("space", 3, [0x0020], "BASE", None))
def test_def_glyph_base_with_unicodevalues(self):
- [def_glyph] = self.parse(
+ [def_glyph] = self.parse_(
'DEF_GLYPH "CR" ID 2 UNICODEVALUES "U+0009" '
'TYPE BASE END_GLYPH'
).statements
@@ -57,7 +55,7 @@ class ParserTest(unittest.TestCase):
("CR", 2, [0x0009, 0x000D], "BASE", None))
def test_def_glyph_base_with_empty_unicodevalues(self):
- [def_glyph] = self.parse(
+ [def_glyph] = self.parse_(
'DEF_GLYPH "i.locl" ID 269 UNICODEVALUES "" '
'TYPE BASE END_GLYPH'
).statements
@@ -108,7 +106,7 @@ class ParserTest(unittest.TestCase):
def test_def_glyph_case_sensitive(self):
def_glyphs = self.parse(
'DEF_GLYPH "A" ID 3 UNICODE 65 TYPE BASE END_GLYPH\n'
- 'DEF_GLYPH "a" ID 4 UNICODE 97 TYPE BASE END_GLYPH\n'
+ 'DEF_GLYPH "a" ID 4 UNICODE 97 TYPE BASE END_GLYPH'
).statements
self.assertEqual((def_glyphs[0].name, def_glyphs[0].id,
def_glyphs[0].unicode, def_glyphs[0].type,
@@ -122,10 +120,10 @@ class ParserTest(unittest.TestCase):
def test_def_group_glyphs(self):
[def_group] = self.parse(
'DEF_GROUP "aaccented"\n'
- 'ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
+ ' ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
'GLYPH "adieresis" GLYPH "ae" GLYPH "agrave" GLYPH "amacron" '
'GLYPH "aogonek" GLYPH "aring" GLYPH "atilde" END_ENUM\n'
- 'END_GROUP\n'
+ 'END_GROUP'
).statements
self.assertEqual((def_group.name, def_group.enum.glyphSet()),
("aaccented",
@@ -136,14 +134,14 @@ class ParserTest(unittest.TestCase):
def test_def_group_groups(self):
[group1, group2, test_group] = self.parse(
'DEF_GROUP "Group1"\n'
- 'ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
+ ' ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "Group2"\n'
- 'ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
+ ' ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "TestGroup"\n'
- 'ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
- 'END_GROUP\n'
+ ' ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
+ 'END_GROUP'
).statements
groups = [g.group for g in test_group.enum.enum]
self.assertEqual((test_group.name, groups),
@@ -153,20 +151,20 @@ class ParserTest(unittest.TestCase):
[group1, test_group1, test_group2, test_group3, group2] = \
self.parse(
'DEF_GROUP "Group1"\n'
- 'ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
+ ' ENUM GLYPH "a" GLYPH "b" GLYPH "c" GLYPH "d" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "TestGroup1"\n'
- 'ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
+ ' ENUM GROUP "Group1" GROUP "Group2" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "TestGroup2"\n'
- 'ENUM GROUP "Group2" END_ENUM\n'
+ ' ENUM GROUP "Group2" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "TestGroup3"\n'
- 'ENUM GROUP "Group2" GROUP "Group1" END_ENUM\n'
+ ' ENUM GROUP "Group2" GROUP "Group1" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "Group2"\n'
- 'ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
- 'END_GROUP\n'
+ ' ENUM GLYPH "e" GLYPH "f" GLYPH "g" GLYPH "h" END_ENUM\n'
+ 'END_GROUP'
).statements
groups = [g.group for g in test_group1.enum.enum]
self.assertEqual(
@@ -197,12 +195,12 @@ class ParserTest(unittest.TestCase):
def test_def_group_glyphs_and_group(self):
[def_group1, def_group2] = self.parse(
'DEF_GROUP "aaccented"\n'
- 'ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
+ ' ENUM GLYPH "aacute" GLYPH "abreve" GLYPH "acircumflex" '
'GLYPH "adieresis" GLYPH "ae" GLYPH "agrave" GLYPH "amacron" '
'GLYPH "aogonek" GLYPH "aring" GLYPH "atilde" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "KERN_lc_a_2ND"\n'
- 'ENUM GLYPH "a" GROUP "aaccented" END_ENUM\n'
+ ' ENUM GLYPH "a" GROUP "aaccented" END_ENUM\n'
'END_GROUP'
).statements
items = def_group2.enum.enum
@@ -221,7 +219,7 @@ class ParserTest(unittest.TestCase):
'DEF_GLYPH "ccedilla" ID 210 UNICODE 231 TYPE BASE END_GLYPH\n'
'DEF_GLYPH "cdotaccent" ID 210 UNICODE 267 TYPE BASE END_GLYPH\n'
'DEF_GROUP "KERN_lc_a_2ND"\n'
- 'ENUM RANGE "a" TO "atilde" GLYPH "b" RANGE "c" TO "cdotaccent" '
+ ' ENUM RANGE "a" TO "atilde" GLYPH "b" RANGE "c" TO "cdotaccent" '
'END_ENUM\n'
'END_GROUP'
).statements[-1]
@@ -240,7 +238,7 @@ class ParserTest(unittest.TestCase):
'END_GROUP\n'
'DEF_GROUP "dupe"\n'
'ENUM GLYPH "x" END_ENUM\n'
- 'END_GROUP\n'
+ 'END_GROUP'
)
def test_group_duplicate_case_insensitive(self):
@@ -253,12 +251,12 @@ class ParserTest(unittest.TestCase):
'END_GROUP\n'
'DEF_GROUP "Dupe"\n'
'ENUM GLYPH "x" END_ENUM\n'
- 'END_GROUP\n'
+ 'END_GROUP'
)
def test_script_without_langsys(self):
[script] = self.parse(
- 'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
+ 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
'END_SCRIPT'
).statements
self.assertEqual((script.name, script.tag, script.langs),
@@ -266,10 +264,10 @@ class ParserTest(unittest.TestCase):
def test_langsys_normal(self):
[def_script] = self.parse(
- 'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
- 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n'
+ 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
+ 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n'
'END_LANGSYS\n'
- 'DEF_LANGSYS NAME "Moldavian" TAG "MOL "\n'
+ 'DEF_LANGSYS NAME "Moldavian" TAG "MOL "\n\n'
'END_LANGSYS\n'
'END_SCRIPT'
).statements
@@ -287,8 +285,8 @@ class ParserTest(unittest.TestCase):
def test_langsys_no_script_name(self):
[langsys] = self.parse(
- 'DEF_SCRIPT TAG "latn"\n'
- 'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
+ 'DEF_SCRIPT TAG "latn"\n\n'
+ 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
'END_LANGSYS\n'
'END_SCRIPT'
).statements
@@ -305,8 +303,8 @@ class ParserTest(unittest.TestCase):
VoltLibError,
r'.*Expected "TAG"'):
[langsys] = self.parse(
- 'DEF_SCRIPT NAME "Latin"\n'
- 'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
+ 'DEF_SCRIPT NAME "Latin"\n\n'
+ 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
'END_LANGSYS\n'
'END_SCRIPT'
).statements
@@ -317,12 +315,12 @@ class ParserTest(unittest.TestCase):
'Script "DFLT" already defined, '
'script tags are case insensitive'):
[langsys1, langsys2] = self.parse(
- 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n'
- 'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
+ 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n\n'
+ 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
'END_LANGSYS\n'
'END_SCRIPT\n'
- 'DEF_SCRIPT TAG "DFLT"\n'
- 'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
+ 'DEF_SCRIPT TAG "DFLT"\n\n'
+ 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
'END_LANGSYS\n'
'END_SCRIPT'
).statements
@@ -338,21 +336,21 @@ class ParserTest(unittest.TestCase):
'END_LANGSYS\n'
'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
'END_LANGSYS\n'
- 'END_SCRIPT\n'
+ 'END_SCRIPT'
).statements
def test_langsys_lang_in_separate_scripts(self):
[langsys1, langsys2] = self.parse(
- 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n'
- 'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
+ 'DEF_SCRIPT NAME "Default" TAG "DFLT"\n\n'
+ 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
'END_LANGSYS\n'
- 'DEF_LANGSYS NAME "Default" TAG "ROM "\n'
+ 'DEF_LANGSYS NAME "Default" TAG "ROM "\n\n'
'END_LANGSYS\n'
'END_SCRIPT\n'
- 'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
- 'DEF_LANGSYS NAME "Default" TAG "dflt"\n'
+ 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
+ 'DEF_LANGSYS NAME "Default" TAG "dflt"\n\n'
'END_LANGSYS\n'
- 'DEF_LANGSYS NAME "Default" TAG "ROM "\n'
+ 'DEF_LANGSYS NAME "Default" TAG "ROM "\n\n'
'END_LANGSYS\n'
'END_SCRIPT'
).statements
@@ -363,8 +361,8 @@ class ParserTest(unittest.TestCase):
def test_langsys_no_lang_name(self):
[langsys] = self.parse(
- 'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
- 'DEF_LANGSYS TAG "dflt"\n'
+ 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
+ 'DEF_LANGSYS TAG "dflt"\n\n'
'END_LANGSYS\n'
'END_SCRIPT'
).statements
@@ -381,18 +379,18 @@ class ParserTest(unittest.TestCase):
VoltLibError,
r'.*Expected "TAG"'):
[langsys] = self.parse(
- 'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
- 'DEF_LANGSYS NAME "Default"\n'
+ 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
+ 'DEF_LANGSYS NAME "Default"\n\n'
'END_LANGSYS\n'
'END_SCRIPT'
).statements
def test_feature(self):
[def_script] = self.parse(
- 'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
- 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n'
+ 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
+ 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n'
'DEF_FEATURE NAME "Fractions" TAG "frac"\n'
- 'LOOKUP "fraclookup"\n'
+ ' LOOKUP "fraclookup"\n'
'END_FEATURE\n'
'END_LANGSYS\n'
'END_SCRIPT'
@@ -404,10 +402,10 @@ class ParserTest(unittest.TestCase):
"frac",
["fraclookup"]))
[def_script] = self.parse(
- 'DEF_SCRIPT NAME "Latin" TAG "latn"\n'
- 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n'
+ 'DEF_SCRIPT NAME "Latin" TAG "latn"\n\n'
+ 'DEF_LANGSYS NAME "Romanian" TAG "ROM "\n\n'
'DEF_FEATURE NAME "Kerning" TAG "kern"\n'
- 'LOOKUP "kern1" LOOKUP "kern2"\n'
+ ' LOOKUP "kern1" LOOKUP "kern2"\n'
'END_FEATURE\n'
'END_LANGSYS\n'
'END_SCRIPT'
@@ -475,6 +473,21 @@ class ParserTest(unittest.TestCase):
'END_SUBSTITUTION\n'
).statements
+ def test_lookup_comments(self):
+ [lookup] = self.parse(
+ 'DEF_LOOKUP "test" PROCESS_BASE PROCESS_MARKS ALL DIRECTION LTR\n'
+ 'COMMENTS "Hello\\nWorld"\n'
+ 'IN_CONTEXT\n'
+ 'END_CONTEXT\n'
+ 'AS_SUBSTITUTION\n'
+ 'SUB GLYPH "a"\n'
+ 'WITH GLYPH "b"\n'
+ 'END_SUB\n'
+ 'END_SUBSTITUTION'
+ ).statements
+ self.assertEqual(lookup.name, "test")
+ self.assertEqual(lookup.comments, "Hello\nWorld")
+
def test_substitution_empty(self):
with self.assertRaisesRegex(
VoltLibError,
@@ -559,12 +572,13 @@ class ParserTest(unittest.TestCase):
def test_substitution_single_in_context(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "Denominators" ENUM GLYPH "one.dnom" GLYPH "two.dnom" '
- 'END_ENUM END_GROUP\n'
+ 'DEF_GROUP "Denominators"\n'
+ ' ENUM GLYPH "one.dnom" GLYPH "two.dnom" END_ENUM\n'
+ 'END_GROUP\n'
'DEF_LOOKUP "fracdnom" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR\n'
- 'IN_CONTEXT LEFT ENUM GROUP "Denominators" GLYPH "fraction" '
- 'END_ENUM\n'
+ 'IN_CONTEXT\n'
+ ' LEFT ENUM GROUP "Denominators" GLYPH "fraction" END_ENUM\n'
'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
'SUB GLYPH "one"\n'
@@ -590,17 +604,18 @@ class ParserTest(unittest.TestCase):
def test_substitution_single_in_contexts(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "Hebrew" ENUM GLYPH "uni05D0" GLYPH "uni05D1" '
- 'END_ENUM END_GROUP\n'
+ 'DEF_GROUP "Hebrew"\n'
+ ' ENUM GLYPH "uni05D0" GLYPH "uni05D1" END_ENUM\n'
+ 'END_GROUP\n'
'DEF_LOOKUP "HebrewCurrency" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR\n'
'IN_CONTEXT\n'
- 'RIGHT GROUP "Hebrew"\n'
- 'RIGHT GLYPH "one.Hebr"\n'
+ ' RIGHT GROUP "Hebrew"\n'
+ ' RIGHT GLYPH "one.Hebr"\n'
'END_CONTEXT\n'
'IN_CONTEXT\n'
- 'LEFT GROUP "Hebrew"\n'
- 'LEFT GLYPH "one.Hebr"\n'
+ ' LEFT GROUP "Hebrew"\n'
+ ' LEFT GLYPH "one.Hebr"\n'
'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
'SUB GLYPH "dollar"\n'
@@ -631,8 +646,9 @@ class ParserTest(unittest.TestCase):
def test_substitution_skip_base(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
- 'END_ENUM END_GROUP\n'
+ 'DEF_GROUP "SomeMarks"\n'
+ ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
+ 'END_GROUP\n'
'DEF_LOOKUP "SomeSub" SKIP_BASE PROCESS_MARKS ALL '
'DIRECTION LTR\n'
'IN_CONTEXT\n'
@@ -649,8 +665,9 @@ class ParserTest(unittest.TestCase):
def test_substitution_process_base(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
- 'END_ENUM END_GROUP\n'
+ 'DEF_GROUP "SomeMarks"\n'
+ ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
+ 'END_GROUP\n'
'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR\n'
'IN_CONTEXT\n'
@@ -665,12 +682,74 @@ class ParserTest(unittest.TestCase):
(lookup.name, lookup.process_base),
("SomeSub", True))
+ def test_substitution_process_marks(self):
+ [group, lookup] = self.parse(
+ 'DEF_GROUP "SomeMarks"\n'
+ ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
+ 'END_GROUP\n'
+ 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS "SomeMarks"\n'
+ 'IN_CONTEXT\n'
+ 'END_CONTEXT\n'
+ 'AS_SUBSTITUTION\n'
+ 'SUB GLYPH "A"\n'
+ 'WITH GLYPH "A.c2sc"\n'
+ 'END_SUB\n'
+ 'END_SUBSTITUTION'
+ ).statements
+ self.assertEqual(
+ (lookup.name, lookup.process_marks),
+ ("SomeSub", 'SomeMarks'))
+
+ def test_substitution_process_marks_all(self):
+ [lookup] = self.parse(
+ 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL\n'
+ 'IN_CONTEXT\n'
+ 'END_CONTEXT\n'
+ 'AS_SUBSTITUTION\n'
+ 'SUB GLYPH "A"\n'
+ 'WITH GLYPH "A.c2sc"\n'
+ 'END_SUB\n'
+ 'END_SUBSTITUTION'
+ ).statements
+ self.assertEqual(
+ (lookup.name, lookup.process_marks),
+ ("SomeSub", True))
+
+ def test_substitution_process_marks_none(self):
+ [lookup] = self.parse_(
+ 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS "NONE"\n'
+ 'IN_CONTEXT\n'
+ 'END_CONTEXT\n'
+ 'AS_SUBSTITUTION\n'
+ 'SUB GLYPH "A"\n'
+ 'WITH GLYPH "A.c2sc"\n'
+ 'END_SUB\n'
+ 'END_SUBSTITUTION'
+ ).statements
+ self.assertEqual(
+ (lookup.name, lookup.process_marks),
+ ("SomeSub", False))
+
+ def test_substitution_process_marks_bad(self):
+ with self.assertRaisesRegex(
+ VoltLibError,
+ 'Expected ALL, NONE, MARK_GLYPH_SET or an ID'):
+ self.parse(
+ 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
+ 'END_ENUM END_GROUP\n'
+ 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS SomeMarks '
+ 'AS_SUBSTITUTION\n'
+ 'SUB GLYPH "A" WITH GLYPH "A.c2sc"\n'
+ 'END_SUB\n'
+ 'END_SUBSTITUTION'
+ )
+
def test_substitution_skip_marks(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "SomeMarks" ENUM GLYPH "marka" GLYPH "markb" '
- 'END_ENUM END_GROUP\n'
- 'DEF_LOOKUP "SomeSub" PROCESS_BASE SKIP_MARKS '
- 'DIRECTION LTR\n'
+ 'DEF_GROUP "SomeMarks"\n'
+ ' ENUM GLYPH "marka" GLYPH "markb" END_ENUM\n'
+ 'END_GROUP\n'
+ 'DEF_LOOKUP "SomeSub" PROCESS_BASE SKIP_MARKS DIRECTION LTR\n'
'IN_CONTEXT\n'
'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
@@ -685,11 +764,13 @@ class ParserTest(unittest.TestCase):
def test_substitution_mark_attachment(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" '
- 'END_ENUM END_GROUP\n'
+ 'DEF_GROUP "SomeMarks"\n'
+ ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n'
+ 'END_GROUP\n'
'DEF_LOOKUP "SomeSub" PROCESS_BASE '
- 'PROCESS_MARKS "SomeMarks" \n'
- 'DIRECTION RTL\n'
+ 'PROCESS_MARKS "SomeMarks" DIRECTION RTL\n'
+ 'IN_CONTEXT\n'
+ 'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
'SUB GLYPH "A"\n'
'WITH GLYPH "A.c2sc"\n'
@@ -702,11 +783,13 @@ class ParserTest(unittest.TestCase):
def test_substitution_mark_glyph_set(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" '
- 'END_ENUM END_GROUP\n'
+ 'DEF_GROUP "SomeMarks"\n'
+ ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n'
+ 'END_GROUP\n'
'DEF_LOOKUP "SomeSub" PROCESS_BASE '
- 'PROCESS_MARKS MARK_GLYPH_SET "SomeMarks" \n'
- 'DIRECTION RTL\n'
+ 'PROCESS_MARKS MARK_GLYPH_SET "SomeMarks" DIRECTION RTL\n'
+ 'IN_CONTEXT\n'
+ 'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
'SUB GLYPH "A"\n'
'WITH GLYPH "A.c2sc"\n'
@@ -719,11 +802,13 @@ class ParserTest(unittest.TestCase):
def test_substitution_process_all_marks(self):
[group, lookup] = self.parse(
- 'DEF_GROUP "SomeMarks" ENUM GLYPH "acutecmb" GLYPH "gravecmb" '
- 'END_ENUM END_GROUP\n'
- 'DEF_LOOKUP "SomeSub" PROCESS_BASE '
- 'PROCESS_MARKS ALL \n'
+ 'DEF_GROUP "SomeMarks"\n'
+ ' ENUM GLYPH "acutecmb" GLYPH "gravecmb" END_ENUM\n'
+ 'END_GROUP\n'
+ 'DEF_LOOKUP "SomeSub" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION RTL\n'
+ 'IN_CONTEXT\n'
+ 'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
'SUB GLYPH "A"\n'
'WITH GLYPH "A.c2sc"\n'
@@ -740,7 +825,7 @@ class ParserTest(unittest.TestCase):
'DEF_LOOKUP "Lookup" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR\n'
'IN_CONTEXT\n'
- 'RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
+ ' RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
'SUB GLYPH "a"\n'
@@ -756,15 +841,15 @@ class ParserTest(unittest.TestCase):
def test_substitution_reversal(self):
lookup = self.parse(
'DEF_GROUP "DFLT_Num_standardFigures"\n'
- 'ENUM GLYPH "zero" GLYPH "one" GLYPH "two" END_ENUM\n'
+ ' ENUM GLYPH "zero" GLYPH "one" GLYPH "two" END_ENUM\n'
'END_GROUP\n'
'DEF_GROUP "DFLT_Num_numerators"\n'
- 'ENUM GLYPH "zero.numr" GLYPH "one.numr" GLYPH "two.numr" END_ENUM\n'
+ ' ENUM GLYPH "zero.numr" GLYPH "one.numr" GLYPH "two.numr" END_ENUM\n'
'END_GROUP\n'
'DEF_LOOKUP "RevLookup" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR REVERSAL\n'
'IN_CONTEXT\n'
- 'RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
+ ' RIGHT ENUM GLYPH "a" GLYPH "b" END_ENUM\n'
'END_CONTEXT\n'
'AS_SUBSTITUTION\n'
'SUB GROUP "DFLT_Num_standardFigures"\n'
@@ -820,7 +905,7 @@ class ParserTest(unittest.TestCase):
'DEF_LOOKUP "numr" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR REVERSAL\n'
'IN_CONTEXT\n'
- 'RIGHT ENUM '
+ ' RIGHT ENUM '
'GLYPH "fraction" '
'RANGE "zero.numr" TO "nine.numr" '
'END_ENUM\n'
@@ -861,7 +946,7 @@ class ParserTest(unittest.TestCase):
'DEF_LOOKUP "empty_position" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR\n'
'EXCEPT_CONTEXT\n'
- 'LEFT GLYPH "glyph"\n'
+ ' LEFT GLYPH "glyph"\n'
'END_CONTEXT\n'
'AS_POSITION\n'
'END_POSITION'
@@ -880,13 +965,13 @@ class ParserTest(unittest.TestCase):
'END_ATTACH\n'
'END_POSITION\n'
'DEF_ANCHOR "MARK_top" ON 120 GLYPH acutecomb COMPONENT 1 '
- 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
+ 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
'DEF_ANCHOR "MARK_top" ON 121 GLYPH gravecomb COMPONENT 1 '
- 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
+ 'AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
'DEF_ANCHOR "top" ON 31 GLYPH a COMPONENT 1 '
- 'AT POS DX 210 DY 450 END_POS END_ANCHOR\n'
+ 'AT POS DX 210 DY 450 END_POS END_ANCHOR\n'
'DEF_ANCHOR "top" ON 35 GLYPH e COMPONENT 1 '
- 'AT POS DX 215 DY 450 END_POS END_ANCHOR\n'
+ 'AT POS DX 215 DY 450 END_POS END_ANCHOR'
).statements
pos = lookup.pos
coverage = [g.glyph for g in pos.coverage]
@@ -926,9 +1011,9 @@ class ParserTest(unittest.TestCase):
'IN_CONTEXT\n'
'END_CONTEXT\n'
'AS_POSITION\n'
- 'ATTACH_CURSIVE EXIT GLYPH "a" GLYPH "b" ENTER GLYPH "c"\n'
+ 'ATTACH_CURSIVE\nEXIT GLYPH "a" GLYPH "b"\nENTER GLYPH "c"\n'
'END_ATTACH\n'
- 'END_POSITION\n'
+ 'END_POSITION'
).statements
exit = [[g.glyph for g in v] for v in lookup.pos.coverages_exit]
enter = [[g.glyph for g in v] for v in lookup.pos.coverages_enter]
@@ -945,12 +1030,12 @@ class ParserTest(unittest.TestCase):
'END_CONTEXT\n'
'AS_POSITION\n'
'ADJUST_PAIR\n'
- ' FIRST GLYPH "A"\n'
- ' SECOND GLYPH "V"\n'
+ ' FIRST GLYPH "A"\n'
+ ' SECOND GLYPH "V"\n'
' 1 2 BY POS ADV -30 END_POS POS END_POS\n'
- ' 2 1 BY POS ADV -30 END_POS POS END_POS\n'
+ ' 2 1 BY POS ADV -30 END_POS POS END_POS\n\n'
'END_ADJUST\n'
- 'END_POSITION\n'
+ 'END_POSITION'
).statements
coverages_1 = [[g.glyph for g in v] for v in lookup.pos.coverages_1]
coverages_2 = [[g.glyph for g in v] for v in lookup.pos.coverages_2]
@@ -969,15 +1054,15 @@ class ParserTest(unittest.TestCase):
'DEF_LOOKUP "TestLookup" PROCESS_BASE PROCESS_MARKS ALL '
'DIRECTION LTR\n'
'IN_CONTEXT\n'
- # 'LEFT GLYPH "leftGlyph"\n'
- # 'RIGHT GLYPH "rightGlyph"\n'
+ # ' LEFT GLYPH "leftGlyph"\n'
+ # ' RIGHT GLYPH "rightGlyph"\n'
'END_CONTEXT\n'
'AS_POSITION\n'
'ADJUST_SINGLE'
- ' GLYPH "glyph1" BY POS ADV 0 DX 123 END_POS\n'
+ ' GLYPH "glyph1" BY POS ADV 0 DX 123 END_POS'
' GLYPH "glyph2" BY POS ADV 0 DX 456 END_POS\n'
'END_ADJUST\n'
- 'END_POSITION\n'
+ 'END_POSITION'
).statements
pos = lookup.pos
adjust = [[[g.glyph for g in a], b] for (a, b) in pos.adjust_single]
@@ -991,11 +1076,11 @@ class ParserTest(unittest.TestCase):
def test_def_anchor(self):
[anchor1, anchor2, anchor3] = self.parse(
'DEF_ANCHOR "top" ON 120 GLYPH a '
- 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
+ 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
'DEF_ANCHOR "MARK_top" ON 120 GLYPH acutecomb '
- 'COMPONENT 1 AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
+ 'COMPONENT 1 AT POS DX 0 DY 450 END_POS END_ANCHOR\n'
'DEF_ANCHOR "bottom" ON 120 GLYPH a '
- 'COMPONENT 1 AT POS DX 250 DY 0 END_POS END_ANCHOR\n'
+ 'COMPONENT 1 AT POS DX 250 DY 0 END_POS END_ANCHOR'
).statements
self.assertEqual(
(anchor1.name, anchor1.gid, anchor1.glyph_name, anchor1.component,
@@ -1019,9 +1104,9 @@ class ParserTest(unittest.TestCase):
def test_def_anchor_multi_component(self):
[anchor1, anchor2] = self.parse(
'DEF_ANCHOR "top" ON 120 GLYPH a '
- 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
+ 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
'DEF_ANCHOR "top" ON 120 GLYPH a '
- 'COMPONENT 2 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
+ 'COMPONENT 2 AT POS DX 250 DY 450 END_POS END_ANCHOR'
).statements
self.assertEqual(
(anchor1.name, anchor1.gid, anchor1.glyph_name, anchor1.component),
@@ -1039,15 +1124,15 @@ class ParserTest(unittest.TestCase):
'anchor names are case insensitive',
self.parse,
'DEF_ANCHOR "dupe" ON 120 GLYPH a '
- 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
+ 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
'DEF_ANCHOR "dupe" ON 120 GLYPH a '
- 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
+ 'COMPONENT 1 AT POS DX 250 DY 450 END_POS END_ANCHOR'
)
def test_def_anchor_locked(self):
[anchor] = self.parse(
'DEF_ANCHOR "top" ON 120 GLYPH a '
- 'COMPONENT 1 LOCKED AT POS DX 250 DY 450 END_POS END_ANCHOR\n'
+ 'COMPONENT 1 LOCKED AT POS DX 250 DY 450 END_POS END_ANCHOR'
).statements
self.assertEqual(
(anchor.name, anchor.gid, anchor.glyph_name, anchor.component,
@@ -1059,7 +1144,7 @@ class ParserTest(unittest.TestCase):
def test_anchor_adjust_device(self):
[anchor] = self.parse(
'DEF_ANCHOR "MARK_top" ON 123 GLYPH diacglyph '
- 'COMPONENT 1 AT POS DX 0 DY 456 ADJUST_BY 12 AT 34 '
+ 'COMPONENT 1 AT POS DX 0 DY 456 ADJUST_BY 12 AT 34 '
'ADJUST_BY 56 AT 78 END_POS END_ANCHOR'
).statements
self.assertEqual(
@@ -1071,7 +1156,7 @@ class ParserTest(unittest.TestCase):
[grid_ppem, pres_ppem, ppos_ppem] = self.parse(
'GRID_PPEM 20\n'
'PRESENTATION_PPEM 72\n'
- 'PPOSITIONING_PPEM 144\n'
+ 'PPOSITIONING_PPEM 144'
).statements
self.assertEqual(
((grid_ppem.name, grid_ppem.value),
@@ -1084,7 +1169,7 @@ class ParserTest(unittest.TestCase):
def test_compiler_flags(self):
[setting1, setting2] = self.parse(
'COMPILER_USEEXTENSIONLOOKUPS\n'
- 'COMPILER_USEPAIRPOSFORMAT2\n'
+ 'COMPILER_USEPAIRPOSFORMAT2'
).statements
self.assertEqual(
((setting1.name, setting1.value),
@@ -1097,7 +1182,7 @@ class ParserTest(unittest.TestCase):
[cmap_format1, cmap_format2, cmap_format3] = self.parse(
'CMAP_FORMAT 0 3 4\n'
'CMAP_FORMAT 1 0 6\n'
- 'CMAP_FORMAT 3 1 4\n'
+ 'CMAP_FORMAT 3 1 4'
).statements
self.assertEqual(
((cmap_format1.name, cmap_format1.value),
@@ -1108,16 +1193,42 @@ class ParserTest(unittest.TestCase):
("CMAP_FORMAT", (3, 1, 4)))
)
+ def test_do_not_touch_cmap(self):
+ [option1, option2, option3, option4] = self.parse(
+ 'DO_NOT_TOUCH_CMAP\n'
+ 'CMAP_FORMAT 0 3 4\n'
+ 'CMAP_FORMAT 1 0 6\n'
+ 'CMAP_FORMAT 3 1 4'
+ ).statements
+ self.assertEqual(
+ ((option1.name, option1.value),
+ (option2.name, option2.value),
+ (option3.name, option3.value),
+ (option4.name, option4.value)),
+ (("DO_NOT_TOUCH_CMAP", True),
+ ("CMAP_FORMAT", (0, 3, 4)),
+ ("CMAP_FORMAT", (1, 0, 6)),
+ ("CMAP_FORMAT", (3, 1, 4)))
+ )
+
def test_stop_at_end(self):
- [def_glyph] = self.parse(
+ doc = self.parse_(
'DEF_GLYPH ".notdef" ID 0 TYPE BASE END_GLYPH END\0\0\0\0'
- ).statements
+ )
+ [def_glyph] = doc.statements
self.assertEqual((def_glyph.name, def_glyph.id, def_glyph.unicode,
def_glyph.type, def_glyph.components),
(".notdef", 0, None, "BASE", None))
+ self.assertEqual(str(doc),
+ '\nDEF_GLYPH ".notdef" ID 0 TYPE BASE END_GLYPH END\n')
+
+ def parse_(self, text):
+ return Parser(StringIO(text)).parse()
def parse(self, text):
- return Parser(UnicodeIO(text)).parse()
+ doc = self.parse_(text)
+ self.assertEqual('\n'.join(str(s) for s in doc.statements), text)
+ return Parser(StringIO(text)).parse()
if __name__ == "__main__":
import sys