tmpBuilders.go 6.4 KB
Newer Older
Eric Myhre's avatar
Eric Myhre committed
1 2
package schema

3 4
import (
	"fmt"
5

tavit ohanian's avatar
tavit ohanian committed
6
	ld "gitlab.dms3.io/ld/go-ld-prime"
7 8
)

Eric Myhre's avatar
Eric Myhre committed
9 10 11 12 13 14 15 16 17
// Everything in this file is __a temporary hack__ and will be __removed__.
//
// These methods will only hang around until more of the "ast" packages are finished;
// thereafter, building schema.Type and schema.TypeSystem values will only be
// possible through first constructing a schema AST, and *then* using Reify(),
// which will validate things correctly, cycle-check, cross-link, etc.
//
// (Meanwhile, we're using these methods in the codegen prototypes.)

18 19 20 21 22 23 24 25 26 27 28 29 30
// These methods use Type objects as parameters when pointing to other things,
//  but this is... turning out consistently problematic.
//   Even when we're doing this hacky direct-call doesn't-need-to-be-serializable temp stuff,
//    as written, this doesn't actually let us express cyclic things viably!
//   The same initialization questions are also going to come up again when we try to make
//    concrete values in the output of codegen.
// Maybe it's actually just a bad idea to have our reified Type types use Type pointers at all.
//  (I will never get tired of the tongue twisters, evidently.)
//  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).
//  And having the AST gen'd types be... just... the thing... sounds nice.  It could save a lot of work.
//   (It would mean the golang types don't tell you whether the values have been checked for global properties or not, but, eh.)
//   (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.)

31 32
func SpawnString(name TypeName) *TypeString {
	return &TypeString{typeBase{name, nil}}
Eric Myhre's avatar
Eric Myhre committed
33 34
}

Eric Myhre's avatar
Eric Myhre committed
35 36 37 38
func SpawnBool(name TypeName) *TypeBool {
	return &TypeBool{typeBase{name, nil}}
}

39 40
func SpawnInt(name TypeName) *TypeInt {
	return &TypeInt{typeBase{name, nil}}
Eric Myhre's avatar
Eric Myhre committed
41 42 43 44
}

func SpawnFloat(name TypeName) *TypeFloat {
	return &TypeFloat{typeBase{name, nil}}
45 46
}

47 48
func SpawnBytes(name TypeName) *TypeBytes {
	return &TypeBytes{typeBase{name, nil}}
49 50
}

51 52
func SpawnLink(name TypeName) *TypeLink {
	return &TypeLink{typeBase{name, nil}, "", false}
53 54
}

55 56
func SpawnLinkReference(name TypeName, pointsTo TypeName) *TypeLink {
	return &TypeLink{typeBase{name, nil}, pointsTo, true}
57
}
58

59 60
func SpawnList(name TypeName, valueType TypeName, nullable bool) *TypeList {
	return &TypeList{typeBase{name, nil}, false, valueType, nullable}
hannahhoward's avatar
hannahhoward committed
61 62
}

63 64
func SpawnMap(name TypeName, keyType TypeName, valueType TypeName, nullable bool) *TypeMap {
	return &TypeMap{typeBase{name, nil}, false, keyType, valueType, nullable}
65 66
}

67 68
func SpawnStruct(name TypeName, fields []StructField, repr StructRepresentation) *TypeStruct {
	v := &TypeStruct{
69
		typeBase{name, nil},
70 71 72
		fields,
		make(map[string]StructField, len(fields)),
		repr,
73
	}
74
	for i := range fields {
75
		fields[i].parent = v
76 77
		v.fieldsMap[fields[i].name] = fields[i]
	}
78 79 80 81 82 83 84 85
	switch repr.(type) {
	case StructRepresentation_Stringjoin:
		for _, f := range fields {
			if f.IsMaybe() {
				panic("neither nullable nor optional is supported on struct stringjoin representation")
			}
		}
	}
86
	return v
Eric Myhre's avatar
Eric Myhre committed
87
}
88
func SpawnStructField(name string, typ TypeName, optional bool, nullable bool) StructField {
89
	return StructField{nil /*populated later*/, name, typ, optional, nullable}
Eric Myhre's avatar
Eric Myhre committed
90
}
91 92 93
func SpawnStructRepresentationMap(renames map[string]string) StructRepresentation_Map {
	return StructRepresentation_Map{renames, nil}
}
94 95 96
func SpawnStructRepresentationTuple() StructRepresentation_Tuple {
	return StructRepresentation_Tuple{}
}
97 98 99
func SpawnStructRepresentationStringjoin(delim string) StructRepresentation_Stringjoin {
	return StructRepresentation_Stringjoin{delim}
}
100

