<commit_before>#!/usr/bin/python

# FontDame-to-FontTools for OpenType Layout tables
#
# Source language spec is available at:
# https://rawgit.com/Monotype/OpenType_Table_Source/master/otl_source.html
# https://github.com/Monotype/OpenType_Table_Source/

from __future__ import print_function, division, absolute_import
from fontTools import ttLib
from fontTools.ttLib.tables import otTables as ot
from fontTools.ttLib.tables.otBase import ValueRecord, valueRecordFormatDict
import re

debug = print

def parseGlyph(s):
	if s[:2] == 'U ':
		return ttLib.TTFont._makeGlyphName(int(s[2:], 16))
	elif s[:2] == '# ':
		return "glyph%.5d" % int(s[2:])
	return s

def parseGlyphs(l):
	return [parseGlyph(g) for g in l]

def parseScriptList(lines):
	line = next(lines)
	assert line[0].lower().endswith('script table begin'), line
	self = ot.ScriptList()
	self.ScriptRecord = []
	for line in lines.readUntil('script table end'):
		scriptTag, langSysTag, defaultFeature, features = line
		debug("Adding script", scriptTag, "language-system", langSysTag)

		langSys = ot.LangSys()
		langSys.LookupOrder = None
		# TODO The following two lines should use lazy feature name-to-index mapping
		langSys.ReqFeatureIndex = int(defaultFeature) if defaultFeature else 0xFFFF
		langSys.FeatureIndex = intSplitComma(features)
		langSys.FeatureCount = len(langSys.FeatureIndex)

		script = [s for s in self.ScriptRecord if s.ScriptTag == scriptTag]
		if script:
			script = script[0].Script
		else:
			scriptRec = ot.ScriptRecord()
			scriptRec.ScriptTag = scriptTag
			scriptRec.Script = ot.Script()
			self.ScriptRecord.append(scriptRec)
			script = scriptRec.Script
			script.DefaultLangSys = None
			script.LangSysRecord = []
			script.LangSysCount = 0

		if langSysTag == 'default':
			script.DefaultLangSys = langSys
		else:
			langSysRec = ot.LangSysRecord()
			langSysRec.LangSysTag = langSysTag + ' '*(4 - len(langSysTag))
			langSysRec.LangSys = langSys
			script.LangSysRecord.append(langSysRec)
			script.LangSysCount = len(script.LangSysRecord)

	self.ScriptCount = len(self.ScriptRecord)
	# TODO sort scripts and langSys's?
	return self

def parseFeatureList(lines):
	line = next(lines)
	assert line[0].lower().endswith('feature table begin'), line
	self = ot.FeatureList()
	self.FeatureRecord = []
	for line in lines.readUntil('feature table end'):
		idx, featureTag, lookups = line
		assert int(idx) == len(self.FeatureRecord), "%d %d" % (idx, len(self.FeatureRecord))
		featureRec = ot.FeatureRecord()
		featureRec.FeatureTag = featureTag
		featureRec.Feature = ot.Feature()
		self.FeatureRecord.append(featureRec)
		feature = featureRec.Feature
		feature.FeatureParams = None
		# TODO The following line should use lazy lookup name-to-index mapping
		feature.LookupListIndex = intSplitComma(lookups)
		feature.LookupCount = len(feature.LookupListIndex)

	self.FeatureCount = len(self.FeatureRecord)
	return self

def parseLookupFlags(lines):
	flags = 0
	filterset = None
	for line in lines:
		flag = {
			'righttoleft':		0x0001,
			'ignorebaseglyphs':	0x0002,
			'ignoreligatures':	0x0004,
			'ignoremarks':		0x0008,
			}.get(line[0].lower())
		if flag:
			assert line[1].lower() in ['yes', 'no'], line[1]
			if line[1].lower() == 'yes':
				flags |= flag
			continue
		if line[0].lower() == 'markattachmenttype':
			flags |= int(line[1]) << 8
			continue
		if line[0].lower() == 'markfiltertype':
			flags |= 0x10
			filterset = int(line[1])
		lines.pack(line)
		break
	return flags, filterset

def parseSingleSubst(self, lines, font):
	self.mapping = {}
	for line in lines:
		assert len(line) == 2, line
		line = parseGlyphs(line)
		self.mapping[line[0]] = line[1]

def parseMultiple(self, lines, font):
	self.mapping = {}
	for line in lines:
		line = parseGlyphs(line)
		self.mapping[line[0]] = line[1:]

def parseAlternate(self, lines, font):
	self.alternates = {}
	for line in lines:
		line = parseGlyphs(line)
		self.alternates[line[0]] = line[1:]

def parseLigature(self, lines, font):
	self.ligatures = {}
	for line in lines:
		assert len(line) >= 2, line
		line = parseGlyphs(line)
		# The following single line can replace the rest of this function with fontTools >= 3.1
		#self.ligatures[tuple(line[1:])] = line[0]
		ligGlyph, firstGlyph = line[:2]
		otherComponents = line[2:]
		ligature = ot.Ligature()
		ligature.Component = otherComponents
		ligature.CompCount = len(ligature.Component) + 1
		ligature.LigGlyph = ligGlyph
		self.ligatures.setdefault(firstGlyph, []).append(ligature)

def parseSinglePos(self, lines, font):
	values = {}
	for line in lines:
		assert len(line) == 3, line
		w = line[0].title().replace(' ', '')
		assert w in valueRecordFormatDict
		g = parseGlyph(line[1])
		v = int(line[2])
		if g not in values:
			values[g] = ValueRecord()
		assert not hasattr(values[g], w), (g, w)
		setattr(values[g], w, v)
	self.Coverage = makeCoverage(values.keys(), font)
	values = [values[k] for k in self.Coverage.glyphs]
	self.ValueFormat = reduce(int.__or__, [v.getFormat() for v in values])
	if all(v == values[0] for v in values):
		self.Format = 1
		self.Value = values[0]
	else:
		self.Format = 2
		self.Value = values
		self.ValueCount = len(self.Value)

def parsePair(self, lines, font):
	self.ValueFormat1 = self.ValueFormat2 = 0
	typ = lines.peek()[0].split()[0].lower()
	if typ in ('left', 'right'):
		self.Format = 1
		values = {}
		for line in lines:
			assert len(line) == 4, line
			side = line[0].split()[0].lower()
			assert side in ('left', 'right'), side
			what = line[0][len(side):].title().replace(' ', '')
			mask = valueRecordFormatDict[what][0]
			glyph1, glyph2 = parseGlyphs(line[1:3])
			value = int(line[3])
			if not glyph1 in values: values[glyph1] = {}
			if not glyph2 in values[glyph1]: values[glyph1][glyph2] = (ValueRecord(),ValueRecord())
			rec2 = values[glyph1][glyph2]
			if side == 'left':
				self.ValueFormat1 |= mask
				vr = rec2[0]
			else:
				self.ValueFormat2 |= mask
				vr = rec2[1]
			assert not hasattr(vr, what), (vr, what)
			setattr(vr, what, value)
		self.Coverage = makeCoverage(values.keys(), font)
		self.PairSet = []
		for glyph1 in self.Coverage.glyphs:
			values1 = values[glyph1]
			pairset = ot.PairSet()
			records = pairset.PairValueRecord = []
			for glyph2 in sorted(values1.keys(), key=font.getGlyphID):
				values2 = values1[glyph2]
				pair = ot.PairValueRecord()
				pair.SecondGlyph = glyph2
				pair.Value1,pair.Value2 = values2
				records.append(pair)
			pairset.PairValueCount = len(pairset.PairValueRecord)
			self.PairSet.append(pairset)
		self.PairSetCount = len(self.PairSet)
	elif typ.endswith('class'):
		self.Format = 2
		classDefs = [None, None]
		while lines.peek()[0].endswith("class definition begin"):
			typ = lines.peek()[0][:-len("class definition begin")].lower()
			idx,klass = {
				'first':	(0,ot.ClassDef1),
				'second':	(1,ot.ClassDef2),
			}[typ]
			assert classDefs[idx] is None
			classDefs[idx] = parseClassDef(lines, klass=klass)
		self.ClassDef1, self.ClassDef2 = classDefs
		self.Class1Count, self.Class2Count = (1+max(c.classDefs.values()) for c in classDefs)
		self.Class1Record = [ot.Class1Record() for i in range(self.Class1Count)]
		for rec1 in self.Class1Record:
			rec1.Class2Record = [ot.Class2Record() for j in range(self.Class2Count)]
			for rec2 in rec1.Class2Record:
				rec2.Value1 = ValueRecord()
				rec2.Value2 = ValueRecord()
		for line in lines:
			assert len(line) == 4, line
			side = line[0].split()[0].lower()
			assert side in ('left', 'right'), side
			what = line[0][len(side):].title().replace(' ', '')
			mask = valueRecordFormatDict[what][0]
			class1, class2, value = (int(x) for x in line[1:4])
			rec2 = self.Class1Record[class1].Class2Record[class2]
			if side == 'left':
				self.ValueFormat1 |= mask
				vr = rec2.Value1
			else:
				self.ValueFormat2 |= mask
				vr = rec2.Value2
			assert not hasattr(vr, what), (vr, what)
			setattr(vr, what, value)
		self.Coverage = makeCoverage(self.ClassDef1.classDefs.keys(), font)
	else:
		assert 0

def parseKernset(self, lines, font):
	typ = lines.peek()[0].split()[0].lower()
	if typ in ('left', 'right'):
		lines = lines.readUntil(("firstclass definition begin", "secondclass definition begin"), packBack=True)
	return parsePair(self, lines, font)

def makeAnchor(data, klass=ot.Anchor):
	assert len(data) <= 2
	anchor = klass()
	anchor.Format = 1
	anchor.XCoordinate,anchor.YCoordinate = intSplitComma(data[0])
	if len(data) > 1 and data[1] != '':
		anchor.Format = 2
		anchor.AnchorPoint = int(data[1])
	return anchor

