From 069b8de8209ed052ce2cffc77468628886c41200 Mon Sep 17 00:00:00 2001 From: Cory Slep Date: Sat, 8 Dec 2018 23:05:02 +0100 Subject: [PATCH] Add initial convert (exp is broken at this commit) Still need to flesh out the types for conversion. Also still need to add the serialize and deserialize calls for individual types. Finally, will need to put the finishing touches on writing the output files in the desired directories. Then the experimental tool will be ready for end to end testing. --- tools/exp/convert/convert.go | 209 +++++++++++++++++++++++++++++++++ tools/exp/props/funcprop.go | 2 +- tools/exp/props/nonfuncprop.go | 2 +- tools/exp/props/property.go | 15 ++- tools/exp/rdf/data.go | 24 ++-- tools/exp/rdf/parse.go | 6 +- tools/exp/rdf/rdf.go | 4 +- tools/exp/types/type.go | 2 +- 8 files changed, 237 insertions(+), 27 deletions(-) create mode 100644 tools/exp/convert/convert.go 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" )