File: function.go

package info (click to toggle)
golang-github-mmcloughlin-avo 0.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 15,024 kB
  • sloc: xml: 71,029; asm: 14,862; sh: 194; makefile: 21; ansic: 11
file content (177 lines) | stat: -rw-r--r-- 3,970 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package api

import (
	"bytes"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"text/tabwriter"

	"github.com/mmcloughlin/avo/internal/inst"
)

// Function represents a function that constructs some collection of
// instruction forms.
type Function struct {
	Instruction inst.Instruction
	Suffixes    inst.Suffixes
	inst.Forms
}

// Name returns the function name.
func (f *Function) Name() string {
	return f.opcodesuffix("_")
}

// Opcode returns the full Go opcode of the instruction built by this function. Includes any suffixes.
func (f *Function) Opcode() string {
	return f.opcodesuffix(".")
}

func (f *Function) opcodesuffix(sep string) string {
	n := f.Instruction.Opcode
	for _, suffix := range f.Suffixes {
		n += sep
		n += suffix.String()
	}
	return n
}

// HasSuffix reports whether the function has the provided suffix.
func (f *Function) HasSuffix(suffix inst.Suffix) bool {
	for _, s := range f.Suffixes {
		if s == suffix {
			return true
		}
	}
	return false
}

// Summary returns a summary of the instruction this function constructs.
func (f *Function) Summary() string {
	summary := f.Instruction.Summary
	if len(f.Suffixes) > 0 {
		summary += " (" + strings.Join(f.Suffixes.Summaries(), ", ") + ")"
	}
	return summary
}

// Doc returns the function document comment as a list of lines.
func (f *Function) Doc() []string {
	lines := []string{
		fmt.Sprintf("%s: %s.", f.Name(), f.Summary()),
		"",
		"Forms:",
		"",
	}

	// Write a table of instruction forms.
	buf := bytes.NewBuffer(nil)
	w := tabwriter.NewWriter(buf, 0, 0, 1, ' ', 0)
	for _, form := range f.Forms {
		row := f.Opcode() + "\t" + strings.Join(form.Signature(), "\t") + "\n"
		fmt.Fprint(w, row)
	}
	w.Flush()

	tbl := strings.TrimSpace(buf.String())
	for _, line := range strings.Split(tbl, "\n") {
		lines = append(lines, "\t"+line)
	}

	return lines
}

// Signature of the function. Derived from the instruction forms generated by this function.
func (f *Function) Signature() Signature {
	// Handle the case of forms with multiple arities.
	switch {
	case f.IsVariadic():
		return variadic{name: "ops"}
	case f.IsNiladic():
		return niladic{}
	}

	// Generate nice-looking variable names.
	n := f.Arity()
	ops := make([]string, n)
	count := map[string]int{}
	for j := 0; j < n; j++ {
		// Collect unique lowercase bytes from first characters of operand types.
		s := map[byte]bool{}
		for _, form := range f.Forms {
			c := form.Operands[j].Type[0]
			if 'a' <= c && c <= 'z' {
				s[c] = true
			}
		}

		// Operand name is the sorted bytes.
		var b []byte
		for c := range s {
			b = append(b, c)
		}
		sort.Slice(b, func(i, j int) bool { return b[i] < b[j] })
		name := string(b)

		// Append a counter if we've seen it already.
		m := count[name]
		count[name]++
		if m > 0 {
			name += strconv.Itoa(m)
		}
		ops[j] = name
	}

	return argslist(ops)
}

// InstructionFunctions builds the list of all functions for a given
// instruction.
func InstructionFunctions(i inst.Instruction) []*Function {
	// One function for each possible suffix combination.
	bysuffix := map[string]*Function{}
	for _, f := range i.Forms {
		for _, suffixes := range f.SupportedSuffixes() {
			k := suffixes.String()
			if _, ok := bysuffix[k]; !ok {
				bysuffix[k] = &Function{
					Instruction: i,
					Suffixes:    suffixes,
				}
			}
			bysuffix[k].Forms = append(bysuffix[k].Forms, f)
		}
	}

	// Convert to a sorted slice.
	var fns []*Function
	for _, fn := range bysuffix {
		fns = append(fns, fn)
	}

	SortFunctions(fns)

	return fns
}

// InstructionsFunctions builds all functions for a list of instructions.
func InstructionsFunctions(is []inst.Instruction) []*Function {
	var all []*Function
	for _, i := range is {
		fns := InstructionFunctions(i)
		all = append(all, fns...)
	}

	SortFunctions(all)

	return all
}

// SortFunctions sorts a list of functions by name.
func SortFunctions(fns []*Function) {
	sort.Slice(fns, func(i, j int) bool {
		return fns[i].Name() < fns[j].Name()
	})
}