// Package main is a code generator that creates functions of different size.
package main

import (
	"fmt"
	"os"
)

//go:generate go run .

func main() {
	if err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run() error {
	file, err := os.Create("generated.go")
	if err != nil {
		return err
	}
	defer file.Close()

	fmt.Fprint(file, `// Code generated by go generate; DO NOT EDIT.

package main

//go:noinline
func stackdepth1(fn func()) { fn() }
`)

	max := 1024
	for i := 2; i <= max; i++ {
		fmt.Fprintf(
			file,
			"//go:noinline\nfunc stackdepth%d(fn func()) { stackdepth%d(fn) }\n",
			i,
			i-1,
		)
	}

	fmt.Fprint(file, "\nvar stackdepth = map[int]func(func()) {\n")
	for i := 1; i <= max; i++ {
		fmt.Fprintf(file, "\t%d: stackdepth%d,\n", i, i)
	}
	fmt.Fprint(file, "}\n")

	// Disabled: Turned out to be a deadend
	//for i := 1; i <= max; i *= 2 {
	//fmt.Fprintf(file, "//go:noinline\n")
	//fmt.Fprintf(file, "func funcsize%d(v0, n int, fn func()) int {\n", i)
	//for n := 1; n <= i; n++ {
	//fmt.Fprintf(file, "\tv%d := v%d\n", n, n-1)
	//fmt.Fprintf(file, "\tv%d = (^v%d + %d)\n", n, n, n)
	//fmt.Fprintf(file, "\tif v%d == 23 {\n", n)
	//sum := []string{}
	//for j := 0; j <= n; j++ {
	//sum = append(sum, fmt.Sprintf("v%d", j))
	//}
	//fmt.Fprintf(file, "\t\treturn %s\n", strings.Join(sum, " + "))
	//fmt.Fprintf(file, "\t}\n")
	//}
	//fmt.Fprintf(file, "\tfn()\n")
	//fmt.Fprintf(file, "\treturn -1\n")
	//fmt.Fprintf(file, "}\n\n")
	//}

	//fmt.Fprint(file, "\nvar funcsize = map[int]func(int, int, func()) int {\n")
	//for i := 1; i <= max; i *= 2 {
	//fmt.Fprintf(file, "\t%d: funcsize%d,\n", i, i)
	//}
	//fmt.Fprint(file, "}\n")

	return file.Close()
}