def parseCursive(self, lines, font):
	self.Format = 1
	self.EntryExitRecord = []
	records = {}
	for line in lines:
		assert len(line) in [3,4], line
		idx,klass = {
			'entry':	(0,ot.EntryAnchor),
			'exit':		(1,ot.ExitAnchor),
		}[line[0]]
		glyph = parseGlyph(line[1])
		if glyph not in records:
			records[glyph] = [None,None]
		assert records[glyph][idx] is None, (glyph, idx)
		records[glyph][idx] = makeAnchor(line[2:], klass)
	self.Coverage = makeCoverage(records.keys(), font)
	recs = self.EntryExitRecord = []
	for glyph in self.Coverage.glyphs:
		rec = ot.EntryExitRecord()
		rec.EntryAnchor,rec.ExitAnchor = records[glyph]
		recs.append(rec)
	self.EntryExitCount = len(self.EntryExitRecord)

def makeMarkRecords(data, coverage, c):
	records = []
	for glyph in coverage.glyphs:
		klass, anchor = data[glyph]
		record = c.MarkRecordClass()
		record.Class = klass
		setattr(record, c.MarkAnchor, anchor)
		records.append(record)
	return records

def makeBaseRecords(data, coverage, c, classCount):
	records = []
	idx = {}
	for glyph in coverage.glyphs:
		idx[glyph] = len(records)
		record = c.BaseRecordClass()
		anchors = [None] * classCount
		setattr(record, c.BaseAnchor, anchors)
		records.append(record)
	for (glyph,klass),anchor in data.items():
		record = records[idx[glyph]]
		anchors = getattr(record, c.BaseAnchor)
		assert anchors[klass] is None, (glyph, klass)
		anchors[klass] = anchor
	return records

def makeLigatureRecords(data, coverage, c, classCount):
	records = [None] * len(coverage.glyphs)
	idx = {g:i for i,g in enumerate(coverage.glyphs)}

	for (glyph,klass,compIdx,compCount),anchor in data.items():
		record = records[idx[glyph]]
		if record is None:
			record = records[idx[glyph]] = ot.LigatureAttach()
			record.ComponentCount = compCount
			record.ComponentRecord = [ot.ComponentRecord() for i in range(compCount)]
			for compRec in record.ComponentRecord:
				compRec.LigatureAnchor = [None] * classCount
		assert record.ComponentCount == compCount, (glyph, record.ComponentCount, compCount)

		anchors = record.ComponentRecord[compIdx - 1].LigatureAnchor
		assert anchors[klass] is None, (glyph, compIdx, klass)
		anchors[klass] = anchor
	return records

def parseMarkToSomething(self, lines, font, c):
	self.Format = 1
	markData = {}
	baseData = {}
	Data = {
		'mark':		(markData, c.MarkAnchorClass),
		'base':		(baseData, c.BaseAnchorClass),
		'ligature':	(baseData, c.BaseAnchorClass),
	}
	for line in lines:
		typ = line[0]
		assert typ in ('mark', 'base', 'ligature')
		glyph = parseGlyph(line[1])
		data, anchorClass = Data[typ]
		extraItems = 2 if typ == 'ligature' else 0
		extras = tuple(int(i) for i in line[2:2+extraItems])
		klass = int(line[2+extraItems])
		anchor = makeAnchor(line[3+extraItems:], anchorClass)
		if typ == 'mark':
			key,value = glyph,(klass,anchor)
		else:
			key,value = ((glyph,klass)+extras),anchor
		assert key not in data, key
		data[key] = value

	# Mark
	markCoverage = makeCoverage(markData.keys(), font, c.MarkCoverageClass)
	markArray = c.MarkArrayClass()
	markRecords = makeMarkRecords(markData, markCoverage, c)
	setattr(markArray, c.MarkRecord, markRecords)
	setattr(markArray, c.MarkCount, len(markRecords))
	setattr(self, c.MarkCoverage, markCoverage)
	setattr(self, c.MarkArray, markArray)

	# Base
	self.classCount = 0 if not baseData else 1+max(k[1] for k,v in baseData.items())
	baseCoverage = makeCoverage([k[0] for k in baseData.keys()], font, c.BaseCoverageClass)
	baseArray = c.BaseArrayClass()
	if c.Base == 'Ligature':
		baseRecords = makeLigatureRecords(baseData, baseCoverage, c, self.classCount)
	else:
		baseRecords = makeBaseRecords(baseData, baseCoverage, c, self.classCount)
	setattr(baseArray, c.BaseRecord, baseRecords)
	setattr(baseArray, c.BaseCount, len(baseRecords))
	setattr(self, c.BaseCoverage, baseCoverage)
	setattr(self, c.BaseArray, baseArray)

class MarkHelper(object):
	def __init__(self):
		for Which in ('Mark', 'Base'):
			for What in ('Coverage', 'Array', 'Count', 'Record', 'Anchor'):
				key = Which + What
				if Which == 'Mark' and What in ('Count', 'Record', 'Anchor'):
					value = key
				else:
					value = getattr(self, Which) + What
				if value == 'LigatureRecord':
					value = 'LigatureAttach'
				setattr(self, key, value)
				if What != 'Count':
					klass = getattr(ot, value)
					setattr(self, key+'Class', klass)

class MarkToBaseHelper(MarkHelper):
	Mark = 'Mark'
	Base = 'Base'
class MarkToMarkHelper(MarkHelper):
	Mark = 'Mark1'
	Base = 'Mark2'
class MarkToLigatureHelper(MarkHelper):
	Mark = 'Mark'
	Base = 'Ligature'

def parseMarkToBase(self, lines, font):
	return parseMarkToSomething(self, lines, font, MarkToBaseHelper())
def parseMarkToMark(self, lines, font):
	return parseMarkToSomething(self, lines, font, MarkToMarkHelper())
def parseMarkToLigature(self, lines, font):
	return parseMarkToSomething(self, lines, font, MarkToLigatureHelper())

def stripSplitComma(line):
	return [s.strip() for s in line.split(',')] if line else []

def intSplitComma(line):
	return [int(i) for i in line.split(',')] if line else []

# Copied from fontTools.subset
class ContextHelper(object):
	def __init__(self, klassName, Format):
		if klassName.endswith('Subst'):
			Typ = 'Sub'
			Type = 'Subst'
		else:
			Typ = 'Pos'
			Type = 'Pos'
		if klassName.startswith('Chain'):
			Chain = 'Chain'
			InputIdx = 1
			DataLen = 3
		else:
			Chain = ''
			InputIdx = 0
			DataLen = 1
		ChainTyp = Chain+Typ

		self.Typ = Typ
		self.Type = Type
		self.Chain = Chain
		self.ChainTyp = ChainTyp
		self.InputIdx = InputIdx
		self.DataLen = DataLen

		self.LookupRecord = Type+'LookupRecord'

		if Format == 1:
			Coverage = lambda r: r.Coverage
			ChainCoverage = lambda r: r.Coverage
			ContextData = lambda r:(None,)
			ChainContextData = lambda r:(None, None, None)
			SetContextData = None
			SetChainContextData = None
			RuleData = lambda r:(r.Input,)
			ChainRuleData = lambda r:(r.Backtrack, r.Input, r.LookAhead)
			def SetRuleData(r, d):
				(r.Input,) = d
				(r.GlyphCount,) = (len(x)+1 for x in d)
			def ChainSetRuleData(r, d):
				(r.Backtrack, r.Input, r.LookAhead) = d
				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(d[0]),len(d[1])+1,len(d[2]))
		elif Format == 2:
			Coverage = lambda r: r.Coverage
			ChainCoverage = lambda r: r.Coverage
			ContextData = lambda r:(r.ClassDef,)
			ChainContextData = lambda r:(r.BacktrackClassDef,
						     r.InputClassDef,
						     r.LookAheadClassDef)
			def SetContextData(r, d):
				(r.ClassDef,) = d
			def SetChainContextData(r, d):
				(r.BacktrackClassDef,
				 r.InputClassDef,
				 r.LookAheadClassDef) = d
			RuleData = lambda r:(r.Class,)
			ChainRuleData = lambda r:(r.Backtrack, r.Input, r.LookAhead)
			def SetRuleData(r, d):
				(r.Class,) = d
				(r.GlyphCount,) = (len(x)+1 for x in d)
			def ChainSetRuleData(r, d):
				(r.Backtrack, r.Input, r.LookAhead) = d
				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(d[0]),len(d[1])+1,len(d[2]))
		elif Format == 3:
			Coverage = lambda r: r.Coverage[0]
			ChainCoverage = lambda r: r.InputCoverage[0]
			ContextData = None
			ChainContextData = None
			SetContextData = None
			SetChainContextData = None
			RuleData = lambda r: r.Coverage
			ChainRuleData = lambda r:(r.BacktrackCoverage +
						  r.InputCoverage +
						  r.LookAheadCoverage)
			def SetRuleData(r, d):
				(r.Coverage,) = d
				(r.GlyphCount,) = (len(x) for x in d)
			def ChainSetRuleData(r, d):
				(r.BacktrackCoverage, r.InputCoverage, r.LookAheadCoverage) = d
				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(x) for x in d)
		else:
			assert 0, "unknown format: %s" % Format

		if Chain:
			self.Coverage = ChainCoverage
			self.ContextData = ChainContextData
			self.SetContextData = SetChainContextData
			self.RuleData = ChainRuleData
			self.SetRuleData = ChainSetRuleData
		else:
			self.Coverage = Coverage
			self.ContextData = ContextData
			self.SetContextData = SetContextData
			self.RuleData = RuleData
			self.SetRuleData = SetRuleData

		if Format == 1:
			self.Rule = ChainTyp+'Rule'
			self.RuleCount = ChainTyp+'RuleCount'
			self.RuleSet = ChainTyp+'RuleSet'
			self.RuleSetCount = ChainTyp+'RuleSetCount'
			self.Intersect = lambda glyphs, c, r: [r] if r in glyphs else []
		elif Format == 2:
			self.Rule = ChainTyp+'ClassRule'
			self.RuleCount = ChainTyp+'ClassRuleCount'
			self.RuleSet = ChainTyp+'ClassSet'
			self.RuleSetCount = ChainTyp+'ClassSetCount'
			self.Intersect = lambda glyphs, c, r: (c.intersect_class(glyphs, r) if c
							       else (set(glyphs) if r == 0 else set()))

			self.ClassDef = 'InputClassDef' if Chain else 'ClassDef'
			self.ClassDefIndex = 1 if Chain else 0
			self.Input = 'Input' if Chain else 'Class'

