Вчора знову дорвався до свого коду і написав на Схемі аналізатор SECD-коду на стекову коректність. Штука невелика, але корисна, та і перша ластівка винесення статичного аналізу із сішного коду у схемівський (а то я намагався зробити аналіз на вільні змінні в сішному коді, вийшло не дуже гарно).
Ганяв «компілятор» на коректність всяких крайових випадків синтаксису типу (cond), (cond (#t)), (let () ), (let ()), (begin) і т.д. - видно, краще буде написати невеликий language test suite, який буде вивіряти синтаксис і семантику операцій (хоч хотілось би готовий фреймворк на Схемі, який би перевіряв r7rs compliance). Виправив let, cond, define-форми на підтримку багатьох форм всередині (насправді, тіло загортається в begin, а begin із однією формою переписується в цю ж форму, так що скомпільований код аналогічний).
Досі є одна величезна проблема із машиною - будь-яке виключення фатальне і навіть незнайдена змінна завершує роботу. Але ж хочеться вирішити це «по-правильному», і тому я перечитував на днях про continuations, щоб через них зробити нормальну обробку помилок, вперше їх нормально зрозумів (хоч delimited ones ще потребують осмислення). Поки що в коді це виразилось тим, що з’явився тип CELL_KONT, який інкапсулює s,e,c (хоч у SECD повний стан машини включає і дамп, але з технічних причин він у клітинку не поміщається, тому будуть конси CELL_KONT і наступного фрейма дампа).
Повільно переписую систему вводу-виводу із тієї, що підтримувала тільки file та string порти, на плагінну. Схоже, плагінність це явний overkill, але коли POSIX відсутній (наприклад, всередині мого недоядра), мені зараз доводиться робити всякі неприємні хаки, щоб завести інтерпретатор, а в ідеалі хотілось би просто збирати його в вигляді максимально абстрагованої від платформи бібліотеки і лінкувати з чим завгодно, а POSIX-залежні частини чітко винести. Ех, модульність, FFI, все це треба.
Ще хочеться нарешті зробити аналіз на вільні змінні, але тут мені потрібні нормальні множини (хоч я міг би все емулювати і через асоціативні списки до пори до часу), а тут я передчуваю написання на Схемі якогось самозбалансованого дерева, чим я поки що не займався.
Ще не терпиться дістатись до по-серйозному брудного байтолюбства і почати писати JIT хоча б із асемблерних виразів прямо в Схемі. Правда, писати
асемблер на Хаскелі це одне, а на Схемі уже страшнувато. І спочатку це буде тільки 32-бітний x86, який я знаю найкраще. Але байтвектори, макроси, можливість легко додати вбудовану процедуру для mmap - це все є, хіба що сішного ffi досі немає.
Інтерпретатор тим часом потихеньку розпухає, і відразу після завантаження займає більше 6000 клітинок, що на 64 бітах є 32 * 6000 = 190 Кб. Тепер не дивуюсь, що колись Ліспи вважали непрактичними (до того ж швидкістю моя машина також похвалитись особливо не може, я думаю).