diff --git a/internal/rosa/azalea/evaluate.go b/internal/rosa/azalea/evaluate.go index 063471e1..617a1618 100644 --- a/internal/rosa/azalea/evaluate.go +++ b/internal/rosa/azalea/evaluate.go @@ -142,10 +142,13 @@ var ( IdentInputs = unique.Make(Ident("inputs")) // IdentRuntime has the same semantics as [IdentInputs]. IdentRuntime = unique.Make(Ident("runtime")) + // IdentSource is a special argument in a package declaration where an + // assignment of a [Val] with a single [Ident] passes through the evaluator. + IdentSource = unique.Make(Ident("source")) - // 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") + // ErrInvalidSpecial is panicked for a special [PF] argument sharing its + // value or set for R. + ErrInvalidSpecial = errors.New("special must not be common or bound to scope") ) // evaluateAny implements [Evaluate]. @@ -291,7 +294,7 @@ func evaluateAny(d PF, s []Frame, expr, rp any) bool { } { if slices.Contains(names, special) { if len(names) != 1 || len(arg.V) != 1 || arg.R { - panic(ErrInvalidInputs) + panic(ErrInvalidSpecial) } farg.K = names[0] if err := storeE(&farg.V, arg.V[0]); err != nil { @@ -301,6 +304,20 @@ func evaluateAny(d PF, s []Frame, expr, rp any) bool { continue args } } + + if slices.Contains(names, IdentSource) { + if len(names) != 1 || len(arg.V) != 1 || arg.R { + panic(ErrInvalidSpecial) + } + if _, ok = arg.V[0].(Ident); ok { + farg.K = names[0] + if err := storeE(&farg.V, arg.V[0]); err != nil { + panic(err) + } + fargs = append(fargs, farg) + continue args + } + } } if !evaluateAny(d, s, arg.V, &farg.V) { diff --git a/internal/rosa/azalea/evaluate_test.go b/internal/rosa/azalea/evaluate_test.go index 26c4e668..b4fa4802 100644 --- a/internal/rosa/azalea/evaluate_test.go +++ b/internal/rosa/azalea/evaluate_test.go @@ -32,7 +32,7 @@ func TestEvaluate(t *testing.T) { name string data string s []Frame - want string + want any err error }{ {"apply unset", `f { v = unset; }`, makeStackCheck(func( @@ -110,7 +110,7 @@ func TestEvaluate(t *testing.T) { }, V: Val{Array(nil)}}, }, }, - Err: ErrInvalidInputs, + Err: ErrInvalidSpecial, }}, {"bound inputs", `package name { inputs* = []; }`, nil, "", EvaluationError{ @@ -122,7 +122,7 @@ func TestEvaluate(t *testing.T) { {K: []Ident{"inputs"}, V: Val{Array(nil)}, R: true}, }, }, - Err: ErrInvalidInputs, + Err: ErrInvalidSpecial, }}, {"bound runtime", `package name { runtime* = []; }`, nil, "", EvaluationError{ @@ -134,7 +134,7 @@ func TestEvaluate(t *testing.T) { {K: []Ident{"runtime"}, V: Val{Array(nil)}, R: true}, }, }, - Err: ErrInvalidInputs, + Err: ErrInvalidSpecial, }}, {"concat inputs", `package name { inputs = ""+""; }`, nil, "", EvaluationError{ @@ -146,8 +146,24 @@ func TestEvaluate(t *testing.T) { {K: []Ident{"inputs"}, V: Val{String(""), String("")}}, }, }, - Err: ErrInvalidInputs, + Err: ErrInvalidSpecial, }}, + + {"concat source", `package name { source = ""+""; }`, nil, "", EvaluationError{ + Expr: Func{ + Ident: Ident("name"), + Package: true, + + Args: []Arg{ + {K: []Ident{"source"}, V: Val{String(""), String("")}}, + }, + }, + Err: ErrInvalidSpecial, + }}, + + {"source handle", `package name { source = name; }`, nil, FArgs{ + {K: unique.Make(Ident("source")), V: Ident("name")}, + }, nil}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { @@ -161,12 +177,23 @@ func TestEvaluate(t *testing.T) { } else { expr = e[0].(Func) } - r, set, err := Evaluate[string](nil, tc.s, expr) + const rPackage = "\xff\xff\xff\xff" + r, set, err := Evaluate[string](func( + name Ident, + args FArgs, + ) (v any, set bool, err error) { + v = rPackage + if !reflect.DeepEqual(args, tc.want) { + err = fmt.Errorf("%#v, want %#v", args, tc.want) + } + set = true + return + }, tc.s, expr) if set != (err == nil) { t.Error("Evaluate: unexpected unset") } - if r != tc.want { + if r != rPackage && r != tc.want { t.Errorf("Evaluate: %q, want %q", r, tc.want) } diff --git a/internal/rosa/state.go b/internal/rosa/state.go index 388a6cc5..2581bb75 100644 --- a/internal/rosa/state.go +++ b/internal/rosa/state.go @@ -789,6 +789,13 @@ func (ctx *evalContext) pf( case deferredGit: source = ctx.t.newTagRemote(p.url, p.tag, p.checksum) + case azalea.Ident: + var _meta *Metadata + _meta, source = ctx.t.Load(H(string(p))) + if meta.Version == "" { + meta.Version = _meta.Version + } + default: panic(azalea.TypeError{ Concrete: reflect.TypeOf(sourceA),