def parseLookupRecords(items, klassName):
	klass = getattr(ot, klassName)
	lst = []
	for item in items:
		rec = klass()
		item = intSplitComma(item)
		assert len(item) == 2, item
		assert item[0] > 0, item[0]
		rec.SequenceIndex = item[0] - 1
		# TODO The following line should use lazy lookup name-to-index mapping
		rec.LookupListIndex = item[1]
		lst.append(rec)
	return lst

def makeClassDef(classDefs, klass=ot.Coverage):
	if not classDefs: return None
	self = klass()
	self.classDefs = dict(classDefs)
	return self

def parseClassDef(lines, klass=ot.ClassDef):
	line = next(lines)
	assert line[0].lower().endswith('class definition begin'), line
	classDefs = {}
	for line in lines.readUntil('class definition end'):
		glyph = parseGlyph(line[0])
		assert glyph not in classDefs, glyph
		classDefs[glyph] = int(line[1])
	return makeClassDef(classDefs, klass)

def makeCoverage(glyphs, font, klass=ot.Coverage):
	if not glyphs: return None
	coverage = klass()
	coverage.glyphs = sorted(set(glyphs), key=font.getGlyphID)
	return coverage

def parseCoverage(lines, font, klass=ot.Coverage):
	line = next(lines)
	assert line[0].lower().endswith('coverage definition begin'), line
	glyphs = []
	for line in lines.readUntil('coverage definition end'):
		glyphs.append(parseGlyph(line[0]))
	return makeCoverage(glyphs, font, klass)

def bucketizeRules(self, c, rules, bucketKeys):
	buckets = {}
	for seq,recs in rules:
		buckets.setdefault(seq[c.InputIdx][0], []).append((tuple(s[1 if i==c.InputIdx else 0:] for i,s in enumerate(seq)), recs))

	rulesets = []
	for firstGlyph in bucketKeys:
		if firstGlyph not in buckets:
			rulesets.append(None)
			continue
		thisRules = []
		for seq,recs in buckets[firstGlyph]:
			rule = getattr(ot, c.Rule)()
			c.SetRuleData(rule, seq)
			setattr(rule, c.Type+'Count', len(recs))
			setattr(rule, c.LookupRecord, recs)
			thisRules.append(rule)

		ruleset = getattr(ot, c.RuleSet)()
		setattr(ruleset, c.Rule, thisRules)
		setattr(ruleset, c.RuleCount, len(thisRules))
		rulesets.append(ruleset)

	setattr(self, c.RuleSet, rulesets)
	setattr(self, c.RuleSetCount, len(rulesets))

def parseContext(self, lines, font, Type):
	typ = lines.peek()[0].split()[0].lower()
	if typ == 'glyph':
		self.Format = 1
		debug("Parsing %s format %s" % (Type, self.Format))
		c = ContextHelper(Type, self.Format)
		rules = []
		for line in lines:
			assert line[0].lower() == 'glyph', line[0]
			seq = tuple(parseGlyphs(stripSplitComma(i)) for i in line[1:1+c.DataLen])
			recs = parseLookupRecords(line[1+c.DataLen:], c.LookupRecord)
			rules.append((seq, recs))

		firstGlyphs = set(seq[c.InputIdx][0] for seq,recs in rules)
		self.Coverage = makeCoverage(firstGlyphs, font)
		bucketizeRules(self, c, rules, self.Coverage.glyphs)
	elif typ.endswith('class'):
		self.Format = 2
		debug("Parsing %s format %s" % (Type, self.Format))
		c = ContextHelper(Type, self.Format)
		classDefs = [None] * c.DataLen
		while lines.peek()[0].endswith("class definition begin"):
			typ = lines.peek()[0][:-len("class definition begin")].lower()
			idx,klass = {
			1: {
				'':		(0,ot.ClassDef),
			},
			3: {
				'backtrack':	(0,ot.BacktrackClassDef),
				'':		(1,ot.InputClassDef),
				'lookahead':	(2,ot.LookAheadClassDef),
			},
			}[c.DataLen][typ]
			assert classDefs[idx] is None, idx
			classDefs[idx] = parseClassDef(lines, klass=klass)
		c.SetContextData(self, classDefs)
		rules = []
		for line in lines:
			assert line[0].lower().startswith('class'), line[0]
			seq = tuple(intSplitComma(i) for i in line[1:1+c.DataLen])
			recs = parseLookupRecords(line[1+c.DataLen:], c.LookupRecord)
			rules.append((seq, recs))
		firstClasses = set(seq[c.InputIdx][0] for seq,recs in rules)
		firstGlyphs = set(g for g,c in classDefs[c.InputIdx].classDefs.items() if c in firstClasses)
		self.Coverage = makeCoverage(firstGlyphs, font)
		bucketizeRules(self, c, rules, range(max(firstClasses) + 1))
	elif typ.endswith('coverage'):
		self.Format = 3
		debug("Parsing %s format %s" % (Type, self.Format))
		c = ContextHelper(Type, self.Format)
		coverages = tuple([] for i in range(c.DataLen))
		while lines.peek()[0].endswith("coverage definition begin"):
			typ = lines.peek()[0][:-len("coverage definition begin")].lower()
			idx,klass = {
			1: {
				'':		(0,ot.Coverage),
			},
			3: {
				'backtrack':	(0,ot.BacktrackCoverage),
				'input':	(1,ot.InputCoverage),
				'lookahead':	(2,ot.LookAheadCoverage),
			},
			}[c.DataLen][typ]
			coverages[idx].append(parseCoverage(lines, font, klass=klass))
		c.SetRuleData(self, coverages)
		lines = list(lines)
		assert len(lines) == 1
		line = lines[0]
		assert line[0].lower() == 'coverage', line[0]
		recs = parseLookupRecords(line[1:], c.LookupRecord)
		setattr(self, c.Type+'Count', len(recs))
		setattr(self, c.LookupRecord, recs)
	else:
		assert 0, typ

def parseContextSubst(self, lines, font):
	return parseContext(self, lines, font, "ContextSubst")
def parseContextPos(self, lines, font):
	return parseContext(self, lines, font, "ContextPos")
def parseChainedSubst(self, lines, font):
	return parseContext(self, lines, font, "ChainContextSubst")
def parseChainedPos(self, lines, font):
	return parseContext(self, lines, font, "ChainContextPos")

def parseReverseChainedSubst(self, lines, font):
	self.Format = 1
	coverages = ([], [])
	while lines.peek()[0].endswith("coverage definition begin"):
		typ = lines.peek()[0][:-len("coverage definition begin")].lower()
		idx,klass = {
			'backtrack':	(0,ot.BacktrackCoverage),
			'lookahead':	(1,ot.LookAheadCoverage),
		}[typ]
		coverages[idx].append(parseCoverage(lines, font, klass=klass))
	self.BacktrackCoverage = coverages[0]
	self.BacktrackGlyphCount = len(self.BacktrackCoverage)
	self.LookAheadCoverage = coverages[1]
	self.LookAheadGlyphCount = len(self.LookAheadCoverage)
	mapping = {}
	for line in lines:
		assert len(line) == 2, line
		line = parseGlyphs(line)
		mapping[line[0]] = line[1]
	self.Coverage = makeCoverage(mapping.keys(), font)
	self.Substitute = [mapping[k] for k in self.Coverage.glyphs]
	self.GlyphCount = len(self.Substitute)

def parseLookup(lines, tableTag, font):
	line = next(lines)
	assert line[0].lower().endswith('lookup'), line
	if line is None: return None, None
	lookupLines = lines.readUntil('lookup end')
	_, name, typ = line
	debug("Parsing lookup type %s %s" % (typ, name))

	lookup = ot.Lookup()
	lookup.LookupFlag,filterset = parseLookupFlags(lookupLines)
	if filterset is not None:
		lookup.MarkFilteringSet = filterset
	lookup.LookupType, parseLookupSubTable = {
		'GSUB': {
			'single':	(1,	parseSingleSubst),
			'multiple':	(2,	parseMultiple),
			'alternate':	(3,	parseAlternate),
			'ligature':	(4,	parseLigature),
			'context':	(5,	parseContextSubst),
			'chained':	(6,	parseChainedSubst),
			'reversechained':(8,	parseReverseChainedSubst),
		},
		'GPOS': {
			'single':	(1,	parseSinglePos),
			'pair':		(2,	parsePair),
			'kernset':	(2,	parseKernset),
			'cursive':	(3,	parseCursive),
			'mark to base':	(4,	parseMarkToBase),
			'mark to ligature':(5,	parseMarkToLigature),
			'mark to mark':	(6,	parseMarkToMark),
			'context':	(7,	parseContextPos),
			'chained':	(8,	parseChainedPos),
		},
	}[tableTag][typ]

	subtables = []

	while True:
		subLookupLines = lookupLines.readUntil(('% subtable', 'subtable end'))
		while subLookupLines.peek() is not None:
			subtable = ot.lookupTypes[tableTag][lookup.LookupType]()
			subtable.LookupType = lookup.LookupType
			parseLookupSubTable(subtable, subLookupLines, font)
			subtables.append(subtable)
		if subLookupLines.peek() is None:
			break

	lookup.SubTable = subtables
	lookup.SubTableCount = len(lookup.SubTable)
	if lookup.SubTableCount is 0:
		return None, name
	return lookup, name

