c65gm/internal/preproc/definelist.go

57 lines
1.4 KiB
Go

package preproc
import (
"strings"
"unicode/utf8"
"github.com/armon/go-radix"
)
type DefineList struct {
tree *radix.Tree
}
func NewDefineList() *DefineList { return &DefineList{tree: radix.New()} }
// Add inserts or updates a define->value mapping.
func (d *DefineList) Add(define, value string) { d.tree.Insert(define, value) }
// Delete removes a define. Returns true if it existed.
func (d *DefineList) Delete(define string) bool {
_, ok := d.tree.Delete(define)
return ok
}
// Defined reports whether a define exists.
func (d *DefineList) Defined(s string) bool {
_, ok := d.tree.Get(s)
return ok
}
// typed wrapper to avoid type assertions sprinkled in hot code
func (d *DefineList) longestPrefixString(s string) (key string, val string, ok bool) {
k, v, ok := d.tree.LongestPrefix(s)
if !ok {
return "", "", false
}
return k, v.(string), true
}
// ReplaceDefines performs a single-pass, longest-prefix replacement.
// Case-sensitive. Matches anywhere. No recursive re-expansion.
func (d *DefineList) ReplaceDefines(s string) string {
var b strings.Builder
b.Grow(len(s)) // baseline; grows if expansions occur
for i := 0; i < len(s); {
if key, val, ok := d.longestPrefixString(s[i:]); ok && key != "" {
b.WriteString(val)
i += len(key) // advance by matched bytes (UTF-8-safe)
continue
}
_, size := utf8.DecodeRuneInString(s[i:])
b.WriteString(s[i : i+size])
i += size
}
return b.String()
}