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 }