diff --git a/tools/exp/convert/convert.go b/tools/exp/convert/convert.go new file mode 100644 index 0000000..2268f09 --- /dev/null +++ b/tools/exp/convert/convert.go @@ -0,0 +1,209 @@ +package convert + +import ( + "fmt" + "github.com/cjslep/activity/tools/exp/props" + "github.com/cjslep/activity/tools/exp/rdf" + "github.com/cjslep/activity/tools/exp/types" + "strings" +) + +type vocabulary struct { + Kinds map[string]*props.Kind + FProps map[string]*props.FunctionalPropertyGenerator + NFProps map[string]*props.NonFunctionalPropertyGenerator + Types map[string]*types.TypeGenerator +} + +func newVocabulary() vocabulary { + return vocabulary{ + Kinds: make(map[string]*props.Kind, 0), + FProps: make(map[string]*props.FunctionalPropertyGenerator, 0), + NFProps: make(map[string]*props.NonFunctionalPropertyGenerator, 0), + Types: make(map[string]*types.TypeGenerator, 0), + } +} + +type PropertyPackagePolicy int + +const ( + FlatUnderRoot PropertyPackagePolicy = iota + IndividualUnderRoot +) + +type Converter struct { + Registry *rdf.RDFRegistry + VocabularyRoot string + PropertyPackagePolicy PropertyPackagePolicy + PropertyPackageRoot string +} + +func (c Converter) convert(p *rdf.ParsedVocabulary) (v vocabulary, e error) { + v = newVocabulary() + for k, val := range p.Vocab.Values { + v.Kinds[k] = c.convertValue(val) + } + for k, prop := range p.Vocab.Properties { + if prop.Functional { + v.FProps[k], e = c.convertFunctionalProperty(prop, v.Kinds, p.Vocab, p.References) + } else { + v.NFProps[k], e = c.convertNonFunctionalProperty(prop, v.Kinds, p.Vocab, p.References) + } + if e != nil { + return + } + } + // TODO: Types in dependency order. + return +} + +func (c Converter) convertFunctionalProperty(p rdf.VocabularyProperty, + kinds map[string]*props.Kind, + v rdf.Vocabulary, + refs map[string]*rdf.Vocabulary) (fp *props.FunctionalPropertyGenerator, e error) { + var k []props.Kind + k, e = c.propertyKinds(p, kinds, v, refs) + if e != nil { + return + } + var pkg string + pkg, e = c.propertyPackageName(p) + if e != nil { + return + } + fp = props.NewFunctionalPropertyGenerator( + pkg, + c.toIdentifier(p), + k, + p.NaturalLanguageMap) + return +} + +func (c Converter) convertNonFunctionalProperty(p rdf.VocabularyProperty, + kinds map[string]*props.Kind, + v rdf.Vocabulary, + refs map[string]*rdf.Vocabulary) (nfp *props.NonFunctionalPropertyGenerator, e error) { + var k []props.Kind + k, e = c.propertyKinds(p, kinds, v, refs) + if e != nil { + return + } + var pkg string + pkg, e = c.propertyPackageName(p) + if e != nil { + return + } + nfp = props.NewNonFunctionalPropertyGenerator( + pkg, + c.toIdentifier(p), + k, + p.NaturalLanguageMap) + return +} + +func (c Converter) convertValue(v rdf.VocabularyValue) (k *props.Kind) { + k = &props.Kind{ + Name: c.toIdentifier(v), + ConcreteKind: v.DefinitionType, + Nilable: c.isNilable(v.DefinitionType), + SerializeFn: v.SerializeFn, + DeserializeFn: v.DeserializeFn, + LessFn: v.LessFn, + } + return +} + +func (c Converter) convertTypeToKind(v rdf.VocabularyType) (k *props.Kind) { + k = &props.Kind{ + Name: c.toIdentifier(v), + ConcreteKind: strings.Title(v.Name), + Nilable: true, + // TODO + SerializeFn: types.SerializeFn, + DeserializeFn: types.DeserializeFn, + LessFn: types.LessFn, + } + return +} + +func (c Converter) propertyKinds(v rdf.VocabularyProperty, + kinds map[string]*props.Kind, + vocab rdf.Vocabulary, + refs map[string]*rdf.Vocabulary) (k []props.Kind, e error) { + for _, r := range v.Range { + if len(r.Vocab) == 0 { + if kind, ok := kinds[r.Name]; !ok { + // It is a Type of the vocabulary + if t, ok := vocab.Types[r.Name]; !ok { + e = fmt.Errorf("cannot find own kind with name %q", r.Name) + return + } else { + k = append(k, *c.convertTypeToKind(t)) + } + } else { + // It is a Value of the vocabulary + k = append(k, *kind) + } + } else { + var url string + url, e = c.Registry.ResolveAlias(r.Vocab) + if e != nil { + return + } + refVocab, ok := refs[url] + if !ok { + e = fmt.Errorf("references do not contain %s", url) + return + } + if val, ok := refVocab.Values[r.Name]; !ok { + // It is a Type of the vocabulary instead + if t, ok := refVocab.Types[r.Name]; !ok { + e = fmt.Errorf("cannot find kind with name %q in %s", r.Name, url) + return + } else { + k = append(k, *c.convertTypeToKind(t)) + } + } else { + // It is a Value of the vocabulary + k = append(k, *c.convertValue(val)) + } + } + } + return +} + +func (c Converter) propertyPackageName(v rdf.VocabularyProperty) (pkg string, e error) { + switch c.PropertyPackagePolicy { + case FlatUnderRoot: + pkg = c.PropertyPackageRoot + case IndividualUnderRoot: + pkg = v.Name + default: + e = fmt.Errorf("unrecognized PropertyPackagePolicy: %v", c.PropertyPackagePolicy) + } + return +} + +// TODO: Use this? +func (c Converter) propertyPackageFile(v rdf.VocabularyProperty) (pkg string, e error) { + switch c.PropertyPackagePolicy { + case FlatUnderRoot: + pkg = fmt.Sprintf("%s/%s", c.VocabularyRoot, c.PropertyPackageRoot) + case IndividualUnderRoot: + pkg = fmt.Sprintf("%s/%s/%s", c.VocabularyRoot, c.PropertyPackageRoot, v.Name) + default: + e = fmt.Errorf("unrecognized PropertyPackagePolicy: %v", c.PropertyPackagePolicy) + } + return +} + +func (c Converter) toIdentifier(n rdf.NameGetter) props.Identifier { + return props.Identifier{ + LowerName: n.GetName(), + CamelName: strings.Title(n.GetName()), + } +} + +func (c Converter) isNilable(goType string) bool { + return goType[0] == '*' +} diff --git a/tools/exp/props/funcprop.go b/tools/exp/props/funcprop.go index 4b8ea54..3eb890a 100644 --- a/tools/exp/props/funcprop.go +++ b/tools/exp/props/funcprop.go @@ -2,8 +2,8 @@ package props import ( "fmt" + "github.com/cjslep/activity/tools/exp/codegen" "github.com/dave/jennifer/jen" - "github.com/go-fed/activity/tools/exp/codegen" "sync" ) diff --git a/tools/exp/props/nonfuncprop.go b/tools/exp/props/nonfuncprop.go index a67ffde..e55a523 100644 --- a/tools/exp/props/nonfuncprop.go +++ b/tools/exp/props/nonfuncprop.go @@ -2,8 +2,8 @@ package props import ( "fmt" + "github.com/cjslep/activity/tools/exp/codegen" "github.com/dave/jennifer/jen" - "github.com/go-fed/activity/tools/exp/codegen" "sync" ) diff --git a/tools/exp/props/property.go b/tools/exp/props/property.go index 994b6de..60b2bdb 100644 --- a/tools/exp/props/property.go +++ b/tools/exp/props/property.go @@ -2,8 +2,8 @@ package props import ( "fmt" + "github.com/cjslep/activity/tools/exp/codegen" "github.com/dave/jennifer/jen" - "github.com/go-fed/activity/tools/exp/codegen" ) const ( @@ -59,13 +59,12 @@ type Identifier struct { // deserialize such types, compare the types, and other meta-information to use // during Go code generation. type Kind struct { - Name Identifier - ConcreteKind string - Nilable bool - HasNaturalLanguageMap bool - SerializeFn codegen.Function - DeserializeFn codegen.Function - LessFn codegen.Function + Name Identifier + ConcreteKind string + Nilable bool + SerializeFn codegen.Function + DeserializeFn codegen.Function + LessFn codegen.Function } // PropertyGenerator is a common base struct used in both Functional and diff --git a/tools/exp/rdf/data.go b/tools/exp/rdf/data.go index b830d48..8b90c20 100644 --- a/tools/exp/rdf/data.go +++ b/tools/exp/rdf/data.go @@ -3,6 +3,7 @@ package rdf import ( "bytes" "fmt" + "github.com/cjslep/activity/tools/exp/codegen" "net/url" ) @@ -99,6 +100,9 @@ type VocabularyValue struct { URI *url.URL DefinitionType string Zero string + SerializeFn codegen.Function + DeserializeFn codegen.Function + LessFn codegen.Function } func (v VocabularyValue) String() string { @@ -109,7 +113,7 @@ func (v *VocabularyValue) SetName(s string) { v.Name = s } -func (v *VocabularyValue) GetName() string { +func (v VocabularyValue) GetName() string { return v.Name } @@ -121,7 +125,7 @@ func (v *VocabularyValue) SetURI(s string) error { var ( _ NameSetter = &VocabularyValue{} - _ nameGetter = &VocabularyValue{} + _ NameGetter = &VocabularyValue{} _ URISetter = &VocabularyValue{} ) @@ -143,7 +147,7 @@ func (v *VocabularyType) SetName(s string) { v.Name = s } -func (v *VocabularyType) GetName() string { +func (v VocabularyType) GetName() string { return v.Name } @@ -163,7 +167,7 @@ func (v *VocabularyType) AddExample(e *VocabularyExample) { var ( _ NameSetter = &VocabularyType{} - _ nameGetter = &VocabularyType{} + _ NameGetter = &VocabularyType{} _ URISetter = &VocabularyType{} _ NotesSetter = &VocabularyType{} _ ExampleAdder = &VocabularyType{} @@ -193,7 +197,7 @@ func (v *VocabularyProperty) SetName(s string) { v.Name = s } -func (v *VocabularyProperty) GetName() string { +func (v VocabularyProperty) GetName() string { return v.Name } @@ -213,7 +217,7 @@ func (v *VocabularyProperty) AddExample(e *VocabularyExample) { var ( _ NameSetter = &VocabularyProperty{} - _ nameGetter = &VocabularyProperty{} + _ NameGetter = &VocabularyProperty{} _ URISetter = &VocabularyProperty{} _ NotesSetter = &VocabularyProperty{} _ ExampleAdder = &VocabularyProperty{} @@ -235,7 +239,7 @@ func (v *VocabularyExample) SetName(s string) { v.Name = s } -func (v *VocabularyExample) GetName() string { +func (v VocabularyExample) GetName() string { return v.Name } @@ -247,7 +251,7 @@ func (v *VocabularyExample) SetURI(s string) error { var ( _ NameSetter = &VocabularyExample{} - _ nameGetter = &VocabularyExample{} + _ NameGetter = &VocabularyExample{} _ URISetter = &VocabularyExample{} ) @@ -268,7 +272,7 @@ func (v *VocabularyReference) SetName(s string) { v.Name = s } -func (v *VocabularyReference) GetName() string { +func (v VocabularyReference) GetName() string { return v.Name } @@ -280,6 +284,6 @@ func (v *VocabularyReference) SetURI(s string) error { var ( _ NameSetter = &VocabularyReference{} - _ nameGetter = &VocabularyReference{} + _ NameGetter = &VocabularyReference{} _ URISetter = &VocabularyReference{} ) diff --git a/tools/exp/rdf/parse.go b/tools/exp/rdf/parse.go index 3147306..78b188e 100644 --- a/tools/exp/rdf/parse.go +++ b/tools/exp/rdf/parse.go @@ -73,7 +73,7 @@ func (p *ParsingContext) Push() { func (p *ParsingContext) Pop() { p.Current = p.Stack[0] p.Stack = p.Stack[1:] - if ng, ok := p.Current.(nameGetter); ok { + if ng, ok := p.Current.(NameGetter); ok { p.Name = ng.GetName() } } @@ -92,7 +92,7 @@ type NameSetter interface { SetName(string) } -type nameGetter interface { +type NameGetter interface { GetName() string } @@ -194,7 +194,7 @@ func resolveReference(reference VocabularyReference, registry *RDFRegistry, ctx vocab := &ctx.Result.Vocab if len(reference.Vocab) > 0 { name = joinAlias(reference.Vocab, reference.Name) - url, e := registry.resolveAlias(reference.Vocab) + url, e := registry.ResolveAlias(reference.Vocab) if e != nil { return e } diff --git a/tools/exp/rdf/rdf.go b/tools/exp/rdf/rdf.go index 59c7f1f..0d42074 100644 --- a/tools/exp/rdf/rdf.go +++ b/tools/exp/rdf/rdf.go @@ -262,9 +262,7 @@ func (r *RDFRegistry) getNode(s string) (n RDFNode, e error) { } // resolveAlias turns an alias into its full qualifier for the ontology. -// -// Package public. -func (r *RDFRegistry) resolveAlias(alias string) (url string, e error) { +func (r *RDFRegistry) ResolveAlias(alias string) (url string, e error) { var ok bool if url, ok = r.aliases[alias]; !ok { e = fmt.Errorf("registry cannot resolve alias %q", alias) diff --git a/tools/exp/types/type.go b/tools/exp/types/type.go index 9f61385..3f861a6 100644 --- a/tools/exp/types/type.go +++ b/tools/exp/types/type.go @@ -2,8 +2,8 @@ package types import ( "fmt" + "github.com/cjslep/activity/tools/exp/codegen" "github.com/dave/jennifer/jen" - "github.com/go-fed/activity/tools/exp/codegen" "sync" )