Git Product home page Git Product logo

extended-js-subset's Introduction

Code Coverage

Package Line Rate Health
Interpreter.Lib 40%
Interpreter 100%
Summary 43% (925 / 2173)

Minimum allowed line rate is 80%

"Расширенное подмножество ЯП JavaScript"

Вводная информация

За основу был взят стандарт ECMA-262

Лексическая структура

Грамматика

Рабочие примеры

Цель проекта

Реализовать JavaScript с объектами и статической структурной типизацией, избавившись от таких понятий, как constructor, class, interface

Конструкции языка

Типизация

В языке структурная статическая сильная типизация.

Есть 5 примитивных типов:

  1. number
  2. boolean
  3. string
  4. null
  5. void

Остальные типы делятся на группы:

  • NullableType (тип, который допускает значение null)
  • ObjectType (тип объекта, является NullableType)
  • ArrayType (списковый тип)
  • FunctionType (тип функции)
Значения по умолчанию
Тип Значение
number 0
boolean false
string ""
NullableType null
ArrayType []
type alias

Можно создать свой type alias по типу того, как это сделано в С++

type int = number
type maybeInt = int?
type ints = int[]
type point = {
    x: int;
    y: int;
}
type handleInts = (ints) => void
type handler = {
    items: ints;
    handle: handleInts;
}

Объявление переменных

let i = 1 // интерпретатор выведет тип из выражения
let j: number // запишет значение по умолчанию в переменную
let k: number = 1 // полностью явное объявление

Объекты

let v2d = {
    // обычное поле
    x: 3;
    y: 4;
    //метод
    lengthSquared => () {
        // в методе доступны поля объекта
        // и указатель this
        return x * x + y * y
    };
}

Списки

let array = [1, 2, 3]
let size = ~array // длина списка
array::1 // удаление элемента по индексу
array = array ++ [5, 7] // конкатенация списков

Операторы

Оператор Вид Типы операндов Тип операции
+ бинарный оба number, оба string number, string
*, -, /, % бинарный number number
||, && бинарный boolean boolean
!=, == бинарный равный с двух сторон boolean
<=, >=, >, < бинарный number boolean
! унарный boolean boolean
- унарный number number
++ бинарный [] []
:: бинарный [] и number void
~ унарный [] number

Ветвление

if (1 == 1) {
    // ...
} else if (2 == 2) {
    // ...
}
else {
    // ...
}
// в общем как в Си подобных языках
// главное, чтобы выражение условия
// возвращало boolean

Также есть тернарный оператор

let x = 1 > 0 ? 0 <= 1 ? 1 : 0 : -2 < 0 ? -1 : 0

Цикл

while (cond) {
    // ...
    continue
    // ...
    break
}

Функции

// объявление
function add(a: number, b: number): number {
    return a + b
}
// вызов
let c = add(1, 2)

Операции доступа

// объекты
let x = v2d.x
let s = v2d.lengthSquared()
// массивы
let l = array[2]

Приведение типов

let s = v2d as string

Стандартная библиотека

  • Функция print c сигнатурой (string) => void; осуществляет печать строки на экран

Требования

  • .NET 7 SDK

Сборка

После клонирования репозитория идём в папку проекта Interpreter.

Там выполняем команду: dotnet publish -r <RUNTIME_IDENTIFIER> -p:PublishSingleFile=true -p:DebugType=embedded --self-contained false -o <OUTPUT_DIRECTORY>

Список идентификаторов рантайма лежит тут

Запуск

Interpreter 1.2.6
Copyright (C) 2022 Interpreter
USAGE:
Simple interpretation call:
  Interpreter file.js
Request dump:
  Interpreter --dump file.js

  -d, --dump                (Default: false) Show dump data of interpreter

  --help                    Display this help screen.

  --version                 Display version information.

  InputFilePath (pos. 0)    Required. Path to input file

Источники:

  1. ECMA-262
  2. DragonBook
  3. Stanford CS143 Lectures

extended-js-subset's People

Contributors

stepami avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

keyros

extended-js-subset's Issues

Инкапсуляция логики формирования имени временных переменных виртуальной машины

При создании временных переменных внутри виртуальной машины, во-первых, подразумевается, что адрес будет только генерируемым, во-вторых, явно указывается логика получения имени на основе данных адреса.

Выглядит это следующим образом:

Left ??= $"_t{unchecked((uint)address.GetHashCode())}";

