Заметка про экспериментальный редактор кода. Создавался для исследования бинарных данных. Графический клиент, консольный интерфейс и встраиваемая библиотека.
Основная идея - каждое изменение мгновенно применяется, любое изменение можно отменить. Концепция похожа на систему контроля версий, только работает не с текстом, а с памятью программы. Понравилось - фиксируешь, не понравилось - откатываешь.
Примечательные возможности:
Живой кодинг.
Создание контрольных точек.
Отладка с перемещением во времени.
Смещения, адреса и размеры в битах (да, если в байте 7 или 9 бит)
Тэгирование данных

Живой кодинг.
Что такое live coding?
Live coding - программирование на-лету или интерактивное программирование. Описывается как форма искусства или импровизации, техника написания и тестирования кода в уже запущенной программе.
Горячая замена
В компилируемых языках, чаще используют отладчик с заменой кода. Применяется JIT или подмена точки входа в функцию. Другой распространенный способ, исполняемый файл не изменяется, код выносят в динамическую библиотеку, перекомпилируют и загружают поверх старой. Стабильно работают правки функций и методов, менять сигнатуры или удалять что-то, не рекомендуется.
В интерпретируемых языках предпочитают REPL. Пользователь самостоятельно загружает необходимую часть кода. Чтобы заменить файл целиком, и не потерять значения глобальных переменных, добавляют проверку на повторную инициализацию.
;; Язык Clojure. defonce - определяет переменную только один раз
(defonce ChatHistory [])
// Язык Javascript. Первая инициализация, устанавливаем дефолтное значение.
if (window['ChatHistory'] == undefined)
window['ChatHistory'] = [];
Основной недостаток - легко поломать рабочее состояние.
Даже когда используется неизменяемая модель памяти или копирование, проще перезапустить отладку, чем ремонтировать поврежденные переменные.

Создание контрольных точек
Когда вводишь в REPL сложное выражение, и где-то в середине вылетает исключение, происходит неприятная ситуация. Часть выражения изменила среду, например, сработало чтение из файла и заполнение буфера. Другая часть, парсинг и запись, не отработали. Если исправить ошибку и повторно выполнить выражение, получится совершенно другой результат. Позиция в файле уже переместилась, а буфер заполнен.
В один из таких моментов, хочется сказать: пожалуйста, верни всё обратно. Так и появилась дурацкая идея, сохранить все переменные, а затем восстановить. Некоторые изменения необратимы, время, запись в сетевой сокет. Другие можно имитировать, например, печать на консоль или изменение поз��ции в файле.

Отладка с перемещением во времени
Когда программа падает, бывает сложно определить причину. Кто испортил указатель, почему индекс массива вычисляется неправильно. В таких случаях добавляют логи или ставят точку останова выше места падения, чтобы проследить путь.
Для сложных случаев есть специальные инструменты, такие как rr. Программу запускают под отладкой и ведется запись каждого действия. Файл записи можно отматывать назад.
XEH по желанию пользователя, включает обратную отладку опцией "RDebug". В простых случаях, достаточно поправить значения переменных и продолжить исполнение.

Заморозка изменений
Область кода редактора не сильно отличается от REPL. Более удобное редактирование и подсветка ошибок. Если нажать запуск, то текущий код исполняется, перемещается в историю и создается контрольная точка. Так проще сфокусироваться на новой порции кода, и не запускать уже отлаженный код. История измененией сохраняется линейно, кнопка "разморозить" собирает все буферы в один исходный файл.
Пример, декодируем base64 строку и исследуем содержимое. Применим xor шифрование, чтобы раскрыть текстовое сообщение. open-input - открывает строку на чтение, а редактор прикрепляет текущий контекст к области данных.
Обратите внимание, во время набора цикла получилась бесконечная петля. Интерпретатор остановил исполнение с ошибкой "превышен лимит инструкций".

Битовые строки
Редактор работает с битовыми строками, порядок чтения MSB. Хорошо для работы с экзотическими форматами и структурами без выравнивания. Плохо для повседневной работы, приходится учитывать что смещения битовые. Текстовое представление битовой строки: шестнадцатеричные буквы A-F кодируют 4 бита, одиночные биты 0 - ., 1 - x.
Пример, сдвигаем позицию в файле на 3 бита.

Стикеры и тэги
Ко всем значениям можно добавить тэги. Они прикрепляются как дополнительный скрытый атрибут. Например, println проверяет тэг "fmt", как отформатировать число. Редактор ищет подсказку, каким цветом отображать значение, есть ли комментарий.

Язык команд
За основу взял стэковые Forth/T1, чтобы работа в REPL была максимально простой. Хорошая выразительность, краткая запись, необязательно сохранять промежуточный результат в переменных. Forth позволяет изменять ключевые конструкции языка или создавать новые, но часть проверок происходит во время исполнения. T1 более строгий, запускает только завершенные контексты.
trial> endif
ERROR: <buffer#2>:1:1
endif
^
balance endif with preceding if/else
Вместо препроцессора используется мета-контекст. Код выполниться во время компиляции. Можно создавать функции, константы или генерировать код, но нельзя получить доступ к переменным времени исполнения.
Пример, #( открывает контекст, #) - закрывает. Все что остается на стэке, записывается в байткод константой.
: fib dup 1 > if
dup 2 - fib
swap 1 - fib
+
endif
;
\ считаем факториал во время компиляции
#( 20 fib #) var fib-of-20
\ Результат компиляции в байткод
\ 000f: loadi64 6765
\ 00010: store heap.0x5
Структурное редактирование
Структурный редактор загружает файлы без ошибок. По��ьзователь должен заранее их исправить в текстовом режиме. Редактор учитывает переносы строк, чтобы сохранить оригинальное форматирование. Сложные конструкции группируются в блоки, чтобы нельзя было нарушить структуру программы. Числа и литералы проходят валидацию ввода.
Первая попытка, вертикальная расстановка блоков, плохо воспринимается.

Вторая попытка, больше похож на режим vim с окном для тулов. Остановился на расстановке маркеров D&D вокруг каждого элемента при наведении, но результат мне не понравился.

Заключение
Вот такой эксперимент. Графический интерфейс постоянно пытается превратиться в классическую IDE. Если добавить все функции, интерфейс станет слишком перегружен, а без них пользоваться неудобно. Это явный признак, что надо переосмыслить подход.
Песочница в браузере
Примеры запускаются из меню Help -> Examples
Консоль и реализация языка: repo xeh
Графический редкатор linux/windows/mac/wasm: repo xeh_egui
