extended-js-subset icon indicating copy to clipboard operation
extended-js-subset copied to clipboard

[feature request] Параметры функций по умолчанию

Open Stepami opened this issue 10 months ago • 13 comments

Is your feature request related to a problem? Please describe. Добавить параметрам функций значение по умолчанию

Describe the solution you'd like

function f(a = 0) {}
function f(a:number, b = 1) {}
  • Могут стоять только в конце
  • Сигнатура такого метода: f (number)
  • Вызов f(1) перекрывает вызов f(0,1)

Describe alternatives you've considered Как в java - отсутствие фичи

Additional context Выполнить после #61

Stepami avatar Mar 12 '25 11:03 Stepami

function f(a:number, b:number, c:number) {
    return a + b + c
}

>>> f(1, 2, 3)
	Goto End_function f(number, number, number)
Start_function f(number, number, number):
	BeginFunction function f(number, number, number)
	PopParameter a
	PopParameter b
	PopParameter c
	_t35054d23d9 = a + b
	_taa76987105 = _t35054d23d9 + c
	Return _taa76987105
End_function f(number, number, number):
	EndFunction function f(number, number, number)
	PushParameter 1
	PushParameter 2
	PushParameter 3
	_t4529d2249b = Call function f(number, number, number)
	_t836545b348 = _t4529d2249b as string
	Print _t836545b348
	End

Для кодогенерации нужна новая инструкция DefaultParameter key value, которая будет эмитироваться в теле функции после серии PopParameter, поскольку эта метаинформация недоступна при обработке вызова функции. Логика простая: если во фрейм не записали значение по указанному ключу, устанавливаем его.

Stepami avatar Apr 04 '25 07:04 Stepami

Есть время до 17:00 попробую что-нибудь )

MaxTube-dot avatar Apr 05 '25 09:04 MaxTube-dot

Есть время до 17:00 попробую что-нибудь )

@MaxTube-dot Обрати внимание на ряд подводных камней:

  1. Надо доделать грамматику с учётом требований в описании issue. Парсер сейчас не понимает конструкцию
function f(a = 0) {}

Предлагаю максимально простую цепочку:

Ident Assign Literal
  1. В рамках статического анализа для функции надо будет делать две символьных регистрации с проверкой перекрытия и заменой на более приоритетную перегрузку. Ориентир - поведение в C#
  2. По кодогенератору подсветил в комменте

Stepami avatar Apr 05 '25 10:04 Stepami

синтаксис function f(a : number = 1) {} тоже поддерживаем?

MaxTube-dot avatar Apr 05 '25 11:04 MaxTube-dot

синтаксис function f(a : number = 1) {} тоже поддерживаем?

Нет, это не имеет смысла.

Литерал - это простейшее выражение, у которого заранее известен тип

Stepami avatar Apr 05 '25 11:04 Stepami

Вот еще подводный камень. Предположим у нас задача задекларировать function f(a:number, b = 1, c=2) {} в таком случае нам нужно задекларировать по капотом

function f(a:number) function f(a:number, b:number) function f(a:number, c:number) function f(a:number, b :number, c :number)

меня смущает function f(a:number, c:number) потому как оно будет требовать указания конкретного параметра c, вывоз должен выглядеть так f(2, c:23). Если не указывать конкретно какому параметру мы передаем значения, то будет вызываться другая перегрузка function f(a:number, b:number). Есть ли в hydrascript фича с указанием конкретного аргумента, которому передаем значение? Кажется что без нее логика будет не интуитивной.

MaxTube-dot avatar Apr 05 '25 13:04 MaxTube-dot

Сколько времени ты готов дать на реализацию? Или будешь делать сам?

MaxTube-dot avatar Apr 05 '25 14:04 MaxTube-dot

Вот еще подводный камень. Предположим у нас задача задекларировать function f(a:number, b = 1, c=2) {} в таком случае нам нужно задекларировать по капотом

function f(a:number) function f(a:number, b:number) function f(a:number, c:number) function f(a:number, b :number, c :number)

