==== Язык M ====

1. Совместим с C. Можно выдвинуть требование безусловной совместимости.
   Также можно оставить на столе совместимость с C++ в версии Mk.

2. Назначение - разработка высокопроизводительных многопоточных асинхронных
   серверов (target application domain - TAD).
     * Высокопроизводительных => язык низкого уровня, развитие "переносимого
       ассемблера" - C. Нельзя превзойти C, не изобретая его заново.
       Дополняю C языковыми средствами, позволяющими повысить эффективность
       разработки программ из TAD.
     * Многопоточных => включаю в язык средства автоматизированного управления
       блокировками (примитивами синхронизации). Ввожу понятия синхронных и
       асинхронных методов.
     * Асинхронных => добавляю языковую поддержку для типичных моделей
       написания кода, использующихся в асинхронных программах;
     * Серверов => в качестве примеров и для тестов будут выступать серверные
       приложения.

3. Способ разработки - пишу ползучую спецификацию в электронном виде. Как только
   вырисовывается логически законченная идея - реализую её с помощью scruffy.
   Требование к scruffy на начальном этапе разработки - должен поддерживать
   разбор большинства типичных C-программ. Позже потребуется более глубокая
   поддержка в соответствии с ISO C99.

4. Поддерживается техника аннотирования - уточнения характеристик языковых
   объектов для развитых статических проверок.

=== Детализация основных свойств языка ===

1. Расширения для поддержки многопоточного программирования.
   Основные идеи:

     * Ввожу M-объекты - объекты с расширенной функционалностью, доступ к
       которым синхронизируется одной блокировкой (state_mutex - sm);
     * Ввоже синхронные/асинхронные функции (методы);
     * Ввожу в язык идеи из MyCpp: CallbackDesc, MemoryDesc, Referenced,
       WeakRef;
     * Дополняю язык стандартной моделью для i/o-функций (PrintTask).

1.1 M-объекты.

    Это "тяжёлые" объекты, _выделенные в куче_ (явно запрещаю создавать
    M-объекты на стеке). Дополнительный багаж, который несёт с собой M-объект:
      * Кол-во ссылок;
      * sm-блокировка;
      * Shadow-объект для WeakRef;
      * Уникальный id с порядком (оп-ей сравнения) - из указателя;
      * Виртуальный деструктор (vrelease);
      * Способ освобождения объекта (vfree).

    Добавление vfree означает, что, в принципе, можно разрешить выделение памяти
    под M-объект любым способом.

1.2 Допускаю поддержку S-объектов. S-объект содержит:
      * Кол-во ссылок - простых, не mt-safe ссылок;
      * Виртуальный деструктор;
      * Способ освобождения объекта (vfree).

    Таким образом, M-объекты - это тяжёлые MT-safe объекты. S-объекты -
    легковесные и не MT-safe.

    async object MyMObject {};

    object MySObject {};

1.3 Оперировать полями M-объектов могут только методы этих объектов.
    Привязка методов к M-объекту производится при объявлении метода.
    В результате привязки метод получает неявный аргумент this, имеющий тип
    структуры данных объекта (обращение к элементам через точку). Когда метод
    обращается к полям своего объекта, компилятор обеспечивает соблюдение
    правил асинхронного доступа. У S-объектов методов нет.

1.4 Методы делятся на синхронные и асинхронные. Асинхронные методы присущи
    только M-объектам. При обращении к полям объекта из асинхронных методов
    захватывается sm-блокировка этого обекта. При вызове асинхронных методов
    не допускается удерживание sm-блокировок других объектов (обеспечивается
    компилятором). На вызов синхронных методов никаких ограничений
    не накладывается. Все методы M-объектов по умолчанию асинхронные.

1.4.1 Асинхронные методы вызываются с помощью оператора call, чтобы явно
      запретить замешивание асинхронных вызовов в выражения.

1.5 Если из тела асинхронного метода вызывается асинхронный метод другого
    объекта, то на время этого вызова sm-блокировка освобождается. Разрыв
    sm-блокировки должен быть явно выделен специальным синтаксисом, т.к. это
    важное семантическое событие.

