stepami / extended-js-subset Goto Github PK
View Code? Open in Web Editor NEWOpen-source TypeScript killer written in C#
License: GNU General Public License v3.0
Open-source TypeScript killer written in C#
License: GNU General Public License v3.0
Сейчас подразумевается существование некой стандартной функции print
в языке.
Для её использования введена специальная инструкция AsString
.
Можно сделать вывод операцией на уровне языка, чтобы избавиться от hard-code конструктов.
Например:
>1
>false
>"str"
>{x:1;y:2;}
>[1,2]
>ident
Is your feature request related to a problem? Please describe.
Стоит рассмотреть возможность перевода проекта на .NET 8, как новую LTS версию платформы
Is your feature request related to a problem? Please describe.
Например, есть следующий код:
function f(b: bool) {
if (b)
return 1
}
Статический анализ должен свалиться с ошибкой о том, что в функции f
не хватает return
выражения.
Is your feature request related to a problem? Please describe.
На текущий момент для построения системы координат (строка, столбец) весь исходный код перебирается регулярным выражением, что крайне неэффективно.
После #50 требуется изменить алгоритм на более производительный с использованием SearchValues
Describe the solution you'd like
private readonly SearchValues<char> _sv = System.Buffers.SearchValues.Create(['e']);
private readonly int _loremIpsumLength = LoremIpsum.Length;
// ...
var loremIpsumSpan = LoremIpsum.AsSpan();
var index = loremIpsumSpan.IndexOfAny(_sv);
List<int> indices = index == -1 ? [] : [index];
for (; index > -1; index = loremIpsumSpan.IndexOfAny(_sv))
{
index += indices[^1] + 1;
indices.Add(index);
loremIpsumSpan = LoremIpsum.AsSpan(
start: index + 1,
length: _loremIpsumLength - (index + 1));
}
Describe alternatives you've considered
List<int> indices = [];
for (var i = 0; i < _loremIpsumLength; i++)
if (LoremIpsum[i] == 'e')
indices.Add(i);
var indices = LoremIpsum
.Select((c, i) => c == 'e' ? i : -1)
.Where(x => x != -1)
.ToList();
List<int> indices = [];
for (
var i = LoremIpsum.IndexOf('e');
i > -1;
i = LoremIpsum.IndexOf('e', i + 1))
indices.Add(i);
Additional context
Бенчмарк показал ускорение по сравнению с наивным перебором порядка 7-10%
Is your feature request related to a problem? Please describe.
В последнее время при отладке различных сценариев возникает NRE, причину которого трудно выявить.
Кажется, что NRT решили бы проблему и помогли в большинстве случаев.
Describe the solution you'd like
Стоит включить поддержку nullable ссылочных типов в проекте.
Additional context
Также, возможно стоит подключить опцию TreatWarningsAsErrors
, чтобы предупреждения по NRT не давали скомпилироваться проекту.
Класс настроек должен служить одной цели - хранение параметров, для их переиспользования, например, с помощью паттерна Options
.
Сейчас там присутствует метод, считывающий текст исходного кода. Такая ответственность не присуща настройкам, операцию необходимо отделить от них. Например, выделить в отдельный сервис.
При создании временных переменных внутри виртуальной машины, во-первых, подразумевается, что адрес будет только генерируемым, во-вторых, явно указывается логика получения имени на основе данных адреса.
Выглядит это следующим образом:
Left ??= $"_t{unchecked((uint)address.GetHashCode())}";
Связано это с тем, что у адресов метод ToString
переопределён для печати дампа в .tac
файл.
Однако, в классе Label
создано строковое свойство Name
для борьбы с появившимся ограничением.
Это свойство, можно сделать характерным для адреса в целом, поскольку для генерируемого адреса его именем, по сути, является хеш. Таким образом, можно будет инкапсулировать эту логику в свойстве Name
.
Интерпретатор мало покрыт тестами, это постоянно всплывает при переписывании грамматики, парсера, семантики и так далее.
Необходимо добить хотя бы 80%.
Можно примерить применимость AutoMoq и AutoFixture.xUnit2
Is your feature request related to a problem? Please describe.
В .NET 7 появилась возможность паблишить приложение AOT таргетировано на конкретную платформу.
При этом оно оптимизировано и изолированно упаковано в единственный файл, на целевой машине даже не должен быть установлен .NET Runtime.
Describe the solution you'd like
https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=net7
Additional context
Поскольку релиз уже собирается с указанием конкретного RID, то выглядит, что работы делать немного - только конфигурация csproj.
По сути сейчас делается приблизительно +/- то же самое, но в парадигмах старых версий дотнета и на уровне CI/CD:
dotnet publish ./Interpreter/Interpreter.csproj -c Release -r ${{ matrix.config.rid }} -p:PublishSingleFile=true -p:DebugType=embedded --self-contained false -o ./output
Is your feature request related to a problem? Please describe.
Сейчас, если у функции пустое тело, то код не будет генерироваться как для определения, так и для вызова.
Describe the solution you'd like
Требуется выявлять во время статического анализа вызовы к функциям, чтобы не генерировать код для тех функций, которые не вызывали.
Некоторые программы выдают неправильную адресацию инструкций для виртуальной машины.
Describe the bug
При использовании ключевого слова, как части идентификатора получаю ошибку:
Wrong syntax: ... expected Ident; actual = (Keyword, const)
To Reproduce
Например, не сработает следующий скрипт:
const constExpr = 1
Expected behavior
Интерпретатор распознает constExpr
как идентификатор
Desktop (please complete the following information):
На данный момент, в грамматике присутствуют серьёзные ошибки приоритета операций в части выражений (expressions).
Например, при работе с полями объекта, доступ через .
надо оборачивать в скобки для верного приоритета:
let xy = this.x + this.y // не спарсится корректно
// ...
let xy = (this.x) + (this.y) // корректно парсится, но приходится извращаться
Необходимо переработать грамматику, а затем, соответственно, парсер + структуру и иерархию узлов AST
Is your feature request related to a problem? Please describe.
Как минимум тесты вот здесь https://github.com/Stepami/extended-js-subset/tree/master/Interpreter.Tests/Unit/Infrastructure
Классические "корпоративные" тесты. И сетапы можно было бы отдать на откуп AutoFixture
Describe the solution you'd like
https://blog.ploeh.dk/2010/10/08/AutoDataTheorieswithAutoFixture/
Describe alternatives you've considered
AutoNSubstitute
Additional context
Не ясно, что делать раньше - этот issue или #52
Допустим, есть тип и его реализация:
type vector2 = {
x: number;
y: number;
lengthSquared: () => number;
}
let v2dOriginal: vector2 = {
x: 0;
y: 0;
lengthSquared => () {
return x * x + y * y
};
}
Если мы хотим сделать ещё один объект типа vector2
, то надо заново расписывать реализацию lengthSquared
.
Is your feature request related to a problem? Please describe.
Сейчас версия выставляется руками после слияния в мастер PR.
Describe the solution you'd like
Хотелось бы, чтобы по пушу тега, он автоматически подцеплялся и проставлялся в версию релиза
Необходимо перейти на .NET 7 для поддержания актуальности проекта и использования некоторых новых фич, например raw json strings
Describe the bug
лексема null
всегда распознаётся как литерал
To Reproduce
в следующих отрывках исходного кода:
let tmp:null = null
или
let tmp:null
Expected behavior
После двоеточия лексема null
должна распознаваться, как идентификатор типа
Desktop (please complete the following information):
Additional context
Add any other context about the problem here.
Is your feature request related to a problem? Please describe.
В проекте есть папка с примерами кода на языке:
https://github.com/Stepami/extended-js-subset/tree/master/samples
Эти примеры необходимо выполнять, чтобы удостовериться в корректности работы интерпретатора
Describe the solution you'd like
Поскольку в таких тестах выполняется полный прогон, очевидно, что это интеграционники, которые нужно добавить в проект.
Additional context
Во-первых, необходимо разработать критерий приёмки теста (выполнения программы).
Во-вторых, требуется доработать ci-cd.
Is your feature request related to a problem? Please describe.
На текущий момент узел AST предоставляет функционал перебора, реализуя итератор:
public abstract class AbstractSyntaxTreeNode : IEnumerable<AbstractSyntaxTreeNode>
Однако, такое позиционирование не до конца корректно, поскольку такая перебираемость подразумевает парадигму ленивых вычислений.
В нашем случае все узлы дерева давно известны, однако их постоянный перебор инициирует повторяющиеся построения коллекций.
Хотя эту коллекцию можно построить один раз и перебирать закешированный результат.
Describe the solution you'd like
public abstract class AbstractSyntaxTreeNode : IReadOnlyCollection<AbstractSyntaxTreeNode>
Describe alternatives you've considered
public abstract class AbstractSyntaxTreeNode : IReadOnlyList<AbstractSyntaxTreeNode>
Например, на виртуальной машине будет исполняться некоторый набор инструкций.
Допустим, он выглядит так:
0: a = 1 + 1
1: c = 0
2: b = a + 5
3: s = b as string
4: Print s
5: End
Мы видим, что идентификатор c
нигде не используется, поэтому его можно удалить.
Однако, инструкции хранятся в массиве, и их номер (адрес) при создании - есть индекс.
Соответственно, после удаления список будет выглядеть так:
0: a = 1 + 1
2: b = a + 5
3: s = b as string
4: Print s
5: End
Номера инструкций не меняются, а значит ломается указатель на следующую инструкцию.
То есть, если у нас встретиться инструкция Goto
, то она может указать куда угодно:
Таким образом, адрес инструкции должен не зависеть от индекса и сохранять актуальным указатель на следующую
Is your feature request related to a problem? Please describe.
Рассмотрим следующий участок кода:
function func(b: boolean) {
if (b)
return
return
}
let x = func(true)
Статический анализ должен завершаться с ошибкой о том, что тип void
не может участвовать в присваивании
Is your feature request related to a problem? Please describe.
По сути своей, лексическая структура языка, диктуется глобальным regex паттерном, который можно собрать во время компиляции приложения, поскольку все теги известны из исходного кода - https://github.com/Stepami/extended-js-subset/blob/master/Interpreter/TokenTypes.cs
Существующая динамическая система призвана упростить процесс доработки классов лексем, сделав его максимально гибким.
Describe the solution you'd like
Некий сурс генератор, который бы подхватывал json файл и выполнял бы указанное построение паттерна:
string.Join(
'|',
types
.Where(t => !t.EndOfProgram())
.Select(t => t.GetNamedRegex())
.ToList()))
Describe alternatives you've considered
Написать этот паттерн руками - однако не ясно как его поддерживать и гарантировать согласованность с перечнем классов лексем (тегов).
Additional context
Требуется понять актуальность модели TokenType
, какая из представленной метаинформации необходима.
https://stevetalkscode.co.uk/regex-source-generator
Сейчас лексическая структура читается следующим образом:
Процесс можно упростить до десериализации массива напрямую в сущность Structure. При этом для работы с JSON достаточно возможностей платформенной библиотеки System.Text.Json
.
Это избавит от лишних абстракций и двух избыточных зависимостей:
AutoMapper
Newtonsoft.Json
Is your feature request related to a problem? Please describe.
Describe the solution you'd like
NSubstitute
Describe alternatives you've considered
https://nsubstitute.github.io/
Additional context
Все связки с AutoFixture также реализованы https://www.nuget.org/packages/AutoFixture.AutoNSubstitute/
Например, объявлены два типа A
и B
:
type A = {
b: B;
}
type B = {
a: A;
}
Такой код не скомпилируется
Сейчас доменная модель чётко сформулирована только для фронтенда интерпретатора.
Как только дело доходит до AST, нарушается SRP.
Дело в том, что дерево помимо хранения синтаксической структуры программы, даёт возможность получения инструкций:
public interface IAbstractSyntaxTree
{
AddressedInstructions GetInstructions();
}
Процесс кодогенерации с проверкой корректности семантики программы не является ответственностью дерева.
Также, контракт не подразумевает доступа к узлам через корень, что довольно странно.
Есть следующее объявление типов:
type node = {
data: number;
next: node;
}
type list = {
head: node;
append: (number) => void;
getOdd: () => number[];
}
Из-за того, что list
это объектный тип, в нём запускается механизм разрешения ссылок на себя.
В результате программа падает на StackOverflow
из-за "вечного гуляния" по node
.
Is your feature request related to a problem? Please describe.
Макбуки на Apple M1 процессорах с ARM архитектурой набирают популярность, однако, в данном репозитории осуществляется сборка релиза для ноутов на Intel.
Describe the solution you'd like
Доработать release workflow так, чтобы добавилась ещё одна сборка.
Is your feature request related to a problem? Please describe.
После завершения #4 сущности домена будут готовы к изоляции за счёт выделения конкретного аппликационного слоя.
Задача #31 это подзадача этого issue, связанная с внедрением новой версии Visitor.NET, которая решит проблему циклической зависимости и нарушения LSP.
Ну а дальше получится разделить домен на три изолированных друг от друга под домена, в терминах которых всё это время писалось приложение - FrontEnd, IR и BackEnd.
AS IS
Текущая архитектура - простое двухслойное приложение с представлением в виде CLI и логикой в сборе Lib:
TO BE
Внедрение луковой архитектуры проявит и DDD строение проекта, сформировав следующую целевую архитектуру:
Сейчас интерпретатор работает с cli через стороннюю 3rd party библиотеку, она не плохая.
Недавно в инфополе попала библиотека https://github.com/dotnet/command-line-api
Надо её изучить и понять, стоит ли переходить на коробочное решение платформы .NET
Из рисков - её непонятный альфа/бета статус
Сейчас уникальность генерируемого адреса базируется лишь на seed
, передаваемом в конструктор:
public class HashAddress : IAddress
{
private readonly int _seed;
public HashAddress(int seed) =>
_seed = seed;
public bool Equals(IAddress other)
{
if (other is HashAddress hashed)
return _seed == hashed._seed;
return false;
}
}
В качестве seed
используется хэш-код инструкции, которой присваивается адрес: instruction.GetHashCode()
.
Поскольку GetHashCode
не переопределён в иерархии инструкций, то по сути это отражение выделения памяти.
В любом, случае чем больше будет инструкций, тем больше вероятность того, что произойдёт коллизия, и для два экземпляра HashAddress
с одинаковым seed
будут означать один и тот же адрес.
Это поведение нужно исправить.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.