Связано это с тем, что у адресов метод ToString переопределён для печати дампа в .tac файл.
Однако, в классе Label создано строковое свойство Name для борьбы с появившимся ограничением.

Это свойство, можно сделать характерным для адреса в целом, поскольку для генерируемого адреса его именем, по сути, является хеш. Таким образом, можно будет инкапсулировать эту логику в свойстве Name.

[feature request] Подключение Nullable Reference Types

Is your feature request related to a problem? Please describe.
В последнее время при отладке различных сценариев возникает NRE, причину которого трудно выявить.
Кажется, что NRT решили бы проблему и помогли в большинстве случаев.

Describe the solution you'd like
Стоит включить поддержку nullable ссылочных типов в проекте.

Additional context
Также, возможно стоит подключить опцию TreatWarningsAsErrors, чтобы предупреждения по NRT не давали скомпилироваться проекту.

[bug] Нельзя использовать идентификатор, частью которого является ключевое слово

Describe the bug
При использовании ключевого слова, как части идентификатора получаю ошибку:

Wrong syntax: ... expected Ident; actual = (Keyword, const)

To Reproduce
Например, не сработает следующий скрипт:

const constExpr = 1

Expected behavior
Интерпретатор распознает constExpr как идентификатор

Desktop (please complete the following information):

  • OS: macOS
  • Platform: arm64
  • Version: 1.2.6

[feature request] возможно стоит перейти на System.CommandLine

Сейчас интерпретатор работает с cli через стороннюю 3rd party библиотеку, она не плохая.

Недавно в инфополе попала библиотека https://github.com/dotnet/command-line-api

Надо её изучить и понять, стоит ли переходить на коробочное решение платформы .NET

Из рисков - её непонятный альфа/бета статус

Неудобно клонировать объекты

Допустим, есть тип и его реализация:

type vector2 = {
    x: number;
    y: number;
    lengthSquared: () => number;
}

let v2dOriginal: vector2 = {
    x: 0;
    y: 0;
    lengthSquared => () {
        return x * x + y * y
    };
}

 
Если мы хотим сделать ещё один объект типа vector2, то надо заново расписывать реализацию lengthSquared.

[feature request] Стоит рассмотреть переход на Native AOT publish

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

Избыточность процесса чтения лексической структуры

Сейчас лексическая структура читается следующим образом:

  1. Массив типов токенов десериализуется из JSON в массив dto-шек.
  2. Массив dto-шек помещается внутрь другой dto
  3. Результирующая dto перегоняется в сущность силами AutoMapper.

Процесс можно упростить до десериализации массива напрямую в сущность Structure. При этом для работы с JSON достаточно возможностей платформенной библиотеки System.Text.Json.

Это избавит от лишних абстракций и двух избыточных зависимостей:

  1. AutoMapper

  2. Newtonsoft.Json

[feature request] Выявлять во время статического анализа вызовы к функциям

Is your feature request related to a problem? Please describe.
Сейчас, если у функции пустое тело, то код не будет генерироваться как для определения, так и для вызова.

Describe the solution you'd like
Требуется выявлять во время статического анализа вызовы к функциям, чтобы не генерировать код для тех функций, которые не вызывали.

У CommandLineSettings присутствует излишний функционал

Класс настроек должен служить одной цели - хранение параметров, для их переиспользования, например, с помощью паттерна Options.

Сейчас там присутствует метод, считывающий текст исходного кода. Такая ответственность не присуща настройкам, операцию необходимо отделить от них. Например, выделить в отдельный сервис.

[feature request] Запретить присваивание void

Is your feature request related to a problem? Please describe.
Рассмотрим следующий участок кода:

function func(b: boolean) {
    if (b)
        return
    return
}
let x = func(true)

Статический анализ должен завершаться с ошибкой о том, что тип void не может участвовать в присваивании

[feature request] Автоматизировать Arrange некоторых тестов при помощи AutoFixture

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

[feature request] Интеграционные тесты

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.

[feature request] Заменить алгоритм поиска переносов строк на более эффективный с SearchValues

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%

Баг при разборе типа

Есть следующее объявление типов:

type node = {
    data: number;
    next: node;
}
type list = {
    head: node;
    append: (number) => void;
    getOdd: () => number[];
}

Из-за того, что list это объектный тип, в нём запускается механизм разрешения ссылок на себя.
В результате программа падает на StackOverflow из-за "вечного гуляния" по node.

[feature request] перейти на компилируемое регулярное выражение

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