101 102
func SpawnUnion(name TypeName, members []TypeName, repr UnionRepresentation) *TypeUnion {
	return &TypeUnion{typeBase{name, nil}, members, repr}
103
}
104
func SpawnUnionRepresentationKeyed(table map[string]TypeName) UnionRepresentation_Keyed {
105 106
	return UnionRepresentation_Keyed{table}
}
tavit ohanian's avatar
tavit ohanian committed
107
func SpawnUnionRepresentationKinded(table map[ld.Kind]TypeName) UnionRepresentation_Kinded {
108 109
	return UnionRepresentation_Kinded{table}
}
110 111 112
func SpawnUnionRepresentationStringprefix(delim string, table map[string]TypeName) UnionRepresentation_Stringprefix {
	return UnionRepresentation_Stringprefix{delim, table}
}
113

114 115 116 117 118 119
// The methods relating to TypeSystem are also mutation-heavy and placeholdery.

func (ts *TypeSystem) Init() {
	ts.namedTypes = make(map[TypeName]Type)
}
func (ts *TypeSystem) Accumulate(typ Type) {
120
	typ._Type(ts)
121 122 123 124 125 126 127 128
	ts.namedTypes[typ.Name()] = typ
}
func (ts TypeSystem) GetTypes() map[TypeName]Type {
	return ts.namedTypes
}
func (ts TypeSystem) TypeByName(n string) Type {
	return ts.namedTypes[TypeName(n)]
}
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

// ValidateGraph checks that all type names referenced are defined.
//
// It does not do any other validations of individual type's sensibleness
// (that should've happened when they were created
// (although also note many of those validates are NYI,
// and are roadmapped for after we research self-hosting)).
func (ts TypeSystem) ValidateGraph() []error {
	var ee []error
	for tn, t := range ts.namedTypes {
		switch t2 := t.(type) {
		case *TypeBool,
			*TypeInt,
			*TypeFloat,
			*TypeString,
			*TypeBytes,
			*TypeEnum:
			continue // nothing to check: these are leaf nodes and refer to no other types.
		case *TypeLink:
			if !t2.hasReferencedType {
				continue
			}
			if _, ok := ts.namedTypes[t2.referencedType]; !ok {
				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as link reference type)", tn, t2.referencedType))
			}
		case *TypeStruct:
			for _, f := range t2.fields {
				if _, ok := ts.namedTypes[f.typ]; !ok {
					ee = append(ee, fmt.Errorf("type %s refers to missing type %s (in field %s)", tn, f.typ, f.name))
				}
			}
		case *TypeMap:
			if _, ok := ts.namedTypes[t2.keyType]; !ok {
				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as key type)", tn, t2.keyType))
			}
			if _, ok := ts.namedTypes[t2.valueType]; !ok {
				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as key type)", tn, t2.valueType))
			}
		case *TypeList:
			if _, ok := ts.namedTypes[t2.valueType]; !ok {
				ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as key type)", tn, t2.valueType))
			}
		case *TypeUnion:
			for _, mn := range t2.members {
				if _, ok := ts.namedTypes[mn]; !ok {
					ee = append(ee, fmt.Errorf("type %s refers to missing type %s (as a member)", tn, mn))
				}
			}
		}
	}
	return ee
}