Added a trie based Definelist for the coming preprocessor.

This commit is contained in:
Mattias Hansson 2025-10-10 20:14:01 +02:00
parent 54f252298c
commit 67703597b2
5 changed files with 126 additions and 0 deletions

31
.gitignore vendored Normal file
View file

@ -0,0 +1,31 @@
# Binaries
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
# Build output
bin/
build/
dist/
# Go workspace
*.out
# Dependency directories (if any)
vendor/
# Go coverage files
coverage.out
# IDE: GoLand / IntelliJ IDEA
.idea/
*.iml
out/
# Logs and temp files
*.log
*.tmp
.DS_Store

5
go.mod Normal file
View file

@ -0,0 +1,5 @@
module c65gm
go 1.25.1
require github.com/armon/go-radix v1.0.0 // indirect

2
go.sum Normal file
View file

@ -0,0 +1,2 @@
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=

View file

@ -0,0 +1,57 @@
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()
}

31
main.go Normal file
View file

@ -0,0 +1,31 @@
package main
import (
"c65gm/internal/preproc"
"fmt"
)
// put the DefineList type in another file (same package) or import it;
// here I assume definelist.go is in its own package "definelist".
// If it's in the same package main, just call New() directly.
func main() {
defs := preproc.NewDefineList() // <-- important
defs.Add("ARRAY_MIN", "0")
defs.Add("ARRAY_MAX", "100")
defs.Add("ARRAY_MAX_PAX", "1000")
defs.Add("VERSION", "1.0")
defs.Add("π", "3.14159")
src := `for i := ARRAY_MIN to ARRAY_MAX_PAX do
writeln(VERSION);
writeln(ARRAY_MAX);
const PI = π;`
fmt.Println("Original:\n" + src)
fmt.Println("\nReplaced:\n" + defs.ReplaceDefines(src))
defs.Delete("ARRAY_MAX_PAX")
fmt.Println("\nReplaced (after .Delete):\n" + defs.ReplaceDefines(src))
}