feat: pattern bindings, empty closures, match-as-expr, string interp
Sessions 10–12 from QUALITY_PLAN:
- Pattern payload bindings (Some(value) => value) in bootstrap and selfhost
- Empty-param closures via || (tkPipePipe) with loop/return bodies
- Expression-form match: let x = match …; newline before arms
- f"…" string interpolation desugared to String_Concat + conversions
- Lexer preserves \{ \} for literal braces in f-strings
- Bootstrap fix: f"plain" strips the f prefix after escape processing
- Examples: pattern_matching, closure_control, match_let, string_interp
Selfhost-loop remains binary-identical; all examples and error goldens pass.
This commit is contained in:
+22
-1
@@ -463,7 +463,10 @@ proc parseStringInterpolation(p: var Parser, tok: Token): Expr =
|
||||
i += 1
|
||||
texts.add(currentText)
|
||||
if exprs.len == 0:
|
||||
return newLiteralExpr(tok)
|
||||
# f"plain" / f"use \{x\}" with no real {expr} — use processed text (escapes applied)
|
||||
var litTok = tok
|
||||
litTok.text = "\"" & texts[0] & "\""
|
||||
return newLiteralExpr(litTok)
|
||||
return newStringInterpExpr(texts, exprs, tok.loc)
|
||||
|
||||
proc parsePrimary(p: var Parser): Expr =
|
||||
@@ -524,9 +527,16 @@ proc parsePrimary(p: var Parser): Expr =
|
||||
p.structInitAllowed = false
|
||||
let subject = p.parseExpr()
|
||||
p.structInitAllowed = true
|
||||
# Same newline rules as statement-form match (needed for `let x = match ...`)
|
||||
while p.check(tkNewLine):
|
||||
discard p.advance()
|
||||
discard p.expect(tkLBrace, "expected '{' to start match")
|
||||
var arms: seq[MatchArm] = @[]
|
||||
while not p.check(tkRBrace) and not p.isAtEnd:
|
||||
while p.check(tkNewLine):
|
||||
discard p.advance()
|
||||
if p.check(tkRBrace) or p.isAtEnd:
|
||||
break
|
||||
let armLoc = p.currentLoc
|
||||
let pat = p.parsePattern()
|
||||
discard p.expect(tkFatArrow, "expected '=>' in match arm")
|
||||
@@ -581,6 +591,17 @@ proc parsePrimary(p: var Parser): Expr =
|
||||
of tkNull:
|
||||
discard p.advance()
|
||||
return newLiteralExpr(Token(kind: tkNull, text: "null", loc: loc))
|
||||
of tkPipePipe:
|
||||
# Empty-param closure written as `||` — lexer merges two '|' into tkPipePipe.
|
||||
# Disambiguate from logical-or (which only appears mid-expression): as a primary,
|
||||
# `|| -> T { ... }` / `|| { ... }` is always a zero-param closure.
|
||||
discard p.advance() # ||
|
||||
var retTypePP: TypeExpr = nil
|
||||
if p.check(tkArrow):
|
||||
discard p.advance() # ->
|
||||
retTypePP = p.parseType()
|
||||
let bodyPP = p.parseBlock()
|
||||
return Expr(kind: ekClosure, loc: loc, exprClosureParams: @[], exprClosureBody: bodyPP, exprClosureReturnType: retTypePP)
|
||||
of tkPipe:
|
||||
# Closure: |params| -> Ret { body }
|
||||
discard p.advance() # |
|
||||
|
||||
Reference in New Issue
Block a user