def parseLookupList(lines, tableTag, font):
	debug("Parsing lookup list")
	self = ot.LookupList()
	self.Lookup = []
	while lines.peek() is not None:
		if lines.peek()[0].lower() != 'lookup':
			debug ('Skipping', lines.peek())
			next(lines)
			continue
		lookup, name = parseLookup(lines, tableTag, font)
		if name is None: break
		assert int(name) == len(self.Lookup), "%d %d" % (name, len(self.Lookup))
		self.Lookup.append(lookup)
	self.LookupCount = len(self.Lookup)
	return self

def parseGSUBGPOS(lines, font, tableTag):
	assert tableTag in ('GSUB', 'GPOS')
	debug("Parsing", tableTag)
	self = getattr(ot, tableTag)()
	self.Version = 1.0
	self.ScriptList = self.FeatureList = self.LookupList = None
	fields = {
		'script table begin':	('ScriptList',		parseScriptList),
		'feature table begin':	('FeaturetList',	parseFeatureList),
		'lookup':		('LookupList',	lambda lines: parseLookupList(lines, tableTag, font)),
	}
	for attr,parser in fields.values():
		setattr(self, attr, None)
	while lines.peek() is not None:
		typ = lines.peek()[0].lower()
		if typ not in fields:
			debug ('Skipping', lines.peek())
			next(lines)
			continue
		attr,parser = fields[typ]
		assert getattr(self, attr) is None, attr
		setattr(self, attr, parser(lines))
	return self

def parseGSUB(lines, font):
	return parseGSUBGPOS(lines, font, 'GSUB')
def parseGPOS(lines, font):
	return parseGSUBGPOS(lines, font, 'GPOS')

def makeAttachList(points, font):
	self = ot.AttachList()
	self.Coverage = makeCoverage(points.keys(), font)
	records = []
	for glyph in self.Coverage.glyphs:
		record = ot.AttachPoint()
		record.PointIndex = sorted(set(points[glyph]))
		record.PointCount = len(record.PointIndex)
		records.append(record)
	self.AttachPoint = records
	self.GlyphCount = len(records)
	return self

def parseAttachList(lines, font):
	line = next(lines)
	assert line[0].lower().endswith('attachment list begin'), line
	points = {}
	for line in lines.readUntil('attachment list end'):
		glyph = parseGlyph(line[0])
		assert glyph not in points, glyph
		points[glyph] = [int(i) for i in line[1:]]
	return makeAttachList(points, font)

def makeCaretList(carets, font):
	self = ot.LigCaretList()
	self.Coverage = makeCoverage(carets.keys(), font)
	records = []
	for glyph in self.Coverage.glyphs:
		record = ot.LigGlyph()
		cvs = record.CaretValue = []
		for v in carets[glyph]:
			cv = ot.CaretValue()
			cv.Format = 1
			cv.Coordinate = v
			cvs.append(cv)
		record.CaretCount = len(record.CaretValue)
		records.append(record)
	self.LigGlyph = records
	self.LigGlyphCount = len(records)
	return self

def parseCaretList(lines, font):
	line = next(lines)
	assert line[0].lower().endswith('carets begin'), line
	carets = {}
	for line in lines.readUntil('carets end'):
		glyph = parseGlyph(line[0])
		assert glyph not in carets, glyph
		num = int(line[1])
		thisCarets = [int(i) for i in line[2:]]
		assert num == len(thisCarets), line
		carets[glyph] = thisCarets
	return makeCaretList(carets, font)

def makeMarkFilteringSets(sets, font):
	self = ot.MarkGlyphSetsDef()
	self.MarkSetTableFormat = 1
	self.MarkSetCount = 1 + max(sets.keys())
	self.Coverage = [None] * self.MarkSetCount
	for k,v in sets.items():
		self.Coverage[k] = makeCoverage(v, font)
	return self

def parseMarkFilteringSets(lines, font):
	line = next(lines)
	assert line[0].lower().endswith('markfilter set definition begin'), line
	sets = {}
	for line in lines.readUntil('set definition end'):
		assert len(line) == 2, line
		glyph = parseGlyph(line[0])
		# TODO accept set names
		st = int(line[1])
		if st not in sets:
			sets[st] = []
		sets[st].append(glyph)
	return makeMarkFilteringSets(sets, font)

def parseGDEF(lines, font):
	debug("Parsing GDEF")
	self = ot.GDEF()
	fields = {
		'class definition begin':
			('GlyphClassDef',
			 lambda lines, font: parseClassDef(lines, klass=ot.GlyphClassDef)),
		'attachment list begin':
			('AttachList', parseAttachList),
		'carets begin':
			('LigCaretList', parseCaretList),
		'mark attachment class definition begin':
			('MarkAttachClassDef',
			 lambda lines, font: parseClassDef(lines, klass=ot.MarkAttachClassDef)),
		'markfilter set definition begin':
			('MarkGlyphSetsDef', parseMarkFilteringSets),
	}
	for attr,parser in fields.values():
		setattr(self, attr, None)
	while lines.peek() is not None:
		typ = lines.peek()[0].lower()
		if typ not in fields:
			debug ('Skipping', line)
			next(lines)
			continue
		attr,parser = fields[typ]
		assert getattr(self, attr) is None, attr
		setattr(self, attr, parser(lines, font))
	self.Version = 1.0 if self.MarkGlyphSetsDef is None else 0x00010002
	return self


class ReadUntilMixin(object):

	def _readUntil(self, what, packBack=False):
		if type(what) is not tuple:
			what = (what,)
		for line in self:
			if line[0].lower() in what:
				if packBack:
					self.pack(line)
				raise StopIteration
			yield line
	def readUntil(self, what, packBack=False):
		return BufferedIter(self._readUntil(what, packBack=packBack))

class BufferedIter(ReadUntilMixin):

	def __init__(self, it):
		self.iter = it
		self.buffer = []

	def __iter__(self):
		return self

	def next(self):
		if self.buffer:
			return self.buffer.pop(0)
		else:
			return self.iter.next()

	def peek(self, n=0):
		"""Return an item n entries ahead in the iteration."""
		while n >= len(self.buffer):
			try:
				self.buffer.append(self.iter.next())
			except StopIteration:
				return None
		return self.buffer[n]

	def pack(self, item):
		"""Push back item into the iterator."""
		self.buffer.insert(0, item)

class Tokenizer(ReadUntilMixin):

	def __init__(self, f):
		# TODO BytesIO / StringIO as needed?  also, figure out whether we work on bytes or unicode

		lines = iter(f)
		lines = ([s.strip() for s in line.split('\t')] for line in lines)
		try:
			self.filename = f.name
		except:
			self.filename = None
		self._lines = lines
		self._lineno = 0

	def __iter__(self):
		return self

	def _next(self):
		self._lineno += 1
		return next(self._lines)

	def next(self):
		while True:
			line = self._next()
			# Skip comments and empty lines
			if line[0] and (line[0][0] != '%' or line[0] == '% subtable'):
				return line

def parseTable(lines, font, tableTag=None):
	debug("Parsing table")
	line = lines.peek()
	if line[0].split()[0] == 'FontDame':
		next(lines)
		tag = line[0].split()[1].ljust(4)
		if tableTag is None:
			tableTag = tag
		else:
			assert tableTag == tag, (tableTag, tag)

	assert tableTag is not None, "Don't know what table to parse and data doesn't specify"

	container = ttLib.getTableClass(tableTag)()
	table = {'GSUB': parseGSUB,
		 'GPOS': parseGPOS,
		 'GDEF': parseGDEF,
		}[tableTag](lines, font)
	container.table = table
	return container

def build(f, font, tableTag=None):
	lines = BufferedIter(Tokenizer(f))
	return parseTable(lines, font, tableTag=tableTag)


class MockFont(object):

	def __init__(self):
		self._glyphOrder = ['.notdef']
		self._reverseGlyphOrder = {'.notdef': 0}
		self.lazy = False

	def getGlyphID(self, glyph, requireReal=None):
		gid = self._reverseGlyphOrder.get(glyph, None)
		if gid is None:
			gid = len(self._glyphOrder)
			self._glyphOrder.append(glyph)
			self._reverseGlyphOrder[glyph] = gid
		return gid

	def getGlyphName(self, gid):
		return self._glyphOrder[gid]

	def getGlyphOrder(self):
		return self._glyphOrder

def main(args):
	font = MockFont()
	tableTag = None
	if args[0].startswith('-t'):
		tableTag = args[0][2:]
		del args[0]
	for f in args:
		debug("Processing", f)
		table = build(open(f, 'rt'), font, tableTag=tableTag)
		blob = table.compile(font)
		decompiled = table.__class__()
		decompiled.decompile(blob, font)

		#continue
		from fontTools.misc import xmlWriter
		tag = table.tableTag
		writer = xmlWriter.XMLWriter(sys.stdout)
		writer.begintag(tag)
		writer.newline()
		#table.toXML(writer, font)
		decompiled.toXML(writer, font)
		writer.endtag(tag)
		writer.newline()

if __name__ == '__main__':
	import sys
	main (sys.argv[1:])
<commit_msg>Rename parseGlyph[s] to makeGlyph[s]<commit_after>#!/usr/bin/python

