forked from rosa/hakurei
internal/rosa/azalea: package special case
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"
|
||||
"maps"
|
||||
"reflect"
|
||||
"slices"
|
||||
"unique"
|
||||
)
|
||||
|
||||
@@ -23,9 +24,12 @@ type (
|
||||
// FArgs are arguments passed to [F].
|
||||
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 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
|
||||
}
|
||||
)
|
||||
@@ -77,8 +81,8 @@ func (e UndefinedError) Error() string {
|
||||
}
|
||||
|
||||
// evaluate is evaluateAny with a type parameter.
|
||||
func evaluate[T Value](s []Frame, expr any, rp *T) bool {
|
||||
return evaluateAny(s, expr, rp)
|
||||
func evaluate[T Value](d PF, s []Frame, expr any, rp *T) bool {
|
||||
return evaluateAny(d, s, expr, rp)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
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].
|
||||
func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
func evaluateAny(d PF, s []Frame, expr, rp any) bool {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
@@ -193,17 +207,17 @@ func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
store(rp, false)
|
||||
return true
|
||||
default:
|
||||
return evaluateAny(s, v, rp)
|
||||
return evaluateAny(d, s, v, rp)
|
||||
}
|
||||
|
||||
default:
|
||||
return evaluateAny(s, e[0], rp)
|
||||
return evaluateAny(d, s, e[0], rp)
|
||||
}
|
||||
}
|
||||
var v string
|
||||
for i := range e {
|
||||
var _r string
|
||||
if evaluate(s, e[i], &_r) {
|
||||
if evaluate(d, s, e[i], &_r) {
|
||||
v += _r
|
||||
}
|
||||
}
|
||||
@@ -214,7 +228,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
r := make([]string, 0, len(e))
|
||||
for i := range e {
|
||||
var _r string
|
||||
if evaluate(s, e[i], &_r) {
|
||||
if evaluate(d, s, e[i], &_r) {
|
||||
r = append(r, _r)
|
||||
}
|
||||
}
|
||||
@@ -225,7 +239,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
r := make([][2]string, 0, len(e))
|
||||
for i := range e {
|
||||
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})
|
||||
}
|
||||
}
|
||||
@@ -237,14 +251,16 @@ func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
f F
|
||||
ok bool
|
||||
)
|
||||
for i := range s {
|
||||
f, ok = s[len(s)-1-i].Func[unique.Make(e.Ident)]
|
||||
if ok {
|
||||
break
|
||||
if !e.Package {
|
||||
for i := range s {
|
||||
f, ok = s[len(s)-1-i].Func[unique.Make(e.Ident)]
|
||||
if ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
panic(UndefinedError(e.Ident))
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
panic(UndefinedError(e.Ident))
|
||||
}
|
||||
|
||||
argc := len(e.Args)
|
||||
@@ -252,29 +268,56 @@ func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
argc += len(arg.K) - 1
|
||||
}
|
||||
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]
|
||||
if !e.Package {
|
||||
fp.Val = maps.Clone(f.V)
|
||||
}
|
||||
|
||||
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}
|
||||
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
|
||||
}
|
||||
for _, name := range arg.K {
|
||||
h := unique.Make(name)
|
||||
farg.K = h
|
||||
for _, name := range names {
|
||||
farg.K = name
|
||||
fargs = append(fargs, farg)
|
||||
|
||||
if arg.R && farg.V != nil {
|
||||
if fp.Val == nil {
|
||||
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 {
|
||||
panic(err)
|
||||
} else if v != nil {
|
||||
@@ -282,7 +325,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return set
|
||||
return ok
|
||||
|
||||
default:
|
||||
panic(UnsupportedExprError{expr})
|
||||
@@ -290,7 +333,7 @@ func evaluateAny(s []Frame, expr, rp any) bool {
|
||||
}
|
||||
|
||||
// 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() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
@@ -303,6 +346,6 @@ func Evaluate[T Value](s []Frame, expr any) (v T, set bool, err error) {
|
||||
}
|
||||
err = _err
|
||||
}()
|
||||
set = evaluate[T](s, expr, &v)
|
||||
set = evaluate[T](d, s, expr, &v)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user