LINUX.ORG.RU

Qod. Опубликовал исходники компилятора, над которым работаю

 , qod, ,


5

4

Финально определился с названием языка, подчистил разные хвосты и написал README. Теперь наконец-то можно посмотреть на нечто большее, чем просто фрагменты кода в постах на форуме: https://github.com/wandrien/qod/

Драфты по дизайну языка пока еще не готовы. Если перед НГ завала работы не будет, то может выложу их в течение пары недель. Черновики пишу на русском, осилить всё чётко сформулировать на английском в разумные сроки я точно не смогу. На русском-то не всегда получается.

Надеюсь, что после публикации материалов по языку, мне щедро насыпят в панамку как конструктивной, так и не очень, критики.

А пока можно посмотреть на сам код вживую.

★★★
Ответ на: комментарий от wandrien

Обращайся по адресу:

ну там нарисован лютейший изврат, к тому ж нарущающий принципы структурного программирования. там continue продолжает блок который лямбда (если это она) видеть не должна. а если это просто такая макра, то финт проходит, но все недостатки макр вылезут наружу.

короче руст это вообще не руководство к действию.

опять же тип noreturn русту нужен, поскольку он занимается анализом потока исполнения, а тебе-то он зачем?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)

«Если перед НГ завала работы не будет»

Новый год, это время, когда компаниям надо освоить остатки годового бюджета, а у торговых компаний пик активности. Как может не быть завала работы перед НГ?

Shushundr ★★★★
()
Ответ на: комментарий от Shushundr

Да))

У моего заказчика в последний момент случилась ситуация «сами не знаем, что нам надо». Видимо завтра как на работу выйдут они, я охренею от списка правок.

wandrien ★★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от alysnix

Стоило про игнор сказать, и сразу мысль связная появилась в комментах. Магия.

ну там нарисован лютейший изврат

Там смысл примера не в том, чтобы показать, как грамотно писать код, а в том, чтобы показать, почему noreturn совместим с любым типом. Или иными словами, t == (t | noreturn), где t — любой тип.

Почему ты делаешь вид, что этого не понимаешь, хотя прекрасно понимаешь – хз.

опять же тип noreturn русту нужен, поскольку он занимается анализом потока исполнения, а тебе-то он зачем?

Ровно по той же причине.

https://github.com/wandrien/qod/blob/master/src/tests/noreturn_1.qd

https://github.com/wandrien/qod/blob/master/src/tests/noreturn_2.qd

https://github.com/wandrien/qod/blob/master/src/tests/noreturn_3.qd

https://github.com/wandrien/qod/blob/master/src/tests/eRETURNEXP.qd

https://github.com/wandrien/qod/blob/master/src/tests/eRETURNEXP_2.qd

wandrien ★★★
() автор топика

Небольшой спойлер того, что ожидается в будущем. Будет круто.

Кто понял, тот понял.

Fixed-size array memory layout

    data[0]  <- reference
    data[1]
    data[2]
    ...

Specified-size array memory layout

    count
    data[0]  <- reference
    data[1]
    data[2]
    ...

Room memory layout

    room
    count
    data[0]  <- reference
    data[1]
    data[2]
    ...

Virtual room memory layout

    virtual_count
    room
    count
    data[0]  <- reference
    data[1]
    data[2]
    ...

Read-only ref-counted string memory layout

    refcount
    count
    data[0]  <- reference
    data[1]
    data[2]
    ...
    string_terminator

Miltidimentional array memory layout

    ...
    count_dim_3
    count_dim_2
    count_dim_1
    data[0]  <- reference
    data[1]
    data[2]
    ...

Slice memory layout

    ptr_to_data
    count

wandrien ★★★
() автор топика
Ответ на: комментарий от gaylord

Насчёт access types я пока не определился.

Вот такие варианты возможны:

  • Ссылка, aka Reference<T>, aka t& в крестах.
  • Указатель, aka Pointer<T> .
  • Указатель, могущий содержать null, aka NullablePointer<T>, aka t* в крестах. (Как это по-русски называть? «Обнулябельный указатель»?)

Еще на задворках болтается AllowZeroPointer<T> который может потребоваться для программирования ядер ОС и микроконтроллёров. Но я его особо не рассматриваю как вариант на включение. Не вижу строгой необходимости.

