1*e1fe3e4aSElliott Hughesfrom fontTools.voltLib.error import VoltLibError 2*e1fe3e4aSElliott Hughesfrom typing import NamedTuple 3*e1fe3e4aSElliott Hughes 4*e1fe3e4aSElliott Hughes 5*e1fe3e4aSElliott Hughesclass Pos(NamedTuple): 6*e1fe3e4aSElliott Hughes adv: int 7*e1fe3e4aSElliott Hughes dx: int 8*e1fe3e4aSElliott Hughes dy: int 9*e1fe3e4aSElliott Hughes adv_adjust_by: dict 10*e1fe3e4aSElliott Hughes dx_adjust_by: dict 11*e1fe3e4aSElliott Hughes dy_adjust_by: dict 12*e1fe3e4aSElliott Hughes 13*e1fe3e4aSElliott Hughes def __str__(self): 14*e1fe3e4aSElliott Hughes res = " POS" 15*e1fe3e4aSElliott Hughes for attr in ("adv", "dx", "dy"): 16*e1fe3e4aSElliott Hughes value = getattr(self, attr) 17*e1fe3e4aSElliott Hughes if value is not None: 18*e1fe3e4aSElliott Hughes res += f" {attr.upper()} {value}" 19*e1fe3e4aSElliott Hughes adjust_by = getattr(self, f"{attr}_adjust_by", {}) 20*e1fe3e4aSElliott Hughes for size, adjustment in adjust_by.items(): 21*e1fe3e4aSElliott Hughes res += f" ADJUST_BY {adjustment} AT {size}" 22*e1fe3e4aSElliott Hughes res += " END_POS" 23*e1fe3e4aSElliott Hughes return res 24*e1fe3e4aSElliott Hughes 25*e1fe3e4aSElliott Hughes 26*e1fe3e4aSElliott Hughesclass Element(object): 27*e1fe3e4aSElliott Hughes def __init__(self, location=None): 28*e1fe3e4aSElliott Hughes self.location = location 29*e1fe3e4aSElliott Hughes 30*e1fe3e4aSElliott Hughes def build(self, builder): 31*e1fe3e4aSElliott Hughes pass 32*e1fe3e4aSElliott Hughes 33*e1fe3e4aSElliott Hughes def __str__(self): 34*e1fe3e4aSElliott Hughes raise NotImplementedError 35*e1fe3e4aSElliott Hughes 36*e1fe3e4aSElliott Hughes 37*e1fe3e4aSElliott Hughesclass Statement(Element): 38*e1fe3e4aSElliott Hughes pass 39*e1fe3e4aSElliott Hughes 40*e1fe3e4aSElliott Hughes 41*e1fe3e4aSElliott Hughesclass Expression(Element): 42*e1fe3e4aSElliott Hughes pass 43*e1fe3e4aSElliott Hughes 44*e1fe3e4aSElliott Hughes 45*e1fe3e4aSElliott Hughesclass VoltFile(Statement): 46*e1fe3e4aSElliott Hughes def __init__(self): 47*e1fe3e4aSElliott Hughes Statement.__init__(self, location=None) 48*e1fe3e4aSElliott Hughes self.statements = [] 49*e1fe3e4aSElliott Hughes 50*e1fe3e4aSElliott Hughes def build(self, builder): 51*e1fe3e4aSElliott Hughes for s in self.statements: 52*e1fe3e4aSElliott Hughes s.build(builder) 53*e1fe3e4aSElliott Hughes 54*e1fe3e4aSElliott Hughes def __str__(self): 55*e1fe3e4aSElliott Hughes return "\n" + "\n".join(str(s) for s in self.statements) + " END\n" 56*e1fe3e4aSElliott Hughes 57*e1fe3e4aSElliott Hughes 58*e1fe3e4aSElliott Hughesclass GlyphDefinition(Statement): 59*e1fe3e4aSElliott Hughes def __init__(self, name, gid, gunicode, gtype, components, location=None): 60*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 61*e1fe3e4aSElliott Hughes self.name = name 62*e1fe3e4aSElliott Hughes self.id = gid 63*e1fe3e4aSElliott Hughes self.unicode = gunicode 64*e1fe3e4aSElliott Hughes self.type = gtype 65*e1fe3e4aSElliott Hughes self.components = components 66*e1fe3e4aSElliott Hughes 67*e1fe3e4aSElliott Hughes def __str__(self): 68*e1fe3e4aSElliott Hughes res = f'DEF_GLYPH "{self.name}" ID {self.id}' 69*e1fe3e4aSElliott Hughes if self.unicode is not None: 70*e1fe3e4aSElliott Hughes if len(self.unicode) > 1: 71*e1fe3e4aSElliott Hughes unicodes = ",".join(f"U+{u:04X}" for u in self.unicode) 72*e1fe3e4aSElliott Hughes res += f' UNICODEVALUES "{unicodes}"' 73*e1fe3e4aSElliott Hughes else: 74*e1fe3e4aSElliott Hughes res += f" UNICODE {self.unicode[0]}" 75*e1fe3e4aSElliott Hughes if self.type is not None: 76*e1fe3e4aSElliott Hughes res += f" TYPE {self.type}" 77*e1fe3e4aSElliott Hughes if self.components is not None: 78*e1fe3e4aSElliott Hughes res += f" COMPONENTS {self.components}" 79*e1fe3e4aSElliott Hughes res += " END_GLYPH" 80*e1fe3e4aSElliott Hughes return res 81*e1fe3e4aSElliott Hughes 82*e1fe3e4aSElliott Hughes 83*e1fe3e4aSElliott Hughesclass GroupDefinition(Statement): 84*e1fe3e4aSElliott Hughes def __init__(self, name, enum, location=None): 85*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 86*e1fe3e4aSElliott Hughes self.name = name 87*e1fe3e4aSElliott Hughes self.enum = enum 88*e1fe3e4aSElliott Hughes self.glyphs_ = None 89*e1fe3e4aSElliott Hughes 90*e1fe3e4aSElliott Hughes def glyphSet(self, groups=None): 91*e1fe3e4aSElliott Hughes if groups is not None and self.name in groups: 92*e1fe3e4aSElliott Hughes raise VoltLibError( 93*e1fe3e4aSElliott Hughes 'Group "%s" contains itself.' % (self.name), self.location 94*e1fe3e4aSElliott Hughes ) 95*e1fe3e4aSElliott Hughes if self.glyphs_ is None: 96*e1fe3e4aSElliott Hughes if groups is None: 97*e1fe3e4aSElliott Hughes groups = set({self.name}) 98*e1fe3e4aSElliott Hughes else: 99*e1fe3e4aSElliott Hughes groups.add(self.name) 100*e1fe3e4aSElliott Hughes self.glyphs_ = self.enum.glyphSet(groups) 101*e1fe3e4aSElliott Hughes return self.glyphs_ 102*e1fe3e4aSElliott Hughes 103*e1fe3e4aSElliott Hughes def __str__(self): 104*e1fe3e4aSElliott Hughes enum = self.enum and str(self.enum) or "" 105*e1fe3e4aSElliott Hughes return f'DEF_GROUP "{self.name}"\n{enum}\nEND_GROUP' 106*e1fe3e4aSElliott Hughes 107*e1fe3e4aSElliott Hughes 108*e1fe3e4aSElliott Hughesclass GlyphName(Expression): 109*e1fe3e4aSElliott Hughes """A single glyph name, such as cedilla.""" 110*e1fe3e4aSElliott Hughes 111*e1fe3e4aSElliott Hughes def __init__(self, glyph, location=None): 112*e1fe3e4aSElliott Hughes Expression.__init__(self, location) 113*e1fe3e4aSElliott Hughes self.glyph = glyph 114*e1fe3e4aSElliott Hughes 115*e1fe3e4aSElliott Hughes def glyphSet(self): 116*e1fe3e4aSElliott Hughes return (self.glyph,) 117*e1fe3e4aSElliott Hughes 118*e1fe3e4aSElliott Hughes def __str__(self): 119*e1fe3e4aSElliott Hughes return f' GLYPH "{self.glyph}"' 120*e1fe3e4aSElliott Hughes 121*e1fe3e4aSElliott Hughes 122*e1fe3e4aSElliott Hughesclass Enum(Expression): 123*e1fe3e4aSElliott Hughes """An enum""" 124*e1fe3e4aSElliott Hughes 125*e1fe3e4aSElliott Hughes def __init__(self, enum, location=None): 126*e1fe3e4aSElliott Hughes Expression.__init__(self, location) 127*e1fe3e4aSElliott Hughes self.enum = enum 128*e1fe3e4aSElliott Hughes 129*e1fe3e4aSElliott Hughes def __iter__(self): 130*e1fe3e4aSElliott Hughes for e in self.glyphSet(): 131*e1fe3e4aSElliott Hughes yield e 132*e1fe3e4aSElliott Hughes 133*e1fe3e4aSElliott Hughes def glyphSet(self, groups=None): 134*e1fe3e4aSElliott Hughes glyphs = [] 135*e1fe3e4aSElliott Hughes for element in self.enum: 136*e1fe3e4aSElliott Hughes if isinstance(element, (GroupName, Enum)): 137*e1fe3e4aSElliott Hughes glyphs.extend(element.glyphSet(groups)) 138*e1fe3e4aSElliott Hughes else: 139*e1fe3e4aSElliott Hughes glyphs.extend(element.glyphSet()) 140*e1fe3e4aSElliott Hughes return tuple(glyphs) 141*e1fe3e4aSElliott Hughes 142*e1fe3e4aSElliott Hughes def __str__(self): 143*e1fe3e4aSElliott Hughes enum = "".join(str(e) for e in self.enum) 144*e1fe3e4aSElliott Hughes return f" ENUM{enum} END_ENUM" 145*e1fe3e4aSElliott Hughes 146*e1fe3e4aSElliott Hughes 147*e1fe3e4aSElliott Hughesclass GroupName(Expression): 148*e1fe3e4aSElliott Hughes """A glyph group""" 149*e1fe3e4aSElliott Hughes 150*e1fe3e4aSElliott Hughes def __init__(self, group, parser, location=None): 151*e1fe3e4aSElliott Hughes Expression.__init__(self, location) 152*e1fe3e4aSElliott Hughes self.group = group 153*e1fe3e4aSElliott Hughes self.parser_ = parser 154*e1fe3e4aSElliott Hughes 155*e1fe3e4aSElliott Hughes def glyphSet(self, groups=None): 156*e1fe3e4aSElliott Hughes group = self.parser_.resolve_group(self.group) 157*e1fe3e4aSElliott Hughes if group is not None: 158*e1fe3e4aSElliott Hughes self.glyphs_ = group.glyphSet(groups) 159*e1fe3e4aSElliott Hughes return self.glyphs_ 160*e1fe3e4aSElliott Hughes else: 161*e1fe3e4aSElliott Hughes raise VoltLibError( 162*e1fe3e4aSElliott Hughes 'Group "%s" is used but undefined.' % (self.group), self.location 163*e1fe3e4aSElliott Hughes ) 164*e1fe3e4aSElliott Hughes 165*e1fe3e4aSElliott Hughes def __str__(self): 166*e1fe3e4aSElliott Hughes return f' GROUP "{self.group}"' 167*e1fe3e4aSElliott Hughes 168*e1fe3e4aSElliott Hughes 169*e1fe3e4aSElliott Hughesclass Range(Expression): 170*e1fe3e4aSElliott Hughes """A glyph range""" 171*e1fe3e4aSElliott Hughes 172*e1fe3e4aSElliott Hughes def __init__(self, start, end, parser, location=None): 173*e1fe3e4aSElliott Hughes Expression.__init__(self, location) 174*e1fe3e4aSElliott Hughes self.start = start 175*e1fe3e4aSElliott Hughes self.end = end 176*e1fe3e4aSElliott Hughes self.parser = parser 177*e1fe3e4aSElliott Hughes 178*e1fe3e4aSElliott Hughes def glyphSet(self): 179*e1fe3e4aSElliott Hughes return tuple(self.parser.glyph_range(self.start, self.end)) 180*e1fe3e4aSElliott Hughes 181*e1fe3e4aSElliott Hughes def __str__(self): 182*e1fe3e4aSElliott Hughes return f' RANGE "{self.start}" TO "{self.end}"' 183*e1fe3e4aSElliott Hughes 184*e1fe3e4aSElliott Hughes 185*e1fe3e4aSElliott Hughesclass ScriptDefinition(Statement): 186*e1fe3e4aSElliott Hughes def __init__(self, name, tag, langs, location=None): 187*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 188*e1fe3e4aSElliott Hughes self.name = name 189*e1fe3e4aSElliott Hughes self.tag = tag 190*e1fe3e4aSElliott Hughes self.langs = langs 191*e1fe3e4aSElliott Hughes 192*e1fe3e4aSElliott Hughes def __str__(self): 193*e1fe3e4aSElliott Hughes res = "DEF_SCRIPT" 194*e1fe3e4aSElliott Hughes if self.name is not None: 195*e1fe3e4aSElliott Hughes res += f' NAME "{self.name}"' 196*e1fe3e4aSElliott Hughes res += f' TAG "{self.tag}"\n\n' 197*e1fe3e4aSElliott Hughes for lang in self.langs: 198*e1fe3e4aSElliott Hughes res += f"{lang}" 199*e1fe3e4aSElliott Hughes res += "END_SCRIPT" 200*e1fe3e4aSElliott Hughes return res 201*e1fe3e4aSElliott Hughes 202*e1fe3e4aSElliott Hughes 203*e1fe3e4aSElliott Hughesclass LangSysDefinition(Statement): 204*e1fe3e4aSElliott Hughes def __init__(self, name, tag, features, location=None): 205*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 206*e1fe3e4aSElliott Hughes self.name = name 207*e1fe3e4aSElliott Hughes self.tag = tag 208*e1fe3e4aSElliott Hughes self.features = features 209*e1fe3e4aSElliott Hughes 210*e1fe3e4aSElliott Hughes def __str__(self): 211*e1fe3e4aSElliott Hughes res = "DEF_LANGSYS" 212*e1fe3e4aSElliott Hughes if self.name is not None: 213*e1fe3e4aSElliott Hughes res += f' NAME "{self.name}"' 214*e1fe3e4aSElliott Hughes res += f' TAG "{self.tag}"\n\n' 215*e1fe3e4aSElliott Hughes for feature in self.features: 216*e1fe3e4aSElliott Hughes res += f"{feature}" 217*e1fe3e4aSElliott Hughes res += "END_LANGSYS\n" 218*e1fe3e4aSElliott Hughes return res 219*e1fe3e4aSElliott Hughes 220*e1fe3e4aSElliott Hughes 221*e1fe3e4aSElliott Hughesclass FeatureDefinition(Statement): 222*e1fe3e4aSElliott Hughes def __init__(self, name, tag, lookups, location=None): 223*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 224*e1fe3e4aSElliott Hughes self.name = name 225*e1fe3e4aSElliott Hughes self.tag = tag 226*e1fe3e4aSElliott Hughes self.lookups = lookups 227*e1fe3e4aSElliott Hughes 228*e1fe3e4aSElliott Hughes def __str__(self): 229*e1fe3e4aSElliott Hughes res = f'DEF_FEATURE NAME "{self.name}" TAG "{self.tag}"\n' 230*e1fe3e4aSElliott Hughes res += " " + " ".join(f'LOOKUP "{l}"' for l in self.lookups) + "\n" 231*e1fe3e4aSElliott Hughes res += "END_FEATURE\n" 232*e1fe3e4aSElliott Hughes return res 233*e1fe3e4aSElliott Hughes 234*e1fe3e4aSElliott Hughes 235*e1fe3e4aSElliott Hughesclass LookupDefinition(Statement): 236*e1fe3e4aSElliott Hughes def __init__( 237*e1fe3e4aSElliott Hughes self, 238*e1fe3e4aSElliott Hughes name, 239*e1fe3e4aSElliott Hughes process_base, 240*e1fe3e4aSElliott Hughes process_marks, 241*e1fe3e4aSElliott Hughes mark_glyph_set, 242*e1fe3e4aSElliott Hughes direction, 243*e1fe3e4aSElliott Hughes reversal, 244*e1fe3e4aSElliott Hughes comments, 245*e1fe3e4aSElliott Hughes context, 246*e1fe3e4aSElliott Hughes sub, 247*e1fe3e4aSElliott Hughes pos, 248*e1fe3e4aSElliott Hughes location=None, 249*e1fe3e4aSElliott Hughes ): 250*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 251*e1fe3e4aSElliott Hughes self.name = name 252*e1fe3e4aSElliott Hughes self.process_base = process_base 253*e1fe3e4aSElliott Hughes self.process_marks = process_marks 254*e1fe3e4aSElliott Hughes self.mark_glyph_set = mark_glyph_set 255*e1fe3e4aSElliott Hughes self.direction = direction 256*e1fe3e4aSElliott Hughes self.reversal = reversal 257*e1fe3e4aSElliott Hughes self.comments = comments 258*e1fe3e4aSElliott Hughes self.context = context 259*e1fe3e4aSElliott Hughes self.sub = sub 260*e1fe3e4aSElliott Hughes self.pos = pos 261*e1fe3e4aSElliott Hughes 262*e1fe3e4aSElliott Hughes def __str__(self): 263*e1fe3e4aSElliott Hughes res = f'DEF_LOOKUP "{self.name}"' 264*e1fe3e4aSElliott Hughes res += f' {self.process_base and "PROCESS_BASE" or "SKIP_BASE"}' 265*e1fe3e4aSElliott Hughes if self.process_marks: 266*e1fe3e4aSElliott Hughes res += " PROCESS_MARKS " 267*e1fe3e4aSElliott Hughes if self.mark_glyph_set: 268*e1fe3e4aSElliott Hughes res += f'MARK_GLYPH_SET "{self.mark_glyph_set}"' 269*e1fe3e4aSElliott Hughes elif isinstance(self.process_marks, str): 270*e1fe3e4aSElliott Hughes res += f'"{self.process_marks}"' 271*e1fe3e4aSElliott Hughes else: 272*e1fe3e4aSElliott Hughes res += "ALL" 273*e1fe3e4aSElliott Hughes else: 274*e1fe3e4aSElliott Hughes res += " SKIP_MARKS" 275*e1fe3e4aSElliott Hughes if self.direction is not None: 276*e1fe3e4aSElliott Hughes res += f" DIRECTION {self.direction}" 277*e1fe3e4aSElliott Hughes if self.reversal: 278*e1fe3e4aSElliott Hughes res += " REVERSAL" 279*e1fe3e4aSElliott Hughes if self.comments is not None: 280*e1fe3e4aSElliott Hughes comments = self.comments.replace("\n", r"\n") 281*e1fe3e4aSElliott Hughes res += f'\nCOMMENTS "{comments}"' 282*e1fe3e4aSElliott Hughes if self.context: 283*e1fe3e4aSElliott Hughes res += "\n" + "\n".join(str(c) for c in self.context) 284*e1fe3e4aSElliott Hughes else: 285*e1fe3e4aSElliott Hughes res += "\nIN_CONTEXT\nEND_CONTEXT" 286*e1fe3e4aSElliott Hughes if self.sub: 287*e1fe3e4aSElliott Hughes res += f"\n{self.sub}" 288*e1fe3e4aSElliott Hughes if self.pos: 289*e1fe3e4aSElliott Hughes res += f"\n{self.pos}" 290*e1fe3e4aSElliott Hughes return res 291*e1fe3e4aSElliott Hughes 292*e1fe3e4aSElliott Hughes 293*e1fe3e4aSElliott Hughesclass SubstitutionDefinition(Statement): 294*e1fe3e4aSElliott Hughes def __init__(self, mapping, location=None): 295*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 296*e1fe3e4aSElliott Hughes self.mapping = mapping 297*e1fe3e4aSElliott Hughes 298*e1fe3e4aSElliott Hughes def __str__(self): 299*e1fe3e4aSElliott Hughes res = "AS_SUBSTITUTION\n" 300*e1fe3e4aSElliott Hughes for src, dst in self.mapping.items(): 301*e1fe3e4aSElliott Hughes src = "".join(str(s) for s in src) 302*e1fe3e4aSElliott Hughes dst = "".join(str(d) for d in dst) 303*e1fe3e4aSElliott Hughes res += f"SUB{src}\nWITH{dst}\nEND_SUB\n" 304*e1fe3e4aSElliott Hughes res += "END_SUBSTITUTION" 305*e1fe3e4aSElliott Hughes return res 306*e1fe3e4aSElliott Hughes 307*e1fe3e4aSElliott Hughes 308*e1fe3e4aSElliott Hughesclass SubstitutionSingleDefinition(SubstitutionDefinition): 309*e1fe3e4aSElliott Hughes pass 310*e1fe3e4aSElliott Hughes 311*e1fe3e4aSElliott Hughes 312*e1fe3e4aSElliott Hughesclass SubstitutionMultipleDefinition(SubstitutionDefinition): 313*e1fe3e4aSElliott Hughes pass 314*e1fe3e4aSElliott Hughes 315*e1fe3e4aSElliott Hughes 316*e1fe3e4aSElliott Hughesclass SubstitutionLigatureDefinition(SubstitutionDefinition): 317*e1fe3e4aSElliott Hughes pass 318*e1fe3e4aSElliott Hughes 319*e1fe3e4aSElliott Hughes 320*e1fe3e4aSElliott Hughesclass SubstitutionReverseChainingSingleDefinition(SubstitutionDefinition): 321*e1fe3e4aSElliott Hughes pass 322*e1fe3e4aSElliott Hughes 323*e1fe3e4aSElliott Hughes 324*e1fe3e4aSElliott Hughesclass PositionAttachDefinition(Statement): 325*e1fe3e4aSElliott Hughes def __init__(self, coverage, coverage_to, location=None): 326*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 327*e1fe3e4aSElliott Hughes self.coverage = coverage 328*e1fe3e4aSElliott Hughes self.coverage_to = coverage_to 329*e1fe3e4aSElliott Hughes 330*e1fe3e4aSElliott Hughes def __str__(self): 331*e1fe3e4aSElliott Hughes coverage = "".join(str(c) for c in self.coverage) 332*e1fe3e4aSElliott Hughes res = f"AS_POSITION\nATTACH{coverage}\nTO" 333*e1fe3e4aSElliott Hughes for coverage, anchor in self.coverage_to: 334*e1fe3e4aSElliott Hughes coverage = "".join(str(c) for c in coverage) 335*e1fe3e4aSElliott Hughes res += f'{coverage} AT ANCHOR "{anchor}"' 336*e1fe3e4aSElliott Hughes res += "\nEND_ATTACH\nEND_POSITION" 337*e1fe3e4aSElliott Hughes return res 338*e1fe3e4aSElliott Hughes 339*e1fe3e4aSElliott Hughes 340*e1fe3e4aSElliott Hughesclass PositionAttachCursiveDefinition(Statement): 341*e1fe3e4aSElliott Hughes def __init__(self, coverages_exit, coverages_enter, location=None): 342*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 343*e1fe3e4aSElliott Hughes self.coverages_exit = coverages_exit 344*e1fe3e4aSElliott Hughes self.coverages_enter = coverages_enter 345*e1fe3e4aSElliott Hughes 346*e1fe3e4aSElliott Hughes def __str__(self): 347*e1fe3e4aSElliott Hughes res = "AS_POSITION\nATTACH_CURSIVE" 348*e1fe3e4aSElliott Hughes for coverage in self.coverages_exit: 349*e1fe3e4aSElliott Hughes coverage = "".join(str(c) for c in coverage) 350*e1fe3e4aSElliott Hughes res += f"\nEXIT {coverage}" 351*e1fe3e4aSElliott Hughes for coverage in self.coverages_enter: 352*e1fe3e4aSElliott Hughes coverage = "".join(str(c) for c in coverage) 353*e1fe3e4aSElliott Hughes res += f"\nENTER {coverage}" 354*e1fe3e4aSElliott Hughes res += "\nEND_ATTACH\nEND_POSITION" 355*e1fe3e4aSElliott Hughes return res 356*e1fe3e4aSElliott Hughes 357*e1fe3e4aSElliott Hughes 358*e1fe3e4aSElliott Hughesclass PositionAdjustPairDefinition(Statement): 359*e1fe3e4aSElliott Hughes def __init__(self, coverages_1, coverages_2, adjust_pair, location=None): 360*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 361*e1fe3e4aSElliott Hughes self.coverages_1 = coverages_1 362*e1fe3e4aSElliott Hughes self.coverages_2 = coverages_2 363*e1fe3e4aSElliott Hughes self.adjust_pair = adjust_pair 364*e1fe3e4aSElliott Hughes 365*e1fe3e4aSElliott Hughes def __str__(self): 366*e1fe3e4aSElliott Hughes res = "AS_POSITION\nADJUST_PAIR\n" 367*e1fe3e4aSElliott Hughes for coverage in self.coverages_1: 368*e1fe3e4aSElliott Hughes coverage = " ".join(str(c) for c in coverage) 369*e1fe3e4aSElliott Hughes res += f" FIRST {coverage}" 370*e1fe3e4aSElliott Hughes res += "\n" 371*e1fe3e4aSElliott Hughes for coverage in self.coverages_2: 372*e1fe3e4aSElliott Hughes coverage = " ".join(str(c) for c in coverage) 373*e1fe3e4aSElliott Hughes res += f" SECOND {coverage}" 374*e1fe3e4aSElliott Hughes res += "\n" 375*e1fe3e4aSElliott Hughes for (id_1, id_2), (pos_1, pos_2) in self.adjust_pair.items(): 376*e1fe3e4aSElliott Hughes res += f" {id_1} {id_2} BY{pos_1}{pos_2}\n" 377*e1fe3e4aSElliott Hughes res += "\nEND_ADJUST\nEND_POSITION" 378*e1fe3e4aSElliott Hughes return res 379*e1fe3e4aSElliott Hughes 380*e1fe3e4aSElliott Hughes 381*e1fe3e4aSElliott Hughesclass PositionAdjustSingleDefinition(Statement): 382*e1fe3e4aSElliott Hughes def __init__(self, adjust_single, location=None): 383*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 384*e1fe3e4aSElliott Hughes self.adjust_single = adjust_single 385*e1fe3e4aSElliott Hughes 386*e1fe3e4aSElliott Hughes def __str__(self): 387*e1fe3e4aSElliott Hughes res = "AS_POSITION\nADJUST_SINGLE" 388*e1fe3e4aSElliott Hughes for coverage, pos in self.adjust_single: 389*e1fe3e4aSElliott Hughes coverage = "".join(str(c) for c in coverage) 390*e1fe3e4aSElliott Hughes res += f"{coverage} BY{pos}" 391*e1fe3e4aSElliott Hughes res += "\nEND_ADJUST\nEND_POSITION" 392*e1fe3e4aSElliott Hughes return res 393*e1fe3e4aSElliott Hughes 394*e1fe3e4aSElliott Hughes 395*e1fe3e4aSElliott Hughesclass ContextDefinition(Statement): 396*e1fe3e4aSElliott Hughes def __init__(self, ex_or_in, left=None, right=None, location=None): 397*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 398*e1fe3e4aSElliott Hughes self.ex_or_in = ex_or_in 399*e1fe3e4aSElliott Hughes self.left = left if left is not None else [] 400*e1fe3e4aSElliott Hughes self.right = right if right is not None else [] 401*e1fe3e4aSElliott Hughes 402*e1fe3e4aSElliott Hughes def __str__(self): 403*e1fe3e4aSElliott Hughes res = self.ex_or_in + "\n" 404*e1fe3e4aSElliott Hughes for coverage in self.left: 405*e1fe3e4aSElliott Hughes coverage = "".join(str(c) for c in coverage) 406*e1fe3e4aSElliott Hughes res += f" LEFT{coverage}\n" 407*e1fe3e4aSElliott Hughes for coverage in self.right: 408*e1fe3e4aSElliott Hughes coverage = "".join(str(c) for c in coverage) 409*e1fe3e4aSElliott Hughes res += f" RIGHT{coverage}\n" 410*e1fe3e4aSElliott Hughes res += "END_CONTEXT" 411*e1fe3e4aSElliott Hughes return res 412*e1fe3e4aSElliott Hughes 413*e1fe3e4aSElliott Hughes 414*e1fe3e4aSElliott Hughesclass AnchorDefinition(Statement): 415*e1fe3e4aSElliott Hughes def __init__(self, name, gid, glyph_name, component, locked, pos, location=None): 416*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 417*e1fe3e4aSElliott Hughes self.name = name 418*e1fe3e4aSElliott Hughes self.gid = gid 419*e1fe3e4aSElliott Hughes self.glyph_name = glyph_name 420*e1fe3e4aSElliott Hughes self.component = component 421*e1fe3e4aSElliott Hughes self.locked = locked 422*e1fe3e4aSElliott Hughes self.pos = pos 423*e1fe3e4aSElliott Hughes 424*e1fe3e4aSElliott Hughes def __str__(self): 425*e1fe3e4aSElliott Hughes locked = self.locked and " LOCKED" or "" 426*e1fe3e4aSElliott Hughes return ( 427*e1fe3e4aSElliott Hughes f'DEF_ANCHOR "{self.name}"' 428*e1fe3e4aSElliott Hughes f" ON {self.gid}" 429*e1fe3e4aSElliott Hughes f" GLYPH {self.glyph_name}" 430*e1fe3e4aSElliott Hughes f" COMPONENT {self.component}" 431*e1fe3e4aSElliott Hughes f"{locked}" 432*e1fe3e4aSElliott Hughes f" AT {self.pos} END_ANCHOR" 433*e1fe3e4aSElliott Hughes ) 434*e1fe3e4aSElliott Hughes 435*e1fe3e4aSElliott Hughes 436*e1fe3e4aSElliott Hughesclass SettingDefinition(Statement): 437*e1fe3e4aSElliott Hughes def __init__(self, name, value, location=None): 438*e1fe3e4aSElliott Hughes Statement.__init__(self, location) 439*e1fe3e4aSElliott Hughes self.name = name 440*e1fe3e4aSElliott Hughes self.value = value 441*e1fe3e4aSElliott Hughes 442*e1fe3e4aSElliott Hughes def __str__(self): 443*e1fe3e4aSElliott Hughes if self.value is True: 444*e1fe3e4aSElliott Hughes return f"{self.name}" 445*e1fe3e4aSElliott Hughes if isinstance(self.value, (tuple, list)): 446*e1fe3e4aSElliott Hughes value = " ".join(str(v) for v in self.value) 447*e1fe3e4aSElliott Hughes return f"{self.name} {value}" 448*e1fe3e4aSElliott Hughes return f"{self.name} {self.value}" 449