mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
* export the checker and ensure no methods or fields are exported * make Checker reusable * add PatchAndCheck method to Checker, and reuse it in visitors * avoid unnecessary map and consolidate structs * make all Nature methods use pointer-receiver * added cache for type and nature information * optimize type and nature checks * more aggressively cache some partial results and add cheap checks * cache reused values * reduce copying in Nature by breaking down optional fields * enforce use of cache * improve ergonomics of FromType and NatureOf * improve struct method fetching * make cache private to Nature * first iteration improving struct reflect caching * cleaned up struct fields data * improve caching of functions data * simplify checker code * simplify and remove dead code * add checker benchmarks * address PR comments and minor improvements * rename from SetCache to Bind * make the benchmarks more fair * fix benchmark option not being applied * move Cache to be argument instead of field * merge FuncData into Optional * rename Optional to TypeData * simplify struct logic * cache builtin numeric types --------- Co-authored-by: Anton Medvedev <[email protected]>
185 lines
3.0 KiB
Go
185 lines
3.0 KiB
Go
package types
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
|
|
. "github.com/expr-lang/expr/checker/nature"
|
|
)
|
|
|
|
// Type is a type that can be used to represent a value.
|
|
type Type interface {
|
|
Nature() Nature
|
|
Equal(Type) bool
|
|
String() string
|
|
}
|
|
|
|
var (
|
|
Int = TypeOf(0)
|
|
Int8 = TypeOf(int8(0))
|
|
Int16 = TypeOf(int16(0))
|
|
Int32 = TypeOf(int32(0))
|
|
Int64 = TypeOf(int64(0))
|
|
Uint = TypeOf(uint(0))
|
|
Uint8 = TypeOf(uint8(0))
|
|
Uint16 = TypeOf(uint16(0))
|
|
Uint32 = TypeOf(uint32(0))
|
|
Uint64 = TypeOf(uint64(0))
|
|
Float = TypeOf(float32(0))
|
|
Float64 = TypeOf(float64(0))
|
|
String = TypeOf("")
|
|
Bool = TypeOf(true)
|
|
Nil = nilType{}
|
|
Any = anyType{}
|
|
)
|
|
|
|
func TypeOf(v any) Type {
|
|
if v == nil {
|
|
return Nil
|
|
}
|
|
return rtype{t: reflect.TypeOf(v)}
|
|
}
|
|
|
|
type anyType struct{}
|
|
|
|
func (anyType) Nature() Nature {
|
|
return FromType(nil)
|
|
}
|
|
|
|
func (anyType) Equal(t Type) bool {
|
|
return true
|
|
}
|
|
|
|
func (anyType) String() string {
|
|
return "any"
|
|
}
|
|
|
|
type nilType struct{}
|
|
|
|
func (nilType) Nature() Nature {
|
|
return NatureOf(nil)
|
|
}
|
|
|
|
func (nilType) Equal(t Type) bool {
|
|
if t == Any {
|
|
return true
|
|
}
|
|
return t == Nil
|
|
}
|
|
|
|
func (nilType) String() string {
|
|
return "nil"
|
|
}
|
|
|
|
type rtype struct {
|
|
t reflect.Type
|
|
}
|
|
|
|
func (r rtype) Nature() Nature {
|
|
return FromType(r.t)
|
|
}
|
|
|
|
func (r rtype) Equal(t Type) bool {
|
|
if t == Any {
|
|
return true
|
|
}
|
|
if rt, ok := t.(rtype); ok {
|
|
return r.t.String() == rt.t.String()
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r rtype) String() string {
|
|
return r.t.String()
|
|
}
|
|
|
|
// Map represents a map[string]any type with defined keys.
|
|
type Map map[string]Type
|
|
|
|
const Extra = "[[__extra_keys__]]"
|
|
|
|
func (m Map) Nature() Nature {
|
|
nt := NatureOf(map[string]any{})
|
|
if nt.TypeData == nil {
|
|
nt.TypeData = new(TypeData)
|
|
}
|
|
nt.Fields = make(map[string]Nature, len(m))
|
|
nt.Strict = true
|
|
for k, v := range m {
|
|
if k == Extra {
|
|
nt.Strict = false
|
|
natureOfDefaultValue := v.Nature()
|
|
nt.DefaultMapValue = &natureOfDefaultValue
|
|
continue
|
|
}
|
|
nt.Fields[k] = v.Nature()
|
|
}
|
|
return nt
|
|
}
|
|
|
|
func (m Map) Equal(t Type) bool {
|
|
if t == Any {
|
|
return true
|
|
}
|
|
mt, ok := t.(Map)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if len(m) != len(mt) {
|
|
return false
|
|
}
|
|
for k, v := range m {
|
|
if !v.Equal(mt[k]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (m Map) String() string {
|
|
pairs := make([]string, 0, len(m))
|
|
for k, v := range m {
|
|
pairs = append(pairs, fmt.Sprintf("%s: %s", k, v.String()))
|
|
}
|
|
return fmt.Sprintf("Map{%s}", strings.Join(pairs, ", "))
|
|
}
|
|
|
|
// Array returns a type that represents an array of the given type.
|
|
func Array(of Type) Type {
|
|
return array{of}
|
|
}
|
|
|
|
type array struct {
|
|
of Type
|
|
}
|
|
|
|
func (a array) Nature() Nature {
|
|
of := a.of.Nature()
|
|
nt := NatureOf([]any{})
|
|
if nt.TypeData == nil {
|
|
nt.TypeData = new(TypeData)
|
|
}
|
|
nt.Fields = make(map[string]Nature, 1)
|
|
nt.Ref = &of
|
|
return nt
|
|
}
|
|
|
|
func (a array) Equal(t Type) bool {
|
|
if t == Any {
|
|
return true
|
|
}
|
|
at, ok := t.(array)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if a.of.Equal(at.of) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (a array) String() string {
|
|
return fmt.Sprintf("Array{%s}", a.of.String())
|
|
}
|