Следует ли ссылку и не-null указатель объединить в один тип, или нет. И какие именно свойства им назначить, если не объединять. Не улавливаю пока.

wandrien ★★★
() автор топика

А еще мне нужен оптимальный алгоритм перемножения двух чисел со знаком фиксированной разрядности с обнаружением переполнения.

Оптимальный алгоритм перемножения без обнаружения переполнения я вроде как понимаю.

А вот про переполнение - хз. Тот вариант, который я знаю, там требуется разрядность в 4 раза увеличивать для получения результат.

wandrien ★★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 2)
Ответ на: комментарий от wandrien

ты не сможешь встроить в язык типы на все случаи жизни(это даже просто неверный подход). и придется тебе идти по пути плюсов - иметь шаблонизацию, всякие там контракты и прочее. и уже через это вот все реализовывать твои nullableptr и все такое (как пример можно обратиться к плюсовому std) . но какие-то базовые указатели тебе нужны по любому. и эти базовые указатели - те, самые что в плюсах.

а как только ты вступишь на этот путь… окажется, что там уйма семантики, и куча работы, которую тебе не сделать. просто потому что в сутках 24 часа, а у тебя одна голова.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)

Немножко подшаманил парсинг, теперь такой тест проходит компиляцию.

Теперь можно сначала сделать предварительное объявление функции, а уже потом импортировать её дефиницию из пространства имён/модуля.

// TEST: should_print '1234 1235 '

include "../include/test_env.qdi";

int foo(int x, y);

int bar(int x, y)
	return foo(x, y) + 1;
end

namespace AAA of
	int foo(int x, y)
		return x + y;
	end
end:namespace

alias foo = AAA.foo;

begin
	put_int(foo(1000, 234)); puts(" ");
	put_int(bar(1000, 234)); puts(" ");
end
wandrien ★★★
() автор топика
Ответ на: комментарий от wandrien

Теперь можно сначала сделать предварительное объявление функции, а уже потом импортировать её дефиницию из пространства имён/модуля.

И теперь можно делать так:

https://github.com/wandrien/qod/commit/f4d3f67c28dfe1e61b0ccf8c75e6e175dff7867b

wandrien ★★★
() автор топика

В процессе отладки кодогенератора удалось добиться такого улучшения генерации кода:

Исходник:

	while j < Size do

		if i >= _nChar then
			exit;
		end

		if Str[j] != Char[i] then

Было:

        mov     EAX,  dword [EBP-12]
        cmp     EAX,  dword [EBP+12]
        jae     @10257
                                         ; #line compiler_chardata.qdi:31
        mov     EAX,  dword [EBP-8]
        cmp     EAX,  dword [@@DATA+49284]
        jae     @10257
                                         ; #line compiler_chardata.qdi:35
        mov     EAX,  dword [EBP-12]
        add     EAX,  dword [EBP+8]
        mov      AL,  byte  [EAX]
        mov     EDX,  dword [EBP-8]
        mov      DL,  byte  [@@DATA+EDX+49288]
        cmp      AL,   DL
        je      @10263

Стало:

        mov     EAX,  dword [EBP-12]
        cmp     EAX,  dword [EBP+12]
        jae     @10257
                                         ; #line compiler_chardata.qdi:31
        mov     EDX,  dword [EBP-8]
        cmp     EDX,  dword [@@DATA+49284]
        jae     @10257
                                         ; #line compiler_chardata.qdi:35
        add     EAX,  dword [EBP+8]
        mov      AL,  byte  [EAX]
        mov      DL,  byte  [@@DATA+EDX+49288]
        cmp      AL,   DL
        je      @10263

И таких мест по коду много, где компилятор «пропускает» содержимое регистров через блок ветвлений, чтобы потом переиспользовать.

Но в некоторых случаях стало хуже, как тут:

Было:

        mov     EDX,  dword [EBP+20]
        cmp     EDX,  127
        ja      @13199
        cmp     EDX,  4294967168

Стало

        mov     EAX,  dword [EBP+20]
        cmp     EAX,  127
        ja      @13199
        mov     ECX,  dword [EBP+20]
        cmp     ECX,  4294967168

Причину регрессии пока не выяснил.

wandrien ★★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от alysnix

по-русски, многомерных небось?

Это не по-русски, а по неграмотному.

Указатель на указатель «многомерным указателем» не хочешь называть? А массив, состоящий из массивов, почему-то хочешь.

wandrien ★★★
() автор топика
Ответ на: комментарий от wandrien
Ответ на: комментарий от alysnix

В системе типов нет такой сущности как многомерный массив.

Она ничем не характеризуется, нет никаких различительных свойств, которые бы отличали многомерный массив.

Вот тебе книжки читать бесполезно, если голову не включаешь. Остаётся только верить написанному. А там дрова.

wandrien ★★★
() автор топика
Ответ на: комментарий от wandrien

Ты б хоть открывал свои ссылки что ли.

тебе сказано, в языках есть термин multidimentional arrays. а то что ты придумал как nested arrays, есть самодеятельность, выдающая в тебе пионера с барабаном, когда ты начинаешь перевыдумывать терминологию, которой лет 50-60, на лету.

все такие «многомерные массивы» реализуются как единый кусок памяти, то есть по сути одномерный массив элементов, просто с правильным вычислением одномерного физического индекса, из вектора логических индексов. это тебе и назвали - одномерностью, просто ты не врубился.

alysnix ★★★
()
Ответ на: комментарий от alysnix

Есть мнение, что имеем дело с началом

Jesus said «I will rebuild this temple in three days.» I could make a compiler in 3 days. (с)

начинаешь перевыдумывать терминологию, которой лет 50-60, на лету.

Опять же, всё протекает похожим образом:
The code is beautiful. I always break compatibility to keep it perfect. (с)

И дело уверенно идёт к
I report to God. You report to me. (с)

anonymous
()
Ответ на: комментарий от wandrien

Какие отличительные свойства у сущности под названием «многомерный массив»?

у чата гпт спроси. он для того и сделан, чтобы спасать умных людей от дурацких вопросов.

alysnix ★★★
()
Ответ на: комментарий от wandrien

Причину регрессии пока не выяснил.

Выяснил.

Немного прокачал возможности генератора кода. Правда дел за 2 дня было столько, что до сих пор не добрался оформить коммит и залить.

На днях работал до 3-х ночи, всё нужно «срочно» перед НГ. Люди так торопятся, будто надеются успеть.

wandrien ★★★
() автор топика
15 марта 2025 г.

@LINUX-ORG-RU, привет. Как думаешь, есть смысл синтаксис двоеточия из Lua перенести в компилируемый язык?

Я сейчас размышляю над реализацией методов для структур в этом проекте.

В качестве примера возьмём существующий код: https://github.com/wandrien/qod/blob/01eb14358580cf4cb7b0ec4aaf85c8608043c770/src/include/strbuf.qdi

Если переписать декларации в предполагаемом синтаксисе объявления методов, то будет:

struct strbuf of
    char @Buff;
    word BuffSize;
    word BuffLen;

    void init(this; char @Buff; word BuffSize);
    word get_virtual_len(this);
    word get_actual_len(this);
    word append_cstr(this; char @Src);
    word append_cstr2(this; char @Src1; char @Src2);
    word append_cstr3(this; char @Src1; char @Src2; char @Src3);
    word append_cstr4(this; char @Src1; char @Src2; char @Src3; char @Src4);
    word append_cstr5(this; char @Src1; char @Src2; char @Src3; char @Src4; char @Src5);
    word append_cstr6(this; char @Src1; char @Src2; char @Src3; char @Src4; char @Src5; char @Src6);
end:struct

Соответственно мы можем вызывать методы либо без синтаксического сахара, как обычную функцию:

strbuf.get_virtual_len(@x)

Либо с синтаксическим сахаром аналогично как в Lua:

x:get_virtual_len()

Пример использования в коде:

Было:

void StopInternal(char @File; word Line)
	char Buff[nMSGBUFF];
	strbuf buf;
	strbuf_init(@buf, @Buff, nMSGBUFF);
	strbuf_append_cstr4(@buf, @eINTERNAL, @File, ":", @str(Line));
	Stop(@Buff);
end

Станет:

void StopInternal(char @File; word Line)
	char Buff[nMSGBUFF];
	strbuf buf;
	buf:init(@Buff, nMSGBUFF);
	buf:append_cstr4(@eINTERNAL, @File, ":", @str(Line));
	Stop(@Buff);
end

