lang: types: Add nil type for placeholder

The nil type is being added, but only slightly. It is not meant for real
use in the language. It will not work in all situations, and it isn't
implemented for many methods.

It is being added only for being a "dummy" placeholder value in the
engine when we have an unused value being propagated along an edge.
This commit is contained in:
James Shubin
2025-09-06 00:36:47 -04:00
parent 2022a31820
commit 474df66ca0
2 changed files with 61 additions and 0 deletions

View File

@@ -51,6 +51,7 @@ const (
// Basic types defined here as a convenience for use with Type.Cmp(X).
var (
TypeNil = NewType("nil")
TypeBool = NewType("bool")
TypeStr = NewType("str")
TypeInt = NewType("int")
@@ -384,6 +385,10 @@ func NewType(s string) *Type {
// return a type with correctly unified unification variables.
func newType(s string, table map[uint]*Elem) *Type {
switch s {
case "nil":
return &Type{
Kind: KindNil,
}
case "bool":
return &Type{
Kind: KindBool,
@@ -683,6 +688,8 @@ func (obj *Type) New() Value {
panic("malformed type")
}
switch obj.Kind {
case KindNil:
return NewNil()
case KindBool:
return NewBool()
case KindStr:
@@ -717,6 +724,8 @@ func (obj *Type) String() string {
// helper function that is used by the real String function.
func (obj *Type) string(table map[*Elem]uint) string {
switch obj.Kind {
case KindNil:
return "nil"
case KindBool:
return "bool"
case KindStr:
@@ -840,6 +849,8 @@ func (obj *Type) cmp(typ *Type, table1, table2 map[*Elem]uint) error {
return fmt.Errorf("base kind does not match (%+v != %+v)", obj.Kind, typ.Kind)
}
switch obj.Kind {
case KindNil:
return nil
case KindBool:
return nil
case KindStr:
@@ -1124,6 +1135,8 @@ func (obj *Type) HasVariant() bool {
return false
}
switch obj.Kind {
case KindNil:
return false
case KindBool:
return false
case KindStr:
@@ -1212,6 +1225,8 @@ func (obj *Type) HasUni() bool {
}
switch obj.Kind {
case KindNil:
return false
case KindBool:
return false
case KindStr:
@@ -1330,6 +1345,8 @@ func (obj *Type) ComplexCmp(typ *Type) (string, error) {
// only container types are left to match...
switch obj.Kind {
case KindNil:
return "", nil // regular cmp
case KindBool:
return "", nil // regular cmp
case KindStr:

View File

@@ -599,6 +599,50 @@ func (obj *Base) Func() interface{} {
// return nil
//}
// NilValue represents a nil value. It should be used only in rare situations.
type NilValue struct {
Base
}
// NewNil creates a new nil value.
func NewNil() *NilValue { return &NilValue{} }
// String returns a visual representation of this value.
func (obj *NilValue) String() string {
return "nil"
}
// Type returns the type data structure that represents this type.
func (obj *NilValue) Type() *Type { return NewType("nil") }
// Less compares to value and returns true if we're smaller. This panics if the
// two types aren't the same. This always returns false for nil.
func (obj *NilValue) Less(v Value) bool {
return false // they're the same
}
// Cmp returns an error if this value isn't the same as the arg passed in.
func (obj *NilValue) Cmp(val Value) error {
if obj == nil || val == nil {
return fmt.Errorf("cannot cmp to nil")
}
if err := obj.Type().Cmp(val.Type()); err != nil {
return errwrap.Wrapf(err, "cannot cmp types")
}
return nil
}
// Copy returns a copy of this value.
func (obj *NilValue) Copy() Value {
return &NilValue{}
}
// Value returns the raw value of this type.
func (obj *NilValue) Value() interface{} {
return nil
}
// BoolValue represents a boolean value.
type BoolValue struct {
Base