diff --git a/internal/rosa/azalea/evaluate.go b/internal/rosa/azalea/evaluate.go index 044e6826..fe9ee177 100644 --- a/internal/rosa/azalea/evaluate.go +++ b/internal/rosa/azalea/evaluate.go @@ -12,7 +12,7 @@ import ( // Value are types supported by the language. type Value interface { - bool | int64 | string | []string | []int64 | [][2]string + bool | int64 | string | []string | []int64 | [][2]string | Nil } type ( @@ -50,6 +50,11 @@ func (args FArgs) Apply(v map[unique.Handle[Ident]]any) error { } return UndefinedError(arg.K.Value()) } + + if arg.V == (Nil{}) { + reflect.ValueOf(r).Elem().SetZero() + continue + } err := storeE(r, arg.V) if err != nil { return err @@ -115,7 +120,7 @@ func (e TypeError) Is(err error) bool { } // storeE is a convenience function to set the value of a result pointer. -func storeE(rp any, r any) error { +func storeE(rp, r any) error { pv := reflect.ValueOf(rp).Elem() v := reflect.ValueOf(r) pt, vt := pv.Type(), v.Type() @@ -166,6 +171,9 @@ var ( ErrInvalidSpecial = errors.New("special must not be common or bound to scope") ) +// Nil represents an untyped nil. +type Nil struct{} + // evaluateAny implements [Evaluate]. func evaluateAny(d PF, s []Frame, expr, rp any) bool { defer func() { @@ -226,6 +234,9 @@ func evaluateAny(d PF, s []Frame, expr, rp any) bool { case "false": store(rp, false) return true + case "nil": + store(rp, Nil{}) + return true default: return evaluateAny(d, s, v, rp) } diff --git a/internal/rosa/azalea/evaluate_test.go b/internal/rosa/azalea/evaluate_test.go index 4a6c2f56..e971e163 100644 --- a/internal/rosa/azalea/evaluate_test.go +++ b/internal/rosa/azalea/evaluate_test.go @@ -100,15 +100,19 @@ func TestEvaluate(t *testing.T) { Err: UndefinedError("f"), }}, - {"error wrap deep", `f { v = nil; }`, makeStackCheck(func( + {"error wrap deep", `f { v = nonexistent; }`, makeStackCheck(func( FArgs, ) (any, error) { panic("unreachable") }), "", EvaluationError{ - Expr: Ident("nil"), - Err: UndefinedError("nil"), + Expr: Ident("nonexistent"), + Err: UndefinedError("nonexistent"), }}, + {"nil", `f { v = nil; }`, checkArgs(FArgs{ + {K: unique.Make(Ident("v")), V: Nil{}}, + }), "\xfd", nil}, + {"common inputs", `package name { inputs, v = []; }`, nil, "", EvaluationError{ Expr: Func{ Ident: Ident("name"),