Собственно, в плане синтаксиса вызова метода я вижу три опции:

  1. В стиле C++-подобных языков:
strbuf::get_virtual_len(@x)
x.get_virtual_len()
  1. В стиле Lua:
strbuf.get_virtual_len(@x)
x:get_virtual_len()
  1. Использовать везде точку, так как синтаксически нет необходимости различать эти варианты, компилятор не запутается:
strbuf.get_virtual_len(@x)
x.get_virtual_len()

Но хоть компилятор не запутается, а вот программист может запутаться. Я предпочитаю делать синтаксис, который не содержит вариативного скрытого поведения.

wandrien ★★★
() автор топика
Ответ на: комментарий от wandrien

программист может запутаться.

программист уже запутался.

в си++ имя класса и имя обьекта могут совпадать. а :: использется для неймспейсов и статических членов класса, берущихся от класса.

strbuf::get_virtual_len(@x)

тут указан и явно класс, и явно this? ну имеет смысл только если функция перекрыта в классе обьекта x, потому явно указывается класс предок.

от класса указывают метод или в случае его перекрытия, или в случае статического метода(то тогда не нужен this).

короче путаница

alysnix ★★★
()
Ответ на: комментарий от wandrien

Ну, сомневаюсь что моё мнение тут будет полезно и что-то значит, но уж раз спросил, во первых как по мне плюсовый вариант :: не надо, слишком жирное написание, а foo::bar::baz::camaz выглядит вообще ужасно.

А вот двоеточие как возможность косвенного обращения к самому себе имеет смысл. Но это скорее относится к структурам данных, чем к сахару позволяющему не указывать первый аргумент в функции.

Удобство в том что когда например возвращаем файл, можно возвращать не примитив вроде просто числа как дескриптора, а структуру (указатель на неё), с полями которые обрабатывают эту же структуру данных.

Ещё удобство в том что в неком роде это решает проблемы именований, если есть несколько типов данных которым мы хотим задать значение то

  type_foo:set("lala")
  type_bar:set(42)

иногда, лучше чем

type_foo_set(type_foo,"lala")
type_bar_set(type_bar,42)

Так set являясь полем может быть легко переопределена, динамически например.
Банальная ситуация, есть у тебя файл и например сетевой сокет, оба могут быть буферизированы и обоим нужно иногда сделать принудительный сброс данных дальше на обработку, семантически это одно и тоже flush и выбора тут два. Первый, представлять всё как файл, строить высокую абстракцию и передавать


flush(file)
flush(socket)

А различать что есть что уже внутри flush, а на уровне кода различать именованием. Или делать просто отдельные именованные вызовы для типа данных

file_flush(file)
socket_flush(socket)

В этом нет проблемы, но чисто технически более гибко будет возвращать конкретный тип данных, с готовыми полями в виде функций

file = newfile()
file:write("lala")
file:flush()

socket = newsocket()
socket:send("lala")
socket:flush()

Тут важнее ещё то что можно будет сделать так

if(getos() == "linux")
{
    file.flush = linux_flush;
}

например, в иных вариантах нужен будет либо препроцессор, либо

   if(getos() == "linux")
   {
       file_flush = linux_flush;
   }

А тут чревато уже может быть.

Я за стиль №2, там визуально видно, чего куда, если уж делать, тут явное разделение обращение к полю как к полю и как только к вызову с неявным аргументом, нужно и то и то порой.

Иными словами, как по мне нет проблем в записи strbuf_append_cstr4 и buf:append_cstr4 в целом разницы то никакой, разница она появляется как следствие, в динамике написания кода. Ну и первый вариант быстрее, даже на просто уровне обработки до компиляции, так что если и привносить косвенный первый аргумент в функции, то оставить и возможность первого варианта, обычного вызова, обычной функции с обычными аргументами, напрмимер в той же Lua дохренища вариантов сделать и так и сяк и эдак, но я часто пишу на Lua как на Си, ну просто такой подход тупо быстрее работает. Например

m3 = matrix_pow(m1,m2)

вместо

m1:pow(m2)

Даже несмотря на краткость записи, в случае обработки этого в цикле удобнее первый вариант.

Но никто не помешает сделать так

m3 = m1.pow(m1,m2)

