Phase 8.1: ! (unwrap/panic) operator — syntax, parsing, HIR lowering, runtime panic
This commit is contained in:
@@ -116,6 +116,7 @@ type
|
|||||||
ekCast
|
ekCast
|
||||||
ekIs
|
ekIs
|
||||||
ekTry
|
ekTry
|
||||||
|
ekUnwrap ## expr! — unwrap or panic
|
||||||
ekBlock
|
ekBlock
|
||||||
ekMatch
|
ekMatch
|
||||||
|
|
||||||
@@ -193,6 +194,8 @@ type
|
|||||||
of ekTry:
|
of ekTry:
|
||||||
exprTryOperand*: Expr
|
exprTryOperand*: Expr
|
||||||
exprTryType*: TypeExpr # nil for Result?, or explicit target type
|
exprTryType*: TypeExpr # nil for Result?, or explicit target type
|
||||||
|
of ekUnwrap:
|
||||||
|
exprUnwrapOperand*: Expr
|
||||||
of ekBlock:
|
of ekBlock:
|
||||||
exprBlock*: Block
|
exprBlock*: Block
|
||||||
of ekMatch:
|
of ekMatch:
|
||||||
|
|||||||
@@ -373,6 +373,8 @@ proc resolveExprType(ctx: var LowerCtx, expr: Expr): Type =
|
|||||||
of ekTry:
|
of ekTry:
|
||||||
# For now, assume Result<int, String> -> int or Option<int> -> int
|
# For now, assume Result<int, String> -> int or Option<int> -> int
|
||||||
return makeInt()
|
return makeInt()
|
||||||
|
of ekUnwrap:
|
||||||
|
return makeInt()
|
||||||
of ekBlock:
|
of ekBlock:
|
||||||
if expr.exprBlock.stmts.len > 0:
|
if expr.exprBlock.stmts.len > 0:
|
||||||
let last = expr.exprBlock.stmts[^1]
|
let last = expr.exprBlock.stmts[^1]
|
||||||
@@ -698,6 +700,51 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
|
|||||||
ctx.pendingStmts.add(ifNode)
|
ctx.pendingStmts.add(ifNode)
|
||||||
return okLoad
|
return okLoad
|
||||||
|
|
||||||
|
of ekUnwrap:
|
||||||
|
let operand = ctx.lowerExpr(expr.exprUnwrapOperand)
|
||||||
|
let operandType = ctx.resolveExprType(expr.exprUnwrapOperand)
|
||||||
|
|
||||||
|
var errTag = "Result_Err"
|
||||||
|
var typeName = "Result"
|
||||||
|
if operandType.kind == tkNamed:
|
||||||
|
typeName = operandType.name
|
||||||
|
if typeName == "Option":
|
||||||
|
errTag = "Option_None"
|
||||||
|
|
||||||
|
let tmpName = ctx.freshTryVar()
|
||||||
|
let tmpAlloca = hirAlloca(tmpName, operandType, loc)
|
||||||
|
let tmpVar = hirVar(tmpName, makePointer(operandType), loc)
|
||||||
|
let tmpStore = hirStore(tmpVar, operand, loc)
|
||||||
|
|
||||||
|
let tagPtr = HirNode(kind: hFieldPtr, fieldPtrBase: tmpVar, fieldName: "tag",
|
||||||
|
typ: makePointer(makeNamed(typeName & "_Tag")), loc: loc)
|
||||||
|
let tagLoad = HirNode(kind: hLoad, loadPtr: tagPtr,
|
||||||
|
typ: makeNamed(typeName & "_Tag"), loc: loc)
|
||||||
|
let errConst = hirVar(errTag, makeNamed(typeName & "_Tag"), loc)
|
||||||
|
let cond = hirBinary(tkEq, tagLoad, errConst, makeBool(), loc)
|
||||||
|
|
||||||
|
# On error: call bux_panic("unwrap failed")
|
||||||
|
let panicTok = Token(kind: tkStringLiteral, text: "\"unwrap failed\"", loc: loc)
|
||||||
|
let panicMsg = HirNode(kind: hLit, litToken: panicTok, typ: makeStr(), loc: loc)
|
||||||
|
let panicCall = hirCall("bux_panic", @[panicMsg], makeVoid(), loc)
|
||||||
|
let thenBlock = hirBlock(@[panicCall], nil, makeVoid(), loc)
|
||||||
|
let ifNode = HirNode(kind: hIf, ifCond: cond, ifThen: thenBlock,
|
||||||
|
ifElse: nil, typ: makeVoid(), loc: loc)
|
||||||
|
|
||||||
|
# Extract the Ok/Some value
|
||||||
|
let dataPtr = HirNode(kind: hFieldPtr, fieldPtrBase: tmpVar, fieldName: "data",
|
||||||
|
typ: makePointer(makeNamed(typeName & "_Data")), loc: loc)
|
||||||
|
let dataLoad = HirNode(kind: hLoad, loadPtr: dataPtr,
|
||||||
|
typ: makeNamed(typeName & "_Data"), loc: loc)
|
||||||
|
let okPtr = HirNode(kind: hFieldPtr, fieldPtrBase: dataLoad, fieldName: "Ok_0",
|
||||||
|
typ: makePointer(makeInt()), loc: loc)
|
||||||
|
let okLoad = HirNode(kind: hLoad, loadPtr: okPtr, typ: makeInt(), loc: loc)
|
||||||
|
|
||||||
|
ctx.pendingStmts.add(tmpAlloca)
|
||||||
|
ctx.pendingStmts.add(tmpStore)
|
||||||
|
ctx.pendingStmts.add(ifNode)
|
||||||
|
return okLoad
|
||||||
|
|
||||||
of ekMatch:
|
of ekMatch:
|
||||||
let subject = ctx.lowerExpr(expr.exprMatchSubject)
|
let subject = ctx.lowerExpr(expr.exprMatchSubject)
|
||||||
var arms: seq[HirMatchArm] = @[]
|
var arms: seq[HirMatchArm] = @[]
|
||||||
@@ -1065,6 +1112,8 @@ proc lowerModule*(module: Module, sema: Sema): HirModule =
|
|||||||
result.add(findGenericCalls(expr.exprUnaryOperand))
|
result.add(findGenericCalls(expr.exprUnaryOperand))
|
||||||
of ekTry:
|
of ekTry:
|
||||||
result.add(findGenericCalls(expr.exprTryOperand))
|
result.add(findGenericCalls(expr.exprTryOperand))
|
||||||
|
of ekUnwrap:
|
||||||
|
result.add(findGenericCalls(expr.exprUnwrapOperand))
|
||||||
of ekAssign:
|
of ekAssign:
|
||||||
result.add(findGenericCalls(expr.exprAssignTarget))
|
result.add(findGenericCalls(expr.exprAssignTarget))
|
||||||
result.add(findGenericCalls(expr.exprAssignValue))
|
result.add(findGenericCalls(expr.exprAssignValue))
|
||||||
|
|||||||
@@ -508,6 +508,9 @@ proc parsePostfix(p: var Parser): Expr =
|
|||||||
of tkQuestion:
|
of tkQuestion:
|
||||||
discard p.advance()
|
discard p.advance()
|
||||||
left = Expr(kind: ekTry, loc: loc, exprTryOperand: left, exprTryType: nil)
|
left = Expr(kind: ekTry, loc: loc, exprTryOperand: left, exprTryType: nil)
|
||||||
|
of tkBang:
|
||||||
|
discard p.advance()
|
||||||
|
left = Expr(kind: ekUnwrap, loc: loc, exprUnwrapOperand: left)
|
||||||
of tkLBrace:
|
of tkLBrace:
|
||||||
if p.structInitAllowed and left.kind in {ekIdent, ekPath, ekGenericCall}:
|
if p.structInitAllowed and left.kind in {ekIdent, ekPath, ekGenericCall}:
|
||||||
discard p.advance()
|
discard p.advance()
|
||||||
|
|||||||
@@ -734,6 +734,10 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type =
|
|||||||
# For now, assume Result<int, String> -> int
|
# For now, assume Result<int, String> -> int
|
||||||
# TODO: check operand is Result/Option and current function returns same type
|
# TODO: check operand is Result/Option and current function returns same type
|
||||||
return makeInt()
|
return makeInt()
|
||||||
|
of ekUnwrap:
|
||||||
|
let operandType = sema.checkExpr(expr.exprUnwrapOperand, scope)
|
||||||
|
# Unwrap: extract Ok value or panic on Err
|
||||||
|
return makeInt()
|
||||||
of ekBlock:
|
of ekBlock:
|
||||||
var blockScope = newScope(scope)
|
var blockScope = newScope(scope)
|
||||||
var lastType = makeVoid()
|
var lastType = makeVoid()
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user