1.6 Ссылки. M- и S-объекты поддерживают управление памятью через подсчёт ссылок.
    M-объекты поддерживают также слабые ссылки (WeakRef). Возможный синтаксис
    для ссылок:
        MyObject  @obj;      // ссылка
	MyObject @@weak_obj; // слабая ссылка

1.7 Для объекта можно задать конструктор по умолчанию. Других типов
    конструкторов нет, т.к. нет способа возврата ошибок из конструкторов. Объект
    можно инициализировать либо конструктором по умолчанию, либо явно. Если для
    объекта определён конструктор по умолчанию, то он вызывается при создании
    объекта всегда, если только его вызов не отменён явно (ключ. слово dirty).

    Примеры синтаксиса:
        new MyObject;
        new malloc MyObject;
	new custom_alloc MyObject;
	new dirty custom_alloc (allocator) MyObject;

1.8 События (Cond). Логически с каждым событием связана проверка на выполнение
    события и примитив синхронизации, обеспечивающий выполнение этой проверки.
    Если в качестве примитива синхронизации выступает state mutex текущего
    объекта, то вызов cond->wait() упрощаем автогенерацией кода. В противном
    случае ограничиваемся статической проверкой на синхронизацию доступа к
    данным, используемым в проверке.

1.9 R/W locks. Не встраиваю в язык и реализую статические проверки на
    корректность использования.

2. Поддержка асинхронных программ.

2.1 М позволяет описывать разнесённые во времени последовательности обработки
    в форме, близкой к последовательной. Набор данных, выделяемых в хранимое
    состояние, определяется автоматически. Программист самостоятельно именует
    аргументы, вводящиеся в контекст в результате вызова асинхронного метода.
    Вызовы асинхронных методов выделяются синтаксически.

    Пример:

    void my_async_handler ()
    {
	int stored_state = 0;

      async call async_call_one ()
      gives int boo,
	    MemoryDesc * const foo $nonnull;

        printf ("%d\n", boo);

      async call async_call_two ();

	// 'stored_state' используется после асинхронного вызова => попадает в
	// хранимое состояние.
	int zoo = stored_state;

	// 'boo' тоже попадает в хранимое состояние.
	zoo = boo;
    }

    Есть большое поле для различных оптимизаций по объёму хранимого состояния.

    Важная возможность - выполнение параллельных асинхронных вызовов. Запускаем
    вызов, ожидая его результата позднее. Здесь появляется сложность: часть
    обработки возвращённых данных нужно выполнить немедленно, чтобы, например,
    обработать ошибки и прервать асинхронную цепочку.

    void my_async_handler ()
    {
	async call MyFirstCall one ()
	handler (bool success) {
	    if (!success) {
		call break;
	    }
	}

	async call MySecondCall two ()
	handler (bool success) {
	    if (!success) {
		call break;
	    }
	}

	// Интересный момент: результаты вызовов попадают в хранимое состояние,
	// потому что расположение gives указывает на параллельное выполнение.
	MyFirstCall gives bool success_one;
	MySecondCall gives bool success_two;
    }

2.2 Чтобы добавить свою переменную к состоянию, достаточно объявить её в начале
    функции асинхронной цепочки. Освобождение состояния (деструктор) задаётся
    блоком release {}, который должен стоять на месте последнего оператора
    в ф-ии:

    async void my_func ()
    {
	MyObject * const obj = new MyObject;

	release {
	    delete obj;
	}
    }