Но в любом случае это палка о двух концах

  • а если у нас есть args/argc то какое количество аргументов мы будем сообщать с учётом неявного аргумента или без его
  • нужно ключевое слово обращения к неявному аргументу
  • как обрабатывать ситуации если через : делается вызов функции у которой единственный аргумент и он не является структурой данных/типом данных который передаётся неявно.
  • можно ли через : вызывать функцию которая не является полем, а просто левой функцией
foo(x) 
{
  print(x+x)
}

bar = {"hello"}

bar:foo() ????????? \o_0/ ! ! \0_O\

И так далее. Как по мне, прежде чем реализовать, нужно пройтись по всем «последствиям» и теоретическим констуркциям которые вдруг будут записаны программистом, так как чисто синтаксически они вполне себе могут быть :D

В динамическом языке проблем нет, там слой абстракции позволяет дичь делать в динамике. А у тебя вот не знаю. Может как в случае с сишным for сахарок будет, делает что-то конкретное, конкретно сахар для неявного аргумента, только для заранее определённых полей данных в виде функций. И всё, на места разворачивать неявный аргумент в явный и всё, как вариант вызова и не более того. Не как замена, а как дополнение к классическим вызовам процедур.

Типа такого. Мысли в слух.

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)

Немножко оптимизировал работу парсера, в результате чего количество I refs под callgrind при сборке самого себя без оптимизации уменьшилось с 302,288,794 до 268,147,786.

Коммиты:

wandrien ★★★
() автор топика
Ответ на: комментарий от LINUX-ORG-RU

как по мне плюсовый вариант :: не надо, слишком жирное написание, а foo::bar::baz::camaz выглядит вообще ужасно.

Согласен.

Но это скорее относится к структурам данных, чем к сахару позволяющему не указывать первый аргумент в функции.

Это и туда, и туда относится. В моей логике это в первую очередь как раз сахар.

ну просто такой подход тупо быстрее работает.

Тут фактическая разница будет не сахаром определяться, а реальным определением в коде.

То есть если это:

struct Foo
	void bar(this; int x);
end

то foo:bar(10) в машинном коде ничем не отличается от прямого вызова функции.

А вот если:

struct Foo
	void bar@(this; int x);
end

то здесь в структуре определенно поле bar, являющееся указателем на функцию. И вызов foo:bar(10) требует чтения этого поля.

То есть общий смысл такой, что запись x:y(...) это сахар для x.y(@x, ...), независимо от того, чем является y.

нужно ключевое слово обращения к неявному аргументу

Это отдельный и хороший вопрос, про неявный аргумент. В крестах он не указывается в сигнатуре фунции, но при этом он может иметь квалификаторы. В результате чего квалификаторы приходится писать так:

struct X {
	void bar(int i) const;
};

Я думаю, что this следует указывать явно, но в упрощенном синтаксисе. Пример с константным this будет выглядеть так:

struct X of
	void bar(const this; int i);
end

И аналогично использование внутри самой функции. Обращения к полям через this.что_то, вызов методов через this:что_то() и т.п. Без «неявного this».

И при желании можно вообще не использовать сахар this в сигнатуре функции, а назвать первый аргумент хоть that, хоть self, просто тогда еще и тип ему нужно указать явным образом, чтобы компилятор понял. Типа такого

struct X of
        /* Эти объявления эквивалентны: */
	void bar1(const this; int i);
	void bar2(const X @that; int i);
end

как обрабатывать ситуации если через : делается вызов функции у которой единственный аргумент и он не является структурой данных/типом данных который передаётся неявно.

Будет выполнена попытка преобразования типа по общим правилам языка.

можно ли через : вызывать функцию которая не является полем, а просто левой функцией

Можно вызывать любое имя, которое объявлено внутри просранства имён структуры, независимо от того, поле это или просто статическое определение функции (или шаблон, макрос, или что угодно, что там будет в языке дальше).

А вот для того, чтобы засовывать первый аргумент «конвеером» вообще в любую функцию, в современных языках придумали оператор |>, типа такого:

int foo(float x, int y);
int a = 100.0 |> foo(20);

Его я наверное тоже добавлю, пока просто руки не дошли.

wandrien ★★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 4)
Ответ на: комментарий от vsnb

Проблема кода, находящегося в README, в том, что такой код не покрывается тестами, и соответственно может быть ошибочным, не актуальным, не компилироваться или компилироваться, но работать неверно.

