#pragma once
#include "BKToken.h"

// определения меток.
constexpr uint32_t LBL_DEFINITE_MASK    = 0x0000000F; // Маска для выделения типа метки
constexpr uint32_t LBL_UNKNOWN          = 0x00000000; // значение для ошибочных ситуаций
constexpr uint32_t LBL_GLOBAL           = 0x00000001; // описание глобальной метки
constexpr uint32_t LBL_LOCAL            = 0x00000002; // описание локальной метки
constexpr uint32_t LBL_DEFINE           = 0x00000003; // описание константы (присваивания) с вычисленным значением
constexpr uint32_t LBL_WEAKDEFINE       = 0x00000004; // описание константы (присваивания) значение которой ещё не вычислено. там арифметическое выражение.
constexpr uint32_t LBL_FLAGS_MASK       = 0x000000F0; // Маска для выделения типа метки
constexpr uint32_t LBL_ABSVALUE         = 0x00000010; // константа, которую не надо корректировать

// определения, где встретилось арифметическое выражение
constexpr uint32_t ARL_DEFINITE_MASK    = 0x0000000F; // Маска для выделения типа метки
constexpr uint32_t ARL_DEFINE           = 0x00000001; // в присваивании (в константе)
constexpr uint32_t ARL_CMDARG           = 0x00000002; // в команде

constexpr uint32_t ARL_FLAGS_MASK       = 0x0000F000; // Маска для выделения флагов арифметического выражения
constexpr uint32_t ARL_ABS              = 0x00001000; // абсолютное выражение
//constexpr uint32_t ARL_DOTS             = 0x00002000; // в выражении были точки (что, возможно, тоже делает его абсолютным)
constexpr uint32_t ARL_LOCAL            = 0x00004000; // ссылка на локальную метку
constexpr uint32_t ARL_BYTEL            = 0x00008000; // флаг байтового результата, т.е. значение надо сохранять в байт
// определения ссылок на метки
constexpr uint32_t REFERENCE_TYPE_MASK  = 0x000000F0; // Маска для выделения типа метки
constexpr uint32_t ARL_BRANCH_LABEL     = 0x00000010; // метка в ветвлении
constexpr uint32_t ARL_OFFSET_LABEL     = 0x00000020; // смещение до адреса
constexpr uint32_t ARL_RELATIVE_LABEL   = 0x00000030; // Метка

class Label
{
	protected:
		uint32_t    type{ 0 };  // тип - метка или определение, это нужно для релокации.
		// при линковке объектника меткам нужно перевычислять адреса, определениям - нет
		// LOCAL,GLOBAL,DEFINE
		int         value{ 0 }; // значение метки или определения
		CBKToken    label;      // имя метки или определения

	public:
		Label()
		    = default;
		Label(uint32_t lt, int lv, CBKToken *pt)
			: type(lt)
			, value(lv)
			, label(*pt)
		{ }

		inline uint32_t getType() const noexcept
		{
			return type;
		}
		inline void setType(const uint32_t t) noexcept
		{
			type = t;
		}
		inline int getValue() const noexcept
		{
			return value;
		}
		inline void setValue(int v) noexcept
		{
			value = v;
		}

		inline const CBKToken &getToken() noexcept
		{
			return label;
		}

		inline CBKToken *getPToken() noexcept
		{
			return &label;
		}

		void Store(FILE *f) const
		{
			const OBJTags tag = OBJTags::OBJ_Label;
			fwrite(&tag, 1, sizeof(tag), f);
			fwrite(&type, 1, sizeof(type), f);
			fwrite(&value, 1, sizeof(value), f);
			label.Store(f);
		}

		bool Load(FILE *f)
		{
			OBJTags tag{};
			fread(&tag, 1, sizeof(tag), f);

			if (tag == OBJTags::OBJ_Label)
			{
				fread(&type, 1, sizeof(type), f);
				fread(&value, 1, sizeof(value), f);

				if (label.Load(f))
				{
					return true;
				}
			}

			return false;
		}
};
