Здравствуйте, Sinclair, Вы писали:
S> Я так понял, что штатный способ прямого порождения байткода Java — это библиотека AST. S> А есть ли аналог этой библиотеки на тайпскрипте?
А у тайпскрипта разве есть байткод? wasm что-ли?
Здравствуйте, ·, Вы писали:
·>А у тайпскрипта разве есть байткод? wasm что-ли?
Я почему-то подумал, что коллега хочет именно Java-байткод на TS.
Под определение странного это вписывается вполне.
Здравствуйте, Sinclair, Вы писали:
S>Я так понял, что штатный способ прямого порождения байткода Java — это библиотека AST. S>А есть ли аналог этой библиотеки на тайпскрипте?
Наверное есть на С++, а оттуда уже можно сделать wasm и к нему интерфейс на TS.
Здравствуйте, ·, Вы писали: ·>А у тайпскрипта разве есть байткод? wasm что-ли?
Нет. Байткод нужен джавный. Просто писать компиляторщину на Java — это боль.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>·>А у тайпскрипта разве есть байткод? wasm что-ли? S>Нет. Байткод нужен джавный. Просто писать компиляторщину на Java — это боль.
А, понял вопрос. Да, сабж, очень сильно. А задача то какая? Зачем генерить именно байт-код? Может джаву лучше? Ещё кстати scala или kotlin если языка не хватает.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали: ·>А, понял вопрос. Да, сабж, очень сильно. А задача то какая? Зачем генерить именно байт-код? Может джаву лучше? Ещё кстати scala или kotlin если языка не хватает.
Задача — сделать компилятор воображаемого языка.
В JVM — потому, что это проще, чем в натив (и даже в LLVM).
В принципе, можно и Java-код порождать, но это не даст студентам понимания устройства байт-кода
Вот, кстати, смотрю в сторону kotlin. Похоже, на нём тоже неплохо пишется компилятор. Но для него, я так понял, в качестве IDE можно использовать только IntelliJ, т.к. интеграция с VS Code у него так себе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Задача — сделать компилятор воображаемого языка. S>В JVM — потому, что это проще, чем в натив (и даже в LLVM).
GraalJs? Ну и "typescript for jvm" находит какие-то проекты, в большинстве случаев архивные.
S>В принципе, можно и Java-код порождать, но это не даст студентам понимания устройства байт-кода S>Вот, кстати, смотрю в сторону kotlin. Похоже, на нём тоже неплохо пишется компилятор. Но для него, я так понял, в качестве IDE можно использовать только IntelliJ, т.к. интеграция с VS Code у него так себе.
Ну Kotlin с IntelliJ (есть community версия) всяко лучше будет, чем натягивать Ts на Jvm
Здравствуйте, amironov79, Вы писали:
A>GraalJs? Ну и "typescript for jvm" находит какие-то проекты, в большинстве случаев архивные.
Большинство этих проектов — про исполнение typescript в JVM. А мне как раз это не очень надо, typescript пускай себе в node.js работает.
A>Ну Kotlin с IntelliJ (есть community версия)
Ладно, попробуем. A>всяко лучше будет, чем натягивать Ts на Jvm
Натягивать TS на JVM нужды нет. Всё, что нужно — это порождать .class. Это можно делать из примерно любого языка — С++, Pascal, Java, you name it.
Вопрос только в доступности инструментальных средств.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ·, Вы писали: S>·>А, понял вопрос. Да, сабж, очень сильно. А задача то какая? Зачем генерить именно байт-код? Может джаву лучше? Ещё кстати scala или kotlin если языка не хватает. S>Задача — сделать компилятор воображаемого языка.
О! Это какой-то курс по трансляторам?
А можете поделиться — вы планируете чтобы студенты и фронт (анализ) и бэк (генерацию) писали врукопашную?
Я в свое время на такое не решился (но там был курс для заочников — они бы просто не успели вообще всё).
И выбрал вариант:
— используем генератор анализаторов (я брал ANTLR)
— для генерации использовал выход в виде IL-файла
Мне такой вариант понравился тем, что:
— всё наглядно: сразу видно, что получилось
— можно использовать текстовые шаблоны генерации — это актуально если делать DSL, который порождает не сразу байткод, а код на другом языке.
Этот подход очень развит в том же ANTLR, с его глубокой интеграцией в текстовые шаблоны
Я делал по практике пару "методичек". Какраз по ANTLR и немного по IL.
Если вдруг заинтересует, можете посмотреть https://mihailromanov.github.io/docs/tutorials/
Но ... сейчас я бы всё сделал иначе + это всё очень устарело, но вдруг натолкнет на интересные мысли...
S>В принципе, можно и Java-код порождать, но это не даст студентам понимания устройства байт-кода
А если рассмотреть вариант с .Net?
Т.е. фронт на C# (или даже F#!) а для генерации, что-то типа https://www.nuget.org/packages/Fluent.IL
Или есть какие-то ограничения и .Net нельзя ни в коем случае?
Здравствуйте, Михаил Романов, Вы писали: МР>О! Это какой-то курс по трансляторам?
Да. "Методы трансляции и компиляции". МР>А можете поделиться — вы планируете чтобы студенты и фронт (анализ) и бэк (генерацию) писали врукопашную?
Нет, пусть они пользуются готовыми инструментами. Но им нужно научиться самим писать грамматики и трансформировать код.
У нас этот курс уже есть, но к нему есть претензии. Основная претензия — чрезмерная воображаемость языков.
Код практики пишется на языке flow9, которым пользуется примерно столько же народу, сколько у нас студентов .
При этом компиляция и верификация пишется для недетерминированного языка, что сильно ломает мозг студентам.
Вот, думаем над тем, чтобы
а) убрать реализацию своей VM — там всё равно VM получается ущербной, и совершенно непохожей на настоящие VM.
б) заменить недетерминированный воображаемый язык на что-то больше похожее на обычные императивные языки
в) использовать в качестве основного языка программирования что-то более промышленно-стандартное, то есть хорошо документированное и стабильно работающее.
МР>- используем генератор анализаторов (я брал ANTLR)
У нас используется PEG. У PEG-грамматик есть ряд преимуществ перед традиционными LL(*), LR(k) и прочимию LALR(1)/LR/IELR(1)/GLR МР>- для генерации использовал выход в виде IL-файла
Ну, я думал над CIL в качестве целевого языка. Но по ряду причин лучше было бы взять Java. В частности, у меня есть желание научить их сразу генерировать отладочные символы, что даст возможность интерактивной отладки программок на их воображаемом языке. На майкрософтовской стороне забора это требует разбираться с PDB, который вообще ортогонален кодогенерации; а в жаве всё лежит в тех же .class файлах.
МР>- можно использовать текстовые шаблоны генерации — это актуально если делать DSL, который порождает не сразу байткод, а код на другом языке.
Порождать текстовый язык мы их и так будем учить — там одна из задач сводится к генерации системы уравнений для Z3 на его языке SMTLIB. МР>Этот подход очень развит в том же ANTLR, с его глубокой интеграцией в текстовые шаблоны МР>Я делал по практике пару "методичек". Какраз по ANTLR и немного по IL. МР>Если вдруг заинтересует, можете посмотреть https://mihailromanov.github.io/docs/tutorials/
Да, спасибо, очень интересно. МР>Но ... сейчас я бы всё сделал иначе + это всё очень устарело, но вдруг натолкнет на интересные мысли...
МР>А если рассмотреть вариант с .Net? МР>Т.е. фронт на C# (или даже F#!) а для генерации, что-то типа https://www.nuget.org/packages/Fluent.IL
Если честно, C# — не лучший язык для таких вещей.
Идеально — строготипизированный язык с автовыводом типов. В частности, это позволяет очень сильно упростить описания грамматик в PEG, потому что не надо выписывать result type для каждого семантического действия.
Из промышленных языков больше всего похож на то, что надо, собственно typescript. Генерация кода — да, в дотнете она сделана сильно более понятно, чем в Java.
Для C# есть библиотека PEG-разбора, но грамматики на ней.... обнять и плакать. На F# не смотрел.
Никакого сравнения с грамматиками Lingo, которая встроена в flow9. МР>Или есть какие-то ограничения и .Net нельзя ни в коем случае?
Да в целом-то ограничений нет; если бы просматривалась возможность покрыть все аспекты курса, оставаясь в рамках дотнета — то можно было бы наверное и его протащить. Но пока выглядит так, что Java в среднем встретит больше понимания (и органичнее впишется в другие курсы, которые читаются тем же студентам).
МР>P.S. Мне еще в качестве генераторов парсеров очень понравился Irony https://www.nuget.org/packages/Irony
Посмотрим. МР>Минимум зависимостей и не нужны специальные инструменты. По сути DSL для описания языка прямо на C#.
Документации маловато. Из сэмплов выглядит так, что он генерирует LR парсеры?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Код практики пишется на языке flow9, которым пользуется примерно столько же народу, сколько у нас студентов .
Ну да, я впервые услышал https://github.com/area9innovation/flow9
Прикольно, что контрибьютеры в подавляющем большинстве из России или с Украины
S>У нас используется PEG. У PEG-грамматик есть ряд преимуществ перед традиционными LL(*), LR(k) и прочимию LALR(1)/LR/IELR(1)/GLR
У меня тут мало опыта, поэтому ничего сказать не могу. Наверное так и есть.
S>Ну, я думал над CIL в качестве целевого языка. Но по ряду причин лучше было бы взять Java. В частности, у меня есть желание научить их сразу генерировать отладочные символы, что даст возможность интерактивной отладки программок на их воображаемом языке. На майкрософтовской стороне забора это требует разбираться с PDB, который вообще ортогонален кодогенерации; а в жаве всё лежит в тех же .class файлах.
Опять же не разбирался, не могу ничего сказать.
Вроде как есть такие вещи как как ILGenerator.MarkSequencePointCore, но они тянут за собой пространство System.Diagnostics.SymbolStore, так что, похоже, всё не так просто как мне казалось.
S>Если честно, C# — не лучший язык для таких вещей. S>Идеально — строготипизированный язык с автовыводом типов. В частности, это позволяет очень сильно упростить описания грамматик в PEG, потому что не надо выписывать result type для каждого семантического действия. S>Из промышленных языков больше всего похож на то, что надо, собственно typescript.
Понятно. Я, увы, забросил этот вопрос весьма давно — хочется вернуться и посмотреть на что-то еще помимо, простых генераторов и как работается с ними в простых императивных языках. Но времени как всегда нет ни на что.
По поводу генерации — я немного ввел вас в заблуждение (хотя, может вы и были в курсе).
В .Net после Framework и вплоть до 9 версии, была недоступна функциональность выгрузки сгенерированной сборки вовне.
В 9 появился PersistedAssemblyBuilder, но всякие обертки над Emit его пока не подхватили.
А если взглянуть на использование его напрямую (на базовом Emit) то, конечно, делается печально https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.
МР>>Минимум зависимостей и не нужны специальные инструменты. По сути DSL для описания языка прямо на C#. S>Документации маловато. Из сэмплов выглядит так, что он генерирует LR парсеры?
Это правда. Я смотрел на примеры и через утилиту (GrammarExplorer вроде)
Ну и я подумал, что вас он вряд ли впечатлит — там нормальной типизации узлов разбора не будет из коробки, а значит всё равно в рукопашную резвись с тем, что он там наразбирал...
Здравствуйте, Sinclair, Вы писали:
S>Задача — сделать компилятор воображаемого языка. S>В JVM — потому, что это проще, чем в натив (и даже в LLVM).
А ты в курсе, что есть древний, как UNIX System 7, паттерн делать такие компиляторы, используя Си в качестве промежуточного представления? А потом уже штатным компилятором Си — в нативный код.
Здравствуйте, Pzz, Вы писали: Pzz>А ты в курсе, что есть древний, как UNIX System 7, паттерн делать такие компиляторы, используя Си в качестве промежуточного представления? А потом уже штатным компилятором Си — в нативный код.
В курсе. А ещё можно их фортрану обучать на перфокартах
Мы-то хотим более-менее современному их обучать. В частности, нет никакого желания тиранить их лексерами — ни рукопашными, ни автопорождёнными.
Ну и с представлениями тоже — никто в здравом уме не будет порождать код для JVM через Си как промежуточный язык.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Михаил Романов, Вы писали: МР>Ну да, я впервые услышал https://github.com/area9innovation/flow9 МР>Прикольно, что контрибьютеры в подавляющем большинстве из России или с Украины
Отож.
МР>У меня тут мало опыта, поэтому ничего сказать не могу. Наверное так и есть.
Главное — он безлексерный и unambiguous. Нет никаких конфликтов, которые нужно как-то разрешать.
Плюс — очень естественно обобщается на инкрементальность.
МР>Вроде как есть такие вещи как как ILGenerator.MarkSequencePointCore, но они тянут за собой пространство System.Diagnostics.SymbolStore, так что, похоже, всё не так просто как мне казалось.
Вот и я не разбирался .
МР>В .Net после Framework и вплоть до 9 версии, была недоступна функциональность выгрузки сгенерированной сборки вовне.
Это вообще не проблема. Я когда переезжал с фреймворка на Core, взял https://github.com/Lokad/ILPack и поехал. МР>В 9 появился PersistedAssemblyBuilder, но всякие обертки над Emit его пока не подхватили. МР>А если взглянуть на использование его напрямую (на базовом Emit) то, конечно, делается печально https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-reflection-emit-persistedassemblybuilder.
МР>По грамматике, вроде как LALR https://www.codeproject.com/Articles/22650/Irony-NET-Compiler-Construction-Kit?msg=2381770
Спасибо за внятный пример.
Вот по нему уже видно, за что можно не любить все эти тяжеловесные парсер-генераторы.
Для сравнения — полный код PEG-грамматики, которая разбирает арифметические выражения и строит типизированное AST на Lingo:
МР>Ну и я подумал, что вас он вряд ли впечатлит — там нормальной типизации узлов разбора не будет из коробки, а значит всё равно в рукопашную резвись с тем, что он там наразбирал...
Именно. Гораздо удобнее работать с типизированным AST.
Как раз автовывод типов этим и прекрасен — ведь любое правило в PEG-грамматике описывается семантическим действием; если тип этого действия известен, то и тип правила известен.
Остаётся правильно вывести тип для правил с альтернативами — и мы получаем то, что нужно.
По идее это должно ездить и на typescript; но пока что я не нашёл идеальной ts-реализации PEG. PEGjs выглядит заброшенным и он всё же JS, а не TS; Ohm неплох (и умеет инкрементальность из коробки), но у них очень странные идеи про то, как привязывать семантические действия к грамматике.
В общем, нету серебряной пули
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Я так понял, что штатный способ прямого порождения байткода Java — это библиотека AST. S>А есть ли аналог этой библиотеки на тайпскрипте?
Каждый раз, когда мне необходимо проделать что-либо с AST, я первым делом открываю astexplorer.net, а затем начинаю действовать. Этот инструмент позволяет проанализировать AST, созданное различными парсерами, в том числе babel/parser и парсером компилятора TypeScript. С помощью astexplorer.net можно визуализировать структуры данных, с которыми вам предстоит работать, и ознакомиться с типами узлов AST каждого парсера.
Взгляните на пример файла исходных данных и AST, созданное на его основе с помощью babel-parser:
example.ts
import { protos } from 'my_company_protos'
export type User = protos.user.User;
Здравствуйте, Serginio1, Вы писали: S> Не там есть пример получения ast.json
Там пример получения AST программы, написанной на typescript.
Предсказуемо, для этого применяется компилятор TS
У нас задача совсем другая — нужно получить AST своего воображаемого языка, а потом сгенерировать для него байткод.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Я так понял, что штатный способ прямого порождения байткода Java — это библиотека AST.
Есть еще JEP 466: Class-File API (Second Preview)
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, ·, Вы писали: S>·>А у тайпскрипта разве есть байткод? wasm что-ли? S>Нет. Байткод нужен джавный. Просто писать компиляторщину на Java — это боль.
Scala? Cotlin? Clojure? https://github.com/caoccao/Javet/?
Здравствуйте, novitk, Вы писали: N>Scala? Cotlin? Clojure? https://github.com/caoccao/Javet/?
Clojure недостаточно типизирована. Учебный компилятор — не то место, которое хочется в шесть слоёв покрывать тестами.
На Kotlin смотрю пока. Вот, вчера поставил IntelliJ.
Есть для него библиотека PEG-парсинга?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S> N>Scala? Cotlin? Clojure? https://github.com/caoccao/Javet/?
S> Clojure недостаточно типизирована. Учебный компилятор — не то место, которое хочется в шесть слоёв покрывать тестами. S> На Kotlin смотрю пока. Вот, вчера поставил IntelliJ. S> Есть для него библиотека PEG-парсинга?
Для всяких CS-изысков обычно всё-таки Скалу юзают. Если я правильно понял, тут вроде всё что надо: https://github.com/sirthias/parboiled2
Здравствуйте, Sinclair, Вы писали:
S>Clojure недостаточно типизирована. Учебный компилятор — не то место, которое хочется в шесть слоёв покрывать тестами. S>На Kotlin смотрю пока. Вот, вчера поставил IntelliJ.
я бывший скалист, Котлином не пользовался. ИМХО Скалка самый удобный и продвинытый язык из немаргинальных. Для компилятора сам бог велел.
S>Есть для него библиотека PEG-парсинга?
Для скалки в компиляторо-писание все есть: https://github.com/lauris/awesome-scala?tab=readme-ov-file#parsing
Здравствуйте, Sinclair, Вы писали:
S>Я так понял, что штатный способ прямого порождения байткода Java — это библиотека AST. S>А есть ли аналог этой библиотеки на тайпскрипте?
Можно попробовать запустить AST в среде JS через TeaVM. Берем AST, прогоняем через TeaVM, получаем AST, которую можно запускать в среде JS. Вроде бы то, что хочется получить.
Здравствуйте, Sinclair, Вы писали:
S>Задача — сделать компилятор воображаемого языка. S>В JVM — потому, что это проще, чем в натив (и даже в LLVM). S>В принципе, можно и Java-код порождать, но это не даст студентам понимания устройства байт-кода
А зачем какие то библиотеки? Почему нельзя тупо писать байтики напрямую? Одно дело когда ты байткод сам анализируешь, тут библиотека поможет и снимет куча геморроя. Но если задача байткод генерить, да еще в учебных целях — ИМХО лучше тупо в файлик сразу байты писать да и все. Если не ставится задача вообще все покрыть, а чтоб было покрытие ограниченного подмножества — достаточно просто быстро и интересно делается.
Здравствуйте, elmal, Вы писали:
E>Здравствуйте, Sinclair, Вы писали:
S>>Задача — сделать компилятор воображаемого языка. S>>В JVM — потому, что это проще, чем в натив (и даже в LLVM). S>>В принципе, можно и Java-код порождать, но это не даст студентам понимания устройства байт-кода E>А зачем какие то библиотеки? Почему нельзя тупо писать байтики напрямую? Одно дело когда ты байткод сам анализируешь, тут библиотека поможет и снимет куча геморроя. Но если задача байткод генерить, да еще в учебных целях — ИМХО лучше тупо в файлик сразу байты писать да и все. Если не ставится задача вообще все покрыть, а чтоб было покрытие ограниченного подмножества — достаточно просто быстро и интересно делается.
Чтобы генерить байтики, нужно знать, какие байтики генерить.
Я не очень разбираюсь в JVM-ном байткоде, но из опыта дотнетного байткода уже понятно, что
а) мнемоники команд. Банальная штука типа "положи в стек целую константу" требует енкодинга команды и енкодинга константы. Делать это каждый раз руками? Код становится невозможно даже прочитать, не то что поддерживать. Интуитивно хочется иметь готовую функцию типа EmitLoadConstant(x byteCodeStream, int value) или byteCodeStream.EmitLoadConstant(value).
б) goto. Не хочется вручную вычислять байтовые смещения с риском промахнуться. Удобнее иметь функции вида MarkLabel() c возможностью использовать результат этой функции в эмите jump-инструкций
в) метаданные. Банальный Call использует в аргументах method token, который весьма нетривиально устроен. Вычислять его вручную — крайне громоздко.
г) предсказание будущего. Каждый метод указывает в заголовке размер байт-кода, количество переменных, а также максимальную глубину стека. При кодогенерации это довольно-таки тяжело оценить заранее — так что либо делать два прохода по внутреннему представлению, либо, всё-таки, инкапсулировать это всё в некий класс, отвечающий за порождение байтиков, который всё это рассчитает самостоятельно с гарантиями корректности и без замусоривания пользовательского кода.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.