# Source code for fontTools.misc.psOperators

    _accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"}

    class ps_object(object):

    	literal = 1
    	access = 0
    	value = None

    	def __init__(self, value):
    		self.value = value
    		self.type = self.__class__.__name__[3:] + "type"

    	def __repr__(self):
    		return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value))

    class ps_operator(ps_object):

    	literal = 0

    	def __init__(self, name, function):
    		self.name = name
    		self.function = function
    		self.type = self.__class__.__name__[3:] + "type"
    	def __repr__(self):
    		return "<operator %s>" % self.name

    class ps_procedure(ps_object):
    	literal = 0
    	def __repr__(self):
    		return "<procedure>"
    	def __str__(self):
    		psstring = '{'
    		for i in range(len(self.value)):
    			if i:
    				psstring = psstring + ' ' + str(self.value[i])
    			else:
    				psstring = psstring + str(self.value[i])
    		return psstring + '}'

    class ps_name(ps_object):
    	literal = 0
    	def __str__(self):
    		if self.literal:
    			return '/' + self.value
    		else:
    			return self.value

    class ps_literal(ps_object):
    	def __str__(self):
    		return '/' + self.value

    class ps_array(ps_object):
    	def __str__(self):
    		psstring = '['
    		for i in range(len(self.value)):
    			item = self.value[i]
    			access = _accessstrings[item.access]
    			if access:
    				access = ' ' + access
    			if i:
    				psstring = psstring + ' ' + str(item) + access
    			else:
    				psstring = psstring + str(item) + access
    		return psstring + ']'
    	def __repr__(self):
    		return "<array>"

    _type1_pre_eexec_order = [
    		"FontInfo",
    		"FontName",
    		"Encoding",
    		"PaintType",
    		"FontType",
    		"FontMatrix",
    		"FontBBox",
    		"UniqueID",
    		"Metrics",
    		"StrokeWidth"
    	]

    _type1_fontinfo_order = [
    		"version",
    		"Notice",
    		"FullName",
    		"FamilyName",
    		"Weight",
    		"ItalicAngle",
    		"isFixedPitch",
    		"UnderlinePosition",
    		"UnderlineThickness"
    	]

    _type1_post_eexec_order = [
    		"Private",
    		"CharStrings",
    		"FID"
    	]

    def _type1_item_repr(key, value):
    	psstring = ""
    	access = _accessstrings[value.access]
    	if access:
    		access = access + ' '
    	if key == 'CharStrings':
    		psstring = psstring + "/%s %s def\n" % (key, _type1_CharString_repr(value.value))
    	elif key == 'Encoding':
    		psstring = psstring + _type1_Encoding_repr(value, access)
    	else:
    		psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access)
    	return psstring

    def _type1_Encoding_repr(encoding, access):
    	encoding = encoding.value
    	psstring = "/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"
    	for i in range(256):
    		name = encoding[i].value
    		if name != '.notdef':
    			psstring = psstring + "dup %d /%s put\n" % (i, name)
    	return psstring + access + "def\n"

    def _type1_CharString_repr(charstrings):
    	items = sorted(charstrings.items())
    	return 'xxx'

    class ps_font(ps_object):
    	def __str__(self):
    		psstring = "%d dict dup begin\n" % len(self.value)
    		for key in _type1_pre_eexec_order:
    			try:
    				value = self.value[key]
    			except KeyError:
    				pass
    			else:
    				psstring = psstring + _type1_item_repr(key, value)
    		items = sorted(self.value.items())
    		for key, value in items:
    			if key not in _type1_pre_eexec_order + _type1_post_eexec_order:
    				psstring = psstring + _type1_item_repr(key, value)
    		psstring = psstring + "currentdict end\ncurrentfile eexec\ndup "
    		for key in _type1_post_eexec_order:
    			try:
    				value = self.value[key]
    			except KeyError:
    				pass
    			else:
    				psstring = psstring + _type1_item_repr(key, value)
    		return psstring + 'dup/FontName get exch definefont pop\nmark currentfile closefile\n' + \
    				8 * (64 * '0' + '\n') + 'cleartomark' + '\n'
    	def __repr__(self):
    		return '<font>'

    class ps_file(ps_object):
    	pass

    class ps_dict(ps_object):
    	def __str__(self):
    		psstring = "%d dict dup begin\n" % len(self.value)
    		items = sorted(self.value.items())
    		for key, value in items:
    			access = _accessstrings[value.access]
    			if access:
    				access = access + ' '
    			psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access)
    		return psstring + 'end '
    	def __repr__(self):
    		return "<dict>"

    class ps_mark(ps_object):
    	def __init__(self):
    		self.value = 'mark'
    		self.type = self.__class__.__name__[3:] + "type"

    class ps_procmark(ps_object):
    	def __init__(self):
    		self.value = 'procmark'
    		self.type = self.__class__.__name__[3:] + "type"

    class ps_null(ps_object):
    	def __init__(self):
    		self.type = self.__class__.__name__[3:] + "type"

    class ps_boolean(ps_object):
    	def __str__(self):
    		if self.value:
    			return 'true'
    		else:
    			return 'false'

    class ps_string(ps_object):
    	def __str__(self):
    		return "(%s)" % repr(self.value)[1:-1]

    class ps_integer(ps_object):
    	def __str__(self):
    		return repr(self.value)

    class ps_real(ps_object):
    	def __str__(self):
    		return repr(self.value)

    class PSOperators(object):

    	def ps_def(self):
    		obj = self.pop()
    		name = self.pop()
    		self.dictstack[-1][name.value] = obj

    	def ps_bind(self):
    		proc = self.pop('proceduretype')
    		self.proc_bind(proc)
    		self.push(proc)

    	def proc_bind(self, proc):
    		for i in range(len(proc.value)):
    			item = proc.value[i]
    			if item.type == 'proceduretype':
    				self.proc_bind(item)
    			else:
    				if not item.literal:
    					try:
    						obj = self.resolve_name(item.value)
    					except:
    						pass
    					else:
    						if obj.type == 'operatortype':
    							proc.value[i] = obj

    	def ps_exch(self):
    		if len(self.stack) < 2:
    			raise RuntimeError('stack underflow')
    		obj1 = self.pop()
    		obj2 = self.pop()
    		self.push(obj1)
    		self.push(obj2)

    	def ps_dup(self):
    		if not self.stack:
    			raise RuntimeError('stack underflow')
    		self.push(self.stack[-1])

    	def ps_exec(self):
    		obj = self.pop()
    		if obj.type == 'proceduretype':
    			self.call_procedure(obj)
    		else:
    			self.handle_object(obj)

    	def ps_count(self):
    		self.push(ps_integer(len(self.stack)))

    	def ps_eq(self):
    		any1 = self.pop()
    		any2 = self.pop()
    		self.push(ps_boolean(any1.value == any2.value))

    	def ps_ne(self):
    		any1 = self.pop()
    		any2 = self.pop()
    		self.push(ps_boolean(any1.value != any2.value))

    	def ps_cvx(self):
    		obj = self.pop()
    		obj.literal = 0
    		self.push(obj)

    	def ps_matrix(self):
    		matrix = [ps_real(1.0), ps_integer(0), ps_integer(0), ps_real(1.0), ps_integer(0), ps_integer(0)]
    		self.push(ps_array(matrix))

    	def ps_string(self):
    		num = self.pop('integertype').value
    		self.push(ps_string('\0' * num))

    	def ps_type(self):
    		obj = self.pop()
    		self.push(ps_string(obj.type))

    	def ps_store(self):
    		value = self.pop()
    		key = self.pop()
    		name = key.value
    		for i in range(len(self.dictstack)-1, -1, -1):
    			if name in self.dictstack[i]:
    				self.dictstack[i][name] = value
    				break
    		self.dictstack[-1][name] = value

    	def ps_where(self):
    		name = self.pop()
    		# XXX
    		self.push(ps_boolean(0))

    	def ps_systemdict(self):
    		self.push(ps_dict(self.dictstack[0]))

    	def ps_userdict(self):
    		self.push(ps_dict(self.dictstack[1]))

    	def ps_currentdict(self):
    		self.push(ps_dict(self.dictstack[-1]))

    	def ps_currentfile(self):
    		self.push(ps_file(self.tokenizer))

    	def ps_eexec(self):
    		f = self.pop('filetype').value
    		f.starteexec()

    	def ps_closefile(self):
    		f = self.pop('filetype').value
    		f.skipwhite()
    		f.stopeexec()

    	def ps_cleartomark(self):
    		obj = self.pop()
    		while obj != self.mark:
    			obj = self.pop()

    	def ps_readstring(self,
    			ps_boolean=ps_boolean,
    			len=len):
    		s = self.pop('stringtype')
    		oldstr = s.value
    		f = self.pop('filetype')
    		#pad = file.value.read(1)
    		# for StringIO, this is faster
    		f.value.pos = f.value.pos + 1
    		newstr = f.value.read(len(oldstr))
    		s.value = newstr
    		self.push(s)
    		self.push(ps_boolean(len(oldstr) == len(newstr)))

    	def ps_known(self):
    		key = self.pop()
    		d = self.pop('dicttype', 'fonttype')
    		self.push(ps_boolean(key.value in d.value))

    	def ps_if(self):
    		proc = self.pop('proceduretype')
    		if self.pop('booleantype').value:
    			self.call_procedure(proc)

    	def ps_ifelse(self):
    		proc2 = self.pop('proceduretype')
    		proc1 = self.pop('proceduretype')
    		if self.pop('booleantype').value:
    			self.call_procedure(proc1)
    		else:
    			self.call_procedure(proc2)

    	def ps_readonly(self):
    		obj = self.pop()
    		if obj.access < 1:
    			obj.access = 1
    		self.push(obj)

    	def ps_executeonly(self):
    		obj = self.pop()
    		if obj.access < 2:
    			obj.access = 2
    		self.push(obj)

    	def ps_noaccess(self):
    		obj = self.pop()
    		if obj.access < 3:
    			obj.access = 3
    		self.push(obj)

    	def ps_not(self):
    		obj = self.pop('booleantype', 'integertype')
    		if obj.type == 'booleantype':
    			self.push(ps_boolean(not obj.value))
    		else:
    			self.push(ps_integer(~obj.value))

    	def ps_print(self):
    		str = self.pop('stringtype')
    		print('PS output --->', str.value)

    	def ps_anchorsearch(self):
    		seek = self.pop('stringtype')
    		s = self.pop('stringtype')
    		seeklen = len(seek.value)
    		if s.value[:seeklen] == seek.value:
    			self.push(ps_string(s.value[seeklen:]))
    			self.push(seek)
    			self.push(ps_boolean(1))
    		else:
    			self.push(s)
    			self.push(ps_boolean(0))

    	def ps_array(self):
    		num = self.pop('integertype')
    		array = ps_array([None] * num.value)
    		self.push(array)

    	def ps_astore(self):
    		array = self.pop('arraytype')
    		for i in range(len(array.value)-1, -1, -1):
    			array.value[i] = self.pop()
    		self.push(array)

    	def ps_load(self):
    		name = self.pop()
    		self.push(self.resolve_name(name.value))

    	def ps_put(self):
    		obj1 = self.pop()
    		obj2 = self.pop()
    		obj3 = self.pop('arraytype', 'dicttype', 'stringtype', 'proceduretype')
    		tp = obj3.type
    		if tp == 'arraytype' or tp == 'proceduretype':
    			obj3.value[obj2.value] = obj1
    		elif tp == 'dicttype':
    			obj3.value[obj2.value] = obj1
    		elif tp == 'stringtype':
    			index = obj2.value
    			obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index+1:]

    	def ps_get(self):
    		obj1 = self.pop()
    		if obj1.value == "Encoding":
    			pass
    		obj2 = self.pop('arraytype', 'dicttype', 'stringtype', 'proceduretype', 'fonttype')
    		tp = obj2.type
    		if tp in ('arraytype', 'proceduretype'):
    			self.push(obj2.value[obj1.value])
    		elif tp in ('dicttype', 'fonttype'):
    			self.push(obj2.value[obj1.value])
    		elif tp == 'stringtype':
    			self.push(ps_integer(ord(obj2.value[obj1.value])))
    		else:
    			assert False, "shouldn't get here"

    	def ps_getinterval(self):
    		obj1 = self.pop('integertype')
    		obj2 = self.pop('integertype')
    		obj3 = self.pop('arraytype', 'stringtype')
    		tp = obj3.type
    		if tp == 'arraytype':
    			self.push(ps_array(obj3.value[obj2.value:obj2.value + obj1.value]))
    		elif tp == 'stringtype':
    			self.push(ps_string(obj3.value[obj2.value:obj2.value + obj1.value]))

    	def ps_putinterval(self):
    		obj1 = self.pop('arraytype', 'stringtype')
    		obj2 = self.pop('integertype')
    		obj3 = self.pop('arraytype', 'stringtype')
    		tp = obj3.type
    		if tp == 'arraytype':
    			obj3.value[obj2.value:obj2.value + len(obj1.value)] = obj1.value
    		elif tp == 'stringtype':
    			newstr = obj3.value[:obj2.value]
    			newstr = newstr + obj1.value
    			newstr = newstr + obj3.value[obj2.value + len(obj1.value):]
    			obj3.value = newstr

    	def ps_cvn(self):
    		self.push(ps_name(self.pop('stringtype').value))

    	def ps_index(self):
    		n = self.pop('integertype').value
    		if n < 0:
    			raise RuntimeError('index may not be negative')
    		self.push(self.stack[-1-n])

    	def ps_for(self):
    		proc = self.pop('proceduretype')
    		limit = self.pop('integertype', 'realtype').value
    		increment = self.pop('integertype', 'realtype').value
    		i = self.pop('integertype', 'realtype').value
    		while 1:
    			if increment > 0:
    				if i > limit:
    					break
    			else:
    				if i < limit:
    					break
    			if type(i) == type(0.0):
    				self.push(ps_real(i))
    			else:
    				self.push(ps_integer(i))
    			self.call_procedure(proc)
    			i = i + increment

    	def ps_forall(self):
    		proc = self.pop('proceduretype')
    		obj = self.pop('arraytype', 'stringtype', 'dicttype')
    		tp = obj.type
    		if tp == 'arraytype':
    			for item in obj.value:
    				self.push(item)
    				self.call_procedure(proc)
    		elif tp == 'stringtype':
    			for item in obj.value:
    				self.push(ps_integer(ord(item)))
    				self.call_procedure(proc)
    		elif tp == 'dicttype':
    			for key, value in obj.value.items():
    				self.push(ps_name(key))
    				self.push(value)
    				self.call_procedure(proc)

    	def ps_definefont(self):
    		font = self.pop('dicttype')
    		name = self.pop()
    		font = ps_font(font.value)
    		self.dictstack[0]['FontDirectory'].value[name.value] = font
    		self.push(font)

    	def ps_findfont(self):
    		name = self.pop()
    		font = self.dictstack[0]['FontDirectory'].value[name.value]
    		self.push(font)

    	def ps_pop(self):
    		self.pop()

    	def ps_dict(self):
    		self.pop('integertype')
    		self.push(ps_dict({}))

    	def ps_begin(self):
    		self.dictstack.append(self.pop('dicttype').value)

    	def ps_end(self):
    		if len(self.dictstack) > 2:
    			del self.dictstack[-1]
    		else:
    			raise RuntimeError('dictstack underflow')

    notdef = '.notdef'
    from fontTools.encodings.StandardEncoding import StandardEncoding
    ps_StandardEncoding = list(map(ps_name, StandardEncoding))