Commit f4bdf071 authored by Eric Myhre's avatar Eric Myhre

Update type system draft.

Giving a type to each, um, kind of type.

Syntax draft changed.  Bigger examples elsewhere.  May need to start
writing up more, but might not belong in this repo, either (it's not
a detail of the golang implementation alone).  Anyway, it's only for
eyecandy at present: I'm not going to start work on a parser for the
DSL any time soon; it's just something to keep in mind so it can be
evaluated against simplicity heuristics.

Struct fields are in a slice now.

Waffling on whether to call that kind "struct" vs "object".  Neither is
very satisfying.  "Struct" is suggestive of something with concrete
memory layout considerings; this is not that.  "Object" is suggestive
of something with methods and behaviors attached; this is not that.

Introduce an enum for different kinds of union.  Some of the terms here
are developed from https://github.com/ipfs/unixfs-v2/issues/20 ; the
term "keyed" is from https://github.com/polydawn/refmt/pull/30 ; and
the style "kinded" is a concept I haven't written up much about before,
but the TypeUnion.ValuesKinded field type should self-explain it.

Flip terminology from "required" to "optional".  Struct fields that are
mentioned in the schema default to being required; why else would you
have mentioned them?  Previous draft of DSL which used question marks
and exclamations points to denote these things dropped; the new hope is
that *neither* nullable nor optional will be used with enough frequency
that the sigil-heavy shorthand will turn out to be desirable.
Signed-off-by: default avatarEric Myhre <hash@exultant.us>
parent f969ae41
package typed package typed
// ReprKind represents the primitive kind in the IPLD data model.
// Note that it contains the concept of "map", but not "object" --
// "object" is a concept up in our type system layers, and *not*
// present in the data model layer.
type ReprKind uint8
const (
ReprKind_Invalid = 0
ReprKind_Bool = 'b'
ReprKind_String = 's'
ReprKind_Bytes = 'x'
ReprKind_Int = 'i'
ReprKind_Float = 'f'
ReprKind_Map = '{' // still feel these should be string-only keys. consider the Type.Fields behavior if it's an int-keyed map: insane?
ReprKind_List = '['
ReprKind_Null = '-'
ReprKind_Link = '/'
)
// Kind is our type level kind. It includes "object", "union", and other
// advanced concepts. "map" at this layer also contains additional constraints;
// it must be a single type of element.
type Kind uint8
const (
Kind_Invalid = 0
Kind_Bool = 'b'
Kind_String = 's'
Kind_Bytes = 'x'
Kind_Int = 'i'
Kind_Float = 'f'
Kind_Map = '{'
Kind_List = '['
Kind_Null = '-'
Kind_Link = '/'
Kind_Union = 'u'
Kind_Obj = 'o'
Kind_Enum = 'e'
)
type Type struct {
Name string // must be unique when scoped to this universe
Kind // the type kind.
ReprKind // the representation kind. if wildly different than the type kind, implies a transform func.
Elem *Type // only valid kind Kind==Map or Kind==List
ElemNullable bool // only valid kind Kind==Map or Kind==List
Fields map[string]ObjField // only valid if Kind==Obj.
Union map[string]*Type // only valid if Kind==Union.
EnumVals []interface{} // only valid if Kind==Enum. can be ReprKind int, str. (maybe bytes? discuss.)
}
type ObjField struct {
Name string // must be unique in scope of this object
Type *Type
Required bool // required means the field must be present for the obj to be recognized (but no comment on if null is valid).
Nullable bool // nullable means that when present, the field may be null.
}
type Universe map[string]*Type
/*
type Foo {
f1: String
f2: [String!]!
?f3: String!
}
*/
var ( var (
// Prelude types // Prelude types
tString = &Type{ tString = TypeString{
Name: "String", Name: "String",
Kind: Kind_String,
ReprKind: ReprKind_String,
} }
// User's types // User's types
tFoo = &Type{ /*
Name: "Foo", struct Foo {
Kind: Kind_Obj, f1 String
ReprKind: ReprKind_Map, f2 [nullable String]
Fields: map[string]ObjField{ f3 optional String
"f1": {"f1", tString, true, true}, }
"f2": {"f2", &Type{ */
Name: "", tFoo = TypeObject{
Kind: Kind_List, Name: "Foo",
ReprKind: Kind_List, Fields: []ObjectField{
Elem: tString, {"f1", tString, false, true},
ElemNullable: false, {"f2", TypeList{
}, true, false}, Name: "[nullable String]",
"f3": {"f3", tString, false, false}, Anon: true,
ValueType: tString,
ValueNullable: true,
}, false, false},
{"f3", tString, true, false},
}, },
} }
// The Universe // The Universe
......
package typed
// ReprKind represents the primitive kind in the IPLD data model.
// Note that it contains the concept of "map", but not "object" --
// "object" is a concept up in our type system layers, and *not*
// present in the data model layer.
type ReprKind uint8
const (
ReprKind_Invalid = 0
ReprKind_Bool = 'b'
ReprKind_String = 's'
ReprKind_Bytes = 'x'
ReprKind_Int = 'i'
ReprKind_Float = 'f'
ReprKind_Map = '{' // still feel these should be string-only keys. consider the Type.Fields behavior if it's an int-keyed map: insane?
ReprKind_List = '['
ReprKind_Null = '-'
ReprKind_Link = '/'
)
// Kind is our type level kind. It includes "object", "union", and other
// advanced concepts. "map" at this layer also contains additional constraints;
// it must be a single type of element.
type Kind uint8
const (
Kind_Invalid = 0
Kind_Bool = 'b'
Kind_String = 's'
Kind_Bytes = 'x'
Kind_Int = 'i'
Kind_Float = 'f'
Kind_Map = '{'
Kind_List = '['
Kind_Null = '-'
Kind_Link = '/'
Kind_Union = 'u'
Kind_Obj = 'o'
Kind_Enum = 'e'
)
package typed
type TypeName string
type Type interface {
// Name() TypeName
// ReprKind() ReprKind
}
type TypeBool struct {
Name TypeName
}
type TypeString struct {
Name TypeName
}
type TypeBytes struct {
Name TypeName
}
type TypeInt struct {
Name TypeName
}
type TypeFloat struct {
Name TypeName
}
type TypeMap struct {
Name TypeName
Anon bool
KeyType Type
ValueType Type
ValueNullable bool
}
type TypeList struct {
Name TypeName
Anon bool
ValueType Type
ValueNullable bool
}
type TypeLink struct {
Name TypeName
// ...?
}
type TypeUnion struct {
Name TypeName
Style UnionStyle
ValuesKinded map[ReprKind]Type // for Style==Kinded
Values map[TypeName]Type // for Style!=Kinded
TypeHintKey string // for Style==Envelope|Inline
ContentKey string // for Style==Envelope
}
type UnionStyle struct{ x string }
var (
UnionStyle_Kinded = UnionStyle{"kinded"}
UnionStyle_Keyed = UnionStyle{"keyed"}
UnionStyle_Envelope = UnionStyle{"envelope"}
UnionStyle_Inline = UnionStyle{"inline"}
)
type TypeObject struct {
Name TypeName
TupleStyle bool // if true, ReprKind=Array instead of map (and optional fields are invalid!)
Fields []ObjectField
}
type ObjectField struct {
Name string
Type Type
Optional bool
Nullable bool
}
type TypeEnum struct {
// TODO
}
package typed
type Universe map[TypeName]Type
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment