Skip to content

Commit

Permalink
Merge pull request #51 from xushiwei/class
Browse files Browse the repository at this point in the history
gop.mod: new import statement
  • Loading branch information
xushiwei authored Jan 31, 2024
2 parents fc31883 + 2680acc commit 5a7b7e1
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 54 deletions.
15 changes: 15 additions & 0 deletions modfile/gop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,21 @@ class ."spx Sprite
doTestParseErr(t, `gop.mod:3: symbol sprite invalid: invalid Go export symbol format`, `
project github.com/goplus/spx math
class .spx sprite
`)
doTestParseErr(t, `gop.mod:3: usage: import [name] pkgPath`, `
project github.com/goplus/spx math
import
`)
doTestParseErr(t, `gop.mod:3: invalid quoted string: invalid syntax`, `
project github.com/goplus/spx math
import "\?"
`)
doTestParseErr(t, `gop.mod:3: invalid syntax`, `
project github.com/goplus/spx math
import "\?" math
`)
doTestParseErr(t, `gop.mod:2: import must declare after a project definition`, `
import math
`)
doTestParseErr(t, `gop.mod:2: unknown directive: unknown`, `
unknown .spx
Expand Down
32 changes: 6 additions & 26 deletions modfile/regtest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
package modfile_test

import (
"os"
"testing"

"github.com/goplus/mod/gopmod"
"github.com/goplus/mod/modload"
"github.com/goplus/mod/modload/modtest"
)

func TestGopMod(t *testing.T) {
Expand All @@ -43,29 +42,10 @@ func TestGopMod(t *testing.T) {
}
}

func TestLoadFromEx(t *testing.T) {
const gomodText = `
module github.com/goplus/community
go 1.18
func TestGopClass(t *testing.T) {
modtest.GopClass(t)
}

require (
github.com/goplus/yap v0.5.0 //gop:class
github.com/qiniu/a v0.1.0
github.com/qiniu/x v1.13.2 // gop:class
)
`
const gomod = "go.mod"
mod, err := modload.LoadFromEx(gomod, "gop.mod", func(s string) ([]byte, error) {
if s == gomod {
return []byte(gomodText), nil
}
return nil, os.ErrNotExist
})
if err != nil {
t.Fatal("LoadFromEx:", err)
}
if n := len(mod.Opt.ClassMods); n != 2 {
t.Fatal("len(mod.Opt.Import):", n)
}
func TestImport(t *testing.T) {
modtest.Import(t)
}
85 changes: 57 additions & 28 deletions modfile/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
type File struct {
Gop *Gop
Projects []*Project
ClassMods []string
ClassMods []string // calc by require statements in go.mod (not gop.mod).

Syntax *FileSyntax
}
Expand All @@ -51,18 +51,27 @@ func (p *File) proj() *Project { // current project
// A Gop is the gop statement.
type Gop = modfile.Go

// A Register is the //gop:class statement.
type Register struct {
ClassfileMod string // module path of classfile
Syntax *Line
// A Class is the work class statement.
type Class struct {
Ext string // can be "_[class].gox" or ".[class]", eg "_yap.gox" or ".spx"
Class string // "Sprite"
Syntax *Line
}

// A Import is the import statement.
type Import struct {
Name string // maybe empty
Path string
Syntax *Line
}

// A Project is the project statement.
type Project struct {
Ext string // can be "_[class].gox" or ".[class]", eg "_yap.gox" or ".gmx"
Class string // "Game"
Works []*Class // work class of classfile
PkgPaths []string // package paths of classfile
Ext string // can be "_[class].gox" or ".[class]", eg "_yap.gox" or ".gmx"
Class string // "Game"
Works []*Class // work class of classfile
PkgPaths []string // package paths of classfile and optional inline-imported packages.
Import []*Import // auto-imported packages
Syntax *Line
}

Expand All @@ -79,13 +88,6 @@ func (p *Project) IsProj(ext, fname string) bool {
return true
}

// A Class is the work class statement.
type Class struct {
Ext string // can be "_[class].gox" or ".[class]", eg "_yap.gox" or ".spx"
Class string // "Sprite"
Syntax *Line
}

func New(gopmod, gopVer string) *File {
gop := &Line{
Token: []string{"gop", gopVer},
Expand Down Expand Up @@ -251,6 +253,34 @@ func (f *File) parseVerb(errs *ErrorList, verb string, line *Line, args []string
Class: class,
Syntax: line,
})
case "import":
proj := f.proj()
if proj == nil {
errorf("import must declare after a project definition")
return
}
var name string
switch len(args) {
case 2:
v, err := parseString(&args[0])
if err != nil {
wrapError(err)
return
}
name = v
args = args[1:]
fallthrough
case 1:
pkgPath, err := parsePkgPath(&args[0])
if err != nil {
wrapError(err)
return
}
proj.Import = append(proj.Import, &Import{Name: name, Path: pkgPath, Syntax: line})
default:
errorf("usage: import [name] pkgPath")
return
}
default:
if strict {
errorf("unknown directive: %s", verb)
Expand Down Expand Up @@ -320,23 +350,22 @@ func parseString(s *string) (string, error) {
return t, nil
}

func parseStrings(args []string) (arr []string, err error) {
arr = make([]string, len(args))
for i := range args {
if arr[i], err = parseString(&args[i]); err != nil {
return
}
func parsePkgPath(s *string) (path string, err error) {
if path, err = parseString(s); err != nil {
err = fmt.Errorf("invalid quoted string: %v", err)
return
}
if !isPkgPath(path) {
err = fmt.Errorf(`"%s" is not a valid package path`, path)
}
return
}

func parsePkgPaths(args []string) (paths []string, err error) {
if paths, err = parseStrings(args); err != nil {
return nil, fmt.Errorf("invalid quoted string: %v", err)
}
for _, pkg := range paths {
if !isPkgPath(pkg) {
return nil, fmt.Errorf(`"%s" is not a valid package path`, pkg)
paths = make([]string, len(args))
for i := range args {
if paths[i], err = parsePkgPath(&args[i]); err != nil {
return
}
}
return
Expand Down
85 changes: 85 additions & 0 deletions modload/modtest/modtest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package modtest

import (
"os"
"testing"

"github.com/goplus/mod/modload"
)

func LoadFrom(gomod, gopmod string, gomodText, gopmodText string) (mod modload.Module, err error) {
return modload.LoadFromEx(gomod, gopmod, func(s string) ([]byte, error) {
if s == gomod {
return []byte(gomodText), nil
} else if s == gopmod && gopmodText != "" {
return []byte(gopmodText), nil
}
return nil, os.ErrNotExist
})
}

func Load(t *testing.T, gomodText, gopmodText string, errMsg string) modload.Module {
mod, err := LoadFrom("/foo/go.mod", "/foo/gop.mod", gomodText, gopmodText)
if err != nil {
if err.Error() != errMsg {
t.Fatal("LoadFrom:", err)
}
}
return mod
}

func GopClass(t *testing.T) {
const gomodText = `
module github.com/goplus/community
go 1.18
require (
github.com/goplus/yap v0.5.0 //gop:class
github.com/qiniu/a v0.1.0
github.com/qiniu/x v1.13.2 // gop:class
)
`
mod := Load(t, gomodText, ``, ``)
if n := len(mod.Opt.ClassMods); n != 2 {
t.Fatal("len(mod.Opt.Import):", n)
}
}

func Import(t *testing.T) {
const gomodText = `
module github.com/goplus/yap
go 1.18
`
const gopmodText = `
gop 1.2
project _yap.gox App github.com/goplus/yap
project _ytest.gox App github.com/goplus/yap/test
class _ytest.gox Case
import github.com/goplus/yap/ytest/auth/jwt
import yauth github.com/goplus/yap/ytest/auth
`
mod := Load(t, gomodText, gopmodText, ``)
if n := len(mod.Opt.Projects); n != 2 {
t.Fatal("len(mod.Opt.Projects):", n)
}
}
31 changes: 31 additions & 0 deletions modload/regtest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package modload_test

import (
"testing"

"github.com/goplus/mod/modload/modtest"
)

func TestGopClass(t *testing.T) {
modtest.GopClass(t)
}

func TestImport(t *testing.T) {
modtest.Import(t)
}

0 comments on commit 5a7b7e1

Please sign in to comment.