Доработка доменной модели кодогенерации

Сейчас доменная модель чётко сформулирована только для фронтенда интерпретатора.
Как только дело доходит до AST, нарушается SRP.

Дело в том, что дерево помимо хранения синтаксической структуры программы, даёт возможность получения инструкций:

public interface IAbstractSyntaxTree
{
    AddressedInstructions GetInstructions();
}

Процесс кодогенерации с проверкой корректности семантики программы не является ответственностью дерева.
Также, контракт не подразумевает доступа к узлам через корень, что довольно странно.

[feature request] Добавить сборку релиза для маков на м1

Is your feature request related to a problem? Please describe.
Макбуки на Apple M1 процессорах с ARM архитектурой набирают популярность, однако, в данном репозитории осуществляется сборка релиза для ноутов на Intel.

Describe the solution you'd like
Доработать release workflow так, чтобы добавилась ещё одна сборка.

Отсутствует независимая система адресации инструкций

Например, на виртуальной машине будет исполняться некоторый набор инструкций.
Допустим, он выглядит так:

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, то она может указать куда угодно:

  • за пределы массива
  • не та инструкция
  • бесконечный цикл

Таким образом, адрес инструкции должен не зависеть от индекса и сохранять актуальным указатель на следующую

[feature request] Изоляция домена и переход на Clean Architecture

Is your feature request related to a problem? Please describe.
После завершения #4 сущности домена будут готовы к изоляции за счёт выделения конкретного аппликационного слоя.

Задача #31 это подзадача этого issue, связанная с внедрением новой версии Visitor.NET, которая решит проблему циклической зависимости и нарушения LSP.

Ну а дальше получится разделить домен на три изолированных друг от друга под домена, в терминах которых всё это время писалось приложение - FrontEnd, IR и BackEnd.

AS IS
Текущая архитектура - простое двухслойное приложение с представлением в виде CLI и логикой в сборе Lib:
AS_IS

TO BE
Внедрение луковой архитектуры проявит и DDD строение проекта, сформировав следующую целевую архитектуру:
TO_BE

[feature request] переход на .NET 8

Is your feature request related to a problem? Please describe.
Стоит рассмотреть возможность перевода проекта на .NET 8, как новую LTS версию платформы

Увеличить покрытие unit тестами

Интерпретатор мало покрыт тестами, это постоянно всплывает при переписывании грамматики, парсера, семантики и так далее.

Необходимо добить хотя бы 80%.

Можно примерить применимость AutoMoq и AutoFixture.xUnit2

Переход на .NET 7

Необходимо перейти на .NET 7 для поддержания актуальности проекта и использования некоторых новых фич, например raw json strings

Требуется усилить уникальность HashAddress

Сейчас уникальность генерируемого адреса базируется лишь на 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 будут означать один и тот же адрес.

Это поведение нужно исправить.

Некорректная грамматика

На данный момент, в грамматике присутствуют серьёзные ошибки приоритета операций в части выражений (expressions).

Например, при работе с полями объекта, доступ через . надо оборачивать в скобки для верного приоритета:

let xy = this.x + this.y // не спарсится корректно

// ...

let xy = (this.x) + (this.y) // корректно парсится, но приходится извращаться

Необходимо переработать грамматику, а затем, соответственно, парсер + структуру и иерархию узлов AST

[bug] неверное распознавание лексемы null

Describe the bug
лексема null всегда распознаётся как литерал
To Reproduce
в следующих отрывках исходного кода:

let tmp:null = null

или

let tmp:null

Expected behavior
После двоеточия лексема null должна распознаваться, как идентификатор типа

Desktop (please complete the following information):

  • OS: Windows 10
  • Platform: x64
  • Version: 1.2.6

Additional context
Add any other context about the problem here.

Изменить способ вывода

Сейчас подразумевается существование некой стандартной функции print в языке.
Для её использования введена специальная инструкция AsString.

Можно сделать вывод операцией на уровне языка, чтобы избавиться от hard-code конструктов.
Например:

>1
>false
>"str"
>{x:1;y:2;}
>[1,2]
>ident

[feature request] Обнаружение недостающего return

Is your feature request related to a problem? Please describe.
Например, есть следующий код:

function f(b: bool) {
    if (b)
        return 1
}

Статический анализ должен свалиться с ошибкой о том, что в функции f не хватает return выражения.

[feature request] Задуматься о переводе узла AST на модель списка или коллекции для чтения

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>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.