Skip to content

Commit

Permalink
typeCase/typeDefaultThen
Browse files Browse the repository at this point in the history
  • Loading branch information
visualfc committed Feb 20, 2024
1 parent be3a1ae commit 86cb196
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 44 deletions.
11 changes: 8 additions & 3 deletions codebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -2497,17 +2497,22 @@ func (p *CodeBuilder) TypeAssertThen() *CodeBuilder {
}

// TypeCase starts case body of a type switch statement.
func (p *CodeBuilder) TypeCase(n int, src ...ast.Node) *CodeBuilder { // n=0 means default case
func (p *CodeBuilder) TypeCase(src ...ast.Node) *CodeBuilder {
if debugInstr {
log.Println("TypeCase", n)
log.Println("TypeCase")
}
if flow, ok := p.current.codeBlock.(*typeSwitchStmt); ok {
flow.TypeCase(p, n, src...)
flow.TypeCase(p, src...)
return p
}
panic("use switch x.(type) .. case please")
}

// TypeDefaultThen starts default clause of a type switch statement.
func (p *CodeBuilder) TypeDefaultThen(src ...ast.Node) *CodeBuilder {
return p.TypeCase(src...).Then(src...)
}

// Select starts a select statement.
func (p *CodeBuilder) Select(src ...ast.Node) *CodeBuilder {
if debugInstr {
Expand Down
4 changes: 2 additions & 2 deletions error_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func TestErrTypeSwitch(t *testing.T) {
v := pkg.NewParam(token.NoPos, "v", tyInterf)
pkg.NewFunc(nil, "foo", types.NewTuple(v), nil, false).BodyStart(pkg).
/**/ TypeSwitch("t").Val(v, source("v", 1, 5)).TypeAssertThen().
/**/ Typ(types.Typ[types.Int], source("int", 2, 9)).TypeCase(1).
/**/ TypeCase().Typ(types.Typ[types.Int], source("int", 2, 9)).Then().
/**/ End().
End()
})
Expand All @@ -211,7 +211,7 @@ func TestErrTypeSwitch(t *testing.T) {
v := pkg.NewParam(token.NoPos, "v", gox.TyEmptyInterface)
pkg.NewFunc(nil, "foo", types.NewTuple(v), nil, false).BodyStart(pkg).
/**/ TypeSwitch("t").Val(v).TypeAssertThen().
/**/ Val(1, source("1", 2, 9)).TypeCase(1).
/**/ TypeCase().Val(1, source("1", 2, 9)).Then().
/**/ End().
End()
})
Expand Down
10 changes: 5 additions & 5 deletions package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -915,13 +915,13 @@ func TestTypeSwitch(t *testing.T) {
newFuncDecl(pkg, "bar", types.NewTuple(p), nil)
newFuncDecl(pkg, "foo", types.NewTuple(v), nil).BodyStart(pkg).
/**/ TypeSwitch("t").Val(v).TypeAssertThen().
/****/ Typ(types.Typ[types.Int]).Typ(types.Typ[types.String]).TypeCase(2).
/****/ TypeCase().Typ(types.Typ[types.Int]).Typ(types.Typ[types.String]).Then().
/******/ Val(ctxRef(pkg, "bar")).VarRef(ctxRef(pkg, "t")).UnaryOp(token.AND).Call(1).EndStmt().
/****/ End().
/**/ Typ(types.Typ[types.Bool]).TypeCase(1).
/**/ TypeCase().Typ(types.Typ[types.Bool]).Then().
/******/ NewVarStart(types.Typ[types.Bool], "x").Val(ctxRef(pkg, "t")).EndInit(1).
/****/ End().
/****/ TypeCase(0).
/****/ TypeDefaultThen().
/******/ Val(ctxRef(pkg, "bar")).VarRef(ctxRef(pkg, "t")).UnaryOp(token.AND).Call(1).EndStmt().
/****/ End().
/**/ End().
Expand Down Expand Up @@ -951,7 +951,7 @@ func TestTypeSwitch2(t *testing.T) {
pkg.NewFunc(nil, "bar", types.NewTuple(p), nil, false).BodyStart(pkg).End()
pkg.NewFunc(nil, "foo", types.NewTuple(v), nil, false).BodyStart(pkg).
/**/ TypeSwitch("").Val(ctxRef(pkg, "bar")).Val(nil).Call(1).EndStmt().Val(v).TypeAssertThen().
/****/ Typ(types.Typ[types.Int]).TypeCase(1).
/****/ TypeCase().Typ(types.Typ[types.Int]).Then().
/******/ Val(ctxRef(pkg, "bar")).VarRef(ctxRef(pkg, "v")).UnaryOp(token.AND).Call(1).EndStmt().
/****/ End().
/**/ End().
Expand Down Expand Up @@ -1261,7 +1261,7 @@ func main() {
pkg.CB().RangeAssignThen(0)
})
safeRun(t, func() {
pkg.CB().TypeCase(1)
pkg.CB().TypeCase()
})
safeRun(t, func() {
pkg.CB().CommCase()
Expand Down
76 changes: 42 additions & 34 deletions stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,17 @@ func (p *commCase) End(cb *CodeBuilder, src ast.Node) {
// ----------------------------------------------------------------------------
//
// typeSwitch(name) init; expr typeAssertThen
// type1, type2, ... typeN typeCase(N)
// typeCase type1, type2, ... typeN then
//
// ...
// end
//
// type1, type2, ... typeM typeCase(M)
// typeCase type1, type2, ... typeM then
//
// ...
// end
//
// typeDefaultThen
//
// ...
// end
Expand Down Expand Up @@ -305,11 +310,42 @@ func (p *typeSwitchStmt) TypeAssertThen(cb *CodeBuilder) {
p.x, p.xSrc, p.xType = x.Val, x.Src, xType
}

func (p *typeSwitchStmt) TypeCase(cb *CodeBuilder, n int, src ...ast.Node) {
var list []ast.Expr
func (p *typeSwitchStmt) TypeCase(cb *CodeBuilder, src ...ast.Node) {
stmt := &typeCaseStmt{p: p}
cb.startBlockStmt(stmt, src, "type case statement", &stmt.old)
}

func (p *typeSwitchStmt) End(cb *CodeBuilder, src ast.Node) {
stmts, flows := cb.endBlockStmt(&p.old)
cb.current.flows |= (flows &^ flowFlagBreak)

body := &ast.BlockStmt{List: stmts}
var assign ast.Stmt
x := &ast.TypeAssertExpr{X: p.x}
if p.name != "" {
assign = &ast.AssignStmt{
Tok: token.DEFINE,
Lhs: []ast.Expr{ident(p.name)},
Rhs: []ast.Expr{x},
}
} else {
assign = &ast.ExprStmt{X: x}
}
cb.emitStmt(&ast.TypeSwitchStmt{Init: p.init, Assign: assign, Body: body})
}

type typeCaseStmt struct {
p *typeSwitchStmt
list []ast.Expr
old codeBlockCtx
}

func (stmt *typeCaseStmt) Then(cb *CodeBuilder, src ...ast.Node) {
var typ types.Type
p := stmt.p
n := cb.stk.Len()
if n > 0 {
list = make([]ast.Expr, n)
stmt.list = make([]ast.Expr, n)
args := cb.stk.GetArgs(n)
for i, arg := range args {
typ = arg.Type
Expand All @@ -326,14 +362,10 @@ func (p *typeSwitchStmt) TypeCase(cb *CodeBuilder, n int, src ...ast.Node) {
src, pos := cb.loadExpr(arg.Src)
cb.panicCodeErrorf(pos, "%s (type %v) is not a type", src, typ)
}
list[i] = arg.Val
stmt.list[i] = arg.Val
}
cb.stk.PopN(n)
}

stmt := &typeCaseStmt{list: list}
cb.startBlockStmt(stmt, src, "type case statement", &stmt.old)

if p.name != "" {
if n != 1 { // default, or case with multi expr
typ = p.xType
Expand All @@ -343,30 +375,6 @@ func (p *typeSwitchStmt) TypeCase(cb *CodeBuilder, n int, src ...ast.Node) {
}
}

func (p *typeSwitchStmt) End(cb *CodeBuilder, src ast.Node) {
stmts, flows := cb.endBlockStmt(&p.old)
cb.current.flows |= (flows &^ flowFlagBreak)

body := &ast.BlockStmt{List: stmts}
var assign ast.Stmt
x := &ast.TypeAssertExpr{X: p.x}
if p.name != "" {
assign = &ast.AssignStmt{
Tok: token.DEFINE,
Lhs: []ast.Expr{ident(p.name)},
Rhs: []ast.Expr{x},
}
} else {
assign = &ast.ExprStmt{X: x}
}
cb.emitStmt(&ast.TypeSwitchStmt{Init: p.init, Assign: assign, Body: body})
}

type typeCaseStmt struct {
list []ast.Expr
old codeBlockCtx
}

func (p *typeCaseStmt) End(cb *CodeBuilder, src ast.Node) {
body, flows := cb.endBlockStmt(&p.old)
cb.current.flows |= flows
Expand Down

0 comments on commit 86cb196

Please sign in to comment.