Комментарии 92
А можете добавить раздел "Для чего это?", а то непонятно зачем, если уже есть c#
Сразу скажу, что это не прототип, а готовый проект
OverScript ещё тестировать и тестировать. Я постоянно нахожу новые ошибки и код, который можно улучшить
вероятно, главное отличие от c# то, что он интерпретируемый и его можно запускать сразу после редактирования скрипта. как с питоном\пхп\жс.
в общем, так и есть.
У C# есть интерактивный вариант — C# Interactive. Запускается через csi.exe
Используется компиляция на лету.
Если хочется что-то более менее стабильное и встраиваемое — есть Mond, Lua, ещё Lua. И это только то, что нашёл сравнительно быстро.
Можно вообще взять Roslyn и просто брать и выполнять C#. В чём смысл ещё одного языка?
если на то пошло, то можно вообще код прямо из C# на лету компилить.
OScript видел, но это что-то совсем узкоспециализированное.
если на то пошло, то можно вообще код прямо из C# на лету компилить.
О том и речь - для этого не нужно ни зависимостей, ни тонны кода, не нужно учить отличия в синтаксисе, производительность не уступает оригинальному коду.
Но как личный проект - круто, конечно 😎
Спасибо!
Компилирование средствами .NET - отдельная тема. Когда код компилируется, он становится частью монолита с жесткими привязками. Плюс - скорость, минус - такая степень интеграции не всегда уместна. Т.е. когда вы переносите исполнение на слой CLR, то теряете некоторую гибкость контроля. Например, зациклится что-то, и вам нужно будет это как-то жестко останавливать.
Не становится он частью монолита - просто байтики в памяти,которые можно как сбору сохранить или выполнить на месте.
Большая степень интеграции - это не минус, просто не используйте те части, что не нужны. Зато когда будут нужны - они есть.
Если что-то зациклится - убиваете поток, и всё. Не понятно что под жесткой и под мягкой остановкой подразумевается, возможно упустил момент из статьи. В любом случае если повисло - значит с кодом что-то не то.
жестко - убиваете поток. Эх, жалко, что Thread.Abort убрали.
Ох, не жалко. Создание механизма который позволяет сломать случайное состояние программы было ошибкой, то что они его убрали это шаг в правильном направлении.
Понимаю, но можно было бы сделать скрытую настройку для включения на свой страх и риск.
А вы как, через Thread.Interrupt имеете в виду убивать?
Убивать можно через управление рантаймом, к примеру интерпретатором. Вручную через CancellationToken. Через инструментацию кода и добавления точек прерывания на вызовы IO, в тело циклов и вызовов суб-рутин. Нормальных вариантов много, Thread.Abort это не выход.
Понимаю, но можно было бы сделать скрытую настройку для включения на свой страх и риск.
Есть winapi и TerminateThread для особо "смелых".
Просто и правильно можно убить только процесс, поток убивается с помощью Thread.Abort
, который задепрекейтили, ну либо с помощью CancellationToken
, но это нужно дополнительно код фиксить, что не всегда уместно.
всё так. Например, в случаях, когда пользователям разрешается расширять функционал какой-то системы скриптами, нет никакой гарантии, что они будут в алгоритмах предусматривать мягкую остановку. И Abort был грубым, но решением.
Прототип - это версия-макет, в которой отсутствует часть базового функционала (стоят заглушки). Готовый проект - тот, в котором всё работает, но в нём могут быть ошибки.
Поделитесь источником определений
Выглядит как жонглирование терминами. Вы уверены что вышли из стадии прототипа, если там ещё "тестировать и тестировать"?
Тестирование же подразумевается не только до релиза, но и после. Это обычное дело. Посмотрите, сколько фиксов в репозиториях известных языков.
Увидеть лучше, чем услышать, познать лучше, чем увидеть, сделать лучше, чем познать ;)
Жениться вам, барин, надо
Начал я этот проект в середине декабря 2020-го. Более-менее рабочий прототип был готов, как мне казалось, уже через месяц. Дальше я доделывал и переделывал, и по мере добавления функционала, становилось понятно, что нужно усложнять общую архитектуру. Правка старого кода приводила к его полному переписыванию. У меня было желание выложить всё уже через 2-3 месяца, но постоянно находилось что-то, что требует обязательной доработки.
Понимаю, что object-переменные выглядят непривычно, но в целом, думаю, код понятен.
Сразу возникает мысль поменять их на var
;-)
Респект за труд! Правда, такие проекты, скорее, для саморазвития, чем для широкого применения.
Если вдруг кто-то не знаком, есть классный онлайн-сервис от команды разработки C# - SharpLab.io. Позволяет прямо в браузере писать программы/скрипты, на лету их компилировать и выполнять. Очень удобный инструмент, чтобы оформить какой-то небольшой код и поделиться им с другими людьми.
Ещё можно поучаствовать в обсуждении новых фич языка или даже предложить свои Issues · dotnet/csharplang (github.com).
можно писать var.
есть классный онлайн-сервис от команды разработки C# — SharpLab.io
А откуда такая информация? Просто в профиле автора (Andrey Shchekin) ничего о месте работы не сказано.
Да и каких-то коммитов в language design или .net у него нет.
Если вдруг кто-то не знаком, есть классный онлайн-сервис от команды разработки C# — SharpLab.io. Позволяет прямо в браузере писать программы/скрипты, на лету их компилировать и выполнять.
C# песочниц и без этого сервиса полно. А SharpLab ценный тем, что позволяет отображать IL и даже ассемблер для фрагмента кода на C#, что удобно для оценки оптимизаций и понимания работы компилятора.
А я вот поддержу автора.
Не так много встраиваемых, статически типизированных языков, и для определенной ниши - крайне полезно;
Это просто клевый Just for fun - я завидую!
Ну уж коль тут такая пляска, вопросы (скорее один вопрос):
Я в свое время, лет 10 назад, пробовал использовать динамическую компиляцию в C#, уперлось все в то, что динамические сборки не выгружались из памяти и плодили версии самих себя. В .Net core, как я понимаю, все уже по другому, есть возможность динамически собирать что-то (сборку, или модуль...)? В Roslyn это было как-то не очень, но я смотрел еще на очень ранние варианты
P.S. Я сейчас не в мире .net, извините за возможно глупые, устаревшие вопросы
очень-очень рад :)
программист-програматик читали? нет прочтите.
Привет! Меня зовут Дмитрий, я написал на C# свой интерпретируемый язык программирования, который назвал — OverScript.
А к0р0ваны можно грабить ? )
Ну зачем ? Вобщем и до меня уже сказали наверное.
Корованы не можно, а нужно!
Вам интересна тема встраиваемых языков для .NET?
Я ожидал, что вопрос "Зачем?" будет самым популярным. Т.к. вопрос задан в краткой форме, то отвечу двусмысленным вопросом, который на самом деле не вопрос: Всегда ли выбор программистами инструментов рационален? Посмотрите с разных сторон.
я написал на C# свой интерпретируемый язык программирования, который назвал — OverScript.
А зачем? Какую конкретную задачу этот язык решает?
Я подробно не интересовался, как написаны другие языки, поэтому вся реализация интерпретатора это моя чистая импровизация.
Но почему?
Месье практик, а не теоретик. Они всегда так делают. На вопрос "почему" здесь скорее может ответить эволюция, которая раздает подобные свойства отдельным людям.
Месье практик, а не теоретик. Они всегда так делают.
Кто "они"?
Практики.
Странно. Я вот практик, я так не делаю. Как раз наоборот, я считаю практичным сначала разобраться, что делали другие в данной области.
Вы, по всей видимости, другого племени практик, такой практик, который сперва ищет и изучает имеющиеся аналоги, вникает в домен, изучает теоретическую базу при необходимости и только потом решает: стоит ли писать свое.
Я вот тоже тот ещё любитель велосипедов, но отвечать, хотя бы самому себе, на вопрос "зачем" определенно стоит.
Тогда несколько странно слышать "они [практики] всегда так делают", если практики могут быть "другого племени".
Я потому, собственно, и спросил, что подумал, может, неправильно фразу понял, и речь о теоретиках идет на самом деле.
Предположу, что это сарказм. Тот кто сперва сначала изучает, сравнивает, проектирует - это определенно уже не практик, поскольку тут приоритет в работе с теоретической информацией. Теоретики тоже делятся на прагматиков и концептуалистов. Но реальные практики не акцентированы вообще на предварительном изучении обобщений. Им вообще обобщениями неудобно пользоваться. Рекомендую поизучать типологии.
Ваше заблуждение в том, что вы зачем-то себя считаете практиком. Если Вы практик, то как тогда выглядят теоретики? И как назвать тех кому не интересно изучать общие правила, а удобнее попробовать самому своими руками?
Ваше заблуждение в том, что вы зачем-то себя считаете практиком.
Это точно не заблуждение. Я больше десяти лет выпускаю разного рода ПО, это точно не теоретические изыскания.
Если Вы практик, то как тогда выглядят теоретики?
Теоретики — это те, кто рассуждают о коде, но (практически) его не пишут. CS, а не SE.
И как назвать тех кому не интересно изучать общие правила, а удобнее попробовать самому своими руками?
Есть хорошее английское слово tinkerer. Русского аналога не знаю.
Любимая тема у музыкантов. А ещё уж очень вся эта дискуссия по духу похожа на рассуждения о "форме и содержании" (с известной коннотацией).
Каждый, в определенной степени, есть и теоретик и практик. Просто одни больше фокусируются на технических нюансах (как работает), а другие на практической реализации (выполняет ли задачу).
Не помню кто из известных авторов (то ли Роберт Мартин, то ли Рой Ошероув) говорил, что главное, чтобы программа выполняла свою задачу. Если цель достигнута, то тех. решение верное. Большинство решений - частные. Теория никогда не применяется в чистом виде, т.к. не подразумевает универсальной имплементации. Например, есть "Цепи Маркова", и какие я только вариации/адаптации не видел! Большая их часть, строго говоря, вообще к оригинальной теории никакого отношения не имеет.
Любимая тема у музыкантов.
Мне прямо любопытно стало, какая же тема "любимая" у музыкантов...
нужно ли знать теорию музыки, чтобы быть крутым музыкантом.
Ой, это как раз очень простой вопрос, я вам как человек с правом преподавания теории музыки говорю: нет, не обязательно знать теорию музыки, чтобы быть крутым музыкантом. Но если знать теорию музыки, то стать крутым музыкантом легче.
В Python можно "abc"*3 и получить "abcabcabc". Удобно, но вдруг
программист по ошибке пытается умножить строку на число?.. Где грань
между допустимыми поблажками и фичами, от которых больше вреда, чем
пользы?..
Решил эту дилемму у себя https://habr.com/ru/company/timeweb/blog/651999/ следующим образом: Изначально отказаться от операторов с двойным смыслом (как для умножения строки на число или сложения двух строк). Но так как эти операции востребованы, то заменить их похожими по смыслу операторами "abc" ** 3 -> "abcabcabc" и "abc" ++ "def" -> "abcdef". Таким образом исключается случайное использование неправильного оператора, а заодно и исключаются сложности с операторами инкремента/декремента, которые по большому счет вообще не нужны.
так-то **
могут воспринять как возведение в степень)
Посмотрел ваш проект - необычно, но интересно! Буду следить.
Да, можно добавлять операторы, правда новички будут пугаться разнообразия.
"Охренеть, Чего б..." Было моей первой мыслью когда увидел пост. Никогда бы не подумал что на шарпе можно писать свой собственный ЯП. Черт, это правда круто. Очень. Я почему то всегда думал что интерпретаторы и компиляторы пишутся на чем-то более низкоуровневом (типа си и т.п.) Спасибо что показали другую грань шарпа. Автор молодец:)
Спасибо! Я тоже так думал. C# недооценен пока.
[Вот здесь](https://habr.com/ru/post/426961/) немного истории о том, как c# переписывали сам на себя.
Вообще, для компилируемых языков существует тру-практика, когда компилятор создаваемого языка переписывается на нам же.
В таком случае возникает вопрос. Если компилятор шарпа написали на шарпе, почему возникла в ваших умах его недооцененность в написании компиляторов для других языков? В чем принципиальная разница?
Компилятор можно на любом языке написать. На скорость программы это не влияет. А интерпретатор, считается, нужно писать на быстрых языках. Управляемый код требует дополнительных затрат, поэтому он как бы не может быть быстрым. Но, за счёт автоматических оптимизаций во время компилирования в машинный код, он получается быстрым. Я недавно сравнивал скорость простого цикла с Rust, и в C# у меня получилась выше процентов на 20-30. Удивился, я не эксперт в Rust, может чего-то не знаю.
Подробно расписывать здесь технические детали не вижу смысла.
Ну вот это как раз было бы интересно.
А так вообще писать новый язык для саморазвития приветствуется, но дальше двигать не стоит, особенно если нет многолетнего опыта в компиляторах.
Это, если всё писать, то целый цикл статей получится.
Для начала я советую посмотреть эти места:
Выполнение функции (проход по логическим строкам).
Выполнение единицы вычисления (эвал-юнита) -
По сути, любое выражение - это дерево из эвал-юнитов. Метод ExecuteFunction проходит сверху вниз по всем строкам и методом Eval выполняет эвал-юниты, из которых строки состоят, передавая номер области видимости (scope), ссылки на текущий экземпляр (inst) и стек вызовов (cstack).
В комментариях очень много вопросов и критических высказываний двух типов:
"А зачем вообще это нужно?"
"Зачем интерпретатор C#, если можно быстро скомпилить?" и типа "Скомпилированное лучше"
Такое ощущение, что на статью обратили внимание многие, кто на определённом уровне знаком с C#, но либо толком не реализовал ни одного достойного внимания проекта, либо относится к кодингу потребительски (использую только то, что сделали другие).
Расписывать теорию о пользе скриптов я не буду. Об этом достаточно информации в сети (гугл в помощь). Есть те, кто познал/ощутил прелести от использования, и те, кто ещё нет. Я использую скрипты уже лет 20, и не представляю для себя ни одного крупного проекта без встроенной консоли с возможностью кодинга "на лету". Не говоря уже о проектах, в которых интерпретатор является основой выполнения ряда рутин (например, в гейминге, CAD, ИИ, 3D редакторы, и тд, и тп). Я использовал интерпретаторы C, C++, C#, Lua, Python. Точно могу сказать, что жизнь без них была бы серой и скучной.
Почему C#? Ну тут автор уже не раз ответил: чтобы использовать тот же язык, на котором пишешь. И это правильно. Написал, попробовал, получилось, добавил в основной проект. Преимуществ море. К сожалению, до сего момента я имел опыт только с одним интерпретатором - PaxScript. Других не встречал (хотя искал).
В общем, автору огромный респект и удачи в развитии проекта!
Спасибо! А этот PaxScript настоящий интерпретатор? Смахивает на транслятор.
Честно говоря, тут получается какая-то тонкая грань, которую я, возможно, не улавливаю (просто не придавал значения). Я не очень глубоко копался, но, насколько помню, там, конечно, нет никакого MSIL, регистров и тд. Он парсит код, создаёт составные объекты - классы, структуры, организовывает списки простейших команд в функции. Но в качестве операторов типов использует встроенные операторы. Подцепляет типа проприетарные, автозагружая из указанных сборок. Но нет реализации интерфейсов (вроде), генериков и естественно нельзя переопределять виртуальные функции, объявленные в объектах из сборок (вирт ф-ции скриптовых классов можно).
Сделайте рефакторинг для интереса, там почти всё понятно. Я хотел купить полные сорцы, но автор не вышел на связь.
удалено
Заместительная идея! Но зачем делать отсебятину?
Прелесть интерпретируемо1 релаизации c# ещё и в том, что можно просто взять и использовать одинаковый код и для интерпретации, и для компиляции.
Ну то есть проверили в интерпретаторе, поправили пока не будет работать - засунули в компилятор. И в обратную сторону тоже бывает нужно.
А в вашей реализации так не сделаешь, из-за специфичных "->".
Сам я не раз хотел замахнуться на свой интерпретатор c#, но как-то ленился. А потом уже и энтузиазм пропал, тем более что я наткнулся на готовый SlowSharp. В котором вроде как всё без отсебятины точно так же, как в c#.
Кстати, хотелось бы сравнений со SlowSharp, ну там в скорости и совместимостью с обычным c#
Про SlowSharp первый раз слышу. Открыл исходники и вижу:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Это значит, что разбор кода делается стандартными средствами .NET. Таких "языков" сотни. Если вам синтаксис C# нужен, то и ок, наверно.
С синтаксисом Шарпа таких языков не сотни. А только SlowSharp.
Так а что плохого в разборе кода стандартными средствами? Ну то есть это может быть плохо, когда целевая платформа не содержит их по каким-то причинам. Но в случае SlowSharp всё целивые платформы их содержат, ведь он работает под unity даже на IOS, UWP, WebGL
Или вы имеете ввиду, что вам хотелось в любом случае сделать именно свой анализ кода?
Так а что плохого в разборе кода стандартными средствами?
Ничего плохого. Работает, устраивает - замечательно. В SlowSharp, как я понял, в основном самопис, а значит автору в любом случае респект.
Или вы имеете ввиду, что вам хотелось в любом случае сделать именно свой анализ кода?
Знаете как барабанщики относятся к драм-машинам? "Голый барабанщик" смотрели? Одна из моих любимых комедий.
С синтаксисом Шарпа таких языков не сотни. А только SlowSharp.
Когда я искал, что пишут люди, то нашёл с десяток проектов под заголовками в духе "пацаны, зацените курсач". К сожалению, ссылки не сохранил. Я удивился, как студенты пишут такие сложные проекты, но потом увидел, что это все через стандартные средства делается. Даже упоминания о методичках встречал, т.е. где-то это на поток поставлено. И люди, когда слышат "я написал свой язык", часто воспринимают это несерьезно потому, что они это много раз уже слышали.
Когда-то давно-давно вышел музыкальный редактор eJay, все бросились создавать треки (и я тоже) на стандартных сэмплах. Получались однотипные поделки, и с тех пор многие воспринимают электронную музыку как конструктор Лего.
Замечательная идея*
Замерил скорость SlowSharp вот так:
int n = 0;
for(int i=0; i<1000000; i++) n = i * 2;
и вот так:
int n = 0;
while(n<1000000) n++;
Если мой тест корректен, то SlowSharp в 11 раз медленнее чем OverScript.
Надеюсь этот язык найдет применение в юнити, а то постоянные перекомпиляции проекта немного уже надоели.
надо распространить пост среди юнити-разработчиков. Можете мне в личку написать, какие сейчас активные комьюнити есть?
UniScript(SlowSharp) как раз для юнити сделан.
Ну а постоянные перекомпиляции проекта в юнити надоедают потому что юнитеки сборку не редко делают специально неправильно, ну и ещё случайно плодят баги
Есть вопрос о реализации (возможно я не всю документацию посмотрел)
Есть документ по грамматике языка ? (БНФ или еще какая грамматика)
А зачем @ при вызове функции ? что бы найти целевую функцию ?
О работе typeof() - Как я понимаю тип переменной определяется в runtime - путем дополнительной ссылки на тип ? как вы выделяете свой тип (класс) от встроенных классов ?
Есть ли механизм для debug ?
Смотрели вы или нет протокол Language Server Protocol ?
Есть документ по грамматике языка ? (БНФ или еще какая грамматика)
Нет.
А зачем @ при вызове функции ? что бы найти целевую функцию ?
С @ будет вызываться базовая функция без поиска перегрузки в коде. Вот пример:
WriteLine("test"); //вызов своей функции
void WriteLine(string str){
//а теперь вызываем базовую функцию:
@WriteLine("str: "+str); //str: test //без @ произойдёт зацикливание
}
О работе typeof() - Как я понимаю тип переменной определяется в runtime - путем дополнительной ссылки на тип ? как вы выделяете свой тип (класс) от встроенных классов ?
typeof при загрузке, а не при выполнении. Про доп. ссылку не понял. Свой тип без кавычек.
Есть ли механизм для debug ?
Пока нет.
Смотрели вы или нет протокол Language Server Protocol ?
Читал описание, но в детали не вдавался. Надо будет разобраться.
Хотите написать IDE или подключить к существующей?
Мне сам протокол LSP интересен, но вот толком еще не разобрался с ним.
Свое IDE - ... не, это для меня слишком, я бы на LSP остановился, свой сервер LSP для своего языка это интересно
typeof при загрузке, а не при выполнении
Про typeof.. и ссылки, тут я наверно не совсем ясно выразился, мне интересно как на уровне компилятора вы определяете тип (класс) и операции над ним (методы класса) - это как я понял класс CustomType в ваших исходниках ?
Вы выделяете фазы компиляции/трансляции (лексический анализ, синтаксический AST, вывод типов) ? то с разбегу не нашел, ScriptClass - выполняет анализ исходника в AST ?
Я хочу написать IDE, но пока не до этого.
Для каждого класса в скрипте создаётся экземпляр ScriptClass. Его конструктор - https://github.com/overscript-lang/OverScript/blob/f59db5296482c23c1da5a05925ebd0c129606864/OverScript/ScriptClass.cs#L544
Там хорошо видна последовательность действий.
Есть метод ParseCode - https://github.com/overscript-lang/OverScript/blob/f59db5296482c23c1da5a05925ebd0c129606864/OverScript/CodeLoading.cs#L324
Он разбивает подготовленный код на логические строки (CodeUnit), определяя вид инструкции.
Потом BuildEvalUnits проходит по строкам и создаёт для каждой эвал-юнит (может состоять из множества эвал-юнитов) - https://github.com/overscript-lang/OverScript/blob/f59db5296482c23c1da5a05925ebd0c129606864/OverScript/CodeLoading.cs#L3050
Метод GetEvalUnit, создающий эвал-юнит - https://github.com/overscript-lang/OverScript/blob/f59db5296482c23c1da5a05925ebd0c129606864/OverScript/CodeLoading.cs#L3856
Именно он превращает строку в структуру, понятную интерпретатору.
После BuildEvalUnits запускается CalcJumps, которая для каждой строки, в зависимости от вида инструкции, определяет, на какую строку дальше переходить -
https://github.com/overscript-lang/OverScript/blob/f59db5296482c23c1da5a05925ebd0c129606864/OverScript/CodeLoading.cs#L4715
Есть метод AddVarTypes, который находит переменные - https://github.com/overscript-lang/OverScript/blob/f59db5296482c23c1da5a05925ebd0c129606864/OverScript/CodeLoading.cs#L3467
Переменные ищутся до "компиляции" функций. Там же и вывод типов для var.
Ещё важный метод DirectGetExpressionType - https://github.com/overscript-lang/OverScript/blob/f59db5296482c23c1da5a05925ebd0c129606864/OverScript/CodeLoading.cs#L2373
Он определяет тип выражения. Для скорости он вызывается через кэширующую результаты GetExpressionType.
Интерпретатор в интерпретаторе, зачёт)
Абстрагирование абстракций, абстрагирующие нижележащие абстракции, над нижележащими абстракциями... Продолжите рекурсию.))
OverScript — язык программирования, написанный на C#