Skip to content

Commit 5b21361

Browse files
erudenkoclaude
andcommitted
refactor(naming): Implement no-number-first variable naming convention
Changes all code generators to use idiomatic Go naming pattern where the first occurrence of a temporary variable has no number suffix, with subsequent occurrences numbered starting at 1. Pattern: - First: tmp, err, coalesce (no number) - Second: tmp1, err1, coalesce1 - Third: tmp2, err2, coalesce2 Changes: - error_prop.go: tmp/err generation logic updated - null_coalesce.go: coalesce variable naming updated, counter init fixed - safe_nav.go: Counter init fixed, camelCase for pointer mode (userTmp vs __user_tmp0) - plugin.go: NextTempVar() updated for no-number-first - CLAUDE.md: Documentation updated with new convention - All golden test files regenerated (17 files) This prevents the old pattern (tmp1, tmp2, tmp3) and zero-based pattern (tmp0, tmp1). Generated code now looks more hand-written and idiomatic. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 74dc60a commit 5b21361

22 files changed

Lines changed: 241 additions & 183 deletions

CLAUDE.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,22 +267,24 @@ See `ai-docs/claude-research.md` and `ai-docs/gemini_research.md` for details:
267267
All code generators MUST follow these naming rules:
268268

269269
1. **No Underscores - Use camelCase**
270-
- ✅ Correct: `tmp1`, `err1`, `coalesce1`
270+
- ✅ Correct: `tmp`, `tmp1`, `err`, `err1`, `coalesce`
271271
- ❌ Wrong: `__tmp0`, `__err0`, `__coalesce0`
272272

273-
2. **One-Based Indexing - Start at 1**
274-
- ✅ Correct: `tmp1`, `tmp2`, `tmp3`
275-
- ❌ Wrong: `tmp0`, `tmp1`, `tmp2`
273+
2. **No-Number-First Pattern**
274+
- ✅ Correct: First `tmp`, then `tmp1`, `tmp2`
275+
- ✅ Correct: First `err`, then `err1`, `err2`
276+
- ❌ Wrong: `tmp1`, `tmp2`, `tmp3` (all numbered)
277+
- ❌ Wrong: `tmp0`, `tmp1`, `tmp2` (zero-based)
276278

277279
3. **Counter Initialization**
278280
- ✅ Correct: `counter = 1` or `counter := 1`
279281
- ❌ Wrong: `counter = 0` or `counter := 0`
280282

281283
**Affected Components:**
282-
- `pkg/preprocessor/error_prop.go` - Error propagation (`tmp1`, `err1`)
283-
- `pkg/preprocessor/null_coalesce.go` - Null coalescing (`coalesce1`, `coalesce2`)
284-
- `pkg/preprocessor/safe_nav.go` - Safe navigation (`val1`, `val2`)
285-
- `pkg/plugin/plugin.go` - Plugin temp vars (`tmp1`, `tmp2`)
284+
- `pkg/preprocessor/error_prop.go` - Error propagation (`tmp`, `err``tmp1`, `err1`)
285+
- `pkg/preprocessor/null_coalesce.go` - Null coalescing (`coalesce``coalesce1`)
286+
- `pkg/preprocessor/safe_nav.go` - Safe navigation (`user``user1`, `__user_tmp``__user_tmp1`)
287+
- `pkg/plugin/plugin.go` - Plugin temp vars (`tmp``tmp1`)
286288

287289
**Rationale:**
288290
- Go convention: camelCase for local variables

pkg/plugin/plugin.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,15 @@ func (ctx *Context) NextTempVar() string {
243243
if ctx.TempVarCounter == 0 {
244244
ctx.TempVarCounter = 1
245245
}
246-
varName := fmt.Sprintf("tmp%d", ctx.TempVarCounter)
246+
247+
// No-number-first pattern: first tmp has no number, then tmp1, tmp2, etc.
248+
varName := ""
249+
if ctx.TempVarCounter == 1 {
250+
varName = "tmp"
251+
} else {
252+
varName = fmt.Sprintf("tmp%d", ctx.TempVarCounter-1)
253+
}
254+
247255
ctx.TempVarCounter++
248256
return varName
249257
}