В данном случае буквально все файлы проекта, являются примерами кода на языке, и они в таком виде намного лучше выполняют иллюстративную задачу.

Пока на данный момент этого достаточно, потому что синтаксис и семантика находятся в развитии.

Когда у меня дойдут руки написать какой-то туториал или введение в язык, я, скорее всего, буду делать это в формате «литературного программирования», то есть примеры кода и документация к ним будут на уровне исходника составлять единое целое, которое также покрывается тестами.

wandrien ★★★
() автор топика
Ответ на: комментарий от wandrien

То есть общий смысл такой, что запись x:y(…) это сахар для x.y(@x, …), независимо от того, чем является y.

Ну, если всё заключается исключительно в дополнительном варианте записи, который никаких последствий не несёт, а лишь даёт выбор альтернативной записи того же самого, что может быть удобнее в конкретной ситуации, то почему нет. Некоторым например приятно написать библиотеку, в реализации которой будут исключительно классические вызовы, а вот интерфейс представлен с возможностью использования записи через двоеточие, например для ситуаций скрытия состояния внутри.

И при желании можно вообще не использовать сахар this в сигнатуре функции

Можно давать косвенному аргументу и произвольное имя, но с учётом того что все косвенные аргументы любой функции, любого типа данных это семантически одно и тоже, иначе говоря это зарезервированная подстановка идентификатора, когда некое неназванное имеет имя, то как по мне удобнее чтобы это имя было разово определено как ключевое слово, в таком случае, сидя в глубине кода и видя this/that/lol/kek ты знаешь что это тот самый первый неявный аргумент функции и это гарантированно, не надо обращаться к прототипу функции для узнавания как там назвали неявный аргумент. Так что произвольное имя для неявного аргумента как по мне ненужная затея. Можно сделать, но зачем, ума не приложу.

Оно либо произвольное, то тогда заданное явно

  • update(data)

Либо ключевое слово, при неявной передаче

  • data:update()

При этом можно совмещать, если приспичит.

  • data.update(data)

А вот произвольное при неявной передаче, ну у меня в голове сразу ситуация такая что, я в глубине кода, и тут стоит имя котрого нет ни в аргументах ни в текущем теле функции и надо искать где там задан у чёрта на куличиках явный идентификатор для неявного аргумента именно этой функции ахах, а может АФТАР МУДАК!!! и у него у каждой функции разное наименование неявного аргумента, ябпсиханул от такого.

Ну, на этом мои мысли вроде всё, пойду кашу варить, молочную.

LINUX-ORG-RU ★★★★★
()

Добавил поддержку генерации асм-кода для NASM:

Компиляция через NASM + LD в несколько раз медленнее, чем компиляция через FASM.

Но поскольку NASM умеет генерировать рудиментарную отладочную информацию, то теперь можно смотреть результаты оценки производительности в qcachegrind.

Это позволило следом выполнить ряд улучшений производительности:

wandrien ★★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 1)

Апрель который уже скоро, но не 2025 года, а 1957, что тогда появилось? Первый компилятор Fortran, с многомерными массивами и операциями над ними, несколькими типами чисел, проверкой переполнения, продвинутым форматированием для ввода/вывода, и прорывным оптимизатором, который даже учитывал вероятности, и у которого был аналог __builtin_expect_with_probability. Еще он предоставлял подробные сообщения об ошибках которые на то время удивляли людей. Его разрабатывала небольшая команда программистов, из около 10 человек.

Интересно, спустя век развития технологий, что может сделать всего один человек? Особенно на такой мощной платформе как x86.

Есть описание продвинутого оптимизатора? Интересных конструкций?

MOPKOBKA ★★★★★
()
Ответ на: комментарий от MOPKOBKA

и прорывным оптимизатором

Прорывной по сравнению с чем? Прохладная история, бро.

Есть описание продвинутого оптимизатора?

А кто тебе обещал продвинутый оптимизатор?

wandrien ★★★
() автор топика
Ответ на: комментарий от wandrien

и прорывным оптимизатором

Прорывной по сравнению с чем? Прохладная история, бро.

Со всем что было.

А кто тебе обещал продвинутый оптимизатор?

Ну ты называешь свой язык новым и экспериментальным, какие виды экспериментов ты на нем ставишь? Надо обозначить в README, я не нашел.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 1)