меня смущает function f(a:number, c:number) потому как оно будет требовать указания конкретного параметра c, вывоз должен выглядеть так f(2, c:23). Если не указывать конкретно какому параметру мы передаем значения, то будет вызываться другая перегрузка function f(a:number, b:number). Есть ли в hydrascript фича с указанием конкретного аргумента, которому передаем значение? Кажется что без нее логика будет не интуитивной.

В голове не могу посчитать, надо опереться на поведение C#

Указание аргумента при передаче отсутствует - хороший поинт

Теперь не понятно, можно ли делать параметры по умолчанию

Stepami avatar Apr 05 '25 14:04 Stepami

Да, без этого будет невозможно полностью скопировать логику. Нужно реализовывать указание параметра.


void MyMethod(int a = 10, int b = 20)
{
    Console.WriteLine($"a: {a}, b: {b}");
}

// Вызов с указанием только второго параметра:
MyMethod(b: 30); // a будет равен 10 (значению по умолчанию)

MaxTube-dot avatar Apr 06 '25 07:04 MaxTube-dot

Вот еще подводный камень. Предположим у нас задача задекларировать function f(a:number, b = 1, c=2) {} в таком случае нам нужно задекларировать по капотом

function f(a:number) function f(a:number, b:number) function f(a:number, c:number) function f(a:number, b :number, c :number)

меня смущает function f(a:number, c:number) потому как оно будет требовать указания конкретного параметра c, вывоз должен выглядеть так f(2, c:23). Если не указывать конкретно какому параметру мы передаем значения, то будет вызываться другая перегрузка function f(a:number, b:number). Есть ли в hydrascript фича с указанием конкретного аргумента, которому передаем значение? Кажется что без нее логика будет не интуитивной.

Только сейчас нашёл ошибку в рассуждениях - имя параметра функции не входит в сигнатуру

Stepami avatar Apr 06 '25 10:04 Stepami

Понял о чем ты, долго доходило как можно сделать иначе.

MaxTube-dot avatar Apr 09 '25 07:04 MaxTube-dot

При регистрации перегрузок функций была обнаружена проблема, корректно склонировать BlockStatement(код внутри метода или If ) без тонн кода не получалось, так или иначе ловил ошибки. Решил попробовать поиграться с движением Вперед/Назад в TokensStream, т.е. получать BlockStatement по алгоритму, не клонируя. Кажется работает, но нужно проверить и покрыть еще тестами.

    var savedTokenIndex = _tokens.Position;
    foreach (var parameters in overloadedFunctions)
    {
        _tokens.SetPosition(savedTokenIndex);
        var blockStatement = BlockStatement();
        var name = new IdentifierReference(ident.Value) { Segment = ident.Segment };
        functionDeclarations.Add(new FunctionDeclaration(name, returnType, parameters, blockStatement) 
            { Segment = ident.Segment });
    }
    
    return functionDeclarations;

MaxTube-dot avatar Apr 09 '25 19:04 MaxTube-dot

При регистрации перегрузок функций была обнаружена проблема, корректно склонировать BlockStatement(код внутри метода или If ) без тонн кода не получалось, так или иначе ловил ошибки. Решил попробовать поиграться с движением Вперед/Назад в TokensStream, т.е. получать BlockStatement по алгоритму, не клонируя. Кажется работает, но нужно проверить и покрыть еще тестами.

    var savedTokenIndex = _tokens.Position;
    foreach (var parameters in overloadedFunctions)
    {
        _tokens.SetPosition(savedTokenIndex);
        var blockStatement = BlockStatement();
        var name = new IdentifierReference(ident.Value) { Segment = ident.Segment };
        functionDeclarations.Add(new FunctionDeclaration(name, returnType, parameters, blockStatement) 
            { Segment = ident.Segment });
    }
    
    return functionDeclarations;

Ты вообще не в ту степь пошёл, тебе не нужно плодить новые узлы AST

Мультирегистрация исключительно к символам относится

Stepami avatar Apr 09 '25 19:04 Stepami