Skip to content

Add named argument support and duplicate parameter name warning#1669

Draft
chrisdp wants to merge 11 commits intomasterfrom
feature/named-function-params
Draft

Add named argument support and duplicate parameter name warning#1669
chrisdp wants to merge 11 commits intomasterfrom
feature/named-function-params

Conversation

@chrisdp
Copy link
Copy Markdown
Contributor

@chrisdp chrisdp commented Mar 28, 2026

Summary

  • Named arguments: allows calling functions using named parameter syntax (e.g. greet(name: "Bob"))
    • Validates unknown named arguments against the function definition
    • Errors on duplicate named arguments in the same call
    • Errors on positional arguments following named arguments
    • Errors when named args are used on an unknown function (can't verify param names)
  • Duplicate parameter warning: emits a warning (code 1150) when a function/sub definition has two or more parameters with the same name (case-insensitive)
  • Fixes Expression import in Scope.ts to pull from parser/AstNode where it is declared

New diagnostic codes

Code Severity Message
1146 Error Unknown named argument '{name}' for function '{func}'
1147 Error Named argument '{name}' was already provided
1148 Error Positional arguments cannot follow named arguments
1149 Error Cannot use named arguments when calling '{func}' because the function definition cannot be found
1150 Warning Duplicate parameter name '{name}'

Test plan

  • Named argument tests in src/parser/tests/expression/NamedArgument.spec.ts
  • Duplicate parameter tests in src/files/BrsFile.spec.ts

🤖 Generated with Claude Code

chrisdp and others added 2 commits March 28, 2026 20:35
- Named arguments: allows calling functions with named params
  (e.g. `greet(name: "Bob")`) with validation for unknown names,
  duplicates, and positional args following named args
- Adds diagnostic codes 1146-1149 for named argument errors
- Adds warning (1150) when a function definition has duplicate
  parameter names (case-insensitive)
- Fixes Expression import in Scope.ts to pull Expression from
  parser/AstNode where it is declared

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@TwitchBronBron TwitchBronBron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to change a few things about this:

  • named arguments should be evaluted in the order they are written in the text. So that will require some hoisting to local __bs* vars. only need to hoist up until the last call expression. (and can likely skip hoisting VariableExpression and literals (maybe even AA and Array literals as long as they're only composed of literals or VariableExpressions themselves)
  • sequence the local hoisted vars on a per-function basis. (maybe use a WeakMap to use the functionExpression as the key and the sequence as the value)?
  • move the code into ScopeValidator.ts instead of living in Scope.ts
  • the transpiler should be the one responsible for reordering the args, and only on the way out....we don't want to manipulate the AST for this if we can help it, because that makes things complicated for other plugins earlier and later in the flow.
  • instead of modifying the transpiler directly, we should do similar to the Ternary transpilation. We modify the CallExpression arguments array during the beforeFileTranspile (see BrsFilePreTranspileProcessor)

Comment thread src/parser/Expression.ts Outdated
* When named arguments are used and successfully resolved during validation, this holds the
* positional-ordered argument list used for transpilation. If undefined, `args` is used directly.
*/
public resolvedArgs?: Expression[];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this, we don't want to be caching this type of information.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in de7a040. Removed the prior named-arg transpile complexity and any call-expression-level cached mapping behavior; named-arg handling now validates order in ScopeValidator and rewrites directly in pre-transpile.

Comment thread src/Scope.ts Outdated
* Validate calls that use named arguments, and resolve them to positional order for transpilation.
* Only handles simple function calls (VariableExpression callee); method calls are not supported.
*/
private validateNamedArgCalls(file: BscFile, callableContainerMap: CallableContainerMap) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this into ScopeValidator.ts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in de7a040. Named-argument validation is handled in ScopeValidator.ts, and the Scope-level function-call count path now defers named-arg cases to that validator.

chrisdp and others added 3 commits March 31, 2026 09:06
…hase

- Move named arg validation from Scope.validateNamedArgCalls() into
  ScopeValidator.walkFiles() — pure diagnostics, no AST mutation
- Remove CallExpression.resolvedArgs; transpile now reads this.args directly
- Add processNamedArgumentCalls() in BrsFilePreTranspileProcessor:
  - Inline reorder for calls with only literal/variable args
  - Hoist complex args to __bsArgsN temp vars before the containing statement
  - IIFE fallback when hoisting is unsafe (else-if conditions, ternary branches)
- Preserve written evaluation order across nesting levels via reversed
  callExpressions iteration and reversible parent-pointer updates on hoisted nodes
- Add tests covering if/for/else-if, nested calls, ternary combinations,
  and outer-variable-as-IIFE-arg (no-closure correctness for BrightScript)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ss-scope conflict detection

- Named args now work on namespace function calls (e.g. MyNs.myFunc(a: 1))
- Named args now work on constructor calls (e.g. new MyClass(a: 1)), including
  inherited constructors resolved by walking the ancestor chain
- New diagnostic bs1151 fires when a shared file's named arg call targets a
  function whose parameter signature differs across component scopes, since
  the transpiler can only produce one output and would silently choose wrong ordering
- Extracted rewriteNamedArgCall helper to share hoisting logic between regular,
  namespace, and constructor call sites
- Added validation and transpilation tests for all three new cases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@luis-j-soares

This comment was marked as resolved.

Populates relatedInformation with links to both conflicting function
definitions so users can navigate directly to each scope's version.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@chrisdp
Copy link
Copy Markdown
Contributor Author

chrisdp commented May 4, 2026

@luis-j-soares doesn't need to be. Just means the amount of places that it can be used in isn't quite as many as it would be in v1. But since this is just a call site feature it can be expanded on in v1 to support more locations.

@chrisdp
Copy link
Copy Markdown
Contributor Author

chrisdp commented May 7, 2026

@copilot i want to update this pr to remove the param reordering for now.

Enforce the order of params

If someone were to do something like this example we would transpile and populated the missing optional details for them.

sub greet(name = “Unknown” as string, excited = false as boolean)
    if excited
        print "Hello, " + name + "!!!"
    else
        print "Hello, " + name
    end if
end sub

sub main()
    greet(excited: true)
end sub

So greet would become:

greet("Unknown", true)

Copy link
Copy Markdown
Contributor

Copilot AI commented May 7, 2026

@copilot i want to update this pr to remove the param reordering for now.

Enforce the order of params...

Implemented in de7a040. Named arguments now enforce declaration order, and transpilation no longer does hoisting/IIFE reordering. Calls like greet(excited: true) now transpile to greet("Unknown", true) by filling skipped leading optional params.

We need to change a few things about this:

  • named arguments should be evaluted in the order they are written in the text. So that will require some hoisting to local __bs* vars. only need to hoist...

Updated in de7a040 based on the latest direction to remove param reordering for now: named args are enforced in declaration order, validation lives in ScopeValidator.ts, and pre-transpile now performs a direct named→positional rewrite (including default backfill for skipped leading optional params) without hoisting/IIFE logic.

Copilot finished work on behalf of chrisdp May 7, 2026 02:18
@chrisdp
Copy link
Copy Markdown
Contributor Author

chrisdp commented May 7, 2026

@copilot lets also have code actions available to the user to to fix the order.

Copy link
Copy Markdown
Contributor

Copilot AI commented May 7, 2026

@copilot lets also have code actions available to the user to to fix the order.

Implemented in f04129a (with core functionality in 1604dce): added a quick-fix code action, Reorder named arguments to match function declaration, for out-of-order named-arg diagnostics so users can auto-fix argument order at the callsite.

Copilot finished work on behalf of chrisdp May 7, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants