internal/rosa/azalea: package special case
All checks were successful
Test / Create distribution (push) Successful in 1m14s
Test / Sandbox (push) Successful in 2m51s
Test / ShareFS (push) Successful in 3m42s
Test / Hakurei (push) Successful in 3m49s
Test / Sandbox (race detector) (push) Successful in 5m23s
Test / Hakurei (race detector) (push) Successful in 6m33s
Test / Flake checks (push) Successful in 1m21s

This is more efficient for the inputs array and packages in general.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-05-17 23:44:00 +09:00
parent 99b324fb17
commit f24ae21af1
2 changed files with 130 additions and 93 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"maps" "maps"
"reflect" "reflect"
"slices"
"unique" "unique"
) )
@@ -23,9 +24,12 @@ type (
// FArgs are arguments passed to [F]. // FArgs are arguments passed to [F].
FArgs []FArg FArgs []FArg
// PF implements the package declaration function.
PF func(name Ident, args FArgs) (v any, set bool, err error)
// F is the implementation of a [Func]. // F is the implementation of a [Func].
F struct { F struct {
F func(isPackage bool, args FArgs) (v any, set bool, err error) F func(args FArgs) (v any, set bool, err error)
V map[unique.Handle[Ident]]any V map[unique.Handle[Ident]]any
} }
) )
@@ -77,8 +81,8 @@ func (e UndefinedError) Error() string {
} }
// evaluate is evaluateAny with a type parameter. // evaluate is evaluateAny with a type parameter.
func evaluate[T Value](s []Frame, expr any, rp *T) bool { func evaluate[T Value](d PF, s []Frame, expr any, rp *T) bool {
return evaluateAny(s, expr, rp) return evaluateAny(d, s, expr, rp)
} }
// TypeError is an unexpected type during evaluation. // TypeError is an unexpected type during evaluation.
@@ -132,8 +136,18 @@ func (e EvaluationError) Error() string {
return fmt.Sprintf("expression %#v: %v", e.Expr, e.Err) return fmt.Sprintf("expression %#v: %v", e.Expr, e.Err)
} }
var (
// IdentInputs is a special array argument in a package declaration whose
// values of [Ident] are kept as is when passed to a [PF].
IdentInputs = unique.Make(Ident("inputs"))
// ErrInvalidInputs is panicked for an [IdentInputs] argument to [PF]
// sharing its value or set for R.
ErrInvalidInputs = errors.New("inputs must not be common or bound to scope")
)
// evaluateAny implements [Evaluate]. // evaluateAny implements [Evaluate].
func evaluateAny(s []Frame, expr, rp any) bool { func evaluateAny(d PF, s []Frame, expr, rp any) bool {
defer func() { defer func() {
r := recover() r := recover()
if r == nil { if r == nil {
@@ -193,17 +207,17 @@ func evaluateAny(s []Frame, expr, rp any) bool {
store(rp, false) store(rp, false)
return true return true
default: default:
return evaluateAny(s, v, rp) return evaluateAny(d, s, v, rp)
} }
default: default:
return evaluateAny(s, e[0], rp) return evaluateAny(d, s, e[0], rp)
} }
} }
var v string var v string
for i := range e { for i := range e {
var _r string var _r string
if evaluate(s, e[i], &_r) { if evaluate(d, s, e[i], &_r) {
v += _r v += _r
} }
} }
@@ -214,7 +228,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
r := make([]string, 0, len(e)) r := make([]string, 0, len(e))
for i := range e { for i := range e {
var _r string var _r string
if evaluate(s, e[i], &_r) { if evaluate(d, s, e[i], &_r) {
r = append(r, _r) r = append(r, _r)
} }
} }
@@ -225,7 +239,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
r := make([][2]string, 0, len(e)) r := make([][2]string, 0, len(e))
for i := range e { for i := range e {
var _r string var _r string
if e[i].V == nil || evaluate(s, e[i].V, &_r) { if e[i].V == nil || evaluate(d, s, e[i].V, &_r) {
r = append(r, [2]string{string(e[i].K), _r}) r = append(r, [2]string{string(e[i].K), _r})
} }
} }
@@ -237,14 +251,16 @@ func evaluateAny(s []Frame, expr, rp any) bool {
f F f F
ok bool ok bool
) )
for i := range s { if !e.Package {
f, ok = s[len(s)-1-i].Func[unique.Make(e.Ident)] for i := range s {
if ok { f, ok = s[len(s)-1-i].Func[unique.Make(e.Ident)]
break if ok {
break
}
}
if !ok {
panic(UndefinedError(e.Ident))
} }
}
if !ok {
panic(UndefinedError(e.Ident))
} }
argc := len(e.Args) argc := len(e.Args)
@@ -252,29 +268,56 @@ func evaluateAny(s []Frame, expr, rp any) bool {
argc += len(arg.K) - 1 argc += len(arg.K) - 1
} }
fargs := make([]FArg, 0, len(e.Args)) fargs := make([]FArg, 0, len(e.Args))
s = append(s, Frame{Val: maps.Clone(f.V)}) s = append(s, Frame{})
fp := &s[len(s)-1] fp := &s[len(s)-1]
if !e.Package {
fp.Val = maps.Clone(f.V)
}
for _, arg := range e.Args { for _, arg := range e.Args {
names := make([]unique.Handle[Ident], len(arg.K))
for i, name := range arg.K {
names[i] = unique.Make(name)
}
farg := FArg{R: arg.R} farg := FArg{R: arg.R}
if !evaluateAny(s, arg.V, &farg.V) { if e.Package && slices.Contains(names, IdentInputs) {
if len(names) != 1 || len(arg.V) != 1 || arg.R {
panic(ErrInvalidInputs)
}
farg.K = names[0]
if err := storeE(&farg.V, arg.V[0]); err != nil {
panic(err)
}
fargs = append(fargs, farg)
continue
}
if !evaluateAny(d, s, arg.V, &farg.V) {
farg.V = nil farg.V = nil
} }
for _, name := range arg.K { for _, name := range names {
h := unique.Make(name) farg.K = name
farg.K = h
fargs = append(fargs, farg) fargs = append(fargs, farg)
if arg.R && farg.V != nil { if arg.R && farg.V != nil {
if fp.Val == nil { if fp.Val == nil {
fp.Val = make(map[unique.Handle[Ident]]any) fp.Val = make(map[unique.Handle[Ident]]any)
} }
(*fp).Val[h] = farg.V (*fp).Val[name] = farg.V
} }
} }
} }
v, set, err := f.F(e.Package, fargs) var (
v any
err error
)
if !e.Package {
v, ok, err = f.F(fargs)
} else {
v, ok, err = d(e.Ident, fargs)
}
if err != nil { if err != nil {
panic(err) panic(err)
} else if v != nil { } else if v != nil {
@@ -282,7 +325,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
panic(err) panic(err)
} }
} }
return set return ok
default: default:
panic(UnsupportedExprError{expr}) panic(UnsupportedExprError{expr})
@@ -290,7 +333,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
} }
// Evaluate evaluates a statement and returns its value. // Evaluate evaluates a statement and returns its value.
func Evaluate[T Value](s []Frame, expr any) (v T, set bool, err error) { func Evaluate[T Value](d PF, s []Frame, expr any) (v T, set bool, err error) {
defer func() { defer func() {
r := recover() r := recover()
if r == nil { if r == nil {
@@ -303,6 +346,6 @@ func Evaluate[T Value](s []Frame, expr any) (v T, set bool, err error) {
} }
err = _err err = _err
}() }()
set = evaluate[T](s, expr, &v) set = evaluate[T](d, s, expr, &v)
return return
} }

View File

@@ -16,14 +16,10 @@ import (
func makeStackCheck(check func(args FArgs) (any, error)) []Frame { func makeStackCheck(check func(args FArgs) (any, error)) []Frame {
return []Frame{{Func: map[unique.Handle[Ident]]F{ return []Frame{{Func: map[unique.Handle[Ident]]F{
unique.Make(Ident("f")): {F: func( unique.Make(Ident("f")): {F: func(
isPackage bool,
args FArgs, args FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
set = true set = true
v, err = check(args) v, err = check(args)
if isPackage {
err = errors.New("unexpected package")
}
return return
}}, }},
}}} }}}
@@ -101,6 +97,45 @@ func TestEvaluate(t *testing.T) {
Expr: Ident("nil"), Expr: Ident("nil"),
Err: UndefinedError("nil"), Err: UndefinedError("nil"),
}}, }},
{"common inputs", `package name { inputs, v = []; }`, nil, "", EvaluationError{
Expr: Func{
Ident: Ident("name"),
Package: true,
Args: []Arg{
{K: []Ident{
"inputs",
"v",
}, V: Val{Array(nil)}},
},
},
Err: ErrInvalidInputs,
}},
{"bound inputs", `package name { inputs* = []; }`, nil, "", EvaluationError{
Expr: Func{
Ident: Ident("name"),
Package: true,
Args: []Arg{
{K: []Ident{"inputs"}, V: Val{Array(nil)}, R: true},
},
},
Err: ErrInvalidInputs,
}},
{"concat inputs", `package name { inputs = ""+""; }`, nil, "", EvaluationError{
Expr: Func{
Ident: Ident("name"),
Package: true,
Args: []Arg{
{K: []Ident{"inputs"}, V: Val{String(""), String("")}},
},
},
Err: ErrInvalidInputs,
}},
} }
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
@@ -114,7 +149,7 @@ func TestEvaluate(t *testing.T) {
} else { } else {
expr = e[0].(Func) expr = e[0].(Func)
} }
r, set, err := Evaluate[string](tc.s, expr) r, set, err := Evaluate[string](nil, tc.s, expr)
if set != (err == nil) { if set != (err == nil) {
t.Error("Evaluate: unexpected unset") t.Error("Evaluate: unexpected unset")
} }
@@ -147,36 +182,19 @@ func TestEvaluateGCC(t *testing.T) {
} }
var got [3]FArgs var got [3]FArgs
if r, set, err := Evaluate[string]([]Frame{{ if r, set, err := Evaluate[string](func(
name Ident,
args FArgs,
) (v any, set bool, err error) {
v = "\x00"
set = true
got[0] = args
return
}, []Frame{{
Func: map[unique.Handle[Ident]]F{ Func: map[unique.Handle[Ident]]F{
unique.Make(Ident("gcc")): {F: func(
isPackage bool,
args FArgs,
) (v any, set bool, err error) {
v = "\x00"
if !isPackage {
err = errors.New("not a package")
}
set = true
got[0] = args
return
}, V: map[unique.Handle[Ident]]any{
unique.Make(Ident("binutils")): "binutils",
unique.Make(Ident("mpc")): "mpc",
unique.Make(Ident("zlib")): "zlib",
unique.Make(Ident("libucontext")): "libucontext",
unique.Make(Ident("kernel-headers")): "kernel-headers",
}},
unique.Make(Ident("remoteTar")): {F: func( unique.Make(Ident("remoteTar")): {F: func(
isPackage bool,
args FArgs, args FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
if isPackage {
err = errors.New("unexpected package")
return
}
var url, checksum string var url, checksum string
var compress int var compress int
if err = args.Apply(map[unique.Handle[Ident]]any{ if err = args.Apply(map[unique.Handle[Ident]]any{
@@ -198,37 +216,25 @@ func TestEvaluateGCC(t *testing.T) {
}}, }},
unique.Make(Ident("make")): {F: func( unique.Make(Ident("make")): {F: func(
isPackage bool,
args FArgs, args FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
v = args v = args
if isPackage {
err = errors.New("unexpected package")
}
set = true set = true
return return
}}, }},
unique.Make(Ident("arch")): {F: func( unique.Make(Ident("arch")): {F: func(
isPackage bool,
args FArgs, args FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
set = false set = false
if isPackage {
err = errors.New("unexpected package")
}
got[1] = args got[1] = args
return return
}}, }},
unique.Make(Ident("noop")): {F: func( unique.Make(Ident("noop")): {F: func(
isPackage bool,
args FArgs, args FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
set = false set = false
if isPackage {
err = errors.New("unexpected package")
}
set = true set = true
got[2] = args got[2] = args
return return
@@ -274,12 +280,12 @@ func TestEvaluateGCC(t *testing.T) {
{K: unique.Make(Ident("skip-check")), V: true}, {K: unique.Make(Ident("skip-check")), V: true},
}}, }},
{K: unique.Make(Ident("inputs")), V: []string{ {K: unique.Make(Ident("inputs")), V: Array{
"binutils", {Ident("binutils")},
"mpc", {Ident("mpc")},
"zlib", {Ident("zlib")},
"libucontext", {Ident("libucontext")},
"kernel-headers", {Ident("kernel-headers")},
}}, }},
}, },
{ {
@@ -304,21 +310,7 @@ func BenchmarkEvaluate(b *testing.B) {
s := []Frame{{ s := []Frame{{
Func: map[unique.Handle[Ident]]F{ Func: map[unique.Handle[Ident]]F{
unique.Make(Ident("gcc")): {F: func(
bool,
FArgs,
) (v any, set bool, err error) {
return
}, V: map[unique.Handle[Ident]]any{
unique.Make(Ident("binutils")): "binutils",
unique.Make(Ident("mpc")): "mpc",
unique.Make(Ident("zlib")): "zlib",
unique.Make(Ident("libucontext")): "libucontext",
unique.Make(Ident("kernel-headers")): "kernel-headers",
}},
unique.Make(Ident("remoteTar")): {F: func( unique.Make(Ident("remoteTar")): {F: func(
bool,
FArgs, FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
return return
@@ -327,21 +319,18 @@ func BenchmarkEvaluate(b *testing.B) {
}}, }},
unique.Make(Ident("make")): {F: func( unique.Make(Ident("make")): {F: func(
bool,
FArgs, FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
return return
}}, }},
unique.Make(Ident("arch")): {F: func( unique.Make(Ident("arch")): {F: func(
bool,
FArgs, FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
return return
}}, }},
unique.Make(Ident("noop")): {F: func( unique.Make(Ident("noop")): {F: func(
bool,
FArgs, FArgs,
) (v any, set bool, err error) { ) (v any, set bool, err error) {
return return
@@ -351,7 +340,12 @@ func BenchmarkEvaluate(b *testing.B) {
}, },
}} }}
for b.Loop() { for b.Loop() {
if _, _, err := Evaluate[string](s, gcc); err != nil { if _, _, err := Evaluate[string](func(
Ident,
FArgs,
) (v any, set bool, err error) {
return
}, s, gcc); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }