# coding: utf8
"""
Модуль определяет разбор секции типов.
"""

if True:
	from пакОберон.пакКомпилятор.пакСущность.пакСлово import тСлово
	from пакОберон.пакКомпилятор.пакСущность.пакСекция import тСекцияТипы
	from пакОберон.пакКомпилятор.пакСущность.пакОшибка import тОшибка

class тСканерТипы(тСекцияТипы):
	__slots__ = ("ош_", "__конс", "__типы", "__бТипыЕсть")
	def __init__(сам, пОберон, пДанные):
		сам.__конс = пОберон.конс
		сам.__конс.Отладить("ТСканерТипы.__init__()")

		сам.ош_ = тОшибка(пОберон, "тСканерТипы")

		тСекцияТипы.__init__(сам, пОберон, пДанные)
		if сам.ошт.бВнутр:
			сам.ош_.Внутр("__init__()", "При создании тСекцияТипы")
			return
		if сам.ошт.бИсх:
			сам.ош_.Исх("__init__()", "При создании тСекцияТипы")
			return
		сам.__типы = {} # словарь по словам каждого типа в модуле
		if сам.__Обработать():
			сам.ош_.Внутр("__init__()", "При сканировании секции типов модуля")
			return

	def __Обработать(сам):
		"""
		Проводит разбор секции TYPE.
		"""
		if сам.__ЕслиТипыПустые():
			return
		else:
			сам.__ЕслиТипыОграничены()
			if сам.ош_.бВнутр or сам.ош_.бИсх:
				return

			сам.СловаСекции_Получить()

	def __ЕслиТипыПустые(сам)->bool:
		"""
		Может быть следующее слово:   ; VAR PROCEDURE BEGIN (* END модуля уже отброшено *)
		Секция TYPE может быть пустой, но если есть типы, они должны заканчиваться на ;
		"""
		бРезПусто = True

		# первое слово после TYPE, а сам TYPE уже распознан и отброшен
		слово = сам.слова_модуля[0]
		строка = слово.строка
		if слово.ош.бВнутр:
			сам.ош_.Внутр("__ЕслиТипыПустые()", "При проверке слова")
			return бРезПусто
		if слово.ош.бИсх:
			сам.ош_.Исх("__ЕслиТипыПустые()", "При проверке слова")
			return бРезПусто

		# проверим на внезапный конец секции
		бРезПусто = not(слово.строка in ["VAR", "PROCEDURE", "BEGIN"])
		return бРезПусто

	def __ЕслиТипыОграничены(сам):
		"""
		Ищет разделитель окончания типов.
		Сканируем слова все подряд.
		Может быть следующее слово-маркер окончания секции типов: VAR PROCEDURE BEGIN,
		так как типов может быть несколько, то ";" не подходит
		Первое слово всегда должен быть именем типа и не может быть маркером
		Произвольное слово может быть ";" и не может быть маркером
		"""
		def Слово_Проверить():
			строка = слово.строка
			if слово.ош.бВнутр:
				сам.ош_.Внутр("Слово_Проверить()", "При проверке слова")
				return
			if слово.ош.бИсх:
				сам.ош_.Исх("Слово_Проверить()", "При проверке слова")
				return

			# проверяем на предварительно равно -- тогда это не ограничитель
			if слово.строка == "PROCEDURE":
				слово1 = сам.слова_модуля[цСловоСчёт-1]
				if слово1.строка == "=":
					стрПроц = "процедура как тип"
				else:
					стрПроц = "PROCEDURE" # если нет скобки -- точно процедура как блок
			else:
					стрПроц = "вообще не процедура"

			# проверяем на предварительную скобку -- тогда это не ограничитель
			if слово.строка == "VAR":
				слово1 = сам.слова_модуля[цСловоСчёт-1]
				if слово1.строка == "(":
					стрПерем = "параметры процедур-типов"
				else:
					стрПерем = "VAR" # если нет скобки -- точно переменные как блок
			else:
					стрПерем = "вообще не переменные"

			сам.__бМаркер = (слово.строка in [стрПерем, стрПроц, "BEGIN"])

		цСловоСчёт = 0 # первый слово после TYPE, а сам TYPE уже распознали и отбросили
		слово = сам.слова_модуля[цСловоСчёт]
		сам.__бМаркер = False
		Слово_Проверить()
		if сам.ош_.бВнутр or сам.ош_.бИсх:
			return
		while  цСловоСчёт < сам.цСловаМодуля - 1:
			if (not сам.__бМаркер):
				цСловоСчёт += 1
				слово = сам.слова_модуля[цСловоСчёт]
				Слово_Проверить()
				if сам.ош_.бВнутр or сам.ош_.бИсх:
					return
			else:
				break
		слово = сам.слова_модуля[цСловоСчёт - 1]
		сам.Конец_Уст(слово)
		# Проверка на окончание секции типов
		if слово.строка != ";":
			стрОш = "Слово ограничение секции типов должно быть ';'" + слово.стрИсх
			сам.ош_.Исх("__ЕслиТипыОграничены", стрОш)
			return

	def __Типы_Разделить(сам):
		"""
		Пока не исчерпаны слова секции -- последовательно вызываем новый тип.
		"""
		while len(сам.слова_секции) > 1:
			парам={}
			парам['секция'] = "TYPE"
			парам['слова']  = сам.слова_секции
			парам['имя'] = ""
			парам['бЭкспорт'] = False

			тип = None
			тип = тТип(парам)
			if тип.бОшВнутр:
				сам.__бОшВнутр = True
				сам.ош_.Внутр("__Типы_Разделить()", "При получении нового типа")
				return
			сам.__типы[len(сам.__типы)] = тип

			сам.слова_секции = {}
			сам.слова_секции = тип.слова_секции

	def Парам_Получ(сам) -> dict:
		парам = {}
		парам['слова'] = сам.слова_модуля
		парам['слова_секции'] = сам.слова_секции
		return парам
