feat: named and default parameters

Bootstrap compiler:
- ast.nim: add exprCallArgNames to ekCall for named arg tracking
- parser.nim: detect name: value syntax in call args
- sema.nim: add resolveCallArgs helper that injects default values
  for missing params and reorders named args into param order.
  Parser already parsed default param values; sema now uses them.

Selfhost compiler:
- ast.bux: add defaultExpr to Param, argName to ExprList
- parser.bux: parse = defaultExpr in param list, detect name: value
  syntax in call arguments
- sema.bux: add Sema_ResolveCallArgs with same logic as bootstrap

Tests:
- _test_named_params verifies defaults, named args, mixed positional+named,
  and named args with defaults in both compilers.

All verifications pass: build, selfhost-loop, test-examples, test-golden.
This commit is contained in:
2026-06-08 22:02:19 +03:00
parent 17c896c4dc
commit 3f0a3901ca
7 changed files with 210 additions and 13 deletions
+11 -1
View File
@@ -589,17 +589,27 @@ proc parsePostfix(p: var Parser): Expr =
# Call expression
discard p.advance()
var args: seq[Expr] = @[]
var argNames: seq[string] = @[]
while not p.check(tkRParen) and not p.isAtEnd:
if p.check(tkDotDotDot):
discard p.advance()
let operand = p.parseExpr()
args.add(Expr(kind: ekSpread, loc: operand.loc, exprSpreadOperand: operand))
argNames.add("")
elif p.peek() == tkIdent and p.peek(1) == tkColon:
# Named argument: name: value
let nameTok = p.advance()
discard p.advance() # :
let value = p.parseExpr()
args.add(value)
argNames.add(nameTok.text)
else:
args.add(p.parseExpr())
argNames.add("")
if p.check(tkComma):
discard p.advance()
discard p.expect(tkRParen, "expected ')' to close call")
left = Expr(kind: ekCall, loc: loc, exprCallCallee: left, exprCallArgs: args)
left = Expr(kind: ekCall, loc: loc, exprCallCallee: left, exprCallArgs: args, exprCallArgNames: argNames)
of tkLt:
# Generic type arguments: Max<int>(10, 20)
# Only treat '<' as generic args if lookahead confirms a matching '>'