# coding: utf8
"""
Модуль "модПеременные".
Пакет содержит в себе определение секции переменных.
"""

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

class тСканерПеременные(тСекцияПерем):
	def __init__(сам, пОберон, пДанные:dict)->None:
		сам.__конс = пОберон.конс
		сам.__конс.Отладить("тСканерПеременные.__init__()")

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

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

	def __Слово_VAR_Обрезать(сам)->bool:
		"""
		Первое слово в списке слов должно быть VAR.
		Если нет -- значит в исходнике нет описания переменных.
		Возвращает результат встречи с VAR
		"""
		слово :тСлово= сам.слова_модуля[0]
		бРез = False
		if слово.строка =='VAR':
			# укоротить типы
			сам.СловаСекции_Обрезать()
			бРез = True
		return бРез

	def __ЕслиПеремНеПустые(сам)->bool:
		"""
		Может быть следующее слово после окончания секции:   PROCEDURE BEGIN (* END модуля уже отброшено *)
		Секция VAR не может быть пустой, но если есть типы, они должны заканчиваться на ;
		"""
		def Слово_Проверить()->None:
			if type(слово) != тСлово:
				стрОш :str= "Слово должно быть тСлово, type=" + str(type(слово))
				сам.ош_с.Внутр("Слово_Проверить()",  стрОш)
				return

		слово :тСлово= сам.слова_модуля[0] # первое слово после VAR, а сам VAR уже распознан и отброшен
		Слово_Проверить()
		if сам.ош_с.бВнутр:
			return

		# проверим на внезапный конец секции
		бМаркер :bool = (слово.строка in ("PROCEDURE", "BEGIN"))
		if not бМаркер: # секция переменных не пустая
			сам.__бПеремНеПустые = True
		return сам.__бПеремНеПустые

	def __ЕслиПеремОграничены(сам)->None:
		"""
		Ищет разделитель окончания переменных.
		Сканируем слова все подряд.
		Может быть следующее слово-маркер окончания секции типов: PROCEDURE BEGIN,
		Первое слово всегда должен быть именем переменной и не может быть маркером
		Произвольное слово может быть ";" и не может быть маркером
		"""
		def УслСтоп()->bool:
			слово :тСлово= сам.слова_модуля[цСловоСчёт]
			if type(слово) != тСлово:
				стрОш :str= "тПеременные: Слово должно быть тСлово, type=" + str(type(слово))
				сам.ош_с.Внутр("__ЕслиПеремОграничены()", стрОш)
			строка :str= слово.строка
			бСтоп1 :bool = False
			if строка == "PROCEDURE":
				бСтоп1 = True
			elif строка == "BEGIN":
				бСтоп1 = True
			бСтоп2 :bool = (цСловоСчёт < цСловМодульВсего)
			return бСтоп1 and бСтоп2

		цСловМодульВсего :int= сам.цСловаМодуля - 1 # отсчёт начинается с нуля
		цСловоСчёт :int= 0 # первый слово после VAR, а сам VAR уже распознали и отбросили

		while not УслСтоп():
			цСловоСчёт += 1
			слово :тСлово= сам.слова_модуля[цСловоСчёт]

		цСловоСчёт -= 1
		слово = сам.слова_модуля[цСловоСчёт]
		сам.Конец_Уст(слово)
		# Проверка на окончание секции типов
		if слово.строка != ";":
			стрОш = "Слово ограничение секции VAR должно быть ';'" + слово.стрИсх
			сам.ош_с.Исх("__ЕслиПеремОграничены()", стрОш)
			return

	def __Обработать(сам)->None:
		"""
		Проводит разбор секции VAR.
		"""
		if сам.__Слово_VAR_Обрезать():
			pass # "Есть переменные!")
		if сам.__ЕслиПеремНеПустые():
			pass # "Переменные не пустые!")
			#сам.__Перем_Печать()
			сам.__ЕслиПеремОграничены()
			if сам.ош_с.бВнутр or сам.ош_с.бИсх:
				return
			#сам.Перем_Печать()
			сам.СловаСекции_Получить()

	def Элемент_Проверить(сам, пПоле)->str:
		"""
		Проверяет предка записи. Должно быть разрешённой строкой и
		не должно быть END.
		Кроме того, имя может быть составным
		"""
		слово_имя :тСлово= сам.слова_секции[0]
		имя :str= слово_имя.Проверить()

		if not слово_имя.ЕслиСтр_Допустимо():
			стрОш :str= "Тип элемента переменной должен быть допустимым именем, имя="
			стрОш += имя
			сам.ош_с.Исх("Элемент_Проверить()", стрОш)
		if пПоле.поле.массив_тип != тРод.сБезТипа:
			стрОш = "Элемент массива уже назначен, элемент=" + пПоле.поле.массив_тип
			сам.ош_с.Исх("Элемент_Проверить()", стрОш)
		элемент :str= ""
		while (имя == ".") or (слово_имя.ЕслиСтр_Допустимо()):
			сам.СловаСекции_Обрезать()
			элемент += имя
			слово_имя = сам.слова_секции[0]
			имя = слово_имя.Проверить()
		return элемент

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