# FontDame-to-FontTools for OpenType Layout tables
#
# Source language spec is available at:
# https://rawgit.com/Monotype/OpenType_Table_Source/master/otl_source.html
# https://github.com/Monotype/OpenType_Table_Source/

from __future__ import print_function, division, absolute_import
from fontTools import ttLib
from fontTools.ttLib.tables import otTables as ot
from fontTools.ttLib.tables.otBase import ValueRecord, valueRecordFormatDict
import re

debug = print

def makeGlyph(s):
	if s[:2] == 'U ':
		return ttLib.TTFont._makeGlyphName(int(s[2:], 16))
	elif s[:2] == '# ':
		return "glyph%.5d" % int(s[2:])
	return s

def makeGlyphs(l):
	return [makeGlyph(g) for g in l]

def parseScriptList(lines):
	line = next(lines)
	assert line[0].lower().endswith('script table begin'), line
	self = ot.ScriptList()
	self.ScriptRecord = []
	for line in lines.readUntil('script table end'):
		scriptTag, langSysTag, defaultFeature, features = line
		debug("Adding script", scriptTag, "language-system", langSysTag)

		langSys = ot.LangSys()
		langSys.LookupOrder = None
		# TODO The following two lines should use lazy feature name-to-index mapping
		langSys.ReqFeatureIndex = int(defaultFeature) if defaultFeature else 0xFFFF
		langSys.FeatureIndex = intSplitComma(features)
		langSys.FeatureCount = len(langSys.FeatureIndex)

		script = [s for s in self.ScriptRecord if s.ScriptTag == scriptTag]
		if script:
			script = script[0].Script
		else:
			scriptRec = ot.ScriptRecord()
			scriptRec.ScriptTag = scriptTag
			scriptRec.Script = ot.Script()
			self.ScriptRecord.append(scriptRec)
			script = scriptRec.Script
			script.DefaultLangSys = None
			script.LangSysRecord = []
			script.LangSysCount = 0

		if langSysTag == 'default':
			script.DefaultLangSys = langSys
		else:
			langSysRec = ot.LangSysRecord()
			langSysRec.LangSysTag = langSysTag + ' '*(4 - len(langSysTag))
			langSysRec.LangSys = langSys
			script.LangSysRecord.append(langSysRec)
			script.LangSysCount = len(script.LangSysRecord)

	self.ScriptCount = len(self.ScriptRecord)
	# TODO sort scripts and langSys's?
	return self

def parseFeatureList(lines):
	line = next(lines)
	assert line[0].lower().endswith('feature table begin'), line
	self = ot.FeatureList()
	self.FeatureRecord = []
	for line in lines.readUntil('feature table end'):
		idx, featureTag, lookups = line
		assert int(idx) == len(self.FeatureRecord), "%d %d" % (idx, len(self.FeatureRecord))
		featureRec = ot.FeatureRecord()
		featureRec.FeatureTag = featureTag
		featureRec.Feature = ot.Feature()
		self.FeatureRecord.append(featureRec)
		feature = featureRec.Feature
		feature.FeatureParams = None
		# TODO The following line should use lazy lookup name-to-index mapping
		feature.LookupListIndex = intSplitComma(lookups)
		feature.LookupCount = len(feature.LookupListIndex)

	self.FeatureCount = len(self.FeatureRecord)
	return self

def parseLookupFlags(lines):
	flags = 0
	filterset = None
	for line in lines:
		flag = {
			'righttoleft':		0x0001,
			'ignorebaseglyphs':	0x0002,
			'ignoreligatures':	0x0004,
			'ignoremarks':		0x0008,
			}.get(line[0].lower())
		if flag:
			assert line[1].lower() in ['yes', 'no'], line[1]
			if line[1].lower() == 'yes':
				flags |= flag
			continue
		if line[0].lower() == 'markattachmenttype':
			flags |= int(line[1]) << 8
			continue
		if line[0].lower() == 'markfiltertype':
			flags |= 0x10
			filterset = int(line[1])
		lines.pack(line)
		break
	return flags, filterset

def parseSingleSubst(self, lines, font):
	self.mapping = {}
	for line in lines:
		assert len(line) == 2, line
		line = makeGlyphs(line)
		self.mapping[line[0]] = line[1]

def parseMultiple(self, lines, font):
	self.mapping = {}
	for line in lines:
		line = makeGlyphs(line)
		self.mapping[line[0]] = line[1:]

def parseAlternate(self, lines, font):
	self.alternates = {}
	for line in lines:
		line = makeGlyphs(line)
		self.alternates[line[0]] = line[1:]

def parseLigature(self, lines, font):
	self.ligatures = {}
	for line in lines:
		assert len(line) >= 2, line
		line = makeGlyphs(line)
		# The following single line can replace the rest of this function with fontTools >= 3.1
		#self.ligatures[tuple(line[1:])] = line[0]
		ligGlyph, firstGlyph = line[:2]
		otherComponents = line[2:]
		ligature = ot.Ligature()
		ligature.Component = otherComponents
		ligature.CompCount = len(ligature.Component) + 1
		ligature.LigGlyph = ligGlyph
		self.ligatures.setdefault(firstGlyph, []).append(ligature)

def parseSinglePos(self, lines, font):
	values = {}
	for line in lines:
		assert len(line) == 3, line
		w = line[0].title().replace(' ', '')
		assert w in valueRecordFormatDict
		g = makeGlyph(line[1])
		v = int(line[2])
		if g not in values:
			values[g] = ValueRecord()
		assert not hasattr(values[g], w), (g, w)
		setattr(values[g], w, v)
	self.Coverage = makeCoverage(values.keys(), font)
	values = [values[k] for k in self.Coverage.glyphs]
	self.ValueFormat = reduce(int.__or__, [v.getFormat() for v in values])
	if all(v == values[0] for v in values):
		self.Format = 1
		self.Value = values[0]
	else:
		self.Format = 2
		self.Value = values
		self.ValueCount = len(self.Value)

def parsePair(self, lines, font):
	self.ValueFormat1 = self.ValueFormat2 = 0
	typ = lines.peek()[0].split()[0].lower()
	if typ in ('left', 'right'):
		self.Format = 1
		values = {}
		for line in lines:
			assert len(line) == 4, line
			side = line[0].split()[0].lower()
			assert side in ('left', 'right'), side
			what = line[0][len(side):].title().replace(' ', '')
			mask = valueRecordFormatDict[what][0]
			glyph1, glyph2 = makeGlyphs(line[1:3])
			value = int(line[3])
			if not glyph1 in values: values[glyph1] = {}
			if not glyph2 in values[glyph1]: values[glyph1][glyph2] = (ValueRecord(),ValueRecord())
			rec2 = values[glyph1][glyph2]
			if side == 'left':
				self.ValueFormat1 |= mask
				vr = rec2[0]
			else:
				self.ValueFormat2 |= mask
				vr = rec2[1]
			assert not hasattr(vr, what), (vr, what)
			setattr(vr, what, value)
		self.Coverage = makeCoverage(values.keys(), font)
		self.PairSet = []
		for glyph1 in self.Coverage.glyphs:
			values1 = values[glyph1]
			pairset = ot.PairSet()
			records = pairset.PairValueRecord = []
			for glyph2 in sorted(values1.keys(), key=font.getGlyphID):
				values2 = values1[glyph2]
				pair = ot.PairValueRecord()
				pair.SecondGlyph = glyph2
				pair.Value1,pair.Value2 = values2
				records.append(pair)
			pairset.PairValueCount = len(pairset.PairValueRecord)
			self.PairSet.append(pairset)
		self.PairSetCount = len(self.PairSet)
	elif typ.endswith('class'):
		self.Format = 2
		classDefs = [None, None]
		while lines.peek()[0].endswith("class definition begin"):
			typ = lines.peek()[0][:-len("class definition begin")].lower()
			idx,klass = {
				'first':	(0,ot.ClassDef1),
				'second':	(1,ot.ClassDef2),
			}[typ]
			assert classDefs[idx] is None
			classDefs[idx] = parseClassDef(lines, klass=klass)
		self.ClassDef1, self.ClassDef2 = classDefs
		self.Class1Count, self.Class2Count = (1+max(c.classDefs.values()) for c in classDefs)
		self.Class1Record = [ot.Class1Record() for i in range(self.Class1Count)]
		for rec1 in self.Class1Record:
			rec1.Class2Record = [ot.Class2Record() for j in range(self.Class2Count)]
			for rec2 in rec1.Class2Record:
				rec2.Value1 = ValueRecord()
				rec2.Value2 = ValueRecord()
		for line in lines:
			assert len(line) == 4, line
			side = line[0].split()[0].lower()
			assert side in ('left', 'right'), side
			what = line[0][len(side):].title().replace(' ', '')
			mask = valueRecordFormatDict[what][0]
			class1, class2, value = (int(x) for x in line[1:4])
			rec2 = self.Class1Record[class1].Class2Record[class2]
			if side == 'left':
				self.ValueFormat1 |= mask
				vr = rec2.Value1
			else:
				self.ValueFormat2 |= mask
				vr = rec2.Value2
			assert not hasattr(vr, what), (vr, what)
			setattr(vr, what, value)
		self.Coverage = makeCoverage(self.ClassDef1.classDefs.keys(), font)
	else:
		assert 0

def parseKernset(self, lines, font):
	typ = lines.peek()[0].split()[0].lower()
	if typ in ('left', 'right'):
		lines = lines.readUntil(("firstclass definition begin", "secondclass definition begin"), packBack=True)
	return parsePair(self, lines, font)

def makeAnchor(data, klass=ot.Anchor):
	assert len(data) <= 2
	anchor = klass()
	anchor.Format = 1
	anchor.XCoordinate,anchor.YCoordinate = intSplitComma(data[0])
	if len(data) > 1 and data[1] != '':
		anchor.Format = 2
		anchor.AnchorPoint = int(data[1])
	return anchor