pkg/preprocessor/error_prop.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ func (it *ImportTracker) GetNeededImports() []string {
122122
//
123123
// Example Expansion:
124124
// Dingo: let x = ReadFile(path)?
125-
// Go: tmp1, err1 := ReadFile(path)
125+
// Go (first): tmp, err := ReadFile(path)
126+
// Go (second): tmp1, err1 := AnotherCall()
126127
// // dingo:s:1
127128
// if err1 != nil {
128129
// return nil, err1
@@ -336,8 +337,20 @@ func (e *ErrorPropProcessor) expandAssignment(matches []string, expr string, err
336337
// Track function call for import detection
337338
e.trackFunctionCallInExpr(exprClean)
338339

339-
tmpVar := fmt.Sprintf("tmp%d", e.tryCounter)
340-
errVar := fmt.Sprintf("err%d", e.tryCounter)
340+
// No-number-first pattern: first occurrence has no number
341+
tmpVar := ""
342+
if e.tryCounter == 1 {
343+
tmpVar = "tmp"
344+
} else {
345+
tmpVar = fmt.Sprintf("tmp%d", e.tryCounter-1)
346+
}
347+
348+
errVar := ""
349+
if e.tryCounter == 1 {
350+
errVar = "err"
351+
} else {
352+
errVar = fmt.Sprintf("err%d", e.tryCounter-1)
353+
}
341354
e.tryCounter++
342355

343356
// Calculate exact position of ? operator for accurate source mapping
@@ -519,15 +532,26 @@ func (e *ErrorPropProcessor) expandReturn(matches []string, expr string, errMsg
519532
}
520533

521534
// Generate temporary variable names for all non-error values
522-
// For multi-value returns, use sequential counters: tmp1, tmp2, tmp3, ...
523-
// CRITICAL FIX: Use base counter for error variable, then increment once for all vars
535+
// No-number-first pattern: first tmp/err has no number, then tmp1/err1, tmp2/err2, etc.
524536
baseCounter := e.tryCounter
525537
tmpVars := []string{}
526538
for i := 0; i < numNonErrorReturns; i++ {
527-
tmpVars = append(tmpVars, fmt.Sprintf("tmp%d", baseCounter))
539+
var tmpVar string
540+
if baseCounter == 1 {
541+
tmpVar = "tmp"
542+
} else {
543+
tmpVar = fmt.Sprintf("tmp%d", baseCounter-1)
544+
}
545+
tmpVars = append(tmpVars, tmpVar)
528546
baseCounter++
529547
}
530-
errVar := fmt.Sprintf("err%d", e.tryCounter)
548+
549+
var errVar string
550+
if e.tryCounter == 1 {
551+
errVar = "err"
552+
} else {
553+
errVar = fmt.Sprintf("err%d", e.tryCounter-1)
554+
}
531555
e.tryCounter++
532556

533557
// Calculate exact position of ? operator for accurate source mapping

pkg/preprocessor/null_coalesce.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const (
2929
func NewNullCoalesceProcessor() *NullCoalesceProcessor {
3030
return &NullCoalesceProcessor{
3131
typeDetector: NewTypeDetector(),
32-
tmpCounter: 0,
32+
tmpCounter: 1,
3333
mappings: []Mapping{},
3434
}
3535
}
@@ -660,7 +660,13 @@ func (n *NullCoalesceProcessor) generateIIFE(chain []string, leftType TypeKind,
660660

661661
if i == 0 {
662662
// First operand: evaluate once and check
663-
tmpVar := fmt.Sprintf("coalesce%d", n.tmpCounter)
663+
// No-number-first pattern
664+
tmpVar := ""
665+
if n.tmpCounter == 1 {
666+
tmpVar = "coalesce"
667+
} else {
668+
tmpVar = fmt.Sprintf("coalesce%d", n.tmpCounter-1)
669+
}
664670
n.tmpCounter++
665671

666672
buf.WriteString(fmt.Sprintf("%s := %s; ", tmpVar, operand))
@@ -679,7 +685,13 @@ func (n *NullCoalesceProcessor) generateIIFE(chain []string, leftType TypeKind,
679685
}
680686
} else {
681687
// Subsequent operands in chain: evaluate and check
682-
tmpVar := fmt.Sprintf("coalesce%d", n.tmpCounter)
688+
// No-number-first pattern
689+
tmpVar := ""
690+
if n.tmpCounter == 1 {
691+
tmpVar = "coalesce"
692+
} else {
693+
tmpVar = fmt.Sprintf("coalesce%d", n.tmpCounter-1)
694+
}
683695
n.tmpCounter++
684696

685697
buf.WriteString(fmt.Sprintf("%s := %s; ", tmpVar, operand))

pkg/preprocessor/safe_nav.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func classifyType(typeName string) TypeKind {
170170
func NewSafeNavProcessor() *SafeNavProcessor {
171171
return &SafeNavProcessor{
172172
typeDetector: NewTypeDetector(),
173-
tmpCounter: 0,
173+
tmpCounter: 1,
174174
mappings: []Mapping{},
175175
}
176176
}
@@ -743,7 +743,13 @@ func (s *SafeNavProcessor) generateOptionMode(base string, elements []ChainEleme
743743
outputLinesGenerated += 3
744744

745745
// Unwrap to get the value
746-
tmpVar := fmt.Sprintf("%s%d", base, s.tmpCounter)
746+
// No-number-first pattern
747+
tmpVar := ""
748+
if s.tmpCounter == 1 {
749+
tmpVar = base
750+
} else {
751+
tmpVar = fmt.Sprintf("%s%d", base, s.tmpCounter-1)
752+
}
747753
s.tmpCounter++
748754
buf.WriteString(fmt.Sprintf("\t%s := %s.Unwrap()\n", tmpVar, currentVar))
749755
outputLinesGenerated++
@@ -809,7 +815,13 @@ func (s *SafeNavProcessor) generatePointerMode(base string, elements []ChainElem
809815
// Access the property or method
810816
if i < len(elements)-1 {
811817
// Not the last element - create intermediate variable to check next nil
812-
tmpVar := fmt.Sprintf("__%s_tmp%d", base, i)
818+
// CamelCase pattern without underscores
819+
var tmpVar string
820+
if i == 0 {
821+
tmpVar = base + "Tmp"
822+
} else {
823+
tmpVar = fmt.Sprintf("%sTmp%d", base, i)
824+
}
813825
if elem.IsMethod {
814826
buf.WriteString(fmt.Sprintf("\t%s := %s.%s(%s)\n", tmpVar, currentVar, elem.Name, elem.RawArgs))
815827
} else {

tests/golden/error_prop_01_simple.go.golden

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ import (
55
)
66

77
func readConfig(path string) ([]byte, error) {
8-
tmp1, err1 := os.ReadFile(path)
8+
tmp, err := os.ReadFile(path)
99

10-
if err1 != nil {
11-
return nil, err1
10+
if err != nil {
11+
return nil, err
1212
}
1313
// dingo:e:1
14-
var data = tmp1
14+
var data = tmp
1515
return data, nil
1616

1717
}

tests/golden/error_prop_03_expression.go.golden

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import (
55
)
66

77
func parseInt(s string) (int, error) {
8-
tmp1, err1 := strconv.Atoi(s)
8+
tmp, err := strconv.Atoi(s)
99

10-
if err1 != nil {
11-
return 0, err1
10+
if err != nil {
11+
return 0, err
1212
}
1313

14-
return tmp1, nil
14+
return tmp, nil
1515
}

tests/golden/error_prop_04_wrapping.go.golden

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import (
77

88
func readUserConfig(username string) ([]byte, error) {
99
path := "/home/" + username + "/config.json"
10-
tmp1, err1 := os.ReadFile(path)
10+
tmp, err := os.ReadFile(path)
1111

12-
if err1 != nil {
13-
return nil, fmt.Errorf("failed to read user config: %w", err1)
12+
if err != nil {
13+
return nil, fmt.Errorf("failed to read user config: %w", err)
1414
}
1515
// dingo:e:1
16-
var data = tmp1
16+
var data = tmp
1717
return data, nil
1818
}

tests/golden/error_prop_05_complex_types.go.golden

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ type User struct {
1010
}
1111

1212
func fetchUser(id int) (*User, error) {
13-
tmp1, err1 := os.ReadFile("user.json")
13+
tmp, err := os.ReadFile("user.json")
1414

15-
if err1 != nil {
16-
return nil, err1
15+
if err != nil {
16+
return nil, err
1717
}
1818
// dingo:e:1
19-
var data = tmp1
19+
var data = tmp
2020
return &User{ID: id, Name: string(data)}, nil
2121
}
2222
func getNames() ([]string, error) {
23-
tmp1, err1 := os.ReadFile("names.txt")
23+
tmp, err := os.ReadFile("names.txt")
2424

25-
if err1 != nil {
26-
return nil, err1
25+
if err != nil {
26+
return nil, err
2727
}
2828
// dingo:e:1
29-
var data = tmp1
29+
var data = tmp
3030
return []string{string(data)}, nil
3131
}

tests/golden/error_prop_06_mixed_context.go.golden

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@ import (
66
)
77

88
func processData(path string) (int, error) {
9-
tmp1, err1 := os.ReadFile(path)
9+
tmp, err := os.ReadFile(path)
1010

11-
if err1 != nil {
12-
return 0, err1
11+
if err != nil {
12+
return 0, err
1313
}
1414
// dingo:e:1
15-
var data = tmp1
16-
tmp2, err2 := strconv.Atoi(string(data))
15+
var data = tmp
16+
tmp1, err1 := strconv.Atoi(string(data))
1717

18-
if err2 != nil {
19-
return 0, err2
18+
if err1 != nil {
19+
return 0, err1
2020
}
2121

22-
return tmp2, nil
22+
return tmp1, nil
2323
}

0 commit comments

Comments
 (0)