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
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:
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user