def parseCursive(self, lines, font):
	self.Format = 1
	self.EntryExitRecord = []
	records = {}
	for line in lines:
		assert len(line) in [3,4], line
		idx,klass = {
			'entry':	(0,ot.EntryAnchor),
			'exit':		(1,ot.ExitAnchor),
		}[line[0]]
		glyph = makeGlyph(line[1])
		if glyph not in records:
			records[glyph] = [None,None]
		assert records[glyph][idx] is None, (glyph, idx)
		records[glyph][idx] = makeAnchor(line[2:], klass)
	self.Coverage = makeCoverage(records.keys(), font)
	recs = self.EntryExitRecord = []
	for glyph in self.Coverage.glyphs:
		rec = ot.EntryExitRecord()
		rec.EntryAnchor,rec.ExitAnchor = records[glyph]
		recs.append(rec)
	self.EntryExitCount = len(self.EntryExitRecord)

def makeMarkRecords(data, coverage, c):
	records = []
	for glyph in coverage.glyphs:
		klass, anchor = data[glyph]
		record = c.MarkRecordClass()
		record.Class = klass
		setattr(record, c.MarkAnchor, anchor)
		records.append(record)
	return records

def makeBaseRecords(data, coverage, c, classCount):
	records = []
	idx = {}
	for glyph in coverage.glyphs:
		idx[glyph] = len(records)
		record = c.BaseRecordClass()
		anchors = [None] * classCount
		setattr(record, c.BaseAnchor, anchors)
		records.append(record)
	for (glyph,klass),anchor in data.items():
		record = records[idx[glyph]]
		anchors = getattr(record, c.BaseAnchor)
		assert anchors[klass] is None, (glyph, klass)
		anchors[klass] = anchor
	return records

def makeLigatureRecords(data, coverage, c, classCount):
	records = [None] * len(coverage.glyphs)
	idx = {g:i for i,g in enumerate(coverage.glyphs)}

	for (glyph,klass,compIdx,compCount),anchor in data.items():
		record = records[idx[glyph]]
		if record is None:
			record = records[idx[glyph]] = ot.LigatureAttach()
			record.ComponentCount = compCount
			record.ComponentRecord = [ot.ComponentRecord() for i in range(compCount)]
			for compRec in record.ComponentRecord:
				compRec.LigatureAnchor = [None] * classCount
		assert record.ComponentCount == compCount, (glyph, record.ComponentCount, compCount)

		anchors = record.ComponentRecord[compIdx - 1].LigatureAnchor
		assert anchors[klass] is None, (glyph, compIdx, klass)
		anchors[klass] = anchor
	return records

def parseMarkToSomething(self, lines, font, c):
	self.Format = 1
	markData = {}
	baseData = {}
	Data = {
		'mark':		(markData, c.MarkAnchorClass),
		'base':		(baseData, c.BaseAnchorClass),
		'ligature':	(baseData, c.BaseAnchorClass),
	}
	for line in lines:
		typ = line[0]
		assert typ in ('mark', 'base', 'ligature')
		glyph = makeGlyph(line[1])
		data, anchorClass = Data[typ]
		extraItems = 2 if typ == 'ligature' else 0
		extras = tuple(int(i) for i in line[2:2+extraItems])
		klass = int(line[2+extraItems])
		anchor = makeAnchor(line[3+extraItems:], anchorClass)
		if typ == 'mark':
			key,value = glyph,(klass,anchor)
		else:
			key,value = ((glyph,klass)+extras),anchor
		assert key not in data, key
		data[key] = value

	# Mark
	markCoverage = makeCoverage(markData.keys(), font, c.MarkCoverageClass)
	markArray = c.MarkArrayClass()
	markRecords = makeMarkRecords(markData, markCoverage, c)
	setattr(markArray, c.MarkRecord, markRecords)
	setattr(markArray, c.MarkCount, len(markRecords))
	setattr(self, c.MarkCoverage, markCoverage)
	setattr(self, c.MarkArray, markArray)

	# Base
	self.classCount = 0 if not baseData else 1+max(k[1] for k,v in baseData.items())
	baseCoverage = makeCoverage([k[0] for k in baseData.keys()], font, c.BaseCoverageClass)
	baseArray = c.BaseArrayClass()
	if c.Base == 'Ligature':
		baseRecords = makeLigatureRecords(baseData, baseCoverage, c, self.classCount)
	else:
		baseRecords = makeBaseRecords(baseData, baseCoverage, c, self.classCount)
	setattr(baseArray, c.BaseRecord, baseRecords)
	setattr(baseArray, c.BaseCount, len(baseRecords))
	setattr(self, c.BaseCoverage, baseCoverage)
	setattr(self, c.BaseArray, baseArray)

class MarkHelper(object):
	def __init__(self):
		for Which in ('Mark', 'Base'):
			for What in ('Coverage', 'Array', 'Count', 'Record', 'Anchor'):
				key = Which + What
				if Which == 'Mark' and What in ('Count', 'Record', 'Anchor'):
					value = key
				else:
					value = getattr(self, Which) + What
				if value == 'LigatureRecord':
					value = 'LigatureAttach'
				setattr(self, key, value)
				if What != 'Count':
					klass = getattr(ot, value)
					setattr(self, key+'Class', klass)

class MarkToBaseHelper(MarkHelper):
	Mark = 'Mark'
	Base = 'Base'
class MarkToMarkHelper(MarkHelper):
	Mark = 'Mark1'
	Base = 'Mark2'
class MarkToLigatureHelper(MarkHelper):
	Mark = 'Mark'
	Base = 'Ligature'

def parseMarkToBase(self, lines, font):
	return parseMarkToSomething(self, lines, font, MarkToBaseHelper())
def parseMarkToMark(self, lines, font):
	return parseMarkToSomething(self, lines, font, MarkToMarkHelper())
def parseMarkToLigature(self, lines, font):
	return parseMarkToSomething(self, lines, font, MarkToLigatureHelper())

def stripSplitComma(line):
	return [s.strip() for s in line.split(',')] if line else []

def intSplitComma(line):
	return [int(i) for i in line.split(',')] if line else []

# Copied from fontTools.subset
class ContextHelper(object):
	def __init__(self, klassName, Format):
		if klassName.endswith('Subst'):
			Typ = 'Sub'
			Type = 'Subst'
		else:
			Typ = 'Pos'
			Type = 'Pos'
		if klassName.startswith('Chain'):
			Chain = 'Chain'
			InputIdx = 1
			DataLen = 3
		else:
			Chain = ''
			InputIdx = 0
			DataLen = 1
		ChainTyp = Chain+Typ

		self.Typ = Typ
		self.Type = Type
		self.Chain = Chain
		self.ChainTyp = ChainTyp
		self.InputIdx = InputIdx
		self.DataLen = DataLen

		self.LookupRecord = Type+'LookupRecord'

		if Format == 1:
			Coverage = lambda r: r.Coverage
			ChainCoverage = lambda r: r.Coverage
			ContextData = lambda r:(None,)
			ChainContextData = lambda r:(None, None, None)
			SetContextData = None
			SetChainContextData = None
			RuleData = lambda r:(r.Input,)
			ChainRuleData = lambda r:(r.Backtrack, r.Input, r.LookAhead)
			def SetRuleData(r, d):
				(r.Input,) = d
				(r.GlyphCount,) = (len(x)+1 for x in d)
			def ChainSetRuleData(r, d):
				(r.Backtrack, r.Input, r.LookAhead) = d
				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(d[0]),len(d[1])+1,len(d[2]))
		elif Format == 2:
			Coverage = lambda r: r.Coverage
			ChainCoverage = lambda r: r.Coverage
			ContextData = lambda r:(r.ClassDef,)
			ChainContextData = lambda r:(r.BacktrackClassDef,
						     r.InputClassDef,
						     r.LookAheadClassDef)
			def SetContextData(r, d):
				(r.ClassDef,) = d
			def SetChainContextData(r, d):
				(r.BacktrackClassDef,
				 r.InputClassDef,
				 r.LookAheadClassDef) = d
			RuleData = lambda r:(r.Class,)
			ChainRuleData = lambda r:(r.Backtrack, r.Input, r.LookAhead)
			def SetRuleData(r, d):
				(r.Class,) = d
				(r.GlyphCount,) = (len(x)+1 for x in d)
			def ChainSetRuleData(r, d):
				(r.Backtrack, r.Input, r.LookAhead) = d
				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(d[0]),len(d[1])+1,len(d[2]))
		elif Format == 3:
			Coverage = lambda r: r.Coverage[0]
			ChainCoverage = lambda r: r.InputCoverage[0]
			ContextData = None
			ChainContextData = None
			SetContextData = None
			SetChainContextData = None
			RuleData = lambda r: r.Coverage
			ChainRuleData = lambda r:(r.BacktrackCoverage +
						  r.InputCoverage +
						  r.LookAheadCoverage)
			def SetRuleData(r, d):
				(r.Coverage,) = d
				(r.GlyphCount,) = (len(x) for x in d)
			def ChainSetRuleData(r, d):
				(r.BacktrackCoverage, r.InputCoverage, r.LookAheadCoverage) = d
				(r.BacktrackGlyphCount,r.InputGlyphCount,r.LookAheadGlyphCount,) = (len(x) for x in d)
		else:
			assert 0, "unknown format: %s" % Format

		if Chain:
			self.Coverage = ChainCoverage
			self.ContextData = ChainContextData
			self.SetContextData = SetChainContextData
			self.RuleData = ChainRuleData
			self.SetRuleData = ChainSetRuleData
		else:
			self.Coverage = Coverage
			self.ContextData = ContextData
			self.SetContextData = SetContextData
			self.RuleData = RuleData
			self.SetRuleData = SetRuleData

		if Format == 1:
			self.Rule = ChainTyp+'Rule'
			self.RuleCount = ChainTyp+'RuleCount'
			self.RuleSet = ChainTyp+'RuleSet'
			self.RuleSetCount = ChainTyp+'RuleSetCount'
			self.Intersect = lambda glyphs, c, r: [r] if r in glyphs else []
		elif Format == 2:
			self.Rule = ChainTyp+'ClassRule'
			self.RuleCount = ChainTyp+'ClassRuleCount'
			self.RuleSet = ChainTyp+'ClassSet'
			self.RuleSetCount = ChainTyp+'ClassSetCount'
			self.Intersect = lambda glyphs, c, r: (c.intersect_class(glyphs, r) if c
							       else (set(glyphs) if r == 0 else set()))

			self.ClassDef = 'InputClassDef' if Chain else 'ClassDef'
			self.ClassDefIndex = 1 if Chain else 0
			self.Input = 'Input' if Chain else 'Class'

def parseLookupRecords(items, klassName):
	klass = getattr(ot, klassName)
	lst = []
	for item in items:
		rec = klass()
		item = intSplitComma(item)
		assert len(item) == 2, item
		assert item[0] > 0, item[0]
		rec.SequenceIndex = item[0] - 1
		# TODO The following line should use lazy lookup name-to-index mapping
		rec.LookupListIndex = item[1]
		lst.append(rec)
	return lst

def makeClassDef(classDefs, klass=ot.Coverage):
	if not classDefs: return None
	self = klass()
	self.classDefs = dict(classDefs)
	return self

def parseClassDef(lines, klass=ot.ClassDef):
	line = next(lines)
	assert line[0].lower().endswith('class definition begin'), line
	classDefs = {}
	for line in lines.readUntil('class definition end'):
		glyph = makeGlyph(line[0])
		assert glyph not in classDefs, glyph
		classDefs[glyph] = int(line[1])
	return makeClassDef(classDefs, klass)

def makeCoverage(glyphs, font, klass=ot.Coverage):
	if not glyphs: return None
	coverage = klass()
	coverage.glyphs = sorted(set(glyphs), key=font.getGlyphID)
	return coverage

def parseCoverage(lines, font, klass=ot.Coverage):
	line = next(lines)
	assert line[0].lower().endswith('coverage definition begin'), line
	glyphs = []
	for line in lines.readUntil('coverage definition end'):
		glyphs.append(makeGlyph(line[0]))
	return makeCoverage(glyphs, font, klass)

def bucketizeRules(self, c, rules, bucketKeys):
	buckets = {}
	for seq,recs in rules:
		buckets.setdefault(seq[c.InputIdx][0], []).append((tuple(s[1 if i==c.InputIdx else 0:] for i,s in enumerate(seq)), recs))

	rulesets = []
	for firstGlyph in bucketKeys:
		if firstGlyph not in buckets:
			rulesets.append(None)
			continue
		thisRules = []
		for seq,recs in buckets[firstGlyph]:
			rule = getattr(ot, c.Rule)()
			c.SetRuleData(rule, seq)
			setattr(rule, c.Type+'Count', len(recs))
			setattr(rule, c.LookupRecord, recs)
			thisRules.append(rule)

		ruleset = getattr(ot, c.RuleSet)()
		setattr(ruleset, c.Rule, thisRules)
		setattr(ruleset, c.RuleCount, len(thisRules))
		rulesets.append(ruleset)

	setattr(self, c.RuleSet, rulesets)
	setattr(self, c.RuleSetCount, len(rulesets))

def parseContext(self, lines, font, Type):
	typ = lines.peek()[0].split()[0].lower()
	if typ == 'glyph':
		self.Format = 1
		debug("Parsing %s format %s" % (Type, self.Format))
		c = ContextHelper(Type, self.Format)
		rules = []
		for line in lines:
			assert line[0].lower() == 'glyph', line[0]
			seq = tuple(makeGlyphs(stripSplitComma(i)) for i in line[1:1+c.DataLen])
			recs = parseLookupRecords(line[1+c.DataLen:], c.LookupRecord)
			rules.append((seq, recs))

		firstGlyphs = set(seq[c.InputIdx][0] for seq,recs in rules)
		self.Coverage = makeCoverage(firstGlyphs, font)
		bucketizeRules(self, c, rules, self.Coverage.glyphs)
	elif typ.endswith('class'):
		self.Format = 2
		debug("Parsing %s format %s" % (Type, self.Format))
		c = ContextHelper(Type, self.Format)
		classDefs = [None] * c.DataLen
		while lines.peek()[0].endswith("class definition begin"):
			typ = lines.peek()[0][:-len("class definition begin")].lower()
			idx,klass = {
			1: {
				'':		(0,ot.ClassDef),
			},
			3: {
				'backtrack':	(0,ot.BacktrackClassDef),
				'':		(1,ot.InputClassDef),
				'lookahead':	(2,ot.LookAheadClassDef),
			},
			}[c.DataLen][typ]
			assert classDefs[idx] is None, idx
			classDefs[idx] = parseClassDef(lines, klass=klass)
		c.SetContextData(self, classDefs)
		rules = []
		for line in lines:
			assert line[0].lower().startswith('class'), line[0]
			seq = tuple(intSplitComma(i) for i in line[1:1+c.DataLen])
			recs = parseLookupRecords(line[1+c.DataLen:], c.LookupRecord)
			rules.append((seq, recs))
		firstClasses = set(seq[c.InputIdx][0] for seq,recs in rules)
		firstGlyphs = set(g for g,c in classDefs[c.InputIdx].classDefs.items() if c in firstClasses)
		self.Coverage = makeCoverage(firstGlyphs, font)
		bucketizeRules(self, c, rules, range(max(firstClasses) + 1))
	elif typ.endswith('coverage'):
		self.Format = 3
		debug("Parsing %s format %s" % (Type, self.Format))
		c = ContextHelper(Type, self.Format)
		coverages = tuple([] for i in range(c.DataLen))
		while lines.peek()[0].endswith("coverage definition begin"):
			typ = lines.peek()[0][:-len("coverage definition begin")].lower()
			idx,klass = {
			1: {
				'':		(0,ot.Coverage),
			},
			3: {
				'backtrack':	(0,ot.BacktrackCoverage),
				'input':	(1,ot.InputCoverage),
				'lookahead':	(2,ot.LookAheadCoverage),
			},
			}[c.DataLen][typ]
			coverages[idx].append(parseCoverage(lines, font, klass=klass))
		c.SetRuleData(self, coverages)
		lines = list(lines)
		assert len(lines) == 1
		line = lines[0]
		assert line[0].lower() == 'coverage', line[0]
		recs = parseLookupRecords(line[1:], c.LookupRecord)
		setattr(self, c.Type+'Count', len(recs))
		setattr(self, c.LookupRecord, recs)
	else:
		assert 0, typ

def parseContextSubst(self, lines, font):
	return parseContext(self, lines, font, "ContextSubst")
def parseContextPos(self, lines, font):
	return parseContext(self, lines, font, "ContextPos")
def parseChainedSubst(self, lines, font):
	return parseContext(self, lines, font, "ChainContextSubst")
def parseChainedPos(self, lines, font):
	return parseContext(self, lines, font, "ChainContextPos")

def parseReverseChainedSubst(self, lines, font):
	self.Format = 1
	coverages = ([], [])
	while lines.peek()[0].endswith("coverage definition begin"):
		typ = lines.peek()[0][:-len("coverage definition begin")].lower()
		idx,klass = {
			'backtrack':	(0,ot.BacktrackCoverage),
			'lookahead':	(1,ot.LookAheadCoverage),
		}[typ]
		coverages[idx].append(parseCoverage(lines, font, klass=klass))
	self.BacktrackCoverage = coverages[0]
	self.BacktrackGlyphCount = len(self.BacktrackCoverage)
	self.LookAheadCoverage = coverages[1]
	self.LookAheadGlyphCount = len(self.LookAheadCoverage)
	mapping = {}
	for line in lines:
		assert len(line) == 2, line
		line = makeGlyphs(line)
		mapping[line[0]] = line[1]
	self.Coverage = makeCoverage(mapping.keys(), font)
	self.Substitute = [mapping[k] for k in self.Coverage.glyphs]
	self.GlyphCount = len(self.Substitute)

def parseLookup(lines, tableTag, font):
	line = next(lines)
	assert line[0].lower().endswith('lookup'), line
	if line is None: return None, None
	lookupLines = lines.readUntil('lookup end')
	_, name, typ = line
	debug("Parsing lookup type %s %s" % (typ, name))

	lookup = ot.Lookup()
	lookup.LookupFlag,filterset = parseLookupFlags(lookupLines)
	if filterset is not None:
		lookup.MarkFilteringSet = filterset
	lookup.LookupType, parseLookupSubTable = {
		'GSUB': {
			'single':	(1,	parseSingleSubst),
			'multiple':	(2,	parseMultiple),
			'alternate':	(3,	parseAlternate),
			'ligature':	(4,	parseLigature),
			'context':	(5,	parseContextSubst),
			'chained':	(6,	parseChainedSubst),
			'reversechained':(8,	parseReverseChainedSubst),
		},
		'GPOS': {
			'single':	(1,	parseSinglePos),
			'pair':		(2,	parsePair),
			'kernset':	(2,	parseKernset),
			'cursive':	(3,	parseCursive),
			'mark to base':	(4,	parseMarkToBase),
			'mark to ligature':(5,	parseMarkToLigature),
			'mark to mark':	(6,	parseMarkToMark),
			'context':	(7,	parseContextPos),
			'chained':	(8,	parseChainedPos),
		},
	}[tableTag][typ]

	subtables = []

	while True:
		subLookupLines = lookupLines.readUntil(('% subtable', 'subtable end'))
		while subLookupLines.peek() is not None:
			subtable = ot.lookupTypes[tableTag][lookup.LookupType]()
			subtable.LookupType = lookup.LookupType
			parseLookupSubTable(subtable, subLookupLines, font)
			subtables.append(subtable)
		if subLookupLines.peek() is None:
			break

	lookup.SubTable = subtables
	lookup.SubTableCount = len(lookup.SubTable)
	if lookup.SubTableCount is 0:
		return None, name
	return lookup, name

