diff --git a/go.mod b/go.mod index 62a095f..5c62e94 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( require ( github.com/Clever/csvlint v0.3.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect + github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/goombaio/orderedmap v0.0.0-20180924084748-ba921b7e2419 // indirect github.com/kr/pretty v0.3.0 // indirect diff --git a/go.sum b/go.sum index 688bba1..7c68023 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/chen3feng/stl4go v0.1.1 h1:0L1+mDw7pomftKDruM23f1mA7miavOj6C6MZeadzN2Q= github.com/chen3feng/stl4go v0.1.1/go.mod h1:5ml3psLgETJjRJnMbPE+JiHLrCpt+Ajc2weeTECXzWU= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/pkg/obilua/obilib.go b/pkg/obilua/obilib.go index a08301a..5d9c180 100644 --- a/pkg/obilua/obilib.go +++ b/pkg/obilua/obilib.go @@ -4,4 +4,5 @@ import lua "github.com/yuin/gopher-lua" func RegisterObilib(luaState *lua.LState) { RegisterObiSeq(luaState) + RegisterObiTaxonomy(luaState) } diff --git a/pkg/obilua/obiseq.go b/pkg/obilua/obiseq.go index 42bddae..456f232 100644 --- a/pkg/obilua/obiseq.go +++ b/pkg/obilua/obiseq.go @@ -1,7 +1,9 @@ package obilua import ( + "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiformats" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiseq" + "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obitax" lua "github.com/yuin/gopher-lua" ) @@ -16,6 +18,7 @@ func registerBioSequenceType(luaState *lua.LState) { bioSequenceType := luaState.NewTypeMetatable(luaBioSequenceTypeName) luaState.SetGlobal(luaBioSequenceTypeName, bioSequenceType) luaState.SetField(bioSequenceType, "new", luaState.NewFunction(newObiSeq)) + luaState.SetField(bioSequenceType, "nil", obiseq2Lua(luaState, nil)) luaState.SetField(bioSequenceType, "__index", luaState.SetFuncs(luaState.NewTable(), @@ -53,6 +56,7 @@ var bioSequenceMethods = map[string]lua.LGFunction{ "definition": bioSequenceGetSetDefinition, "count": bioSequenceGetSetCount, "taxid": bioSequenceGetSetTaxid, + "taxon": bioSequenceGetSetTaxon, "attribute": bioSequenceGetSetAttribute, "len": bioSequenceGetLength, "has_sequence": bioSequenceHasSequence, @@ -62,6 +66,9 @@ var bioSequenceMethods = map[string]lua.LGFunction{ "md5_string": bioSequenceGetMD5String, "subsequence": bioSequenceGetSubsequence, "reverse_complement": bioSequenceGetRevcomp, + "fasta": bioSequenceGetFasta, + "fastq": bioSequenceGetFastq, + "string": bioSequenceAsString, } // checkBioSequence checks if the first argument in the Lua stack is a *obiseq.BioSequence. @@ -254,3 +261,88 @@ func bioSequenceGetRevcomp(luaState *lua.LState) int { luaState.Push(obiseq2Lua(luaState, revcomp)) return 1 } + +func bioSequenceGetSetTaxon(luaState *lua.LState) int { + s := checkBioSequence(luaState) + + if luaState.GetTop() > 1 { + taxon := checkTaxon(luaState, 2) + + s.SetTaxon(taxon) + + return 0 + } + + taxon := s.Taxon(obitax.DefaultTaxonomy()) + luaState.Push(taxon2Lua(luaState, taxon)) + + return 1 +} + +func bioSequenceGetFasta(luaState *lua.LState) int { + s := checkBioSequence(luaState) + + formater := obiformats.FormatFastSeqJsonHeader + + if luaState.GetTop() > 1 { + format := luaState.CheckString(2) + switch format { + case "json": + formater = obiformats.FormatFastSeqJsonHeader + case "obi": + formater = obiformats.FormatFastSeqOBIHeader + } + } + + txt := obiformats.FormatFasta(s, formater) + + luaState.Push(lua.LString(txt)) + return 1 +} + +func bioSequenceGetFastq(luaState *lua.LState) int { + s := checkBioSequence(luaState) + + formater := obiformats.FormatFastSeqJsonHeader + + if luaState.GetTop() > 1 { + format := luaState.CheckString(2) + switch format { + case "json": + formater = obiformats.FormatFastSeqJsonHeader + case "obi": + formater = obiformats.FormatFastSeqOBIHeader + } + } + + txt := obiformats.FormatFastq(s, formater) + + luaState.Push(lua.LString(txt)) + return 1 +} + +func bioSequenceAsString(luaState *lua.LState) int { + s := checkBioSequence(luaState) + + formater := obiformats.FormatFastSeqJsonHeader + format := obiformats.FormatFasta + + if s.HasQualities() { + format = obiformats.FormatFastq + } + + if luaState.GetTop() > 1 { + format := luaState.CheckString(2) + switch format { + case "json": + formater = obiformats.FormatFastSeqJsonHeader + case "obi": + formater = obiformats.FormatFastSeqOBIHeader + } + } + + txt := format(s, formater) + + luaState.Push(lua.LString(txt)) + return 1 +} diff --git a/pkg/obilua/obiseqslice.go b/pkg/obilua/obiseqslice.go index 15dd3b2..6f6f443 100644 --- a/pkg/obilua/obiseqslice.go +++ b/pkg/obilua/obiseqslice.go @@ -1,6 +1,9 @@ package obilua import ( + "strings" + + "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiformats" "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiseq" lua "github.com/yuin/gopher-lua" ) @@ -11,6 +14,7 @@ func registerBioSequenceSliceType(luaState *lua.LState) { bioSequenceSliceType := luaState.NewTypeMetatable(luaBioSequenceSliceTypeName) luaState.SetGlobal(luaBioSequenceSliceTypeName, bioSequenceSliceType) luaState.SetField(bioSequenceSliceType, "new", luaState.NewFunction(newObiSeqSlice)) + luaState.SetField(bioSequenceSliceType, "nil", obiseqslice2Lua(luaState, nil)) luaState.SetField(bioSequenceSliceType, "__index", luaState.SetFuncs(luaState.NewTable(), @@ -37,6 +41,9 @@ var bioSequenceSliceMethods = map[string]lua.LGFunction{ "pop": bioSequenceSlicePop, "sequence": bioSequenceSliceGetSetSequence, "len": bioSequenceSliceGetLength, + "fasta": bioSequenceSliceGetFasta, + "fastq": bioSequenceSliceGetFastq, + "string": bioSequenceSliceAsString, } func checkBioSequenceSlice(L *lua.LState) *obiseq.BioSequenceSlice { @@ -105,3 +112,96 @@ func bioSequenceSlicePop(luaState *lua.LState) int { return 1 } + +func bioSequenceSliceGetFasta(luaState *lua.LState) int { + s := checkBioSequenceSlice(luaState) + + formater := obiformats.FormatFastSeqJsonHeader + + if luaState.GetTop() > 1 { + format := luaState.CheckString(2) + switch format { + case "json": + formater = obiformats.FormatFastSeqJsonHeader + case "obi": + formater = obiformats.FormatFastSeqOBIHeader + } + } + + txts := make([]string, len(*s)) + + for i, seq := range *s { + txts[i] = obiformats.FormatFasta(seq, formater) + } + + txt := strings.Join(txts, "\n") + + luaState.Push(lua.LString(txt)) + return 1 +} + +func bioSequenceSliceGetFastq(luaState *lua.LState) int { + s := checkBioSequenceSlice(luaState) + + formater := obiformats.FormatFastSeqJsonHeader + + if luaState.GetTop() > 1 { + format := luaState.CheckString(2) + switch format { + case "json": + formater = obiformats.FormatFastSeqJsonHeader + case "obi": + formater = obiformats.FormatFastSeqOBIHeader + } + } + + txts := make([]string, len(*s)) + + for i, seq := range *s { + txts[i] = obiformats.FormatFastq(seq, formater) + } + + txt := strings.Join(txts, "\n") + + luaState.Push(lua.LString(txt)) + return 1 +} + +func bioSequenceSliceAsString(luaState *lua.LState) int { + s := checkBioSequenceSlice(luaState) + + formater := obiformats.FormatFastSeqJsonHeader + + if luaState.GetTop() > 1 { + format := luaState.CheckString(2) + switch format { + case "json": + formater = obiformats.FormatFastSeqJsonHeader + case "obi": + formater = obiformats.FormatFastSeqOBIHeader + } + } + + txts := make([]string, len(*s)) + + format := obiformats.FormatFasta + + allQual := true + + for _, s := range *s { + allQual = allQual && s.HasQualities() + } + + if allQual { + format = obiformats.FormatFastq + } + + for i, seq := range *s { + txts[i] = format(seq, formater) + } + + txt := strings.Join(txts, "\n") + + luaState.Push(lua.LString(txt)) + return 1 +} diff --git a/pkg/obilua/obitaxon.go b/pkg/obilua/obitaxon.go new file mode 100644 index 0000000..b8448c6 --- /dev/null +++ b/pkg/obilua/obitaxon.go @@ -0,0 +1,139 @@ +package obilua + +import ( + "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obitax" + lua "github.com/yuin/gopher-lua" +) + +const luaTaxonTypeName = "Taxon" + +func registerTaxonType(luaState *lua.LState) { + taxonType := luaState.NewTypeMetatable(luaTaxonTypeName) + luaState.SetGlobal(luaTaxonTypeName, taxonType) + luaState.SetField(taxonType, "new", luaState.NewFunction(newTaxon)) + luaState.SetField(taxonType, "nil", taxonomy2Lua(luaState, nil)) + + luaState.SetField(taxonType, "__index", + luaState.SetFuncs(luaState.NewTable(), + taxonMethods)) +} + +func taxon2Lua(interpreter *lua.LState, + taxon *obitax.Taxon) lua.LValue { + ud := interpreter.NewUserData() + ud.Value = taxon + interpreter.SetMetatable(ud, interpreter.GetTypeMetatable(luaTaxonTypeName)) + + return ud +} + +func newTaxon(luaState *lua.LState) int { + taxonomy := checkTaxonomy(luaState) + taxid := luaState.CheckString(2) + parent := luaState.CheckString(3) + sname := luaState.CheckString(4) + rank := luaState.CheckString(5) + + isroot := false + + if luaState.GetTop() > 5 { + isroot = luaState.CheckBool(6) + } + + taxon, err := taxonomy.AddTaxon(taxid, parent, rank, isroot, false) + + if err != nil { + luaState.RaiseError("(%v,%v,%v) : Error on taxon creation: %v", taxid, parent, sname, err) + return 0 + } + + taxon.SetName(sname, "scientific name") + + luaState.Push(taxon2Lua(luaState, taxon)) + return 1 +} + +var taxonMethods = map[string]lua.LGFunction{ + "string": taxonAsString, + "scientific_name": taxonGetSetScientificName, + "parent": taxonGetParent, + "taxon_at_rank": taxGetTaxonAtRank, + "species": taxonGetSpecies, + "genus": taxonGetGenus, + "family": taxonGetFamily, +} + +func checkTaxon(L *lua.LState, i int) *obitax.Taxon { + ud := L.CheckUserData(i) + if v, ok := ud.Value.(*obitax.Taxon); ok { + return v + } + L.ArgError(i, "obitax.Taxon expected") + return nil +} + +func taxonAsString(luaState *lua.LState) int { + taxon := checkTaxon(luaState, 1) + luaState.Push(lua.LString(taxon.String())) + return 1 +} + +func taxonGetSetScientificName(luaState *lua.LState) int { + taxon := checkTaxon(luaState, 1) + + if luaState.GetTop() > 1 { + sname := luaState.CheckString(2) + taxon.SetName(sname, "scientific name") + return 0 + } + + luaState.Push(lua.LString(taxon.ScientificName())) + return 1 +} + +func taxonGetParent(luaState *lua.LState) int { + taxon := checkTaxon(luaState, 1) + + parent := taxon.Parent() + luaState.Push(taxon2Lua(luaState, parent)) + + return 1 +} + +func taxonGetSpecies(luaState *lua.LState) int { + taxon := checkTaxon(luaState, 1) + + species := taxon.Species() + luaState.Push(taxon2Lua(luaState, species)) + + return 1 +} + +func taxonGetGenus(luaState *lua.LState) int { + taxon := checkTaxon(luaState, 1) + + genus := taxon.Genus() + luaState.Push(taxon2Lua(luaState, genus)) + + return 1 +} + +func taxonGetFamily(luaState *lua.LState) int { + taxon := checkTaxon(luaState, 1) + + family := taxon.Family() + luaState.Push(taxon2Lua(luaState, family)) + + return 1 +} + +func taxGetTaxonAtRank(luaState *lua.LState) int { + taxon := checkTaxon(luaState, 1) + rank := luaState.CheckString(2) + + taxonAt := taxon.TaxonAtRank(rank) + + luaState.Push(taxon2Lua(luaState, taxonAt)) + + return 1 +} diff --git a/pkg/obilua/obitaxonomy.go b/pkg/obilua/obitaxonomy.go new file mode 100644 index 0000000..a4f4b3a --- /dev/null +++ b/pkg/obilua/obitaxonomy.go @@ -0,0 +1,110 @@ +package obilua + +import ( + "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obitax" + "git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiutils" + lua "github.com/yuin/gopher-lua" +) + +func RegisterObiTaxonomy(luaState *lua.LState) { + registerTaxonomyType(luaState) + registerTaxonType(luaState) +} + +const luaTaxonomyTypeName = "Taxonomy" + +func registerTaxonomyType(luaState *lua.LState) { + taxonomyType := luaState.NewTypeMetatable(luaTaxonomyTypeName) + luaState.SetGlobal(luaTaxonomyTypeName, taxonomyType) + luaState.SetField(taxonomyType, "new", luaState.NewFunction(newTaxonomy)) + luaState.SetField(taxonomyType, "default", luaState.NewFunction(defaultTaxonomy)) + luaState.SetField(taxonomyType, "has_default", luaState.NewFunction(hasDefaultTaxonomy)) + luaState.SetField(taxonomyType, "nil", taxon2Lua(luaState, nil)) + luaState.SetField(taxonomyType, "__index", + luaState.SetFuncs(luaState.NewTable(), + taxonomyMethods)) +} + +func taxonomy2Lua(interpreter *lua.LState, + taxonomy *obitax.Taxonomy) lua.LValue { + ud := interpreter.NewUserData() + ud.Value = taxonomy + interpreter.SetMetatable(ud, interpreter.GetTypeMetatable(luaTaxonomyTypeName)) + + return ud +} + +func newTaxonomy(luaState *lua.LState) int { + name := luaState.CheckString(1) + code := luaState.CheckString(2) + + charset := obiutils.AsciiAlphaNumSet + if luaState.GetTop() > 2 { + charset = obiutils.AsciiSetFromString(luaState.CheckString(3)) + } + + taxonomy := obitax.NewTaxonomy(name, code, charset) + + luaState.Push(taxonomy2Lua(luaState, taxonomy)) + return 1 +} + +func defaultTaxonomy(luaState *lua.LState) int { + taxonomy := obitax.DefaultTaxonomy() + + if taxonomy == nil { + luaState.RaiseError("No default taxonomy") + return 0 + } + + luaState.Push(taxonomy2Lua(luaState, taxonomy)) + return 1 +} + +func hasDefaultTaxonomy(luaState *lua.LState) int { + taxonomy := obitax.DefaultTaxonomy() + + luaState.Push(lua.LBool(taxonomy != nil)) + return 1 +} + +var taxonomyMethods = map[string]lua.LGFunction{ + "name": taxonomyGetName, + "code": taxonomyGetCode, + "taxon": taxonomyGetTaxon, +} + +func checkTaxonomy(L *lua.LState) *obitax.Taxonomy { + ud := L.CheckUserData(1) + if v, ok := ud.Value.(*obitax.Taxonomy); ok { + return v + } + L.ArgError(1, "obitax.Taxonomy expected") + return nil +} + +func taxonomyGetName(luaState *lua.LState) int { + taxo := checkTaxonomy(luaState) + luaState.Push(lua.LString(taxo.Name())) + return 1 +} + +func taxonomyGetCode(luaState *lua.LState) int { + taxo := checkTaxonomy(luaState) + luaState.Push(lua.LString(taxo.Code())) + return 1 +} + +func taxonomyGetTaxon(luaState *lua.LState) int { + taxo := checkTaxonomy(luaState) + taxid := luaState.CheckString(2) + taxon, err := taxo.Taxon(taxid) + + if err != nil { + luaState.RaiseError("%s : Error on taxon taxon: %v", taxid, err) + return 0 + } + + luaState.Push(taxon2Lua(luaState, taxon)) + return 1 +} diff --git a/pkg/obioptions/version.go b/pkg/obioptions/version.go index e746eb7..4e25321 100644 --- a/pkg/obioptions/version.go +++ b/pkg/obioptions/version.go @@ -8,7 +8,7 @@ import ( // corresponds to the last commit, and not the one when the file will be // commited -var _Commit = "d3dac1b" +var _Commit = "c10df07" var _Version = "Release 4.2.0" // Version returns the version of the obitools package.