github.com/ipld/go-ipld-prime@v0.21.0/schema/tmpBuilders.go (about)

     1  package schema
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/ipld/go-ipld-prime/datamodel"
     7  )
     8  
     9  // Everything in this file is __a temporary hack__ and will be __removed__.
    10  //
    11  // These methods will only hang around until more of the "ast" packages are finished;
    12  // thereafter, building schema.Type and schema.TypeSystem values will only be
    13  // possible through first constructing a schema AST, and *then* using Reify(),
    14  // which will validate things correctly, cycle-check, cross-link, etc.
    15  //
    16  // (Meanwhile, we're using these methods in the codegen prototypes.)
    17  
    18  // These methods use Type objects as parameters when pointing to other things,
    19  //  but this is... turning out consistently problematic.
    20  //   Even when we're doing this hacky direct-call doesn't-need-to-be-serializable temp stuff,
    21  //    as written, this doesn't actually let us express cyclic things viably!
    22  //   The same initialization questions are also going to come up again when we try to make
    23  //    concrete values in the output of codegen.
    24  // Maybe it's actually just a bad idea to have our reified Type types use Type pointers at all.
    25  //  (I will never get tired of the tongue twisters, evidently.)
    26  //  I'm not actually using that much, and it's always avoidable (it's trivial to replace with a map lookup bouncing through a 'ts' variable somewhere).
    27  //  And having the AST gen'd types be... just... the thing... sounds nice.  It could save a lot of work.
    28  //   (It would mean the golang types don't tell you whether the values have been checked for global properties or not, but, eh.)
    29  //   (It's not really compatible with "Prototype and Type are the same thing for codegen'd stuff", either (or, we need more interfaces, and to *really* lean into them), but maybe that's okay.)
    30  
    31  func SpawnTypeSystem(types ...Type) (*TypeSystem, []error) {
    32  	ts := TypeSystem{}
    33  	ts.Init()
    34  	for _, typ := range types {
    35  		ts.Accumulate(typ)
    36  	}
    37  	if errs := ts.ValidateGraph(); errs != nil {
    38  		return nil, errs
    39  	}
    40  	return &ts, nil
    41  }
    42  func MustTypeSystem(types ...Type) *TypeSystem {
    43  	if ts, err := SpawnTypeSystem(types...); err != nil {
    44  		panic(err)
    45  	} else {
    46  		return ts
    47  	}
    48  }
    49  
    50  func SpawnString(name TypeName) *TypeString {
    51  	return &TypeString{typeBase{name, nil}}
    52  }
    53  
    54  func SpawnBool(name TypeName) *TypeBool {
    55  	return &TypeBool{typeBase{name, nil}}
    56  }
    57  
    58  func SpawnInt(name TypeName) *TypeInt {
    59  	return &TypeInt{typeBase{name, nil}}
    60  }
    61  
    62  func SpawnFloat(name TypeName) *TypeFloat {
    63  	return &TypeFloat{typeBase{name, nil}}
    64  }
    65  
    66  func SpawnBytes(name TypeName) *TypeBytes {
    67  	return &TypeBytes{typeBase{name, nil}}
    68  }
    69  
    70  func SpawnLink(name TypeName) *TypeLink {
    71  	return &TypeLink{typeBase{name, nil}, "", false}
    72  }
    73  
    74  func SpawnLinkReference(name TypeName, pointsTo TypeName) *TypeLink {
    75  	return &TypeLink{typeBase{name, nil}, pointsTo, true}
    76  }
    77  
    78  func SpawnList(name TypeName, valueType TypeName, nullable bool) *TypeList {
    79  	return &TypeList{typeBase{name, nil}, false, valueType, nullable}
    80  }
    81  
    82  func SpawnMap(name TypeName, keyType TypeName, valueType TypeName, nullable bool) *TypeMap {
    83  	return &TypeMap{typeBase{name, nil}, false, keyType, valueType, nullable}
    84  }
    85  
    86  func SpawnAny(name TypeName) *TypeAny {
    87  	return &TypeAny{typeBase{name, nil}}
    88  }
    89  
    90  func SpawnStruct(name TypeName, fields []StructField, repr StructRepresentation) *TypeStruct {
    91  	v := &TypeStruct{
    92  		typeBase{name, nil},
    93  		fields,
    94  		make(map[string]StructField, len(fields)),
    95  		repr,
    96  	}
    97  	for i := range fields {
    98  		fields[i].parent = v
    99  		v.fieldsMap[fields[i].name] = fields[i]
   100  	}
   101  	switch repr.(type) {
   102  	case StructRepresentation_Stringjoin:
   103  		for _, f := range fields {
   104  			if f.IsMaybe() {
   105  				panic("neither nullable nor optional is supported on struct stringjoin representation")
   106  			}
   107  		}
   108  	case nil:
   109  		v.representation = SpawnStructRepresentationMap(nil)
   110  	}
   111  	return v
   112  }
   113  func SpawnStructField(name string, typ TypeName, optional bool, nullable bool) StructField {
   114  	return StructField{nil /*populated later*/, name, typ, optional, nullable}
   115  }
   116  func SpawnStructRepresentationMap(renames map[string]string) StructRepresentation_Map {
   117  	return StructRepresentation_Map{renames, nil}
   118  }
   119  func SpawnStructRepresentationMap2(renames map[string]string, implicits map[string]ImplicitValue) StructRepresentation_Map {
   120  	return StructRepresentation_Map{renames, implicits}
   121  }
   122  func SpawnStructRepresentationTuple() StructRepresentation_Tuple {
   123  	return StructRepresentation_Tuple{}
   124  }
   125  func SpawnStructRepresentationListPairs() StructRepresentation_ListPairs {
   126  	return StructRepresentation_ListPairs{}
   127  }
   128  func SpawnStructRepresentationStringjoin(delim string) StructRepresentation_Stringjoin {
   129  	return StructRepresentation_Stringjoin{delim}
   130  }
   131  
   132  func SpawnUnion(name TypeName, members []TypeName, repr UnionRepresentation) *TypeUnion {
   133  	return &TypeUnion{typeBase{name, nil}, members, repr}
   134  }
   135  func SpawnUnionRepresentationKeyed(table map[string]TypeName) UnionRepresentation_Keyed {
   136  	return UnionRepresentation_Keyed{table}
   137  }
   138  func SpawnUnionRepresentationKinded(table map[datamodel.Kind]TypeName) UnionRepresentation_Kinded {
   139  	return UnionRepresentation_Kinded{table}
   140  }
   141  func SpawnUnionRepresentationStringprefix(delim string, table map[string]TypeName) UnionRepresentation_Stringprefix {
   142  	return UnionRepresentation_Stringprefix{delim, table}
   143  }
   144  func SpawnUnionRepresentationInline(discriminantKey string, table map[string]TypeName) UnionRepresentation_Inline {
   145  	return UnionRepresentation_Inline{discriminantKey, table}
   146  }
   147  
   148  func SpawnEnum(name TypeName, members []string, repr EnumRepresentation) *TypeEnum {
   149  	return &TypeEnum{typeBase{name, nil}, members, repr}
   150  }
   151  
   152  // The methods relating to TypeSystem are also mutation-heavy and placeholdery.
   153  
   154  func (ts *TypeSystem) Init() {
   155  	ts.namedTypes = make(map[TypeName]Type)
   156  }
   157  func (ts *TypeSystem) Accumulate(typ Type) {
   158  	typ._Type(ts)
   159  	name := typ.Name()
   160  	if _, ok := ts.namedTypes[name]; ok {
   161  		panic(fmt.Sprintf("duplicate type name: %s", name))
   162  	}
   163  	ts.namedTypes[name] = typ
   164  	ts.names = append(ts.names, name)
   165  }
   166  func (ts TypeSystem) GetTypes() map[TypeName]Type {
   167  	return ts.namedTypes
   168  }
   169  func (ts TypeSystem) TypeByName(n string) Type {
   170  	return ts.namedTypes[n]
   171  }
   172  func (ts TypeSystem) Names() []TypeName {
   173  	return ts.names
   174  }
   175  
   176  // ValidateGraph checks that all type names referenced are defined.
   177  //
   178  // It does not do any other validations of individual type's sensibleness
   179  // (that should've happened when they were created
   180  // (although also note many of those validates are NYI,
   181  // and are roadmapped for after we research self-hosting)).
   182  func (ts TypeSystem) ValidateGraph() []error {
   183  	var ee []error
   184  	for tn, t := range ts.namedTypes {
   185  		switch t2 := t.(type) {
   186  		case *TypeBool,
   187  			*TypeInt,
   188  			*TypeFloat,
   189  			*TypeString,
   190  			*TypeBytes,
   191  			*TypeEnum:
   192  			continue // nothing to check: these are leaf nodes and refer to no other types.
   193  		case *TypeLink:
   194  			if !t2.hasReferencedType {
   195  				continue
   196  			}
   197  			if _, ok := ts.namedTypes[t2.referencedType]; !ok {
   198  				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as link reference type)", tn, t2.referencedType))
   199  			}
   200  		case *TypeStruct:
   201  			for _, f := range t2.fields {
   202  				if _, ok := ts.namedTypes[f.typ]; !ok {
   203  					ee = append(ee, fmt.Errorf("type %s refers to missing type %s (in field %q)", tn, f.typ, f.name))
   204  				}
   205  			}
   206  		case *TypeMap:
   207  			if _, ok := ts.namedTypes[t2.keyType]; !ok {
   208  				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as key type)", tn, t2.keyType))
   209  			}
   210  			if _, ok := ts.namedTypes[t2.valueType]; !ok {
   211  				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as value type)", tn, t2.valueType))
   212  			}
   213  		case *TypeList:
   214  			if _, ok := ts.namedTypes[t2.valueType]; !ok {
   215  				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as value type)", tn, t2.valueType))
   216  			}
   217  		case *TypeUnion:
   218  			for _, mn := range t2.members {
   219  				if _, ok := ts.namedTypes[mn]; !ok {
   220  					ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as a member)", tn, mn))
   221  				}
   222  			}
   223  		}
   224  	}
   225  	return ee
   226  }