def parseLookupList(lines, tableTag, font):
	debug("Parsing lookup list")
	self = ot.LookupList()
	self.Lookup = []
	while lines.peek() is not None:
		if lines.peek()[0].lower() != 'lookup':
			debug ('Skipping', lines.peek())
			next(lines)
			continue
		lookup, name = parseLookup(lines, tableTag, font)
		if name is None: break
		assert int(name) == len(self.Lookup), "%d %d" % (name, len(self.Lookup))
		self.Lookup.append(lookup)
	self.LookupCount = len(self.Lookup)
	return self

def parseGSUBGPOS(lines, font, tableTag):
	assert tableTag in ('GSUB', 'GPOS')
	debug("Parsing", tableTag)
	self = getattr(ot, tableTag)()
	self.Version = 1.0
	self.ScriptList = self.FeatureList = self.LookupList = None
	fields = {
		'script table begin':	('ScriptList',		parseScriptList),
		'feature table begin':	('FeaturetList',	parseFeatureList),
		'lookup':		('LookupList',	lambda lines: parseLookupList(lines, tableTag, font)),
	}
	for attr,parser in fields.values():
		setattr(self, attr, None)
	while lines.peek() is not None:
		typ = lines.peek()[0].lower()
		if typ not in fields:
			debug ('Skipping', lines.peek())
			next(lines)
			continue
		attr,parser = fields[typ]
		assert getattr(self, attr) is None, attr
		setattr(self, attr, parser(lines))
	return self

def parseGSUB(lines, font):
	return parseGSUBGPOS(lines, font, 'GSUB')
def parseGPOS(lines, font):
	return parseGSUBGPOS(lines, font, 'GPOS')

def makeAttachList(points, font):
	self = ot.AttachList()
	self.Coverage = makeCoverage(points.keys(), font)
	records = []
	for glyph in self.Coverage.glyphs:
		record = ot.AttachPoint()
		record.PointIndex = sorted(set(points[glyph]))
		record.PointCount = len(record.PointIndex)
		records.append(record)
	self.AttachPoint = records
	self.GlyphCount = len(records)
	return self

def parseAttachList(lines, font):
	line = next(lines)
	assert line[0].lower().endswith('attachment list begin'), line
	points = {}
	for line in lines.readUntil('attachment list end'):
		glyph = makeGlyph(line[0])
		assert glyph not in points, glyph
		points[glyph] = [int(i) for i in line[1:]]
	return makeAttachList(points, font)

def makeCaretList(carets, font):
	self = ot.LigCaretList()
	self.Coverage = makeCoverage(carets.keys(), font)
	records = []
	for glyph in self.Coverage.glyphs:
		record = ot.LigGlyph()
		cvs = record.CaretValue = []
		for v in carets[glyph]:
			cv = ot.CaretValue()
			cv.Format = 1
			cv.Coordinate = v
			cvs.append(cv)
		record.CaretCount = len(record.CaretValue)
		records.append(record)
	self.LigGlyph = records
	self.LigGlyphCount = len(records)
	return self

def parseCaretList(lines, font):
	line = next(lines)
	assert line[0].lower().endswith('carets begin'), line
	carets = {}
	for line in lines.readUntil('carets end'):
		glyph = makeGlyph(line[0])
		assert glyph not in carets, glyph
		num = int(line[1])
		thisCarets = [int(i) for i in line[2:]]
		assert num == len(thisCarets), line
		carets[glyph] = thisCarets
	return makeCaretList(carets, font)

def makeMarkFilteringSets(sets, font):
	self = ot.MarkGlyphSetsDef()
	self.MarkSetTableFormat = 1
	self.MarkSetCount = 1 + max(sets.keys())
	self.Coverage = [None] * self.MarkSetCount
	for k,v in sets.items():
		self.Coverage[k] = makeCoverage(v, font)
	return self

def parseMarkFilteringSets(lines, font):
	line = next(lines)
	assert line[0].lower().endswith('markfilter set definition begin'), line
	sets = {}
	for line in lines.readUntil('set definition end'):
		assert len(line) == 2, line
		glyph = makeGlyph(line[0])
		# TODO accept set names
		st = int(line[1])
		if st not in sets:
			sets[st] = []
		sets[st].append(glyph)
	return makeMarkFilteringSets(sets, font)

def parseGDEF(lines, font):
	debug("Parsing GDEF")
	self = ot.GDEF()
	fields = {
		'class definition begin':
			('GlyphClassDef',
			 lambda lines, font: parseClassDef(lines, klass=ot.GlyphClassDef)),
		'attachment list begin':
			('AttachList', parseAttachList),
		'carets begin':
			('LigCaretList', parseCaretList),
		'mark attachment class definition begin':
			('MarkAttachClassDef',
			 lambda lines, font: parseClassDef(lines, klass=ot.MarkAttachClassDef)),
		'markfilter set definition begin':
			('MarkGlyphSetsDef', parseMarkFilteringSets),
	}
	for attr,parser in fields.values():
		setattr(self, attr, None)
	while lines.peek() is not None:
		typ = lines.peek()[0].lower()
		if typ not in fields:
			debug ('Skipping', line)
			next(lines)
			continue
		attr,parser = fields[typ]
		assert getattr(self, attr) is None, attr
		setattr(self, attr, parser(lines, font))
	self.Version = 1.0 if self.MarkGlyphSetsDef is None else 0x00010002
	return self


class ReadUntilMixin(object):

	def _readUntil(self, what, packBack=False):
		if type(what) is not tuple:
			what = (what,)
		for line in self:
			if line[0].lower() in what:
				if packBack:
					self.pack(line)
				raise StopIteration
			yield line
	def readUntil(self, what, packBack=False):
		return BufferedIter(self._readUntil(what, packBack=packBack))

class BufferedIter(ReadUntilMixin):

	def __init__(self, it):
		self.iter = it
		self.buffer = []

	def __iter__(self):
		return self

	def next(self):
		if self.buffer:
			return self.buffer.pop(0)
		else:
			return self.iter.next()

	def peek(self, n=0):
		"""Return an item n entries ahead in the iteration."""
		while n >= len(self.buffer):
			try:
				self.buffer.append(self.iter.next())
			except StopIteration:
				return None
		return self.buffer[n]

	def pack(self, item):
		"""Push back item into the iterator."""
		self.buffer.insert(0, item)

class Tokenizer(ReadUntilMixin):

	def __init__(self, f):
		# TODO BytesIO / StringIO as needed?  also, figure out whether we work on bytes or unicode

		lines = iter(f)
		lines = ([s.strip() for s in line.split('\t')] for line in lines)
		try:
			self.filename = f.name
		except:
			self.filename = None
		self._lines = lines
		self._lineno = 0

	def __iter__(self):
		return self

	def _next(self):
		self._lineno += 1
		return next(self._lines)

	def next(self):
		while True:
			line = self._next()
			# Skip comments and empty lines
			if line[0] and (line[0][0] != '%' or line[0] == '% subtable'):
				return line

def parseTable(lines, font, tableTag=None):
	debug("Parsing table")
	line = lines.peek()
	if line[0].split()[0] == 'FontDame':
		next(lines)
		tag = line[0].split()[1].ljust(4)
		if tableTag is None:
			tableTag = tag
		else:
			assert tableTag == tag, (tableTag, tag)

	assert tableTag is not None, "Don't know what table to parse and data doesn't specify"

	container = ttLib.getTableClass(tableTag)()
	table = {'GSUB': parseGSUB,
		 'GPOS': parseGPOS,
		 'GDEF': parseGDEF,
		}[tableTag](lines, font)
	container.table = table
	return container

def build(f, font, tableTag=None):
	lines = BufferedIter(Tokenizer(f))
	return parseTable(lines, font, tableTag=tableTag)


class MockFont(object):

	def __init__(self):
		self._glyphOrder = ['.notdef']
		self._reverseGlyphOrder = {'.notdef': 0}
		self.lazy = False

	def getGlyphID(self, glyph, requireReal=None):
		gid = self._reverseGlyphOrder.get(glyph, None)
		if gid is None:
			gid = len(self._glyphOrder)
			self._glyphOrder.append(glyph)
			self._reverseGlyphOrder[glyph] = gid
		return gid

	def getGlyphName(self, gid):
		return self._glyphOrder[gid]

	def getGlyphOrder(self):
		return self._glyphOrder

def main(args):
	font = MockFont()
	tableTag = None
	if args[0].startswith('-t'):
		tableTag = args[0][2:]
		del args[0]
	for f in args:
		debug("Processing", f)
		table = build(open(f, 'rt'), font, tableTag=tableTag)
		blob = table.compile(font)
		decompiled = table.__class__()
		decompiled.decompile(blob, font)

		#continue
		from fontTools.misc import xmlWriter
		tag = table.tableTag
		writer = xmlWriter.XMLWriter(sys.stdout)
		writer.begintag(tag)
		writer.newline()
		#table.toXML(writer, font)
		decompiled.toXML(writer, font)
		writer.endtag(tag)
		writer.newline()

if __name__ == '__main__':
	import sys
	main (sys.argv[1:])

{'fraction_non_alphanumeric': 0.14022475999818007, 'fraction_numerical': 0.010737522180262978, 'mean_word_length': 4.371293580971001, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '992310', 'n_tokens_mistral': 26028, 'n_tokens_neox': 23357, 'n_words': 5681}