2.3 В асинхронных цепочках поддерживается полный набор обычных операторов C.

    * goto:
	async void my_handler ()
	{
	    int a = some_action ();

	  _label:

	    async call one ();

	    a = another_action (a);

	    goto _label;
	}

      Здесь _label является асинхронной точкой входа, потому что эта метка
      реально использована в операторе goto.

      Этот пример компилируется в следующий код:

	typedef struct {
	    MReferenced parent_referenced;
	    int a;

	    MBool fallthrough;
	    MBool label_called;
	    MBool label_goto;
	} MyHandler_Data;

	static void
	my_handler__data_init (MyHandler_Data * const data)
	{
	    m_referenced_init ((MReferenced*) data);

	    data->fallthrough = MFalse;
	    data->label_called = MFalse;
	    data->label_goto = MFalse;
	}

	static void my_handler__label (MyHandler_Data *_data);

	void
	my_handler ()
	{
	    MyHandler_Data * const data = m_malloc (sizeof (MyHandler_Data));
	    my_handler__data_init (data);

	    data->a = some_action ();

	    my_handler__label (data);
	}

	static void my_handler__one_ret (void *_data);

	static void my_handler__label (MyHandler_Data * const data)
	{
	    data->label_called = MTrue;

	    do {
		MCallbackDesc cb;
		m_callback_desc_reset (&cb);

		cb.callback = my_handler__one_ret;
		cb.data = data;
		cb.destructor = m_destructor_unref;

		one (&cb);
		if (data->fallthrough) {
		    if (data->label_goto) {
			data->fallthrough = MFalse;
			data->label_goto = MFalse;
			continue;
		    }
		}
	    } while (0);

	    data->label_called = MFalse;
	}

	static void
	my_handler__one_ret (void * const _data)
	{
	    MyHandler_Data * const data = (MyHandler_Data*) _data;

	    data->a = another_action ();

	    if (!data->label_called) {
		my_handler__label (data);
	    } else {
		data->fallthrough = MTrue;
		data->label_goto = MTrue;
	    }

	  // We're not unrefing 'data' because of the goto statement.
	}

      Упрощение исходного кода за счёт автогенерации очевидно.

      Ещё один пример:

	async chain foo ();

	async chain zoo ();

	async chain void f ()
	{
	    async call foo ()
	    gives bool success;

	    async call ZooCall zoo ()
	    result (bool success) {
		if (!success) {
		    log_e ("zoo() failed");
		    call break;
		}
	    }

	    ZooCall gives bool success, int result;
	    if (result == 0)
		log_d ("zero");
	}

	int main (void)
	{
	}

3. Расширения языка для повышения верифицируемости кода.
     * Аннотирование;
     * Идиомы CallbackDesc и MemoryDesc;
     * Идиома PrintTask.

3.1 Аннотирование является встроенным инструментом языка, но конкретных
    аннотирующих слов на начальном этапе разработки языка не вводится.
    Доступные символы для выделения аннотаций: + / : ^ % $ `
    Выбираю форму $nonnull, потому что gcc позволяет писать так:

        #define $nonnull
        int $nonnull const a;

    По-видимому, это особенность gcc (и, как пишут - многих других
    компиляторов). Очень кстати :)

3.2 Детализацию дополнительных идиом пока откладываю.

4. Базовые классы и интерфейсы. В языке M отказываюсь от наследования. Это удел
   Mx, если он увидит свет. Тем не менее, в M возможно однонаправленное
   невиртуальное наследование, заключающееся в пометке первого элемента
   структуры словом parent:

   object A {};
   object B { parent A a_parent; };
   void f (A *a);

   Всё, что это даёт - послабление при контроле типов, позволяющее писать
   f (&b) вместо f ((A*) &b);

   Интерфейсы реализуются явно, _но_ при этом возникает проблема с подсчётом
   ссылок. Это решается введением структур типа CallbackDesc, задающих способ
   освобождения интерфейса (destructor = m_referenced_unref, destructor_data =
   obj). Поэтому в язык вводятся _деструкторы_ - чтобы с объектами типа
   CallbackDesc было удобно работать.

5. Контроль типов во время компиляции. Контроль типов - по строгости
   соответствует C++, но не влияет на поиск имён. В первоначальной реализации
   контроля типов вообще не будет.

6. В Mt есть классы (class). Классы Mt значительно проще классов C++:
     * Нет множественного наследования;
     * Нет поиска имён в родительских классах;
     * Нет ADL (поиска имён, зависящего от аргументов);
     * Нет перегрузки операторов и перегрузки имён функций-членов;
     * Разрешена только одна форма конструктора - конструктор по умолчанию;
     * Упрощённая схема защиты: есть только public и private. При этом можно
       использовать private-поля в произвольном месте, пометив такое
       использование словом force: obj->force member (это замена для friend).


=> ! Выписал все основные идеи, можно приступать к реализации транслятора
     из M в C. Приступаю.

