// UserTypeJS returns a string containing the JS type that should be used when the Noms type described by t needs to be returned by a generated getter or taken as a parameter to a generated setter. func (gen *Generator) UserTypeJS(t types.Type) string { rt := gen.R.Resolve(t) k := rt.Kind() switch k { case types.BlobKind: return gen.ImportJSType("Blob") case types.BoolKind: return "boolean" case types.StringKind: return "string" case types.Float32Kind, types.Float64Kind, types.Int16Kind, types.Int32Kind, types.Int64Kind, types.Int8Kind, types.Uint16Kind, types.Uint32Kind, types.Uint64Kind, types.Uint8Kind: return gen.ImportJSType(strings.ToLower(kindToString(k))) case types.EnumKind, types.StructKind: if t.HasPackageRef() { return gen.importedUserNameJS(t) } return gen.UserName(t) case types.ListKind: return fmt.Sprintf("%s<%s>", gen.ImportJSType("NomsList"), gen.UserTypeJS(t.Desc.(types.CompoundDesc).ElemTypes[0])) case types.SetKind: return fmt.Sprintf("%s<%s>", gen.ImportJSType("NomsSet"), gen.UserTypeJS(t.Desc.(types.CompoundDesc).ElemTypes[0])) case types.RefKind: return fmt.Sprintf("%s<%s>", gen.ImportJSType("RefValue"), gen.UserTypeJS(t.Desc.(types.CompoundDesc).ElemTypes[0])) case types.MapKind: elemTypes := t.Desc.(types.CompoundDesc).ElemTypes return fmt.Sprintf("%s<%s, %s>", gen.ImportJSType("NomsMap"), gen.UserTypeJS(elemTypes[0]), gen.UserTypeJS(elemTypes[1])) case types.PackageKind: return gen.ImportJSType("Package") case types.ValueKind: return gen.ImportJSType("Value") case types.TypeKind: return gen.ImportJSType("Type") } panic("unreachable") }
func (gen *codeGen) writeTopLevel(t types.Type, ordinal int) { switch t.Kind() { case types.EnumKind: gen.writeEnum(t, ordinal) case types.StructKind: gen.writeStruct(t, ordinal) default: gen.write(t) } }
// UserToValue returns a string containing Go code to convert an instance of a User type (named val) to a Noms types.Value of the type described by t. For Go primitive types, this will use NativeToValue(). For other types, their UserType is a Noms types.Value (or a wrapper around one), so this is more-or-less a pass-through. func (gen *Generator) UserToValue(val string, t types.Type) string { t = gen.R.Resolve(t) k := t.Kind() switch k { case types.BlobKind, types.EnumKind, types.ListKind, types.MapKind, types.PackageKind, types.RefKind, types.SetKind, types.StructKind, types.TypeKind, types.ValueKind: return val case types.BoolKind, types.Float32Kind, types.Float64Kind, types.Int16Kind, types.Int32Kind, types.Int64Kind, types.Int8Kind, types.StringKind, types.Uint16Kind, types.Uint32Kind, types.Uint64Kind, types.Uint8Kind: return gen.NativeToValue(val, t) } panic("unreachable") }
// ValueToNative returns a string containing Go code to convert an instance of a types.Value (val) into the native type appropriate for t. func (gen *Generator) ValueToNative(val string, t types.Type) string { k := t.Kind() switch k { case types.BoolKind, types.Float32Kind, types.Float64Kind, types.Int16Kind, types.Int32Kind, types.Int64Kind, types.Int8Kind, types.Uint16Kind, types.Uint32Kind, types.Uint64Kind, types.Uint8Kind: n := kindToString(k) return fmt.Sprintf("%s(%s.(%s%s))", strings.ToLower(n), val, gen.TypesPackage, n) case types.StringKind: return fmt.Sprintf("%s.(%sString).String()", val, gen.TypesPackage) } panic("unreachable") }
// NativeToValue returns a string containing Go code to convert an instance of a native type (named val) to a Noms types.Value of the type described by t. func (gen *Generator) NativeToValue(val string, t types.Type) string { t = gen.R.Resolve(t) k := t.Kind() switch k { case types.BoolKind, types.Float32Kind, types.Float64Kind, types.Int16Kind, types.Int32Kind, types.Int64Kind, types.Int8Kind, types.Uint16Kind, types.Uint32Kind, types.Uint64Kind, types.Uint8Kind: return fmt.Sprintf("%s%s(%s)", gen.TypesPackage, kindToString(k), val) case types.StringKind: return fmt.Sprintf("%sNewString(%s)", gen.TypesPackage, val) } panic("unreachable") }
func (res *testResolver) Resolve(t types.Type) types.Type { if !t.IsUnresolved() { return t } if !t.HasPackageRef() { res.assert.Fail("Test does not handle local references") } dep, ok := res.deps[t.PackageRef()] res.assert.True(ok, "Package %s is referenced in %+v, but is not a dependency.", t.PackageRef().String(), t) return dep.Types()[t.Ordinal()] }
func (gen *codeGen) writeEnum(t types.Type, ordinal int) { d.Chk.True(ordinal >= 0) data := struct { sharedData Name string Type types.Type Ordinal int Ids []string }{ gen.sharedData, t.Name(), t, ordinal, t.Desc.(types.EnumDesc).IDs, } gen.writeTemplate("enum.tmpl", t, data) }
func (gen *codeGen) resolveInPackage(t types.Type, p types.Package) (types.Type, types.Package) { d.Chk.True(t.IsUnresolved()) // For unresolved types that references types in the same package the ref is empty and we need to use the passed in package. if t.HasPackageRef() { p = gen.deps[t.PackageRef()] d.Chk.NotNil(p) } return p.Types()[t.Ordinal()], p }
// write generates the code for the given type. func (gen *codeGen) write(t types.Type) { if !gen.shouldBeWritten(t) { return } k := t.Kind() switch k { case types.BlobKind, types.BoolKind, types.Float32Kind, types.Float64Kind, types.Int16Kind, types.Int32Kind, types.Int64Kind, types.Int8Kind, types.PackageKind, types.StringKind, types.Uint16Kind, types.Uint32Kind, types.Uint64Kind, types.Uint8Kind, types.ValueKind, types.TypeKind: return case types.ListKind: gen.writeList(t) case types.MapKind: gen.writeMap(t) case types.RefKind: gen.writeRef(t) case types.SetKind: gen.writeSet(t) default: panic("unreachable") } }
func (gen *codeGen) canUseDef(t types.Type, p types.Package) bool { cache := map[string]bool{} var rec func(t types.Type, p types.Package) bool rec = func(t types.Type, p types.Package) bool { switch t.Kind() { case types.UnresolvedKind: t2, p2 := gen.resolveInPackage(t, p) d.Chk.False(t2.IsUnresolved()) return rec(t2, p2) case types.ListKind: return rec(t.Desc.(types.CompoundDesc).ElemTypes[0], p) case types.SetKind: elemType := t.Desc.(types.CompoundDesc).ElemTypes[0] return !gen.containsNonComparable(elemType, p) && rec(elemType, p) case types.MapKind: elemTypes := t.Desc.(types.CompoundDesc).ElemTypes return !gen.containsNonComparable(elemTypes[0], p) && rec(elemTypes[0], p) && rec(elemTypes[1], p) case types.StructKind: userName := gen.generator.UserName(t) if b, ok := cache[userName]; ok { return b } cache[userName] = true for _, f := range t.Desc.(types.StructDesc).Fields { if f.T.Equals(t) || !rec(f.T, p) { cache[userName] = false return false } } return true default: return true } } return rec(t, p) }
func (gen *codeGen) shouldBeWritten(t types.Type) bool { if t.IsUnresolved() { return false } if t.Kind() == types.EnumKind || t.Kind() == types.StructKind { name := gen.generator.UserName(t) d.Chk.False(gen.written[name], "Multiple definitions of type named %s", name) return true } return !gen.written[gen.generator.UserName(t)] }
// ToTypeValueJS returns a string containing JS code that instantiates a Type instance equivalent to t for JavaScript. func (gen *Generator) ToTypeValueJS(t types.Type, inPackageDef bool, indent int) string { d.Chk.True(!t.HasPackageRef() && !t.IsUnresolved() || t.HasOrdinal(), "%s does not have an ordinal set", t.Name()) if t.HasPackageRef() { return fmt.Sprintf(`%s(%s.parse('%s'), %d)`, gen.ImportJS("makeType"), gen.ImportJS("Ref"), t.PackageRef().String(), t.Ordinal()) } if t.IsUnresolved() { if inPackageDef { return fmt.Sprintf(`%s(new %s(), %d)`, gen.ImportJS("makeType"), gen.ImportJS("Ref"), t.Ordinal()) } return fmt.Sprintf("%s(_pkg.ref, %d)", gen.ImportJS("makeType"), t.Ordinal()) } if types.IsPrimitiveKind(t.Kind()) { return gen.ImportJS(firstToLower(kindToString(t.Kind())) + "Type") } switch desc := t.Desc.(type) { case types.CompoundDesc: types := make([]string, len(desc.ElemTypes)) for i, t := range desc.ElemTypes { types[i] = gen.ToTypeValueJS(t, inPackageDef, 0) } return fmt.Sprintf(`%s(%s.%s, %s)`, gen.ImportJS("makeCompoundType"), gen.ImportJS("Kind"), kindToString(t.Kind()), strings.Join(types, ", ")) case types.EnumDesc: return fmt.Sprintf(`%s('%s', '%s')`, gen.ImportJS("makeEnumType"), t.Name(), strings.Join(desc.IDs, `', '`)) case types.StructDesc: flatten := func(f []types.Field) string { out := make([]string, 0, len(f)) for _, field := range f { out = append(out, fmt.Sprintf(`%snew %s('%s', %s, %t),`, ind(indent+1), gen.ImportJS("Field"), field.Name, gen.ToTypeValueJS(field.T, inPackageDef, 0), field.Optional)) } return strings.Join(out, "\n") } fields := fmt.Sprintf("%s[\n%s\n%s]", ind(indent), flatten(desc.Fields), ind(indent)) choices := fmt.Sprintf("%s[\n%s\n%s]", ind(indent), flatten(desc.Union), ind(indent)) return fmt.Sprintf("%s('%s',\n%s,\n%s\n%s)", gen.ImportJS("makeStructType"), t.Name(), fields, choices, ind(indent-1)) default: d.Chk.Fail("Unknown TypeDesc.", "%#v (%T)", desc, desc) } panic("Unreachable") }
// ToType returns a string containing Go code that instantiates a types.Type instance equivalent to t. func (gen *Generator) ToType(t types.Type, fileID, packageName string) string { d.Chk.True(!t.HasPackageRef() && !t.IsUnresolved() || t.HasOrdinal(), "%s does not have an ordinal set", t.Name()) if t.HasPackageRef() { d.Chk.True(t.HasOrdinal(), "%s does not have an ordinal set", t.Name()) return fmt.Sprintf(`%sMakeType(ref.Parse("%s"), %d)`, gen.TypesPackage, t.PackageRef().String(), t.Ordinal()) } if t.IsUnresolved() { if fileID != "" { return fmt.Sprintf(`%sMakeType(__%sPackageInFile_%s_CachedRef, %d)`, gen.TypesPackage, packageName, fileID, t.Ordinal()) } d.Chk.True(t.HasOrdinal(), "%s does not have an ordinal set", t.Name()) return fmt.Sprintf(`%sMakeType(ref.Ref{}, %d)`, gen.TypesPackage, t.Ordinal()) } if types.IsPrimitiveKind(t.Kind()) { return fmt.Sprintf("%sMakePrimitiveType(%s%sKind)", gen.TypesPackage, gen.TypesPackage, kindToString(t.Kind())) } switch desc := t.Desc.(type) { case types.CompoundDesc: types := make([]string, len(desc.ElemTypes)) for i, t := range desc.ElemTypes { types[i] = gen.ToType(t, fileID, packageName) } return fmt.Sprintf(`%sMakeCompoundType(%s%sKind, %s)`, gen.TypesPackage, gen.TypesPackage, kindToString(t.Kind()), strings.Join(types, ", ")) case types.EnumDesc: return fmt.Sprintf(`%sMakeEnumType("%s", "%s")`, gen.TypesPackage, t.Name(), strings.Join(desc.IDs, `", "`)) case types.StructDesc: flatten := func(f []types.Field) string { out := make([]string, 0, len(f)) for _, field := range f { out = append(out, fmt.Sprintf(`%sField{"%s", %s, %t},`, gen.TypesPackage, field.Name, gen.ToType(field.T, fileID, packageName), field.Optional)) } return strings.Join(out, "\n") } fields := fmt.Sprintf("[]%sField{\n%s\n}", gen.TypesPackage, flatten(desc.Fields)) choices := fmt.Sprintf("%sChoices{\n%s\n}", gen.TypesPackage, flatten(desc.Union)) return fmt.Sprintf("%sMakeStructType(\"%s\",\n%s,\n%s,\n)", gen.TypesPackage, t.Name(), fields, choices) default: d.Chk.Fail("Unknown TypeDesc.", "%#v (%T)", desc, desc) } panic("Unreachable") }
func (gen *Generator) refToID(t types.Type) string { if !t.IsUnresolved() || !t.HasPackageRef() { return gen.UserName(t) } return gen.UserName(gen.R.Resolve(t)) }
func (gen Generator) importedUserNameJS(t types.Type) string { d.Chk.True(t.HasPackageRef()) return fmt.Sprintf("%s.%s", gen.RefToAliasName(t.PackageRef()), gen.UserName(t)) }
func (gen *codeGen) Resolve(t types.Type) types.Type { if !t.IsUnresolved() { return t } if !t.HasPackageRef() { return gen.pkg.Types()[t.Ordinal()] } dep, ok := gen.deps[t.PackageRef()] d.Chk.True(ok, "Package %s is referenced in %+v, but is not a dependency.", t.PackageRef().String(), t) return dep.Types()[t.Ordinal()] }