Pull to refresh
4
11
Wilhelm@willy2312

User

Send message

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

Для предотвращения исключения new(), можно целиком заменить инструкцию, примерно так:

replace {
  $source;
  if (!$2) {
    out("FATAL");
  }
}

Программа при исключении завершится только если там такое прописано. Пока что в стандартной библеотеке нет одной такой функцией, поэтому пока завершать программу вне main() нужно вручную через ASM syscall или ExitProcess.

И в исключении можно писать всё что угодно, потому что на этапе вставки проверок и прочего пройден только синтаксический анализ, но ошибки вылезут при парсинге. Так как код вставляется - обработчик в исключении имеет доступ ко всему, что имеют остальные в этом скоупе.

Исключения будут описаны заранее в стандартной библеотеке, вручную ничего описывать не пртидётся. Если у вас очень много делений, то да, на каждое действие будет немногие оверхед на несколько примерно 20-35 тактов процессора. Но никто не обязывает пользоваться исключениями если вам нужна максимальная скорость. В теории это может компенсироваться оптимизациями LLVM, но я не проверял. Слышал что с оптимизациями прирост от 50% до 200%, не проверял

Ну если new() не выделил память, указатель не валидный, и обращаться по нему - сегфолт. new() магическим образом не будет пытаться ещё раз пробовать выделение в памяти.

Ну, там в имени в начале есть символ звёздочки, а со звёздочкой аллоцировать в стеке нельзя через alloca().

Вот пример:

exception DivByZero {
  int op;
  instruction {
    %n / %"("^")":op
  }
  check {
    if (op == 0) {
      out("FATAL");
      exit(1);
    }
  }
}

int main() {
  // Здесь вставится:
  //int op = (6 - 6);
  //if (op == 0) {
  //  out("FATAL");
  //  exit(1);
  //}
  int a = 5 / op;
  return 0;
}

Насколько я знаю, так препроцессор не умеет

В языке так и есть, там в парсере прямо так и написано, что "->" и "." делают одно и то же

Имел в виду что если поле структуры которая ещё сама не удалена указывает на уже удалённый объект - поле останется висячим

Ну вообще язык делает упор не в ООП. Реализовано это все без оверхеда (по типу vtable), классы это те же структуры, методы это функции которые неявно получают объект как аргумент. new() и delete() - под капотом те же malloc/free, но вызывают конструктор или деструктуор (delete() автоматически выставляет указатель на null)

В отличии от препроцессора, исключения могут и вставлять проверки, захватывать значения, и проводить с ними действия. Если написать #define, препроцессор заменит всё что совпадает, не проверяя последующие или предыдущие токены

Я поленился, и решил просто дать ИИ искходники языка, и скинуть эту статью, вот что выдал:

Это как раз то, для чего Flame делался. var Node* node = new Node() — autodel вставит delete автоматически после последнего использования. Иерархия владения выражается естественно: документ владеет карточками, карточки — элементами. Деструкторы вызываются по цепочке. Это уже работает.

Неизменяемые ресурсы (стили, битмапы) — copy-on-write

Здесь Flame пока ничего специального не предлагает. Copy-on-write придётся писать руками — завернуть стиль в структуру со счётчиком ссылок и клонировать при изменении. Это решаемо, но языковой поддержки нет. Можно сделать через notdel указатели для "слабого" хранения общих ресурсов.

Перекрёстные ссылки с автообрывом

Вот здесь пока больная точка. В Flame нет слабых ссылок в смысле weak_ptr. Коннектор, ссылающийся на другой элемент, получит висячий указатель после удаления цели. Нужно будет либо добавить в язык концепцию weak*, либо делать это через явный реестр/ID и проверку.

Удаление карточки из метода элемента этой карточки

autodel здесь может конфликтовать — если self удаляется в процессе выполнения метода, это UB. Это общая проблема даже в C++. Flame наследует её.

Копирование с сохранением топологии

Нужен явный "deep copy с remapping" — обойти дерево, создать копии, построить таблицу старый указатель → новый, пройти заново и перешить ссылки. Языковой магии нет, но класс с new-конструктором это выразит чисто.

С недавнего времени autodel автоматический, его писать не надо. Можно написать notdel чтобы предотавратить удаление компилятором...

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

Да, спустя время верится, что результат будет. Уже сейчас неплохие результаты. Не хватает сообщества, чтоб быстро выявлять баги и недочёты. Пока концепция справляется с любыми припятствами, в том числе и цикличных ссылок, но не уверен что на 100%....

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

autodel работает только для переменных в куче. Но спасибо за замечание, логичнее сделать notdel чтоб говорить компилятору самому не удалять...

autodel на такое не расчитан, если говорить про висячую ссылку. В будущем что нибудь придумаю, спасибо за замечание! Но в Flame это не проблема потому что autodel не считает ссылки — он просто вызывает delete по области видимости. B удалится, потом A удалится. Висячий указатель внутри уже удалённого B — это проблема программиста, но утечки не будет.

Удаление будет после выхода из цикла. Если передать значение через разыменовывание - это не изменит поведение. А если передать в поле структуры указатель... то autodel сработает криво. Спасибо за замечание, можете писать такое в issues в GitHub. Поработаю над этим!

Нет, отличие от других макросов - это то, что вносятся правки на уровне токенов, а не AST (если в тексте написано что это в AST, извиняюсь, статья была отправлена на модерацию 2 недели назад, с тех пор многое изменилось). Это позволяет менять грамматику гибко, например:

exception Repeat {
  var int count;

  instruction {
    repeat %n:count
  }

  replace {
    for (int i = 0; i < count; i++)
  }
}
// Этого в грамматике нет, но исключение позволяет так писать
repeat 5 {  //это превратится в for цикл
  log("Hello");
}

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

Потому что check {} в исключении опирается на ; как завершение прошлой инструкции. Это может временно, со временем точки с запятой могут стать необязательным.

1

Information

Rating
661-st
Registered
Activity

Specialization

Системный инженер, Архитектор программного обеспечения
Git
Python
Linux
ООП
C++
C
Assembler
Системное программирование
Компиляторы
Математика