func (c *funcContext) translateLoopingStmt(cond func() string, body *ast.BlockStmt, bodyPrefix, post func(), label *types.Label, flatten bool) { prevFlowData := c.flowDatas[nil] data := &flowData{ postStmt: post, } if flatten { data.beginCase = c.caseCounter data.endCase = c.caseCounter + 1 c.caseCounter += 2 } c.flowDatas[nil] = data c.flowDatas[label] = data defer func() { delete(c.flowDatas, label) c.flowDatas[nil] = prevFlowData }() if !flatten && label != nil { c.Printf("%s:", label.Name()) } c.PrintCond(!flatten, "while (true) {", fmt.Sprintf("case %d:", data.beginCase)) c.Indent(func() { condStr := cond() if condStr != "true" { c.PrintCond(!flatten, fmt.Sprintf("if (!(%s)) { break; }", condStr), fmt.Sprintf("if(!(%s)) { $s = %d; continue; }", condStr, data.endCase)) } prevEV := c.p.escapingVars c.handleEscapingVars(body) if bodyPrefix != nil { bodyPrefix() } c.translateStmtList(body.List) isTerminated := false if len(body.List) != 0 { switch body.List[len(body.List)-1].(type) { case *ast.ReturnStmt, *ast.BranchStmt: isTerminated = true } } if !isTerminated { post() } c.p.escapingVars = prevEV }) c.PrintCond(!flatten, "}", fmt.Sprintf("$s = %d; continue; case %d:", data.beginCase, data.endCase)) }
func (r *renamer) checkLabel(label *types.Label) { // Check there are no identical labels in the function's label block. // (Label blocks don't nest, so this is easy.) if prev := label.Parent().Lookup(r.to); prev != nil { r.errorf(label.Pos(), "renaming this label %q to %q", label.Name(), prev.Name()) r.errorf(prev.Pos(), "\twould conflict with this one") } }
func (c *funcContext) translateBranchingStmt(caseClauses []ast.Stmt, isSwitch bool, translateCond func(ast.Expr) *expression, printCaseBodyPrefix func(int), label *types.Label, flatten bool) { var branches []*branch var defaultBranch *branch var openBranches []*branch clauseLoop: for i, cc := range caseClauses { clause := cc.(*ast.CaseClause) branch := &branch{index: i, clause: clause} openBranches = append(openBranches, branch) for _, openBranch := range openBranches { openBranch.body = append(openBranch.body, clause.Body...) } if !hasFallthrough(clause) { openBranches = nil } if len(clause.List) == 0 { defaultBranch = branch continue } for _, cond := range clause.List { if translateCond == nil { if b, ok := analysis.BoolValue(cond, c.p.Info.Info); ok { if b { defaultBranch = branch break clauseLoop } continue } } branch.conds = append(branch.conds, cond) } if len(branch.conds) == 0 { continue } branches = append(branches, branch) } for defaultBranch == nil && len(branches) != 0 && len(branches[len(branches)-1].body) == 0 { branches = branches[:len(branches)-1] } if len(branches) == 0 { if defaultBranch != nil { c.translateStmtList(defaultBranch.body) return } return } hasBreak := false if isSwitch { switch label { case nil: for _, child := range caseClauses { if analysis.HasBreak(child) { hasBreak = true break } } default: hasBreak = true // always assume break if label is given } } var caseOffset, endCase int if flatten { caseOffset = c.caseCounter endCase = caseOffset + len(branches) if defaultBranch != nil { endCase++ } c.caseCounter = endCase + 1 } if isSwitch { prevFlowData := c.flowDatas[nil] data := &flowData{ postStmt: prevFlowData.postStmt, // for "continue" of outer loop beginCase: prevFlowData.beginCase, // same endCase: endCase, } c.flowDatas[nil] = data c.flowDatas[label] = data defer func() { delete(c.flowDatas, label) c.flowDatas[nil] = prevFlowData }() } if isSwitch && !flatten && label != nil { c.Printf("%s:", label.Name()) } prefix := "" if hasBreak { prefix = "switch (0) { default: " } for i, b := range branches { conds := make([]string, len(b.conds)) for i, cond := range b.conds { if translateCond == nil { conds[i] = c.translateExpr(cond).String() continue } conds[i] = translateCond(cond).String() } b.condStr = strings.Join(conds, " || ") if flatten { c.Printf("/* */ if (%s) { $s = %d; continue; }", b.condStr, caseOffset+i) } } if flatten { c.Printf("/* */ $s = %d; continue;", caseOffset+len(branches)) } for i, b := range branches { c.SetPos(b.clause.Pos()) c.PrintCond(!flatten, fmt.Sprintf("%sif (%s) {", prefix, b.condStr), fmt.Sprintf("case %d:", caseOffset+i)) c.Indent(func() { if printCaseBodyPrefix != nil { printCaseBodyPrefix(b.index) } c.translateStmtList(b.body) if flatten && (defaultBranch != nil || i != len(branches)-1) { c.Printf("$s = %d; continue;", endCase) } }) prefix = "} else " } if defaultBranch != nil { c.PrintCond(!flatten, "} else {", fmt.Sprintf("case %d:", caseOffset+len(branches))) c.Indent(func() { if printCaseBodyPrefix != nil { printCaseBodyPrefix(defaultBranch.index) } c.translateStmtList(defaultBranch.body) }) } if hasBreak { c.PrintCond(!flatten, "} }", fmt.Sprintf("case %d:", endCase)) return } c.PrintCond(!flatten, "}", fmt.Sprintf("case %d:", endCase)) }