Compare commits

...

79 Commits

Author SHA1 Message Date
Kevin Wan
e267d94ee1 chore: update go-zero to v1.2.5 (#1410) 2022-01-03 21:54:53 +08:00
anqiansong
89ce5e492b refactor file|path (#1409)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2022-01-03 21:32:40 +08:00
Kevin Wan
290de6aa96 docs: update roadmap (#1405) 2022-01-02 21:30:02 +08:00
Kevin Wan
a7aeb8ac0e feat: support tls for etcd client (#1390)
* feat: support tls for etcd client

* chore: fix typo

* refactor: rename TrustedCAFile to CACertFile

* docs: add comments

* fix: missing tls registration

* feat: add InsecureSkipVerify config for testing
2022-01-02 20:23:50 +08:00
Kevin Wan
a8e7fafebf refactor: optimize fx (#1404)
* refactor: optimize fx

* chore: add more comments

* ci: make test robust
2022-01-02 14:56:30 +08:00
Kevin Wan
7cc64070b1 docs: update goctl installation command (#1403) 2022-01-02 14:31:31 +08:00
Kevin Wan
c19d2637ea feat: implement fx.NoneMatch, fx.First, fx.Last (#1402)
* chore: use workers from options in fx.unlimitedWalk

* feat: add fx.NoneMatch

* feat: add fx.First, fx.Last

* chore: add more comments

* docs: add mr readme
2022-01-02 13:33:15 +08:00
Kevin Wan
fe1da14332 chore: simplify mapreduce (#1401) 2022-01-01 19:24:35 +08:00
anqiansong
8e9110cedf fix #1330 (#1382)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-12-30 20:44:04 +08:00
Kevin Wan
d6ff30a570 chore: fix golint issues (#1396) 2021-12-30 17:44:15 +08:00
Kevin Wan
b98d46bfd6 chore: update goctl version (#1394) 2021-12-30 15:30:16 +08:00
Kevin Wan
768936b256 ci: remove 386 binaries (#1393) 2021-12-30 15:18:24 +08:00
Kevin Wan
c6eb1a9670 ci: remove windows 386 binary (#1392)
* ci: remove windows 386 binary

* chore: update go-zero

* chore: update go-zero
2021-12-30 14:47:53 +08:00
Kevin Wan
e4ab518576 test: add more tests (#1391) 2021-12-30 14:21:55 +08:00
moyrne
dfc67b5fac fix readme-cn (#1388) 2021-12-30 10:42:23 +08:00
Kevin Wan
62266d8f91 fix #1070 (#1389)
* fix #1070

* test: add more tests
2021-12-29 21:34:28 +08:00
anqiansong
b8ea16a88e feat: Add --remote (#1387)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-12-29 18:16:42 +08:00
Kevin Wan
23deaf50e6 feat: support array in default and options tags (#1386)
* feat: support array in default and options tags

* feat: ignore spaces in tags

* test: add more tests
2021-12-29 17:37:36 +08:00
Kevin Wan
38a36ed8d3 docs: add go-zero users (#1381) 2021-12-28 17:12:51 +08:00
anqiansong
49bab23c54 fix #1376 (#1380)
* fix #1376

* fix #1376

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-12-28 16:40:26 +08:00
Leizhengzi
78ba00d3a7 fix: command system info missing go version (#1377) 2021-12-27 22:05:27 +08:00
Kevin Wan
787b046a70 docs: update slack invitation link (#1378) 2021-12-27 16:52:08 +08:00
Kevin Wan
f827a7b985 chore: update goctl version to 1.2.4 for release tools/goctl/v1.2.4 (#1372) 2021-12-27 10:57:55 +08:00
行者
f5f2097d14 Updated MySQL生成表结构体遇到关键字db部分保持原字段名定义 (#1369) 2021-12-26 21:56:04 +08:00
Kevin Wan
cfcfb87fd4 ci: add release action to auto build binaries (#1371) 2021-12-26 21:44:33 +08:00
Kevin Wan
1d223fc114 docs: update goctl markdown (#1370) 2021-12-26 20:32:31 +08:00
Kevin Wan
c0647f0719 feat: support context in MapReduce (#1368) 2021-12-25 20:42:52 +08:00
Kevin Wan
8745ed9c61 chore: add 1s for tolerance in redislock (#1367) 2021-12-25 19:44:27 +08:00
种豆得豆
836726e710 fix redis try-lock bug (#1366)
#issue_id: 1338

Co-authored-by: zhangwei <>
2021-12-25 19:20:53 +08:00
JiangYiJun
a67c118dcf go-zero tools ,fix a func,api new can not choose style (#1356) 2021-12-23 10:28:46 +08:00
Kevin Wan
cd289465fd chore: coding style and comments (#1361)
* chore: coding style and comments

* chore: optimize `ParseJsonBody` (#1353)

* chore: optimize `ParseJsonBody`

* chore: optimize `ParseJsonBody`

* fix: fix a test

* chore: optimize `ParseJsonBody`

* fix a test

* chore: add comment

* chore: refactor

Co-authored-by: chenquan <chenquan.dev@foxmail.com>
2021-12-22 21:43:37 +08:00
chenquan
263e426ae1 chore: optimize ParseJsonBody (#1353)
* chore: optimize `ParseJsonBody`

* chore: optimize `ParseJsonBody`

* fix: fix a test

* chore: optimize `ParseJsonBody`

* fix a test

* chore: add comment
2021-12-22 20:24:55 +08:00
charliecen
d5e493383a chose: cancel the assignment and judge later (#1359)
Co-authored-by: charliecen <chq@abierr.com>
2021-12-22 20:05:35 +08:00
Kevin Wan
6f1d27354a chore: put error message in error.log for verbose mode (#1355) 2021-12-21 11:36:01 +08:00
Kevin Wan
26101732d2 test: add more tests (#1352) 2021-12-20 22:42:36 +08:00
Kevin Wan
71d40e0c08 Revert "排除客户端中断导致的503错误 (#1343)" (#1351)
This reverts commit 2cdf5e7395.
2021-12-20 20:34:43 +08:00
Kevin Wan
4ba2ff7cdd feat: treat client closed requests as code 499 (#1350)
* feat: treat client closed requests as code 499

* chore: add comments
2021-12-20 19:43:38 +08:00
vic
2cdf5e7395 排除客户端中断导致的503错误 (#1343) 2021-12-20 19:43:13 +08:00
Kevin Wan
8315a55b3f Update FUNDING.yml
enable sponsorship.
2021-12-20 15:27:05 +08:00
Kevin Wan
d1c2a31af7 chore: add tests & refactor (#1346)
* chore: add tests & refactor

* chore: refactor
2021-12-18 23:11:38 +08:00
MarkJoyMa
3e6c217408 Feature: support adding custom cache to mongoc and sqlc (#1313)
* merge

* Feature: support adding custom cache to mongoc and sqlc
2021-12-18 22:45:07 +08:00
Kevin Wan
b299f350be chore: add comments (#1345) 2021-12-18 22:39:14 +08:00
Kevin Wan
8fd16c17dc chore: update goctl version to 1.2.5 (#1337) 2021-12-16 00:21:54 +08:00
anqiansong
5979b2aa0f Update template (#1335)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-12-15 23:24:32 +08:00
anqiansong
0b17e0e5d9 Feat goctl bug (#1332)
* Support goctl bug

* fix typo

* format code

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-12-15 22:43:58 +08:00
Kevin Wan
3d8ad5e4f6 feat: tidy mod, update go-zero to latest (#1334) 2021-12-15 22:34:58 +08:00
Kevin Wan
ff1752dd39 feat: tidy mod, update go-zero to latest (#1333) 2021-12-15 22:23:06 +08:00
Kevin Wan
1becaeb7be chore: refactor (#1331) 2021-12-15 20:44:23 +08:00
yangkequn
171afaadb9 Update types.go (#1314) 2021-12-15 20:16:17 +08:00
Kevin Wan
776e6e647d feat: tidy mod, add go.mod for goctl (#1328) 2021-12-15 19:44:49 +08:00
Kevin Wan
4ccdf4ec72 chore: format code (#1327) 2021-12-15 13:43:05 +08:00
CrazyZard
a7bd993c0c commit missing method for redis (#1325)
* commit `decr ` `decrby` `lindex` missing method for redis

* fix(store_test):TestRedis_DecrBy

* add unit tests for redis commands. And put the functions in alphabetical order

* put the functions in alphabetical order

* add `lindex` unit test

* sort func
2021-12-15 13:15:39 +08:00
Kevin Wan
a290ff4486 docs: add go-zero users (#1323) 2021-12-14 13:37:49 +08:00
Kevin Wan
490ef13822 style: format code (#1322) 2021-12-14 11:29:44 +08:00
anqiansong
1b14de2ff9 fix: #1318 (#1321)
* fix #1318

* fix #1318

* remove never used code

* fix unit tes

Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-12-13 22:55:11 +08:00
Kevin Wan
914692cc82 fix #1309 (#1317) 2021-12-13 11:58:58 +08:00
anqiansong
07191dc430 fix #1305 (#1307)
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-12-07 22:24:18 +08:00
BYT0723
af3fb2b04d fix: go issue 16206 (#1298) 2021-12-07 15:52:37 +08:00
Kevin Wan
0240fa131a chore: rename service context from ctx to svcCtx (#1299) 2021-12-05 22:10:47 +08:00
Kevin Wan
e96577dd38 docs: add go-zero users (#1294) 2021-12-03 22:32:35 +08:00
Kevin Wan
403dd7367a fix #1288 (#1292)
* fix #1288

* chore: make wrapup & shutdown callbacks run simulatenously
2021-12-02 22:41:57 +08:00
Kevin Wan
8086ad120b Revert "feat: reduce dependencies of framework by add go.mod in goctl (#1290)" (#1291)
This reverts commit 87a445689c.
2021-12-02 19:40:23 +08:00
Kevin Wan
87a445689c feat: reduce dependencies of framework by add go.mod in goctl (#1290) 2021-12-02 16:57:07 +08:00
Kevin Wan
b6bda54870 chore: update cli version (#1287) 2021-12-01 23:33:23 +08:00
Kevin Wan
9d528dddd6 feat: support third party orm to interact with go-zero (#1286)
* fixes #987

* chore: fix test failure

* chore: add comments

* feat: support third party orm to interact with go-zero

* chore: refactor
2021-12-01 20:22:15 +08:00
Kevin Wan
543d590710 fixes #987 (#1283)
* fixes #987

* chore: fix test failure

* chore: add comments
2021-12-01 17:45:48 +08:00
anqiansong
f1d70eb6b2 Feature api root path (#1261) 2021-12-01 10:09:07 +08:00
Kevin Wan
d828c3f37e feat: add etcd resolver scheme, fix discov minor issue (#1281) 2021-11-28 20:08:18 +08:00
Kevin Wan
038491b7bc chore: cleanup zRPC retry code (#1280) 2021-11-27 18:39:52 +08:00
chenquan
cf683411ee feature(retry): Delete retry mechanism (#1279) 2021-11-27 11:32:33 +08:00
Kevin Wan
de5ed6a677 feat: support %w in logx.Errorf (#1278) 2021-11-26 15:57:23 +08:00
Kevin Wan
3dda557410 chore: only allow cors middleware to change headers (#1276) 2021-11-26 14:14:06 +08:00
Kevin Wan
c800f6f723 chore: avoid superfluous WriteHeader call errors (#1275) 2021-11-26 11:09:57 +08:00
Kevin Wan
0395ba1816 feat: add rest.WithCustomCors to let caller customize the response (#1274) 2021-11-25 23:03:37 +08:00
Kevin Wan
86f9f63b46 Cli (#1272)
* Fix issue 1260 (#1262)

* Fix #1238 (#1266)

* docs: update readme to use goctl@cli (#1255)

* chore: update goctl version

* style: coding style

* docs: update readme to use goctl@cli

* fix #1238

* format code

* format code

Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
Co-authored-by: anqiansong <anqiansong@bytedance.com>

Co-authored-by: anqiansong <anqiansong@gmail.com>
Co-authored-by: anqiansong <anqiansong@bytedance.com>
2021-11-25 11:08:49 +08:00
Kevin Wan
a7a6753118 fixes #1257 (#1271)
* fixes #1257

* chore: format code

* test: add more tests
2021-11-25 10:26:16 +08:00
Kevin Wan
2e80d12d6a docs: update readme to use goctl@cli (#1255)
* chore: update goctl version

* style: coding style

* docs: update readme to use goctl@cli
2021-11-17 21:10:45 +08:00
Kevin Wan
417a96cbf2 chore: update goctl version (#1250)
* chore: update goctl version

* style: coding style
2021-11-16 21:57:55 +08:00
Kevin Wan
2d4c29ea7c Revert "Revert "feat: enable retry for zrpc (#1237)"" (#1246) 2021-11-16 10:29:31 +08:00
216 changed files with 9500 additions and 6951 deletions

2
.github/FUNDING.yml vendored
View File

@@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # https://gitee.com/kevwan/static/raw/master/images/sponsor.jpg
custom: https://gitee.com/kevwan/static/raw/master/images/sponsor.jpg

View File

@@ -14,9 +14,10 @@ We hope that the items listed below will inspire further engagement from the com
## 2021 Q4
- [x] Support `username/password` authentication in ETCD
- [x] Support `SSL/TLS` in ETCD
- [x] Support `SSL/TLS` in `zRPC`
- [x] Support `TLS` in redis connections
- [ ] Support `retry strategies` in `zRPC`
- [x] Support `goctl bug` to report bugs conveniently
## 2022
- [ ] Support `goctl mock` command to start a mocking server with given `.api` file

View File

@@ -2,6 +2,13 @@ package discov
import "github.com/tal-tech/go-zero/core/discov/internal"
// RegisterAccount registers the username/password to the given etcd cluster.
func RegisterAccount(endpoints []string, user, pass string) {
internal.AddAccount(endpoints, user, pass)
}
// RegisterTLS registers the CertFile/CertKeyFile/CACertFile to the given etcd.
func RegisterTLS(endpoints []string, certFile, certKeyFile, caFile string,
insecureSkipVerify bool) error {
return internal.AddTLS(endpoints, certFile, certKeyFile, caFile, insecureSkipVerify)
}

View File

@@ -4,10 +4,14 @@ import "errors"
// EtcdConf is the config item with the given key on etcd.
type EtcdConf struct {
Hosts []string
Key string
User string `json:",optional"`
Pass string `json:",optional"`
Hosts []string
Key string
User string `json:",optional"`
Pass string `json:",optional"`
CertFile string `json:",optional"`
CertKeyFile string `json:",optional=CertFile"`
CACertFile string `json:",optional=CertFile"`
InsecureSkipVerify bool `json:",optional"`
}
// HasAccount returns if account provided.
@@ -15,6 +19,11 @@ func (c EtcdConf) HasAccount() bool {
return len(c.User) > 0 && len(c.Pass) > 0
}
// HasTLS returns if TLS CertFile/CertKeyFile/CACertFile are provided.
func (c EtcdConf) HasTLS() bool {
return len(c.CertFile) > 0 && len(c.CertKeyFile) > 0 && len(c.CACertFile) > 0
}
// Validate validates c.
func (c EtcdConf) Validate() error {
if len(c.Hosts) == 0 {

View File

@@ -1,17 +1,25 @@
package internal
import "sync"
import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"sync"
)
var (
accounts = make(map[string]Account)
tlsConfigs = make(map[string]*tls.Config)
lock sync.RWMutex
)
// Account holds the username/password for an etcd cluster.
type Account struct {
User string
Pass string
}
var (
accounts = make(map[string]Account)
lock sync.RWMutex
)
// AddAccount adds the username/password for the given etcd cluster.
func AddAccount(endpoints []string, user, pass string) {
lock.Lock()
defer lock.Unlock()
@@ -22,6 +30,33 @@ func AddAccount(endpoints []string, user, pass string) {
}
}
// AddTLS adds the tls cert files for the given etcd cluster.
func AddTLS(endpoints []string, certFile, certKeyFile, caFile string, insecureSkipVerify bool) error {
cert, err := tls.LoadX509KeyPair(certFile, certKeyFile)
if err != nil {
return err
}
caData, err := ioutil.ReadFile(caFile)
if err != nil {
return err
}
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(caData)
lock.Lock()
defer lock.Unlock()
tlsConfigs[getClusterKey(endpoints)] = &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: pool,
InsecureSkipVerify: insecureSkipVerify,
}
return nil
}
// GetAccount gets the username/password for the given etcd cluster.
func GetAccount(endpoints []string) (Account, bool) {
lock.RLock()
defer lock.RUnlock()
@@ -29,3 +64,12 @@ func GetAccount(endpoints []string) (Account, bool) {
account, ok := accounts[getClusterKey(endpoints)]
return account, ok
}
// GetTLS gets the tls config for the given etcd cluster.
func GetTLS(endpoints []string) (*tls.Config, bool) {
lock.RLock()
defer lock.RUnlock()
cfg, ok := tlsConfigs[getClusterKey(endpoints)]
return cfg, ok
}

View File

@@ -37,25 +37,35 @@ func GetRegistry() *Registry {
// GetConn returns an etcd client connection associated with given endpoints.
func (r *Registry) GetConn(endpoints []string) (EtcdClient, error) {
return r.getCluster(endpoints).getClient()
c, _ := r.getCluster(endpoints)
return c.getClient()
}
// Monitor monitors the key on given etcd endpoints, notify with the given UpdateListener.
func (r *Registry) Monitor(endpoints []string, key string, l UpdateListener) error {
return r.getCluster(endpoints).monitor(key, l)
c, exists := r.getCluster(endpoints)
// if exists, the existing values should be updated to the listener.
if exists {
kvs := c.getCurrent(key)
for _, kv := range kvs {
l.OnAdd(kv)
}
}
return c.monitor(key, l)
}
func (r *Registry) getCluster(endpoints []string) *cluster {
func (r *Registry) getCluster(endpoints []string) (c *cluster, exists bool) {
clusterKey := getClusterKey(endpoints)
r.lock.Lock()
defer r.lock.Unlock()
c, ok := r.clusters[clusterKey]
if !ok {
c, exists = r.clusters[clusterKey]
if !exists {
c = newCluster(endpoints)
r.clusters[clusterKey] = c
}
return c
return
}
type cluster struct {
@@ -94,6 +104,21 @@ func (c *cluster) getClient() (EtcdClient, error) {
return val.(EtcdClient), nil
}
func (c *cluster) getCurrent(key string) []KV {
c.lock.Lock()
defer c.lock.Unlock()
var kvs []KV
for k, v := range c.values[key] {
kvs = append(kvs, KV{
Key: k,
Val: v,
})
}
return kvs
}
func (c *cluster) handleChanges(key string, kvs []KV) {
var add []KV
var remove []KV
@@ -197,14 +222,12 @@ func (c *cluster) load(cli EtcdClient, key string) {
}
var kvs []KV
c.lock.Lock()
for _, ev := range resp.Kvs {
kvs = append(kvs, KV{
Key: string(ev.Key),
Val: string(ev.Value),
})
}
c.lock.Unlock()
c.handleChanges(key, kvs)
}
@@ -314,6 +337,9 @@ func DialClient(endpoints []string) (EtcdClient, error) {
cfg.Username = account.User
cfg.Password = account.Pass
}
if tlsCfg, ok := GetTLS(endpoints); ok {
cfg.TLS = tlsCfg
}
return clientv3.New(cfg)
}

View File

@@ -34,9 +34,9 @@ func setMockClient(cli EtcdClient) func() {
func TestGetCluster(t *testing.T) {
AddAccount([]string{"first"}, "foo", "bar")
c1 := GetRegistry().getCluster([]string{"first"})
c2 := GetRegistry().getCluster([]string{"second"})
c3 := GetRegistry().getCluster([]string{"first"})
c1, _ := GetRegistry().getCluster([]string{"first"})
c2, _ := GetRegistry().getCluster([]string{"second"})
c3, _ := GetRegistry().getCluster([]string{"first"})
assert.Equal(t, c1, c3)
assert.NotEqual(t, c1, c2)
}

View File

@@ -145,16 +145,23 @@ func (p *Publisher) revoke(cli internal.EtcdClient) {
}
}
// WithPubEtcdAccount provides the etcd username/password.
func WithPubEtcdAccount(user, pass string) PubOption {
return func(pub *Publisher) {
internal.AddAccount(pub.endpoints, user, pass)
}
}
// WithId customizes a Publisher with the id.
func WithId(id int64) PubOption {
return func(publisher *Publisher) {
publisher.id = id
}
}
// WithPubEtcdAccount provides the etcd username/password.
func WithPubEtcdAccount(user, pass string) PubOption {
return func(pub *Publisher) {
RegisterAccount(pub.endpoints, user, pass)
}
}
// WithPubEtcdTLS provides the etcd CertFile/CertKeyFile/CACertFile.
func WithPubEtcdTLS(certFile, certKeyFile, caFile string, insecureSkipVerify bool) PubOption {
return func(pub *Publisher) {
logx.Must(RegisterTLS(pub.endpoints, certFile, certKeyFile, caFile, insecureSkipVerify))
}
}

View File

@@ -5,6 +5,7 @@ import (
"sync/atomic"
"github.com/tal-tech/go-zero/core/discov/internal"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/syncx"
)
@@ -58,9 +59,17 @@ func Exclusive() SubOption {
}
}
// WithSubEtcdAccount provides the etcd username/password.
func WithSubEtcdAccount(user, pass string) SubOption {
return func(sub *Subscriber) {
internal.AddAccount(sub.endpoints, user, pass)
RegisterAccount(sub.endpoints, user, pass)
}
}
// WithSubEtcdTLS provides the etcd CertFile/CertKeyFile/CACertFile.
func WithSubEtcdTLS(certFile, certKeyFile, caFile string, insecureSkipVerify bool) SubOption {
return func(sub *Subscriber) {
logx.Must(RegisterTLS(sub.endpoints, certFile, certKeyFile, caFile, insecureSkipVerify))
}
}

View File

@@ -90,6 +90,8 @@ func Range(source <-chan interface{}) Stream {
func (s Stream) AllMach(predicate func(item interface{}) bool) bool {
for item := range s.source {
if !predicate(item) {
// make sure the former goroutine not block, and current func returns fast.
go drain(s.source)
return false
}
}
@@ -103,6 +105,8 @@ func (s Stream) AllMach(predicate func(item interface{}) bool) bool {
func (s Stream) AnyMach(predicate func(item interface{}) bool) bool {
for item := range s.source {
if predicate(item) {
// make sure the former goroutine not block, and current func returns fast.
go drain(s.source)
return true
}
}
@@ -186,8 +190,7 @@ func (s Stream) Distinct(fn KeyFunc) Stream {
// Done waits all upstreaming operations to be done.
func (s Stream) Done() {
for range s.source {
}
drain(s.source)
}
// Filter filters the items by the given FilterFunc.
@@ -199,9 +202,22 @@ func (s Stream) Filter(fn FilterFunc, opts ...Option) Stream {
}, opts...)
}
// First returns the first item, nil if no items.
func (s Stream) First() interface{} {
for item := range s.source {
// make sure the former goroutine not block, and current func returns fast.
go drain(s.source)
return item
}
return nil
}
// ForAll handles the streaming elements from the source and no later streams.
func (s Stream) ForAll(fn ForAllFunc) {
fn(s.source)
// avoid goroutine leak on fn not consuming all items.
go drain(s.source)
}
// ForEach seals the Stream with the ForEachFunc on each item, no successive operations.
@@ -246,11 +262,14 @@ func (s Stream) Head(n int64) Stream {
}
if n == 0 {
// let successive method go ASAP even we have more items to skip
// why we don't just break the loop, because if break,
// this former goroutine will block forever, which will cause goroutine leak.
close(source)
// why we don't just break the loop, and drain to consume all items.
// because if breaks, this former goroutine will block forever,
// which will cause goroutine leak.
drain(s.source)
}
}
// not enough items in s.source, but we need to let successive method to go ASAP.
if n > 0 {
close(source)
}
@@ -259,6 +278,13 @@ func (s Stream) Head(n int64) Stream {
return Range(source)
}
// Last returns the last item, or nil if no items.
func (s Stream) Last() (item interface{}) {
for item = range s.source {
}
return
}
// Map converts each item to another corresponding item, which means it's a 1:1 model.
func (s Stream) Map(fn MapFunc, opts ...Option) Stream {
return s.Walk(func(item interface{}, pipe chan<- interface{}) {
@@ -280,6 +306,21 @@ func (s Stream) Merge() Stream {
return Range(source)
}
// NoneMatch returns whether all elements of this stream don't match the provided predicate.
// May not evaluate the predicate on all elements if not necessary for determining the result.
// If the stream is empty then true is returned and the predicate is not evaluated.
func (s Stream) NoneMatch(predicate func(item interface{}) bool) bool {
for item := range s.source {
if predicate(item) {
// make sure the former goroutine not block, and current func returns fast.
go drain(s.source)
return false
}
}
return true
}
// Parallel applies the given ParallelFunc to each item concurrently with given number of workers.
func (s Stream) Parallel(fn ParallelFunc, opts ...Option) {
s.Walk(func(item interface{}, pipe chan<- interface{}) {
@@ -411,15 +452,12 @@ func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
var wg sync.WaitGroup
pool := make(chan lang.PlaceholderType, option.workers)
for {
for item := range s.source {
// important, used in another goroutine
val := item
pool <- lang.Placeholder
item, ok := <-s.source
if !ok {
<-pool
break
}
wg.Add(1)
// better to safely run caller defined method
threading.GoSafe(func() {
defer func() {
@@ -427,7 +465,7 @@ func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
<-pool
}()
fn(item, pipe)
fn(val, pipe)
})
}
@@ -439,22 +477,19 @@ func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
}
func (s Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
pipe := make(chan interface{}, defaultWorkers)
pipe := make(chan interface{}, option.workers)
go func() {
var wg sync.WaitGroup
for {
item, ok := <-s.source
if !ok {
break
}
for item := range s.source {
// important, used in another goroutine
val := item
wg.Add(1)
// better to safely run caller defined method
threading.GoSafe(func() {
defer wg.Done()
fn(item, pipe)
fn(val, pipe)
})
}
@@ -465,14 +500,14 @@ func (s Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
return Range(pipe)
}
// UnlimitedWorkers lets the caller to use as many workers as the tasks.
// UnlimitedWorkers lets the caller use as many workers as the tasks.
func UnlimitedWorkers() Option {
return func(opts *rxOptions) {
opts.unlimitedWorkers = true
}
}
// WithWorkers lets the caller to customize the concurrent workers.
// WithWorkers lets the caller customize the concurrent workers.
func WithWorkers(workers int) Option {
return func(opts *rxOptions) {
if workers < minWorkers {
@@ -483,6 +518,7 @@ func WithWorkers(workers int) Option {
}
}
// buildOptions returns a rxOptions with given customizations.
func buildOptions(opts ...Option) *rxOptions {
options := newOptions()
for _, opt := range opts {
@@ -492,6 +528,13 @@ func buildOptions(opts ...Option) *rxOptions {
return options
}
// drain drains the given channel.
func drain(channel <-chan interface{}) {
for range channel {
}
}
// newOptions returns a default rxOptions.
func newOptions() *rxOptions {
return &rxOptions{
workers: defaultWorkers,

View File

@@ -17,320 +17,489 @@ import (
)
func TestBuffer(t *testing.T) {
const N = 5
var count int32
var wait sync.WaitGroup
wait.Add(1)
From(func(source chan<- interface{}) {
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
runCheckedTest(t, func(t *testing.T) {
const N = 5
var count int32
var wait sync.WaitGroup
wait.Add(1)
From(func(source chan<- interface{}) {
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
for i := 0; i < 2*N; i++ {
select {
case source <- i:
atomic.AddInt32(&count, 1)
case <-ticker.C:
wait.Done()
return
for i := 0; i < 2*N; i++ {
select {
case source <- i:
atomic.AddInt32(&count, 1)
case <-ticker.C:
wait.Done()
return
}
}
}
}).Buffer(N).ForAll(func(pipe <-chan interface{}) {
wait.Wait()
// why N+1, because take one more to wait for sending into the channel
assert.Equal(t, int32(N+1), atomic.LoadInt32(&count))
}).Buffer(N).ForAll(func(pipe <-chan interface{}) {
wait.Wait()
// why N+1, because take one more to wait for sending into the channel
assert.Equal(t, int32(N+1), atomic.LoadInt32(&count))
})
})
}
func TestBufferNegative(t *testing.T) {
var result int
Just(1, 2, 3, 4).Buffer(-1).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4).Buffer(-1).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, 10, result)
})
assert.Equal(t, 10, result)
}
func TestCount(t *testing.T) {
tests := []struct {
name string
elements []interface{}
}{
{
name: "no elements with nil",
},
{
name: "no elements",
elements: []interface{}{},
},
{
name: "1 element",
elements: []interface{}{1},
},
{
name: "multiple elements",
elements: []interface{}{1, 2, 3},
},
}
runCheckedTest(t, func(t *testing.T) {
tests := []struct {
name string
elements []interface{}
}{
{
name: "no elements with nil",
},
{
name: "no elements",
elements: []interface{}{},
},
{
name: "1 element",
elements: []interface{}{1},
},
{
name: "multiple elements",
elements: []interface{}{1, 2, 3},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
val := Just(test.elements...).Count()
assert.Equal(t, len(test.elements), val)
})
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
val := Just(test.elements...).Count()
assert.Equal(t, len(test.elements), val)
})
}
})
}
func TestDone(t *testing.T) {
var count int32
Just(1, 2, 3).Walk(func(item interface{}, pipe chan<- interface{}) {
time.Sleep(time.Millisecond * 100)
atomic.AddInt32(&count, int32(item.(int)))
}).Done()
assert.Equal(t, int32(6), count)
runCheckedTest(t, func(t *testing.T) {
var count int32
Just(1, 2, 3).Walk(func(item interface{}, pipe chan<- interface{}) {
time.Sleep(time.Millisecond * 100)
atomic.AddInt32(&count, int32(item.(int)))
}).Done()
assert.Equal(t, int32(6), count)
})
}
func TestJust(t *testing.T) {
var result int
Just(1, 2, 3, 4).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, 10, result)
})
assert.Equal(t, 10, result)
}
func TestDistinct(t *testing.T) {
var result int
Just(4, 1, 3, 2, 3, 4).Distinct(func(item interface{}) interface{} {
return item
}).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
runCheckedTest(t, func(t *testing.T) {
var result int
Just(4, 1, 3, 2, 3, 4).Distinct(func(item interface{}) interface{} {
return item
}).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, 10, result)
})
assert.Equal(t, 10, result)
}
func TestFilter(t *testing.T) {
var result int
Just(1, 2, 3, 4).Filter(func(item interface{}) bool {
return item.(int)%2 == 0
}).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4).Filter(func(item interface{}) bool {
return item.(int)%2 == 0
}).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, 6, result)
})
}
func TestFirst(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
assert.Nil(t, Just().First())
assert.Equal(t, "foo", Just("foo").First())
assert.Equal(t, "foo", Just("foo", "bar").First())
})
assert.Equal(t, 6, result)
}
func TestForAll(t *testing.T) {
var result int
Just(1, 2, 3, 4).Filter(func(item interface{}) bool {
return item.(int)%2 == 0
}).ForAll(func(pipe <-chan interface{}) {
for item := range pipe {
result += item.(int)
}
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4).Filter(func(item interface{}) bool {
return item.(int)%2 == 0
}).ForAll(func(pipe <-chan interface{}) {
for item := range pipe {
result += item.(int)
}
})
assert.Equal(t, 6, result)
})
assert.Equal(t, 6, result)
}
func TestGroup(t *testing.T) {
var groups [][]int
Just(10, 11, 20, 21).Group(func(item interface{}) interface{} {
v := item.(int)
return v / 10
}).ForEach(func(item interface{}) {
v := item.([]interface{})
var group []int
for _, each := range v {
group = append(group, each.(int))
}
groups = append(groups, group)
})
runCheckedTest(t, func(t *testing.T) {
var groups [][]int
Just(10, 11, 20, 21).Group(func(item interface{}) interface{} {
v := item.(int)
return v / 10
}).ForEach(func(item interface{}) {
v := item.([]interface{})
var group []int
for _, each := range v {
group = append(group, each.(int))
}
groups = append(groups, group)
})
assert.Equal(t, 2, len(groups))
for _, group := range groups {
assert.Equal(t, 2, len(group))
assert.True(t, group[0]/10 == group[1]/10)
}
assert.Equal(t, 2, len(groups))
for _, group := range groups {
assert.Equal(t, 2, len(group))
assert.True(t, group[0]/10 == group[1]/10)
}
})
}
func TestHead(t *testing.T) {
var result int
Just(1, 2, 3, 4).Head(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4).Head(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, 3, result)
})
assert.Equal(t, 3, result)
}
func TestHeadZero(t *testing.T) {
assert.Panics(t, func() {
Just(1, 2, 3, 4).Head(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
return nil, nil
runCheckedTest(t, func(t *testing.T) {
assert.Panics(t, func() {
Just(1, 2, 3, 4).Head(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
return nil, nil
})
})
})
}
func TestHeadMore(t *testing.T) {
var result int
Just(1, 2, 3, 4).Head(6).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4).Head(6).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, 10, result)
})
}
func TestLast(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
goroutines := runtime.NumGoroutine()
assert.Nil(t, Just().Last())
assert.Equal(t, "foo", Just("foo").Last())
assert.Equal(t, "bar", Just("foo", "bar").Last())
// let scheduler schedule first
runtime.Gosched()
assert.Equal(t, goroutines, runtime.NumGoroutine())
})
assert.Equal(t, 10, result)
}
func TestMap(t *testing.T) {
log.SetOutput(ioutil.Discard)
runCheckedTest(t, func(t *testing.T) {
log.SetOutput(ioutil.Discard)
tests := []struct {
mapper MapFunc
expect int
}{
{
mapper: func(item interface{}) interface{} {
v := item.(int)
return v * v
tests := []struct {
mapper MapFunc
expect int
}{
{
mapper: func(item interface{}) interface{} {
v := item.(int)
return v * v
},
expect: 30,
},
expect: 30,
},
{
mapper: func(item interface{}) interface{} {
v := item.(int)
if v%2 == 0 {
return 0
}
return v * v
},
expect: 10,
},
{
mapper: func(item interface{}) interface{} {
v := item.(int)
if v%2 == 0 {
panic(v)
}
return v * v
},
expect: 10,
},
}
// Map(...) works even WithWorkers(0)
for i, test := range tests {
t.Run(stringx.Rand(), func(t *testing.T) {
var result int
var workers int
if i%2 == 0 {
workers = 0
} else {
workers = runtime.NumCPU()
}
From(func(source chan<- interface{}) {
for i := 1; i < 5; i++ {
source <- i
}
}).Map(test.mapper, WithWorkers(workers)).Reduce(
func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
{
mapper: func(item interface{}) interface{} {
v := item.(int)
if v%2 == 0 {
return 0
}
return result, nil
})
return v * v
},
expect: 10,
},
{
mapper: func(item interface{}) interface{} {
v := item.(int)
if v%2 == 0 {
panic(v)
}
return v * v
},
expect: 10,
},
}
assert.Equal(t, test.expect, result)
})
}
// Map(...) works even WithWorkers(0)
for i, test := range tests {
t.Run(stringx.Rand(), func(t *testing.T) {
var result int
var workers int
if i%2 == 0 {
workers = 0
} else {
workers = runtime.NumCPU()
}
From(func(source chan<- interface{}) {
for i := 1; i < 5; i++ {
source <- i
}
}).Map(test.mapper, WithWorkers(workers)).Reduce(
func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, test.expect, result)
})
}
})
}
func TestMerge(t *testing.T) {
Just(1, 2, 3, 4).Merge().ForEach(func(item interface{}) {
assert.ElementsMatch(t, []interface{}{1, 2, 3, 4}, item.([]interface{}))
runCheckedTest(t, func(t *testing.T) {
Just(1, 2, 3, 4).Merge().ForEach(func(item interface{}) {
assert.ElementsMatch(t, []interface{}{1, 2, 3, 4}, item.([]interface{}))
})
})
}
func TestParallelJust(t *testing.T) {
var count int32
Just(1, 2, 3).Parallel(func(item interface{}) {
time.Sleep(time.Millisecond * 100)
atomic.AddInt32(&count, int32(item.(int)))
}, UnlimitedWorkers())
assert.Equal(t, int32(6), count)
runCheckedTest(t, func(t *testing.T) {
var count int32
Just(1, 2, 3).Parallel(func(item interface{}) {
time.Sleep(time.Millisecond * 100)
atomic.AddInt32(&count, int32(item.(int)))
}, UnlimitedWorkers())
assert.Equal(t, int32(6), count)
})
}
func TestReverse(t *testing.T) {
Just(1, 2, 3, 4).Reverse().Merge().ForEach(func(item interface{}) {
assert.ElementsMatch(t, []interface{}{4, 3, 2, 1}, item.([]interface{}))
runCheckedTest(t, func(t *testing.T) {
Just(1, 2, 3, 4).Reverse().Merge().ForEach(func(item interface{}) {
assert.ElementsMatch(t, []interface{}{4, 3, 2, 1}, item.([]interface{}))
})
})
}
func TestSort(t *testing.T) {
var prev int
Just(5, 3, 7, 1, 9, 6, 4, 8, 2).Sort(func(a, b interface{}) bool {
return a.(int) < b.(int)
}).ForEach(func(item interface{}) {
next := item.(int)
assert.True(t, prev < next)
prev = next
runCheckedTest(t, func(t *testing.T) {
var prev int
Just(5, 3, 7, 1, 9, 6, 4, 8, 2).Sort(func(a, b interface{}) bool {
return a.(int) < b.(int)
}).ForEach(func(item interface{}) {
next := item.(int)
assert.True(t, prev < next)
prev = next
})
})
}
func TestSplit(t *testing.T) {
assert.Panics(t, func() {
Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(0).Done()
runCheckedTest(t, func(t *testing.T) {
assert.Panics(t, func() {
Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(0).Done()
})
var chunks [][]interface{}
Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(4).ForEach(func(item interface{}) {
chunk := item.([]interface{})
chunks = append(chunks, chunk)
})
assert.EqualValues(t, [][]interface{}{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10},
}, chunks)
})
var chunks [][]interface{}
Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(4).ForEach(func(item interface{}) {
chunk := item.([]interface{})
chunks = append(chunks, chunk)
})
assert.EqualValues(t, [][]interface{}{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10},
}, chunks)
}
func TestTail(t *testing.T) {
var result int
Just(1, 2, 3, 4).Tail(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4).Tail(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
for item := range pipe {
result += item.(int)
}
return result, nil
})
assert.Equal(t, 7, result)
})
assert.Equal(t, 7, result)
}
func TestTailZero(t *testing.T) {
assert.Panics(t, func() {
Just(1, 2, 3, 4).Tail(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
return nil, nil
runCheckedTest(t, func(t *testing.T) {
assert.Panics(t, func() {
Just(1, 2, 3, 4).Tail(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) {
return nil, nil
})
})
})
}
func TestWalk(t *testing.T) {
var result int
Just(1, 2, 3, 4, 5).Walk(func(item interface{}, pipe chan<- interface{}) {
if item.(int)%2 != 0 {
pipe <- item
}
}, UnlimitedWorkers()).ForEach(func(item interface{}) {
result += item.(int)
runCheckedTest(t, func(t *testing.T) {
var result int
Just(1, 2, 3, 4, 5).Walk(func(item interface{}, pipe chan<- interface{}) {
if item.(int)%2 != 0 {
pipe <- item
}
}, UnlimitedWorkers()).ForEach(func(item interface{}) {
result += item.(int)
})
assert.Equal(t, 9, result)
})
}
func TestStream_AnyMach(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 4
}))
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 0
}))
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 2
}))
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 2
}))
})
}
func TestStream_AllMach(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
assetEqual(
t, true, Just(1, 2, 3).AllMach(func(item interface{}) bool {
return true
}),
)
assetEqual(
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool {
return false
}),
)
assetEqual(
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool {
return item.(int) == 1
}),
)
})
}
func TestStream_NoneMatch(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
assetEqual(
t, true, Just(1, 2, 3).NoneMatch(func(item interface{}) bool {
return false
}),
)
assetEqual(
t, false, Just(1, 2, 3).NoneMatch(func(item interface{}) bool {
return true
}),
)
assetEqual(
t, true, Just(1, 2, 3).NoneMatch(func(item interface{}) bool {
return item.(int) == 4
}),
)
})
}
func TestConcat(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
a1 := []interface{}{1, 2, 3}
a2 := []interface{}{4, 5, 6}
s1 := Just(a1...)
s2 := Just(a2...)
stream := Concat(s1, s2)
var items []interface{}
for item := range stream.source {
items = append(items, item)
}
sort.Slice(items, func(i, j int) bool {
return items[i].(int) < items[j].(int)
})
ints := make([]interface{}, 0)
ints = append(ints, a1...)
ints = append(ints, a2...)
assetEqual(t, ints, items)
})
}
func TestStream_Skip(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
assetEqual(t, 3, Just(1, 2, 3, 4).Skip(1).Count())
assetEqual(t, 1, Just(1, 2, 3, 4).Skip(3).Count())
assetEqual(t, 4, Just(1, 2, 3, 4).Skip(0).Count())
equal(t, Just(1, 2, 3, 4).Skip(3), []interface{}{4})
assert.Panics(t, func() {
Just(1, 2, 3, 4).Skip(-1)
})
})
}
func TestStream_Concat(t *testing.T) {
runCheckedTest(t, func(t *testing.T) {
stream := Just(1).Concat(Just(2), Just(3))
var items []interface{}
for item := range stream.source {
items = append(items, item)
}
sort.Slice(items, func(i, j int) bool {
return items[i].(int) < items[j].(int)
})
assetEqual(t, []interface{}{1, 2, 3}, items)
just := Just(1)
equal(t, just.Concat(just), []interface{}{1})
})
assert.Equal(t, 9, result)
}
func BenchmarkParallelMapReduce(b *testing.B) {
@@ -377,6 +546,12 @@ func BenchmarkMapReduce(b *testing.B) {
}).Map(mapper).Reduce(reducer)
}
func assetEqual(t *testing.T, except, data interface{}) {
if !reflect.DeepEqual(except, data) {
t.Errorf(" %v, want %v", data, except)
}
}
func equal(t *testing.T, stream Stream, data []interface{}) {
items := make([]interface{}, 0)
for item := range stream.source {
@@ -387,85 +562,10 @@ func equal(t *testing.T, stream Stream, data []interface{}) {
}
}
func assetEqual(t *testing.T, except, data interface{}) {
if !reflect.DeepEqual(except, data) {
t.Errorf(" %v, want %v", data, except)
}
}
func TestStream_AnyMach(t *testing.T) {
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 4
}))
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 0
}))
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 2
}))
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool {
return item.(int) == 2
}))
}
func TestStream_AllMach(t *testing.T) {
assetEqual(
t, true, Just(1, 2, 3).AllMach(func(item interface{}) bool {
return true
}),
)
assetEqual(
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool {
return false
}),
)
assetEqual(
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool {
return item.(int) == 1
}),
)
}
func TestConcat(t *testing.T) {
a1 := []interface{}{1, 2, 3}
a2 := []interface{}{4, 5, 6}
s1 := Just(a1...)
s2 := Just(a2...)
stream := Concat(s1, s2)
var items []interface{}
for item := range stream.source {
items = append(items, item)
}
sort.Slice(items, func(i, j int) bool {
return items[i].(int) < items[j].(int)
})
ints := make([]interface{}, 0)
ints = append(ints, a1...)
ints = append(ints, a2...)
assetEqual(t, ints, items)
}
func TestStream_Skip(t *testing.T) {
assetEqual(t, 3, Just(1, 2, 3, 4).Skip(1).Count())
assetEqual(t, 1, Just(1, 2, 3, 4).Skip(3).Count())
assetEqual(t, 4, Just(1, 2, 3, 4).Skip(0).Count())
equal(t, Just(1, 2, 3, 4).Skip(3), []interface{}{4})
assert.Panics(t, func() {
Just(1, 2, 3, 4).Skip(-1)
})
}
func TestStream_Concat(t *testing.T) {
stream := Just(1).Concat(Just(2), Just(3))
var items []interface{}
for item := range stream.source {
items = append(items, item)
}
sort.Slice(items, func(i, j int) bool {
return items[i].(int) < items[j].(int)
})
assetEqual(t, []interface{}{1, 2, 3}, items)
just := Just(1)
equal(t, just.Concat(just), []interface{}{1})
func runCheckedTest(t *testing.T, fn func(t *testing.T)) {
goroutines := runtime.NumGoroutine()
fn(t)
// let scheduler schedule first
time.Sleep(time.Millisecond)
assert.True(t, runtime.NumGoroutine() <= goroutines)
}

View File

@@ -4,8 +4,8 @@ package lang
var Placeholder PlaceholderType
type (
// GenericType can be used to hold any type.
GenericType = interface{}
// AnyType can be used to hold any type.
AnyType = interface{}
// PlaceholderType represents a placeholder type.
PlaceholderType = struct{}
)

View File

@@ -79,8 +79,10 @@ func (l *durationLogger) WithDuration(duration time.Duration) Logger {
}
func (l *durationLogger) write(writer io.Writer, level string, val interface{}) {
l.Timestamp = getTimestamp()
l.Level = level
l.Content = val
outputJson(writer, l)
outputJson(writer, &durationLogger{
Timestamp: getTimestamp(),
Level: level,
Content: val,
Duration: l.Duration,
})
}

View File

@@ -23,6 +23,13 @@ func TestWithDurationErrorf(t *testing.T) {
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationErrorv(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Errorv("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationInfo(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
@@ -37,6 +44,13 @@ func TestWithDurationInfof(t *testing.T) {
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationInfov(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).Infov("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationSlow(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
@@ -50,3 +64,10 @@ func TestWithDurationSlowf(t *testing.T) {
WithDuration(time.Second).WithDuration(time.Hour).Slowf("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}
func TestWithDurationSlowv(t *testing.T) {
var builder strings.Builder
log.SetOutput(&builder)
WithDuration(time.Second).WithDuration(time.Hour).Slowv("foo")
assert.True(t, strings.Contains(builder.String(), "duration"), builder.String())
}

View File

@@ -217,7 +217,7 @@ func ErrorCaller(callDepth int, v ...interface{}) {
// ErrorCallerf writes v with context in format into error log.
func ErrorCallerf(callDepth int, format string, v ...interface{}) {
errorTextSync(fmt.Sprintf(format, v...), callDepth+callerInnerDepth)
errorTextSync(fmt.Errorf(format, v...).Error(), callDepth+callerInnerDepth)
}
// Errorf writes v with format into error log.

View File

@@ -2,6 +2,7 @@ package logx
import (
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@@ -242,6 +243,16 @@ func TestSetLevelWithDuration(t *testing.T) {
assert.Equal(t, 0, writer.builder.Len())
}
func TestErrorfWithWrappedError(t *testing.T) {
SetLevel(ErrorLevel)
const message = "there"
writer := new(mockWriter)
errorLog = writer
atomic.StoreUint32(&initialized, 1)
Errorf("hello %w", errors.New(message))
assert.True(t, strings.Contains(writer.builder.String(), "hello there"))
}
func TestMustNil(t *testing.T) {
Must(nil)
}

View File

@@ -77,12 +77,16 @@ func (l *traceLogger) WithDuration(duration time.Duration) Logger {
}
func (l *traceLogger) write(writer io.Writer, level string, val interface{}) {
l.Timestamp = getTimestamp()
l.Level = level
l.Content = val
l.Trace = traceIdFromContext(l.ctx)
l.Span = spanIdFromContext(l.ctx)
outputJson(writer, l)
outputJson(writer, &traceLogger{
logEntry: logEntry{
Timestamp: getTimestamp(),
Level: level,
Duration: l.Duration,
Content: val,
},
Trace: traceIdFromContext(l.ctx),
Span: spanIdFromContext(l.ctx),
})
}
// WithContext sets ctx to log, for keeping tracing information.

View File

@@ -51,6 +51,10 @@ func TestTraceError(t *testing.T) {
l.WithDuration(time.Second).Errorf(testlog)
assert.True(t, strings.Contains(buf.String(), traceKey))
assert.True(t, strings.Contains(buf.String(), spanKey))
buf.Reset()
l.WithDuration(time.Second).Errorv(testlog)
assert.True(t, strings.Contains(buf.String(), traceKey))
assert.True(t, strings.Contains(buf.String(), spanKey))
}
func TestTraceInfo(t *testing.T) {
@@ -72,6 +76,10 @@ func TestTraceInfo(t *testing.T) {
l.WithDuration(time.Second).Infof(testlog)
assert.True(t, strings.Contains(buf.String(), traceKey))
assert.True(t, strings.Contains(buf.String(), spanKey))
buf.Reset()
l.WithDuration(time.Second).Infov(testlog)
assert.True(t, strings.Contains(buf.String(), traceKey))
assert.True(t, strings.Contains(buf.String(), spanKey))
}
func TestTraceSlow(t *testing.T) {
@@ -93,6 +101,10 @@ func TestTraceSlow(t *testing.T) {
l.WithDuration(time.Second).Slowf(testlog)
assert.True(t, strings.Contains(buf.String(), traceKey))
assert.True(t, strings.Contains(buf.String(), spanKey))
buf.Reset()
l.WithDuration(time.Second).Slowv(testlog)
assert.True(t, strings.Contains(buf.String(), traceKey))
assert.True(t, strings.Contains(buf.String(), spanKey))
}
func TestTraceWithoutContext(t *testing.T) {

View File

@@ -15,6 +15,11 @@ func UnmarshalJsonBytes(content []byte, v interface{}) error {
return unmarshalJsonBytes(content, v, jsonUnmarshaler)
}
// UnmarshalJsonMap unmarshals content from m into v.
func UnmarshalJsonMap(m map[string]interface{}, v interface{}) error {
return jsonUnmarshaler.Unmarshal(m, v)
}
// UnmarshalJsonReader unmarshals content from reader into v.
func UnmarshalJsonReader(reader io.Reader, v interface{}) error {
return unmarshalJsonReader(reader, v, jsonUnmarshaler)

View File

@@ -871,3 +871,50 @@ func TestUnmarshalReaderError(t *testing.T) {
assert.NotNil(t, err)
assert.True(t, strings.Contains(err.Error(), payload))
}
func TestUnmarshalMap(t *testing.T) {
t.Run("nil map and valid", func(t *testing.T) {
var m map[string]interface{}
var v struct {
Any string `json:",optional"`
}
err := UnmarshalJsonMap(m, &v)
assert.Nil(t, err)
assert.True(t, len(v.Any) == 0)
})
t.Run("empty map but not valid", func(t *testing.T) {
m := map[string]interface{}{}
var v struct {
Any string
}
err := UnmarshalJsonMap(m, &v)
assert.NotNil(t, err)
})
t.Run("empty map and valid", func(t *testing.T) {
m := map[string]interface{}{}
var v struct {
Any string `json:",optional"`
}
err := UnmarshalJsonMap(m, &v)
assert.Nil(t, err)
assert.True(t, len(v.Any) == 0)
})
t.Run("valid map", func(t *testing.T) {
m := map[string]interface{}{
"Any": "foo",
}
var v struct {
Any string
}
err := UnmarshalJsonMap(m, &v)
assert.Nil(t, err)
assert.Equal(t, "foo", v.Any)
})
}

View File

@@ -7,7 +7,6 @@ import (
"reflect"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/tal-tech/go-zero/core/jsonx"
@@ -25,15 +24,17 @@ var (
errValueNotSettable = errors.New("value is not settable")
errValueNotStruct = errors.New("value type is not struct")
keyUnmarshaler = NewUnmarshaler(defaultKeyName)
cacheKeys atomic.Value
cacheKeysLock sync.Mutex
durationType = reflect.TypeOf(time.Duration(0))
cacheKeys map[string][]string
cacheKeysLock sync.Mutex
defaultCache map[string]interface{}
defaultCacheLock sync.Mutex
emptyMap = map[string]interface{}{}
emptyValue = reflect.ValueOf(lang.Placeholder)
)
type (
// A Unmarshaler is used to unmarshal with given tag key.
// Unmarshaler is used to unmarshal with given tag key.
Unmarshaler struct {
key string
opts unmarshalOptions
@@ -46,12 +47,11 @@ type (
fromString bool
canonicalKey func(key string) string
}
keyCache map[string][]string
)
func init() {
cacheKeys.Store(make(keyCache))
cacheKeys = make(map[string][]string)
defaultCache = make(map[string]interface{})
}
// NewUnmarshaler returns a Unmarshaler.
@@ -207,6 +207,8 @@ func (u *Unmarshaler) processFieldNotFromString(field reflect.StructField, value
switch {
case valueKind == reflect.Map && typeKind == reflect.Struct:
return u.processFieldStruct(field, value, mapValue, fullName)
case valueKind == reflect.Map && typeKind == reflect.Map:
return u.fillMap(field, value, mapValue)
case valueKind == reflect.String && typeKind == reflect.Slice:
return u.fillSliceFromString(fieldType, value, mapValue)
case valueKind == reflect.String && derefedFieldType == durationType:
@@ -386,7 +388,13 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(field reflect.StructField, v
if derefedType == durationType {
return fillDurationValue(fieldKind, value, defaultValue)
}
return setValue(fieldKind, value, defaultValue)
switch fieldKind {
case reflect.Array, reflect.Slice:
return u.fillSliceWithDefault(derefedType, value, defaultValue)
default:
return setValue(fieldKind, value, defaultValue)
}
}
switch fieldKind {
@@ -500,7 +508,8 @@ func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.
return nil
}
func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int, baseKind reflect.Kind, value interface{}) error {
func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
baseKind reflect.Kind, value interface{}) error {
ithVal := slice.Index(index)
switch v := value.(type) {
case json.Number:
@@ -529,6 +538,28 @@ func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int, baseKind re
}
}
func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value reflect.Value,
defaultValue string) error {
baseFieldType := Deref(derefedType.Elem())
baseFieldKind := baseFieldType.Kind()
defaultCacheLock.Lock()
slice, ok := defaultCache[defaultValue]
defaultCacheLock.Unlock()
if !ok {
if baseFieldKind == reflect.String {
slice = parseGroupedSegments(defaultValue)
} else if err := jsonx.UnmarshalFromString(defaultValue, &slice); err != nil {
return err
}
defaultCacheLock.Lock()
defaultCache[defaultValue] = slice
defaultCacheLock.Unlock()
}
return u.fillSlice(derefedType, value, slice)
}
func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue interface{}) (reflect.Value, error) {
mapType := reflect.MapOf(keyType, elemType)
valueType := reflect.TypeOf(mapValue)
@@ -584,6 +615,8 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue inter
targetValue.SetMapIndex(key, innerValue)
default:
switch v := keythData.(type) {
case bool:
targetValue.SetMapIndex(key, reflect.ValueOf(v))
case string:
targetValue.SetMapIndex(key, reflect.ValueOf(v))
case json.Number:
@@ -720,20 +753,6 @@ func getValueWithChainedKeys(m Valuer, keys []string) (interface{}, bool) {
return nil, false
}
func insertKeys(key string, cache []string) {
cacheKeysLock.Lock()
defer cacheKeysLock.Unlock()
keys := cacheKeys.Load().(keyCache)
// copy the contents into the new map, to guarantee the old map is immutable
newKeys := make(keyCache)
for k, v := range keys {
newKeys[k] = v
}
newKeys[key] = cache
cacheKeys.Store(newKeys)
}
func join(elem ...string) string {
var builder strings.Builder
@@ -764,15 +783,19 @@ func newTypeMismatchError(name string) error {
}
func readKeys(key string) []string {
cache := cacheKeys.Load().(keyCache)
if keys, ok := cache[key]; ok {
cacheKeysLock.Lock()
keys, ok := cacheKeys[key]
cacheKeysLock.Unlock()
if ok {
return keys
}
keys := strings.FieldsFunc(key, func(c rune) bool {
keys = strings.FieldsFunc(key, func(c rune) bool {
return c == delimiter
})
insertKeys(key, keys)
cacheKeysLock.Lock()
cacheKeys[key] = keys
cacheKeysLock.Unlock()
return keys
}

View File

@@ -198,6 +198,66 @@ func TestUnmarshalIntWithDefault(t *testing.T) {
assert.Equal(t, 1, in.Int)
}
func TestUnmarshalBoolSliceWithDefault(t *testing.T) {
type inner struct {
Bools []bool `key:"bools,default=[true,false]"`
}
var in inner
assert.Nil(t, UnmarshalKey(nil, &in))
assert.ElementsMatch(t, []bool{true, false}, in.Bools)
}
func TestUnmarshalIntSliceWithDefault(t *testing.T) {
type inner struct {
Ints []int `key:"ints,default=[1,2,3]"`
}
var in inner
assert.Nil(t, UnmarshalKey(nil, &in))
assert.ElementsMatch(t, []int{1, 2, 3}, in.Ints)
}
func TestUnmarshalIntSliceWithDefaultHasSpaces(t *testing.T) {
type inner struct {
Ints []int `key:"ints,default=[1, 2, 3]"`
}
var in inner
assert.Nil(t, UnmarshalKey(nil, &in))
assert.ElementsMatch(t, []int{1, 2, 3}, in.Ints)
}
func TestUnmarshalFloatSliceWithDefault(t *testing.T) {
type inner struct {
Floats []float32 `key:"floats,default=[1.1,2.2,3.3]"`
}
var in inner
assert.Nil(t, UnmarshalKey(nil, &in))
assert.ElementsMatch(t, []float32{1.1, 2.2, 3.3}, in.Floats)
}
func TestUnmarshalStringSliceWithDefault(t *testing.T) {
type inner struct {
Strs []string `key:"strs,default=[foo,bar,woo]"`
}
var in inner
assert.Nil(t, UnmarshalKey(nil, &in))
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, in.Strs)
}
func TestUnmarshalStringSliceWithDefaultHasSpaces(t *testing.T) {
type inner struct {
Strs []string `key:"strs,default=[foo, bar, woo]"`
}
var in inner
assert.Nil(t, UnmarshalKey(nil, &in))
assert.ElementsMatch(t, []string{"foo", "bar", "woo"}, in.Strs)
}
func TestUnmarshalUint(t *testing.T) {
type inner struct {
Uint uint `key:"uint"`
@@ -861,10 +921,12 @@ func TestUnmarshalSliceOfStruct(t *testing.T) {
func TestUnmarshalWithStringOptionsCorrect(t *testing.T) {
type inner struct {
Value string `key:"value,options=first|second"`
Foo string `key:"foo,options=[bar,baz]"`
Correct string `key:"correct,options=1|2"`
}
m := map[string]interface{}{
"value": "first",
"foo": "bar",
"correct": "2",
}
@@ -872,6 +934,7 @@ func TestUnmarshalWithStringOptionsCorrect(t *testing.T) {
ast := assert.New(t)
ast.Nil(UnmarshalKey(m, &in))
ast.Equal("first", in.Value)
ast.Equal("bar", in.Foo)
ast.Equal("2", in.Correct)
}
@@ -943,6 +1006,22 @@ func TestUnmarshalStringOptionsWithStringOptionsIncorrect(t *testing.T) {
ast.NotNil(unmarshaler.Unmarshal(m, &in))
}
func TestUnmarshalStringOptionsWithStringOptionsIncorrectGrouped(t *testing.T) {
type inner struct {
Value string `key:"value,options=[first,second]"`
Correct string `key:"correct,options=1|2"`
}
m := map[string]interface{}{
"value": "third",
"correct": "2",
}
var in inner
unmarshaler := NewUnmarshaler(defaultKeyName, WithStringValues())
ast := assert.New(t)
ast.NotNil(unmarshaler.Unmarshal(m, &in))
}
func TestUnmarshalWithStringOptionsIncorrect(t *testing.T) {
type inner struct {
Value string `key:"value,options=first|second"`
@@ -2518,3 +2597,29 @@ func TestUnmarshalJsonReaderPtrArray(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 3, len(res.B))
}
func TestUnmarshalJsonWithoutKey(t *testing.T) {
payload := `{"A": "1", "B": "2"}`
var res struct {
A string `json:""`
B string `json:","`
}
reader := strings.NewReader(payload)
err := UnmarshalJsonReader(reader, &res)
assert.Nil(t, err)
assert.Equal(t, "1", res.A)
assert.Equal(t, "2", res.B)
}
func BenchmarkDefaultValue(b *testing.B) {
for i := 0; i < b.N; i++ {
var a struct {
Ints []int `json:"ints,default=[1,2,3]"`
Strs []string `json:"strs,default=[foo,bar,baz]"`
}
_ = UnmarshalJsonMap(nil, &a)
if len(a.Strs) != 3 || len(a.Ints) != 3 {
b.Fatal("failed")
}
}
}

View File

@@ -14,13 +14,19 @@ import (
)
const (
defaultOption = "default"
stringOption = "string"
optionalOption = "optional"
optionsOption = "options"
rangeOption = "range"
optionSeparator = "|"
equalToken = "="
defaultOption = "default"
stringOption = "string"
optionalOption = "optional"
optionsOption = "options"
rangeOption = "range"
optionSeparator = "|"
equalToken = "="
escapeChar = '\\'
leftBracket = '('
rightBracket = ')'
leftSquareBracket = '['
rightSquareBracket = ']'
segmentSeparator = ','
)
var (
@@ -118,7 +124,7 @@ func convertType(kind reflect.Kind, str string) (interface{}, error) {
}
func doParseKeyAndOptions(field reflect.StructField, value string) (string, *fieldOptions, error) {
segments := strings.Split(value, ",")
segments := parseSegments(value)
key := strings.TrimSpace(segments[0])
options := segments[1:]
@@ -198,6 +204,16 @@ func maybeNewValue(field reflect.StructField, value reflect.Value) {
}
}
func parseGroupedSegments(val string) []string {
val = strings.TrimLeftFunc(val, func(r rune) bool {
return r == leftBracket || r == leftSquareBracket
})
val = strings.TrimRightFunc(val, func(r rune) bool {
return r == rightBracket || r == rightSquareBracket
})
return parseSegments(val)
}
// don't modify returned fieldOptions, it's cached and shared among different calls.
func parseKeyAndOptions(tagName string, field reflect.StructField) (string, *fieldOptions, error) {
value := field.Tag.Get(tagName)
@@ -309,7 +325,7 @@ func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
return fmt.Errorf("field %s has wrong options", fieldName)
}
fieldOpts.Options = strings.Split(segs[1], optionSeparator)
fieldOpts.Options = parseOptions(segs[1])
case strings.HasPrefix(option, defaultOption):
segs := strings.Split(option, equalToken)
if len(segs) != 2 {
@@ -334,6 +350,69 @@ func parseOption(fieldOpts *fieldOptions, fieldName, option string) error {
return nil
}
// parseOptions parses the given options in tag.
// for example: `json:"name,options=foo|bar"` or `json:"name,options=[foo,bar]"`
func parseOptions(val string) []string {
if len(val) == 0 {
return nil
}
if val[0] == leftSquareBracket {
return parseGroupedSegments(val)
}
return strings.Split(val, optionSeparator)
}
func parseSegments(val string) []string {
var segments []string
var escaped, grouped bool
var buf strings.Builder
for _, ch := range val {
if escaped {
buf.WriteRune(ch)
escaped = false
continue
}
switch ch {
case segmentSeparator:
if grouped {
buf.WriteRune(ch)
} else {
// need to trim spaces, but we cannot ignore empty string,
// because the first segment stands for the key might be empty.
// if ignored, the later tag will be used as the key.
segments = append(segments, strings.TrimSpace(buf.String()))
buf.Reset()
}
case escapeChar:
if grouped {
buf.WriteRune(ch)
} else {
escaped = true
}
case leftBracket, leftSquareBracket:
buf.WriteRune(ch)
grouped = true
case rightBracket, rightSquareBracket:
buf.WriteRune(ch)
grouped = false
default:
buf.WriteRune(ch)
}
}
last := strings.TrimSpace(buf.String())
// ignore last empty string
if len(last) > 0 {
segments = append(segments, last)
}
return segments
}
func reprOfValue(val reflect.Value) string {
switch vt := val.Interface().(type) {
case bool:

View File

@@ -90,6 +90,82 @@ func TestParseKeyAndOptionWithTagAndOption(t *testing.T) {
assert.True(t, options.FromString)
}
func TestParseSegments(t *testing.T) {
tests := []struct {
input string
expect []string
}{
{
input: "",
expect: []string{},
},
{
input: ",",
expect: []string{""},
},
{
input: "foo,",
expect: []string{"foo"},
},
{
input: ",foo",
// the first empty string cannot be ignored, it's the key.
expect: []string{"", "foo"},
},
{
input: "foo",
expect: []string{"foo"},
},
{
input: "foo,bar",
expect: []string{"foo", "bar"},
},
{
input: "foo,bar,baz",
expect: []string{"foo", "bar", "baz"},
},
{
input: "foo,options=a|b",
expect: []string{"foo", "options=a|b"},
},
{
input: "foo,bar,default=[baz,qux]",
expect: []string{"foo", "bar", "default=[baz,qux]"},
},
{
input: "foo,bar,options=[baz,qux]",
expect: []string{"foo", "bar", "options=[baz,qux]"},
},
{
input: `foo\,bar,options=[baz,qux]`,
expect: []string{`foo,bar`, "options=[baz,qux]"},
},
{
input: `foo,bar,options=\[baz,qux]`,
expect: []string{"foo", "bar", "options=[baz", "qux]"},
},
{
input: `foo,bar,options=[baz\,qux]`,
expect: []string{"foo", "bar", `options=[baz\,qux]`},
},
{
input: `foo\,bar,options=[baz,qux],default=baz`,
expect: []string{`foo,bar`, "options=[baz,qux]", "default=baz"},
},
{
input: `foo\,bar,options=[baz,qux, quux],default=[qux, baz]`,
expect: []string{`foo,bar`, "options=[baz,qux, quux]", "default=[qux, baz]"},
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
assert.ElementsMatch(t, test.expect, parseSegments(test.input))
})
}
}
func TestValidatePtrWithNonPtr(t *testing.T) {
var foo string
rve := reflect.ValueOf(foo)

View File

@@ -945,6 +945,70 @@ func TestUnmarshalYamlBadReader(t *testing.T) {
assert.NotNil(t, err)
}
func TestUnmarshalYamlMapBool(t *testing.T) {
text := `machine:
node1: true
node2: true
node3: true
`
var v struct {
Machine map[string]bool `json:"machine,optional"`
}
reader := strings.NewReader(text)
assert.Nil(t, UnmarshalYamlReader(reader, &v))
assert.True(t, v.Machine["node1"])
assert.True(t, v.Machine["node2"])
assert.True(t, v.Machine["node3"])
}
func TestUnmarshalYamlMapInt(t *testing.T) {
text := `machine:
node1: 1
node2: 2
node3: 3
`
var v struct {
Machine map[string]int `json:"machine,optional"`
}
reader := strings.NewReader(text)
assert.Nil(t, UnmarshalYamlReader(reader, &v))
assert.Equal(t, 1, v.Machine["node1"])
assert.Equal(t, 2, v.Machine["node2"])
assert.Equal(t, 3, v.Machine["node3"])
}
func TestUnmarshalYamlMapByte(t *testing.T) {
text := `machine:
node1: 1
node2: 2
node3: 3
`
var v struct {
Machine map[string]byte `json:"machine,optional"`
}
reader := strings.NewReader(text)
assert.Nil(t, UnmarshalYamlReader(reader, &v))
assert.Equal(t, byte(1), v.Machine["node1"])
assert.Equal(t, byte(2), v.Machine["node2"])
assert.Equal(t, byte(3), v.Machine["node3"])
}
func TestUnmarshalYamlMapRune(t *testing.T) {
text := `machine:
node1: 1
node2: 2
node3: 3
`
var v struct {
Machine map[string]rune `json:"machine,optional"`
}
reader := strings.NewReader(text)
assert.Nil(t, UnmarshalYamlReader(reader, &v))
assert.Equal(t, rune(1), v.Machine["node1"])
assert.Equal(t, rune(2), v.Machine["node2"])
assert.Equal(t, rune(3), v.Machine["node3"])
}
type badReader struct{}
func (b *badReader) Read(p []byte) (n int, err error) {

View File

@@ -1,13 +1,13 @@
package mr
import (
"context"
"errors"
"fmt"
"sync"
"github.com/tal-tech/go-zero/core/errorx"
"github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/core/syncx"
"github.com/tal-tech/go-zero/core/threading"
)
@@ -43,6 +43,7 @@ type (
Option func(opts *mapReduceOptions)
mapReduceOptions struct {
ctx context.Context
workers int
}
@@ -93,16 +94,17 @@ func Map(generate GenerateFunc, mapper MapFunc, opts ...Option) chan interface{}
options := buildOptions(opts...)
source := buildSource(generate)
collector := make(chan interface{}, options.workers)
done := syncx.NewDoneChan()
done := make(chan lang.PlaceholderType)
go executeMappers(mapper, source, collector, done.Done(), options.workers)
go executeMappers(options.ctx, mapper, source, collector, done, options.workers)
return collector
}
// MapReduce maps all elements generated from given generate func,
// and reduces the output elements with given reducer.
func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc, opts ...Option) (interface{}, error) {
func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc,
opts ...Option) (interface{}, error) {
source := buildSource(generate)
return MapReduceWithSource(source, mapper, reducer, opts...)
}
@@ -119,13 +121,13 @@ func MapReduceWithSource(source <-chan interface{}, mapper MapperFunc, reducer R
}()
collector := make(chan interface{}, options.workers)
done := syncx.NewDoneChan()
writer := newGuardedWriter(output, done.Done())
done := make(chan lang.PlaceholderType)
writer := newGuardedWriter(options.ctx, output, done)
var closeOnce sync.Once
var retErr errorx.AtomicError
finish := func() {
closeOnce.Do(func() {
done.Close()
close(done)
close(output)
})
}
@@ -154,9 +156,9 @@ func MapReduceWithSource(source <-chan interface{}, mapper MapperFunc, reducer R
reducer(collector, writer, cancel)
}()
go executeMappers(func(item interface{}, w Writer) {
go executeMappers(options.ctx, func(item interface{}, w Writer) {
mapper(item, w, cancel)
}, source, collector, done.Done(), options.workers)
}, source, collector, done, options.workers)
value, ok := <-output
if err := retErr.Load(); err != nil {
@@ -187,6 +189,13 @@ func MapVoid(generate GenerateFunc, mapper VoidMapFunc, opts ...Option) {
}, opts...))
}
// WithContext customizes a mapreduce processing accepts a given ctx.
func WithContext(ctx context.Context) Option {
return func(opts *mapReduceOptions) {
opts.ctx = ctx
}
}
// WithWorkers customizes a mapreduce processing with given workers.
func WithWorkers(workers int) Option {
return func(opts *mapReduceOptions) {
@@ -224,8 +233,8 @@ func drain(channel <-chan interface{}) {
}
}
func executeMappers(mapper MapFunc, input <-chan interface{}, collector chan<- interface{},
done <-chan lang.PlaceholderType, workers int) {
func executeMappers(ctx context.Context, mapper MapFunc, input <-chan interface{},
collector chan<- interface{}, done <-chan lang.PlaceholderType, workers int) {
var wg sync.WaitGroup
defer func() {
wg.Wait()
@@ -233,9 +242,11 @@ func executeMappers(mapper MapFunc, input <-chan interface{}, collector chan<- i
}()
pool := make(chan lang.PlaceholderType, workers)
writer := newGuardedWriter(collector, done)
writer := newGuardedWriter(ctx, collector, done)
for {
select {
case <-ctx.Done():
return
case <-done:
return
case pool <- lang.Placeholder:
@@ -261,6 +272,7 @@ func executeMappers(mapper MapFunc, input <-chan interface{}, collector chan<- i
func newOptions() *mapReduceOptions {
return &mapReduceOptions{
ctx: context.Background(),
workers: defaultWorkers,
}
}
@@ -275,12 +287,15 @@ func once(fn func(error)) func(error) {
}
type guardedWriter struct {
ctx context.Context
channel chan<- interface{}
done <-chan lang.PlaceholderType
}
func newGuardedWriter(channel chan<- interface{}, done <-chan lang.PlaceholderType) guardedWriter {
func newGuardedWriter(ctx context.Context, channel chan<- interface{},
done <-chan lang.PlaceholderType) guardedWriter {
return guardedWriter{
ctx: ctx,
channel: channel,
done: done,
}
@@ -288,6 +303,8 @@ func newGuardedWriter(channel chan<- interface{}, done <-chan lang.PlaceholderTy
func (gw guardedWriter) Write(v interface{}) {
select {
case <-gw.ctx.Done():
return
case <-gw.done:
return
default:

View File

@@ -1,6 +1,7 @@
package mr
import (
"context"
"errors"
"io/ioutil"
"log"
@@ -410,6 +411,50 @@ func TestMapReduceWithoutReducerWrite(t *testing.T) {
assert.Nil(t, res)
}
func TestMapReduceVoidPanicInReducer(t *testing.T) {
const message = "foo"
var done syncx.AtomicBool
err := MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ {
source <- i
}
done.Set(true)
}, func(item interface{}, writer Writer, cancel func(error)) {
i := item.(int)
writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) {
panic(message)
}, WithWorkers(1))
assert.NotNil(t, err)
assert.Equal(t, message, err.Error())
assert.True(t, done.True())
}
func TestMapReduceWithContext(t *testing.T) {
var done syncx.AtomicBool
var result []int
ctx, cancel := context.WithCancel(context.Background())
err := MapReduceVoid(func(source chan<- interface{}) {
for i := 0; i < defaultWorkers*2; i++ {
source <- i
}
done.Set(true)
}, func(item interface{}, writer Writer, c func(error)) {
i := item.(int)
if i == defaultWorkers/2 {
cancel()
}
writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) {
for item := range pipe {
i := item.(int)
result = append(result, i)
}
}, WithContext(ctx))
assert.NotNil(t, err)
assert.Equal(t, ErrReduceNoOutput, err)
}
func BenchmarkMapReduce(b *testing.B) {
b.ReportAllocs()

89
core/mr/readme-cn.md Normal file
View File

@@ -0,0 +1,89 @@
# mapreduce
[English](readme.md) | 简体中文
## 为什么需要 MapReduce
在实际的业务场景中我们常常需要从不同的 rpc 服务中获取相应属性来组装成复杂对象。
比如要查询商品详情:
1. 商品服务-查询商品属性
2. 库存服务-查询库存属性
3. 价格服务-查询价格属性
4. 营销服务-查询营销属性
如果是串行调用的话响应时间会随着 rpc 调用次数呈线性增长,所以我们要优化性能一般会将串行改并行。
简单的场景下使用 `WaitGroup` 也能够满足需求,但是如果我们需要对 rpc 调用返回的数据进行校验、数据加工转换、数据汇总呢?继续使用 `WaitGroup` 就有点力不从心了go 的官方库中并没有这种工具java 中提供了 CompleteFuture我们依据 MapReduce 架构思想实现了进程内的数据批处理 MapReduce 并发工具类。
## 设计思路
我们尝试把自己代入到作者的角色梳理一下并发工具可能的业务场景:
1. 查询商品详情:支持并发调用多个服务来组合产品属性,支持调用错误可以立即结束。
2. 商品详情页自动推荐用户卡券:支持并发校验卡券,校验失败自动剔除,返回全部卡券。
以上实际都是在进行对输入数据进行处理最后输出清洗后的数据,针对数据处理有个非常经典的异步模式:生产者消费者模式。于是我们可以抽象一下数据批处理的生命周期,大致可以分为三个阶段:
<img src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/mapreduce-serial-cn.png" width="500">
1. 数据生产 generate
2. 数据加工 mapper
3. 数据聚合 reducer
其中数据生产是不可或缺的阶段,数据加工、数据聚合是可选阶段,数据生产与加工支持并发调用,数据聚合基本属于纯内存操作单协程即可。
再来思考一下不同阶段之间数据应该如何流转,既然不同阶段的数据处理都是由不同 goroutine 执行的,那么很自然的可以考虑采用 channel 来实现 goroutine 之间的通信。
<img src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/mapreduce-cn.png" width="500">
如何实现随时终止流程呢?
`goroutine` 中监听一个全局的结束 `channel` 和调用方提供的 `ctx` 就行。
## 简单示例
并行求平方和(不要嫌弃示例简单,只是模拟并发)
```go
package main
import (
"fmt"
"log"
"github.com/tal-tech/go-zero/core/mr"
)
func main() {
val, err := mr.MapReduce(func(source chan<- interface{}) {
// generator
for i := 0; i < 10; i++ {
source <- i
}
}, func(item interface{}, writer mr.Writer, cancel func(error)) {
// mapper
i := item.(int)
writer.Write(i * i)
}, func(pipe <-chan interface{}, writer mr.Writer, cancel func(error)) {
// reducer
var sum int
for i := range pipe {
sum += i.(int)
}
writer.Write(sum)
})
if err != nil {
log.Fatal(err)
}
fmt.Println("result:", val)
}
```
更多示例:[https://github.com/zeromicro/zero-examples/tree/main/mapreduce](https://github.com/zeromicro/zero-examples/tree/main/mapreduce)
## 欢迎 star
如果你正在使用或者觉得这个项目对你有帮助,请 **star** 支持,感谢!

90
core/mr/readme.md Normal file
View File

@@ -0,0 +1,90 @@
<img align="right" width="150px" src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/go-zero.png">
# mapreduce
English | [简体中文](readme-cn.md)
## Why MapReduce is needed
In practical business scenarios we often need to get the corresponding properties from different rpc services to assemble complex objects.
For example, to query product details.
1. product service - query product attributes
2. inventory service - query inventory properties
3. price service - query price attributes
4. marketing service - query marketing properties
If it is a serial call, the response time will increase linearly with the number of rpc calls, so we will generally change serial to parallel to optimize response time.
Simple scenarios using `WaitGroup` can also meet the needs, but what if we need to check the data returned by the rpc call, data processing, data aggregation? The official go library does not have such a tool (CompleteFuture is provided in java), so we implemented an in-process data batching MapReduce concurrent tool based on the MapReduce architecture.
## Design ideas
Let's try to put ourselves in the author's shoes and sort out the possible business scenarios for the concurrency tool:
1. querying product details: supporting concurrent calls to multiple services to combine product attributes, and supporting call errors that can be ended immediately.
2. automatic recommendation of user card coupons on product details page: support concurrently verifying card coupons, automatically rejecting them if they fail, and returning all of them.
The above is actually processing the input data and finally outputting the cleaned data. There is a very classic asynchronous pattern for data processing: the producer-consumer pattern. So we can abstract the life cycle of data batch processing, which can be roughly divided into three phases.
<img src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/mapreduce-serial-en.png" width="500">
1. data production generate
2. data processing mapper
3. data aggregation reducer
Data producing is an indispensable stage, data processing and data aggregation are optional stages, data producing and processing support concurrent calls, data aggregation is basically a pure memory operation, so a single concurrent process can do it.
Since different stages of data processing are performed by different goroutines, it is natural to consider the use of channel to achieve communication between goroutines.
<img src="https://raw.githubusercontent.com/zeromicro/zero-doc/main/doc/images/mapreduce-en.png" width="500">
How can I terminate the process at any time?
It's simple, just receive from a channel or the given context in the goroutine.
## A simple example
Calculate the sum of squares, simulating the concurrency.
```go
package main
import (
"fmt"
"log"
"github.com/tal-tech/go-zero/core/mr"
)
func main() {
val, err := mr.MapReduce(func(source chan<- interface{}) {
// generator
for i := 0; i < 10; i++ {
source <- i
}
}, func(item interface{}, writer mr.Writer, cancel func(error)) {
// mapper
i := item.(int)
writer.Write(i * i)
}, func(pipe <-chan interface{}, writer mr.Writer, cancel func(error)) {
// reducer
var sum int
for i := range pipe {
sum += i.(int)
}
writer.Write(sum)
})
if err != nil {
log.Fatal(err)
}
fmt.Println("result:", val)
}
```
More examples: [https://github.com/zeromicro/zero-examples/tree/main/mapreduce](https://github.com/zeromicro/zero-examples/tree/main/mapreduce)
## Give a Star! ⭐
If you like or are using this project to learn or start your solution, please give it a star. Thanks!

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/threading"
)
const (
@@ -46,10 +47,10 @@ func gracefulStop(signals chan os.Signal) {
signal.Stop(signals)
logx.Info("Got signal SIGTERM, shutting down...")
wrapUpListeners.notifyListeners()
go wrapUpListeners.notifyListeners()
time.Sleep(wrapUpTime)
shutdownListeners.notifyListeners()
go shutdownListeners.notifyListeners()
time.Sleep(delayTimeBeforeForceQuit - wrapUpTime)
logx.Infof("Still alive after %v, going to force kill the process...", delayTimeBeforeForceQuit)
@@ -81,7 +82,9 @@ func (lm *listenerManager) notifyListeners() {
lm.lock.Lock()
defer lm.lock.Unlock()
group := threading.NewRoutineGroup()
for _, listener := range lm.listeners {
listener()
group.RunSafe(listener)
}
group.Wait()
}

View File

@@ -1,32 +0,0 @@
package backoff
import (
"math/rand"
"time"
)
// Func defines the method to calculate how long to retry.
type Func func(attempt int) time.Duration
// LinearWithJitter waits a set period of time, allowing for jitter (fractional adjustment).
func LinearWithJitter(waitBetween time.Duration, jitterFraction float64) Func {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
return func(attempt int) time.Duration {
multiplier := jitterFraction * (r.Float64()*2 - 1)
return time.Duration(float64(waitBetween) * (1 + multiplier))
}
}
// Interval it waits for a fixed period of time between calls.
func Interval(interval time.Duration) Func {
return func(attempt int) time.Duration {
return interval
}
}
// Exponential produces increasing intervals for each attempt.
func Exponential(scalar time.Duration) Func {
return func(attempt int) time.Duration {
return scalar * time.Duration((1<<attempt)>>1)
}
}

View File

@@ -1,30 +0,0 @@
package backoff
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestWaitBetween(t *testing.T) {
fn := Interval(time.Second)
assert.EqualValues(t, time.Second, fn(1))
}
func TestExponential(t *testing.T) {
fn := Exponential(time.Second)
assert.EqualValues(t, time.Second, fn(1))
}
func TestLinearWithJitter(t *testing.T) {
const rounds = 1000000
var total time.Duration
fn := LinearWithJitter(time.Second, 0.5)
for i := 0; i < rounds; i++ {
total += fn(1)
}
// 0.1% tolerance
assert.True(t, total/time.Duration(rounds)-time.Second < time.Millisecond)
}

View File

@@ -1,42 +0,0 @@
package retry
import (
"time"
"github.com/tal-tech/go-zero/core/retry/backoff"
"google.golang.org/grpc/codes"
)
// WithDisable disables the retry behaviour on this call, or this interceptor.
// It's semantically the same to `WithMax(0)`
func WithDisable() *CallOption {
return WithMax(0)
}
// WithMax sets the maximum number of retries on this call, or this interceptor.
func WithMax(maxRetries int) *CallOption {
return &CallOption{apply: func(options *options) {
options.max = maxRetries
}}
}
// WithBackoff sets the `BackoffFunc` used to control time between retries.
func WithBackoff(backoffFunc backoff.Func) *CallOption {
return &CallOption{apply: func(o *options) {
o.backoffFunc = backoffFunc
}}
}
// WithCodes Allow code to be retried.
func WithCodes(retryCodes ...codes.Code) *CallOption {
return &CallOption{apply: func(o *options) {
o.codes = retryCodes
}}
}
// WithPerRetryTimeout timeout for each retry
func WithPerRetryTimeout(timeout time.Duration) *CallOption {
return &CallOption{apply: func(o *options) {
o.perCallTimeout = timeout
}}
}

View File

@@ -1,91 +0,0 @@
package retry
import (
"context"
"errors"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/logx"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
func TestRetryWithDisable(t *testing.T) {
opt := &options{}
assert.EqualValues(t, &options{}, parseRetryCallOptions(opt, WithDisable()))
}
func TestRetryWithMax(t *testing.T) {
n := 5
for i := 0; i < n; i++ {
opt := &options{}
assert.EqualValues(t, &options{max: i}, parseRetryCallOptions(opt, WithMax(i)))
}
}
func TestRetryWithBackoff(t *testing.T) {
opt := &options{}
retryCallOptions := parseRetryCallOptions(opt, WithBackoff(func(attempt int) time.Duration {
return time.Millisecond
}))
assert.EqualValues(t, time.Millisecond, retryCallOptions.backoffFunc(1))
}
func TestRetryWithCodes(t *testing.T) {
opt := &options{}
c := []codes.Code{codes.Unknown, codes.NotFound}
options := parseRetryCallOptions(opt, WithCodes(c...))
assert.EqualValues(t, c, options.codes)
}
func TestRetryWithPerRetryTimeout(t *testing.T) {
opt := &options{}
options := parseRetryCallOptions(opt, WithPerRetryTimeout(time.Millisecond))
assert.EqualValues(t, time.Millisecond, options.perCallTimeout)
}
func Test_waitRetryBackoff(t *testing.T) {
logx.Disable()
opt := &options{perCallTimeout: time.Second, backoffFunc: func(attempt int) time.Duration {
return time.Second
}}
logger := logx.WithContext(context.Background())
err := waitRetryBackoff(logger, 1, context.Background(), opt)
assert.NoError(t, err)
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Millisecond)
defer cancelFunc()
err = waitRetryBackoff(logger, 1, ctx, opt)
assert.ErrorIs(t, err, status.FromContextError(context.DeadlineExceeded).Err())
}
func Test_isRetriable(t *testing.T) {
assert.False(t, isRetriable(status.FromContextError(context.DeadlineExceeded).Err(), &options{codes: DefaultRetriableCodes}))
assert.True(t, isRetriable(status.Error(codes.ResourceExhausted, ""), &options{codes: DefaultRetriableCodes}))
assert.False(t, isRetriable(errors.New("error"), &options{}))
}
func Test_perCallContext(t *testing.T) {
opt := &options{perCallTimeout: time.Second, includeRetryHeader: true}
ctx := metadata.NewIncomingContext(context.Background(), map[string][]string{"1": {"1"}})
callContext := perCallContext(ctx, opt, 1)
md, ok := metadata.FromOutgoingContext(callContext)
assert.True(t, ok)
assert.EqualValues(t, metadata.MD{"1": {"1"}, AttemptMetadataKey: {"1"}}, md)
}
func Test_filterCallOptions(t *testing.T) {
grpcEmptyCallOpt := &grpc.EmptyCallOption{}
retryCallOpt := &CallOption{}
options, retryCallOptions := filterCallOptions([]grpc.CallOption{
grpcEmptyCallOpt,
retryCallOpt,
})
assert.EqualValues(t, []grpc.CallOption{grpcEmptyCallOpt}, options)
assert.EqualValues(t, []*CallOption{retryCallOpt}, retryCallOptions)
}

View File

@@ -1,189 +0,0 @@
package retry
import (
"context"
"strconv"
"time"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/core/retry/backoff"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
const AttemptMetadataKey = "x-retry-attempt"
var (
// DefaultRetriableCodes default retry code
DefaultRetriableCodes = []codes.Code{codes.ResourceExhausted, codes.Unavailable}
// defaultRetryOptions default retry configuration
defaultRetryOptions = &options{
max: 0, // disabled
perCallTimeout: 0, // disabled
includeRetryHeader: true,
codes: DefaultRetriableCodes,
backoffFunc: backoff.LinearWithJitter(50*time.Millisecond /*jitter*/, 0.10),
}
)
type (
// options retry the configuration
options struct {
max int
perCallTimeout time.Duration
includeRetryHeader bool
codes []codes.Code
backoffFunc backoff.Func
}
// CallOption is a grpc.CallOption that is local to grpc retry.
CallOption struct {
grpc.EmptyCallOption // make sure we implement private after() and before() fields so we don't panic.
apply func(opt *options)
}
)
func waitRetryBackoff(logger logx.Logger, attempt int, ctx context.Context, retryOptions *options) error {
var waitTime time.Duration = 0
if attempt > 0 {
waitTime = retryOptions.backoffFunc(attempt)
}
if waitTime > 0 {
timer := time.NewTimer(waitTime)
defer timer.Stop()
logger.Infof("grpc retry attempt: %d, backoff for %v", attempt, waitTime)
select {
case <-ctx.Done():
return status.FromContextError(ctx.Err()).Err()
case <-timer.C:
// double check
err := ctx.Err()
if err != nil {
return status.FromContextError(err).Err()
}
}
}
return nil
}
func isRetriable(err error, retryOptions *options) bool {
errCode := status.Code(err)
if isContextError(err) {
return false
}
for _, code := range retryOptions.codes {
if code == errCode {
return true
}
}
return false
}
func isContextError(err error) bool {
code := status.Code(err)
return code == codes.DeadlineExceeded || code == codes.Canceled
}
func reuseOrNewWithCallOptions(opt *options, retryCallOptions []*CallOption) *options {
if len(retryCallOptions) == 0 {
return opt
}
return parseRetryCallOptions(opt, retryCallOptions...)
}
func parseRetryCallOptions(opt *options, opts ...*CallOption) *options {
for _, option := range opts {
option.apply(opt)
}
return opt
}
func perCallContext(ctx context.Context, callOpts *options, attempt int) context.Context {
if attempt > 0 {
if callOpts.perCallTimeout != 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, callOpts.perCallTimeout)
_ = cancel
}
if callOpts.includeRetryHeader {
cloneMd := extractIncomingAndClone(ctx)
cloneMd.Set(AttemptMetadataKey, strconv.Itoa(attempt))
ctx = metadata.NewOutgoingContext(ctx, cloneMd)
}
}
return ctx
}
func extractIncomingAndClone(ctx context.Context) metadata.MD {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return metadata.MD{}
}
return md.Copy()
}
func filterCallOptions(callOptions []grpc.CallOption) (grpcOptions []grpc.CallOption, retryOptions []*CallOption) {
for _, opt := range callOptions {
if co, ok := opt.(*CallOption); ok {
retryOptions = append(retryOptions, co)
} else {
grpcOptions = append(grpcOptions, opt)
}
}
return grpcOptions, retryOptions
}
func Do(ctx context.Context, call func(ctx context.Context, opts ...grpc.CallOption) error, opts ...grpc.CallOption) error {
logger := logx.WithContext(ctx)
grpcOpts, retryOpts := filterCallOptions(opts)
callOpts := reuseOrNewWithCallOptions(defaultRetryOptions, retryOpts)
if callOpts.max == 0 {
return call(ctx, opts...)
}
var lastErr error
for attempt := 0; attempt <= callOpts.max; attempt++ {
if err := waitRetryBackoff(logger, attempt, ctx, callOpts); err != nil {
return err
}
callCtx := perCallContext(ctx, callOpts, attempt)
lastErr = call(callCtx, grpcOpts...)
if lastErr == nil {
return nil
}
if attempt == 0 {
logger.Errorf("grpc call failed, got err: %v", lastErr)
} else {
logger.Errorf("grpc retry attempt: %d, got err: %v", attempt, lastErr)
}
if isContextError(lastErr) {
if ctx.Err() != nil {
logger.Errorf("grpc retry attempt: %d, parent context error: %v", attempt, ctx.Err())
return lastErr
} else if callOpts.perCallTimeout != 0 {
logger.Errorf("grpc retry attempt: %d, context error from retry call", attempt)
continue
}
}
if !isRetriable(lastErr, callOpts) {
return lastErr
}
}
return lastErr
}

View File

@@ -1,24 +0,0 @@
package retry
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestDo(t *testing.T) {
n := 4
for i := 0; i < n; i++ {
count := 0
err := Do(context.Background(), func(ctx context.Context, opts ...grpc.CallOption) error {
count++
return status.Error(codes.ResourceExhausted, "ResourceExhausted")
}, WithMax(i))
assert.Error(t, err)
assert.Equal(t, i+1, count)
}
}

View File

@@ -1,9 +1,12 @@
package search
import (
"math/rand"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/core/stringx"
)
type mockedRoute struct {
@@ -139,11 +142,9 @@ func TestStrictSearchSibling(t *testing.T) {
tree.Add(r.route, r.value)
}
for i := 0; i < 1000; i++ {
result, ok := tree.Search(query)
assert.True(t, ok)
assert.Equal(t, 3, result.Item.(int))
}
result, ok := tree.Search(query)
assert.True(t, ok)
assert.Equal(t, 3, result.Item.(int))
}
func TestAddDuplicate(t *testing.T) {
@@ -185,3 +186,41 @@ func TestSearchInvalidItem(t *testing.T) {
err := tree.Add("/", nil)
assert.Equal(t, errEmptyItem, err)
}
func BenchmarkSearchTree(b *testing.B) {
const (
avgLen = 1000
entries = 10000
)
tree := NewTree()
generate := func() string {
var buf strings.Builder
size := rand.Intn(avgLen) + avgLen/2
val := stringx.Randn(size)
prev := 0
for j := rand.Intn(9) + 1; j < size; j += rand.Intn(9) + 1 {
buf.WriteRune('/')
buf.WriteString(val[prev:j])
prev = j
}
if prev < size {
buf.WriteRune('/')
buf.WriteString(val[prev:])
}
return buf.String()
}
index := rand.Intn(entries)
var query string
for i := 0; i < entries; i++ {
val := generate()
if i == index {
query = val
}
tree.Add(val, i)
}
for i := 0; i < b.N; i++ {
tree.Search(query)
}
}

View File

@@ -53,8 +53,8 @@ func TestCacheNode_DelCache(t *testing.T) {
func TestCacheNode_DelCacheWithErrors(t *testing.T) {
store, clean, err := redistest.CreateRedis()
assert.Nil(t, err)
defer clean()
store.Type = redis.ClusterType
clean()
cn := cacheNode{
rds: store,

View File

@@ -16,6 +16,8 @@ var ErrNoRedisNode = errors.New("no redis node")
type (
// Store interface represents a KV store.
Store interface {
Decr(key string) (int64, error)
Decrby(key string, increment int64) (int64, error)
Del(keys ...string) (int, error)
Eval(script, key string, args ...interface{}) (interface{}, error)
Exists(key string) (bool, error)
@@ -36,6 +38,7 @@ type (
Hvals(key string) ([]string, error)
Incr(key string) (int64, error)
Incrby(key string, increment int64) (int64, error)
Lindex(key string, index int64) (string, error)
Llen(key string) (int, error)
Lpop(key string) (string, error)
Lpush(key string, values ...interface{}) (int, error)
@@ -102,6 +105,24 @@ func NewStore(c KvConf) Store {
}
}
func (cs clusterStore) Decr(key string) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Decr(key)
}
func (cs clusterStore) Decrby(key string, increment int64) (int64, error) {
node, err := cs.getRedis(key)
if err != nil {
return 0, err
}
return node.Decrby(key, increment)
}
func (cs clusterStore) Del(keys ...string) (int, error) {
var val int
var be errorx.BatchError
@@ -303,6 +324,15 @@ func (cs clusterStore) Llen(key string) (int, error) {
return node.Llen(key)
}
func (cs clusterStore) Lindex(key string, index int64) (string, error) {
node, err := cs.getRedis(key)
if err != nil {
return "", err
}
return node.Lindex(key, index)
}
func (cs clusterStore) Lpop(key string) (string, error) {
node, err := cs.getRedis(key)
if err != nil {

View File

@@ -17,6 +17,36 @@ var (
s2, _ = miniredis.Run()
)
func TestRedis_Decr(t *testing.T) {
store := clusterStore{dispatcher: hash.NewConsistentHash()}
_, err := store.Decr("a")
assert.NotNil(t, err)
runOnCluster(t, func(client Store) {
val, err := client.Decr("a")
assert.Nil(t, err)
assert.Equal(t, int64(-1), val)
val, err = client.Decr("a")
assert.Nil(t, err)
assert.Equal(t, int64(-2), val)
})
}
func TestRedis_DecrBy(t *testing.T) {
store := clusterStore{dispatcher: hash.NewConsistentHash()}
_, err := store.Incrby("a", 2)
assert.NotNil(t, err)
runOnCluster(t, func(client Store) {
val, err := client.Decrby("a", 2)
assert.Nil(t, err)
assert.Equal(t, int64(-2), val)
val, err = client.Decrby("a", 3)
assert.Nil(t, err)
assert.Equal(t, int64(-5), val)
})
}
func TestRedis_Exists(t *testing.T) {
store := clusterStore{dispatcher: hash.NewConsistentHash()}
_, err := store.Exists("foo")
@@ -234,6 +264,8 @@ func TestRedis_List(t *testing.T) {
assert.NotNil(t, err)
_, err = store.Lrem("key", 0, "val")
assert.NotNil(t, err)
_, err = store.Lindex("key", 0)
assert.NotNil(t, err)
runOnCluster(t, func(client Store) {
val, err := client.Lpush("key", "value1", "value2")
@@ -245,6 +277,9 @@ func TestRedis_List(t *testing.T) {
val, err = client.Llen("key")
assert.Nil(t, err)
assert.Equal(t, 4, val)
value, err := client.Lindex("key", 0)
assert.Nil(t, err)
assert.Equal(t, "value2", value)
vals, err := client.Lrange("key", 0, 10)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value2", "value1", "value3", "value4"}, vals)

View File

@@ -36,20 +36,23 @@ func MustNewModel(url, collection string, c cache.CacheConf, opts ...cache.Optio
return model
}
// NewNodeModel returns a Model with a cache node.
func NewNodeModel(url, collection string, rds *redis.Redis, opts ...cache.Option) (*Model, error) {
c := cache.NewNode(rds, sharedCalls, stats, mgo.ErrNotFound, opts...)
// NewModel returns a Model with a cache cluster.
func NewModel(url, collection string, conf cache.CacheConf, opts ...cache.Option) (*Model, error) {
c := cache.New(conf, sharedCalls, stats, mgo.ErrNotFound, opts...)
return NewModelWithCache(url, collection, c)
}
// NewModelWithCache returns a Model with a custom cache.
func NewModelWithCache(url, collection string, c cache.Cache) (*Model, error) {
return createModel(url, collection, c, func(collection mongo.Collection) CachedCollection {
return newCollection(collection, c)
})
}
// NewModel returns a Model with a cache cluster.
func NewModel(url, collection string, conf cache.CacheConf, opts ...cache.Option) (*Model, error) {
c := cache.New(conf, sharedCalls, stats, mgo.ErrNotFound, opts...)
return createModel(url, collection, c, func(collection mongo.Collection) CachedCollection {
return newCollection(collection, c)
})
// NewNodeModel returns a Model with a cache node.
func NewNodeModel(url, collection string, rds *redis.Redis, opts ...cache.Option) (*Model, error) {
c := cache.NewNode(rds, sharedCalls, stats, mgo.ErrNotFound, opts...)
return NewModelWithCache(url, collection, c)
}
// Count returns the count of given query.

View File

@@ -238,6 +238,36 @@ func (s *Redis) BlpopEx(redisNode RedisNode, key string) (string, bool, error) {
return vals[1], true, nil
}
// Decr is the implementation of redis decr command.
func (s *Redis) Decr(key string) (val int64, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
val, err = conn.Decr(key).Result()
return err
}, acceptable)
return
}
// Decrby is the implementation of redis decrby command.
func (s *Redis) Decrby(key string, increment int64) (val int64, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
val, err = conn.DecrBy(key, increment).Result()
return err
}, acceptable)
return
}
// Del deletes keys.
func (s *Redis) Del(keys ...string) (val int, err error) {
err = s.brk.DoWithAcceptable(func() error {
@@ -765,6 +795,21 @@ func (s *Redis) Llen(key string) (val int, err error) {
return
}
// Lindex is the implementation of redis lindex command.
func (s *Redis) Lindex(key string, index int64) (val string, err error) {
err = s.brk.DoWithAcceptable(func() error {
conn, err := getRedis(s)
if err != nil {
return err
}
val, err = conn.LIndex(key, index).Result()
return err
}, acceptable)
return
}
// Lpop is the implementation of redis lpop command.
func (s *Redis) Lpop(key string) (val string, err error) {
err = s.brk.DoWithAcceptable(func() error {

View File

@@ -14,6 +14,32 @@ import (
"github.com/tal-tech/go-zero/core/stringx"
)
func TestRedis_Decr(t *testing.T) {
runOnRedis(t, func(client *Redis) {
_, err := New(client.Addr, badType()).Decr("a")
assert.NotNil(t, err)
val, err := client.Decr("a")
assert.Nil(t, err)
assert.Equal(t, int64(-1), val)
val, err = client.Decr("a")
assert.Nil(t, err)
assert.Equal(t, int64(-2), val)
})
}
func TestRedis_DecrBy(t *testing.T) {
runOnRedis(t, func(client *Redis) {
_, err := New(client.Addr, badType()).Decrby("a", 2)
assert.NotNil(t, err)
val, err := client.Decrby("a", 2)
assert.Nil(t, err)
assert.Equal(t, int64(-2), val)
val, err = client.Decrby("a", 3)
assert.Nil(t, err)
assert.Equal(t, int64(-5), val)
})
}
func TestRedis_Exists(t *testing.T) {
runOnRedis(t, func(client *Redis) {
_, err := New(client.Addr, badType()).Exists("a")
@@ -295,6 +321,11 @@ func TestRedis_List(t *testing.T) {
val, err = client.Llen("key")
assert.Nil(t, err)
assert.Equal(t, 4, val)
_, err = New(client.Addr, badType()).Lindex("key", 1)
assert.NotNil(t, err)
value, err := client.Lindex("key", 0)
assert.Nil(t, err)
assert.Equal(t, "value2", value)
vals, err := client.Lrange("key", 0, 10)
assert.Nil(t, err)
assert.EqualValues(t, []string{"value2", "value1", "value3", "value4"}, vals)

View File

@@ -2,7 +2,6 @@ package redis
import (
"math/rand"
"strconv"
"sync/atomic"
"time"
@@ -12,26 +11,19 @@ import (
)
const (
lockCommand = `if redis.call("GET", KEYS[1]) == ARGV[1] then
redis.call("SET", KEYS[1], ARGV[1], "PX", ARGV[2])
return "OK"
else
return redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2])
end`
delCommand = `if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end`
randomLen = 16
tolerance = 500 // milliseconds
millisPerSecond = 1000
randomLen = 16
)
// A RedisLock is a redis lock.
type RedisLock struct {
store *Redis
seconds uint32
count int32
key string
id string
}
@@ -51,30 +43,35 @@ func NewRedisLock(store *Redis, key string) *RedisLock {
// Acquire acquires the lock.
func (rl *RedisLock) Acquire() (bool, error) {
seconds := atomic.LoadUint32(&rl.seconds)
resp, err := rl.store.Eval(lockCommand, []string{rl.key}, []string{
rl.id, strconv.Itoa(int(seconds)*millisPerSecond + tolerance),
})
if err == red.Nil {
return false, nil
} else if err != nil {
logx.Errorf("Error on acquiring lock for %s, %s", rl.key, err.Error())
return false, err
} else if resp == nil {
return false, nil
}
reply, ok := resp.(string)
if ok && reply == "OK" {
newCount := atomic.AddInt32(&rl.count, 1)
if newCount > 1 {
return true, nil
}
logx.Errorf("Unknown reply when acquiring lock for %s: %v", rl.key, resp)
return false, nil
seconds := atomic.LoadUint32(&rl.seconds)
ok, err := rl.store.SetnxEx(rl.key, rl.id, int(seconds+1)) // +1s for tolerance
if err == red.Nil {
atomic.AddInt32(&rl.count, -1)
return false, nil
} else if err != nil {
atomic.AddInt32(&rl.count, -1)
logx.Errorf("Error on acquiring lock for %s, %s", rl.key, err.Error())
return false, err
} else if !ok {
atomic.AddInt32(&rl.count, -1)
return false, nil
}
return true, nil
}
// Release releases the lock.
func (rl *RedisLock) Release() (bool, error) {
newCount := atomic.AddInt32(&rl.count, -1)
if newCount > 0 {
return true, nil
}
resp, err := rl.store.Eval(delCommand, []string{rl.key}, []string{rl.id})
if err != nil {
return false, err
@@ -88,7 +85,7 @@ func (rl *RedisLock) Release() (bool, error) {
return reply == 1, nil
}
// SetExpire sets the expire.
// SetExpire sets the expiration.
func (rl *RedisLock) SetExpire(seconds int) {
atomic.StoreUint32(&rl.seconds, uint32(seconds))
}

View File

@@ -29,5 +29,25 @@ func TestRedisLock(t *testing.T) {
endAcquire, err := secondLock.Acquire()
assert.Nil(t, err)
assert.True(t, endAcquire)
endAcquire, err = secondLock.Acquire()
assert.Nil(t, err)
assert.True(t, endAcquire)
release, err = secondLock.Release()
assert.Nil(t, err)
assert.True(t, release)
againAcquire, err = firstLock.Acquire()
assert.Nil(t, err)
assert.False(t, againAcquire)
release, err = secondLock.Release()
assert.Nil(t, err)
assert.True(t, release)
firstAcquire, err = firstLock.Acquire()
assert.Nil(t, err)
assert.True(t, firstAcquire)
})
}

View File

@@ -39,20 +39,24 @@ type (
}
)
// NewNodeConn returns a CachedConn with a redis node cache.
func NewNodeConn(db sqlx.SqlConn, rds *redis.Redis, opts ...cache.Option) CachedConn {
// NewConn returns a CachedConn with a redis cluster cache.
func NewConn(db sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) CachedConn {
cc := cache.New(c, exclusiveCalls, stats, sql.ErrNoRows, opts...)
return NewConnWithCache(db, cc)
}
// NewConnWithCache returns a CachedConn with a custom cache.
func NewConnWithCache(db sqlx.SqlConn, c cache.Cache) CachedConn {
return CachedConn{
db: db,
cache: cache.NewNode(rds, exclusiveCalls, stats, sql.ErrNoRows, opts...),
cache: c,
}
}
// NewConn returns a CachedConn with a redis cluster cache.
func NewConn(db sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) CachedConn {
return CachedConn{
db: db,
cache: cache.New(c, exclusiveCalls, stats, sql.ErrNoRows, opts...),
}
// NewNodeConn returns a CachedConn with a redis node cache.
func NewNodeConn(db sqlx.SqlConn, rds *redis.Redis, opts ...cache.Option) CachedConn {
c := cache.NewNode(rds, exclusiveCalls, stats, sql.ErrNoRows, opts...)
return NewConnWithCache(db, c)
}
// DelCache deletes cache with keys.

View File

@@ -562,6 +562,18 @@ func TestQueryRowNoCache(t *testing.T) {
assert.True(t, ran)
}
func TestNewConnWithCache(t *testing.T) {
r, clean, err := redistest.CreateRedis()
assert.Nil(t, err)
defer clean()
var conn trackedConn
c := NewConnWithCache(&conn, cache.NewNode(r, exclusiveCalls, stats, sql.ErrNoRows))
_, err = c.ExecNoCache("delete from user_table where id='kevin'")
assert.Nil(t, err)
assert.True(t, conn.execValue)
}
func resetStats() {
atomic.StoreUint64(&stats.Total, 0)
atomic.StoreUint64(&stats.Hit, 0)

View File

@@ -25,6 +25,7 @@ type (
SqlConn interface {
Session
// RawDB is for other ORM to operate with, use it with caution.
// Notice: don't close it.
RawDB() (*sql.DB, error)
Transact(func(session Session) error) error
}

8
go.mod
View File

@@ -6,29 +6,21 @@ require (
github.com/ClickHouse/clickhouse-go v1.5.1
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/alicebob/miniredis/v2 v2.16.0
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/emicklei/proto v1.9.1
github.com/fatih/color v1.9.0 // indirect
github.com/fatih/structtag v1.2.0
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt v3.2.1+incompatible
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0
github.com/iancoleman/strcase v0.2.0
github.com/justinas/alice v1.2.0
github.com/lib/pq v1.10.3
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mattn/go-colorable v0.1.6 // indirect
github.com/olekukonko/tablewriter v0.0.5
github.com/openzipkin/zipkin-go v0.3.0 // indirect
github.com/prometheus/client_golang v1.11.0
github.com/spaolacci/murmur3 v1.1.0
github.com/stretchr/testify v1.7.0
github.com/urfave/cli v1.22.5
github.com/zeromicro/antlr v0.0.1
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348
go.etcd.io/etcd/api/v3 v3.5.1
go.etcd.io/etcd/client/v3 v3.5.1
go.opentelemetry.io/otel v1.1.0

20
go.sum
View File

@@ -54,8 +54,6 @@ github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGn
github.com/alicebob/miniredis/v2 v2.16.0 h1:ALkyFg7bSTEd1Mkrb4ppq4fnwjklA59dVtIehXCUZkU=
github.com/alicebob/miniredis/v2 v2.16.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODVXVpYDRaGhWaL6I=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -86,8 +84,6 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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=
@@ -102,8 +98,6 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/proto v1.9.1 h1:MUgjFo5xlMwYv72TnF5xmmdKZ04u+dVbv6wdARv16D8=
github.com/emicklei/proto v1.9.1/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -115,8 +109,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
@@ -235,8 +227,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
@@ -275,8 +265,6 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -364,8 +352,6 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -390,8 +376,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
@@ -401,10 +385,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg=
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da/go.mod h1:E1AXubJBdNmFERAOucpDIxNzeGfLzg0mYh+UfMWdChA=
github.com/zeromicro/antlr v0.0.1 h1:CQpIn/dc0pUjgGQ81y98s/NGOm2Hfru2NNio2I9mQgk=
github.com/zeromicro/antlr v0.0.1/go.mod h1:nfpjEwFR6Q4xGDJMcZnCL9tEfQRgszMwu3rDz2Z+p5M=
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348 h1:OhxL9tn28gDeJVzreIUiE5oVxZCjL3tBJ0XBNw8p5R8=
github.com/zeromicro/ddl-parser v0.0.0-20210712021150-63520aca7348/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8=
go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM=
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.1 h1:XIQcHCFSG53bJETYeRJtIxdLv2EWRGxcfzR8lSnTH4E=

View File

@@ -104,10 +104,10 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
```shell
# Go 1.15 及之前版本
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero/tools/goctl
GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/go-zero/tools/goctl@latest
# Go 1.16 及以后版本
go install github.com/tal-tech/go-zero/tools/goctl@latest
GOPROXY=https://goproxy.cn/,direct go install github.com/tal-tech/go-zero/tools/goctl@latest
```
确保 goctl 可执行
@@ -141,7 +141,7 @@ GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go get -u github.com/tal-tech/
编写业务代码:
* api 文件定义了服务对外 HTTP 接口,可参考 [api 规范](https://github.com/zeromicro/zero-doc/blob/main/doc/goctl.md)
* api 文件定义了服务对外 HTTP 接口,可参考 [api 规范](https://github.com/zeromicro/zero-doc/blob/main/docs/zero/goctl-api.md)
* 可以在 `servicecontext.go` 里面传递依赖给 logic比如 mysql, redis 等
* 在 api 定义的 `get/post/put/delete` 等请求对应的 logic 里增加业务处理逻辑
@@ -232,6 +232,9 @@ go-zero 已被许多公司用于生产部署,接入场景如在线教育、电
>46. 上海游族网络
>47. 深信服
>48. 中免日上科技互联有限公司
>48. ECLOUDVALLEY TECHNOLOGY (HK) LIMITED
>48. 馨科智(深圳)科技有限公司
>48. 成都松珀科技有限公司
如果贵公司也已使用 go-zero欢迎在 [登记地址](https://github.com/zeromicro/go-zero/issues/602) 登记,仅仅为了推广,不做其它用途。

View File

@@ -107,7 +107,7 @@ go get -u github.com/tal-tech/go-zero
```shell
# for Go 1.15 and earlier
GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl
GO111MODULE=on go get -u github.com/tal-tech/go-zero/tools/goctl@latest
# for Go 1.16 and later
go install github.com/tal-tech/go-zero/tools/goctl@latest
@@ -221,7 +221,7 @@ go get -u github.com/tal-tech/go-zero
## 9. Chat group
Join the chat via https://join.slack.com/t/go-zero/shared_invite/zt-ulzixfgi-NAkZjq856TewLY2KQSxHCw
Join the chat via https://join.slack.com/t/go-zero/shared_invite/zt-10ruju779-BE4y6lQNB_R21samtyKTgA
## 10. Cloud Native Landscape

View File

@@ -196,12 +196,13 @@ func logDetails(r *http.Request, response *detailLoggedResponseWriter, timer *ut
logs *internal.LogCollector) {
var buf bytes.Buffer
duration := timer.Duration()
code := response.writer.code
logger := logx.WithContext(r.Context())
buf.WriteString(fmt.Sprintf("[HTTP] %s - %d - %s - %s\n=> %s\n",
r.Method, response.writer.code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r)))
r.Method, code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r)))
if duration > defaultSlowThreshold {
logger.Slowf("[HTTP] %s - %d - %s - slowcall(%s)\n=> %s\n",
r.Method, response.writer.code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r))
r.Method, code, r.RemoteAddr, timex.ReprOfDuration(duration), dumpRequest(r))
}
body := logs.Flush()
@@ -214,7 +215,11 @@ func logDetails(r *http.Request, response *detailLoggedResponseWriter, timer *ut
buf.WriteString(fmt.Sprintf("<= %s", respBuf))
}
logger.Info(buf.String())
if isOkResponse(code) {
logger.Info(buf.String())
} else {
logger.Error(buf.String())
}
}
func isOkResponse(code int) bool {

View File

@@ -1,19 +1,192 @@
package handler
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"path"
"runtime"
"strings"
"sync"
"time"
"github.com/tal-tech/go-zero/rest/httpx"
"github.com/tal-tech/go-zero/rest/internal"
)
const reason = "Request Timeout"
const (
statusClientClosedRequest = 499
reason = "Request Timeout"
)
// TimeoutHandler returns the handler with given timeout.
// If client closed request, code 499 will be logged.
// Notice: even if canceled in server side, 499 will be logged as well.
func TimeoutHandler(duration time.Duration) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
if duration > 0 {
return http.TimeoutHandler(next, duration, reason)
return &timeoutHandler{
handler: next,
dt: duration,
}
}
return next
}
}
// timeoutHandler is the handler that controls the request timeout.
// Why we implement it on our own, because the stdlib implementation
// treats the ClientClosedRequest as http.StatusServiceUnavailable.
// And we write the codes in logs as code 499, which is defined by nginx.
type timeoutHandler struct {
handler http.Handler
dt time.Duration
}
func (h *timeoutHandler) errorBody() string {
return reason
}
func (h *timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, cancelCtx := context.WithTimeout(r.Context(), h.dt)
defer cancelCtx()
r = r.WithContext(ctx)
done := make(chan struct{})
tw := &timeoutWriter{
w: w,
h: make(http.Header),
req: r,
}
panicChan := make(chan interface{}, 1)
go func() {
defer func() {
if p := recover(); p != nil {
panicChan <- p
}
}()
h.handler.ServeHTTP(tw, r)
close(done)
}()
select {
case p := <-panicChan:
panic(p)
case <-done:
tw.mu.Lock()
defer tw.mu.Unlock()
dst := w.Header()
for k, vv := range tw.h {
dst[k] = vv
}
if !tw.wroteHeader {
tw.code = http.StatusOK
}
w.WriteHeader(tw.code)
w.Write(tw.wbuf.Bytes())
case <-ctx.Done():
tw.mu.Lock()
defer tw.mu.Unlock()
// there isn't any user-defined middleware before TimoutHandler,
// so we can guarantee that cancelation in biz related code won't come here.
httpx.Error(w, ctx.Err(), func(w http.ResponseWriter, err error) {
if errors.Is(err, context.Canceled) {
w.WriteHeader(statusClientClosedRequest)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
io.WriteString(w, h.errorBody())
})
tw.timedOut = true
}
}
type timeoutWriter struct {
w http.ResponseWriter
h http.Header
wbuf bytes.Buffer
req *http.Request
mu sync.Mutex
timedOut bool
wroteHeader bool
code int
}
var _ http.Pusher = (*timeoutWriter)(nil)
// Push implements the Pusher interface.
func (tw *timeoutWriter) Push(target string, opts *http.PushOptions) error {
if pusher, ok := tw.w.(http.Pusher); ok {
return pusher.Push(target, opts)
}
return http.ErrNotSupported
}
func (tw *timeoutWriter) Header() http.Header { return tw.h }
func (tw *timeoutWriter) Write(p []byte) (int, error) {
tw.mu.Lock()
defer tw.mu.Unlock()
if tw.timedOut {
return 0, http.ErrHandlerTimeout
}
if !tw.wroteHeader {
tw.writeHeaderLocked(http.StatusOK)
}
return tw.wbuf.Write(p)
}
func (tw *timeoutWriter) writeHeaderLocked(code int) {
checkWriteHeaderCode(code)
switch {
case tw.timedOut:
return
case tw.wroteHeader:
if tw.req != nil {
caller := relevantCaller()
internal.Errorf(tw.req, "http: superfluous response.WriteHeader call from %s (%s:%d)",
caller.Function, path.Base(caller.File), caller.Line)
}
default:
tw.wroteHeader = true
tw.code = code
}
}
func (tw *timeoutWriter) WriteHeader(code int) {
tw.mu.Lock()
defer tw.mu.Unlock()
tw.writeHeaderLocked(code)
}
func checkWriteHeaderCode(code int) {
if code < 100 || code > 599 {
panic(fmt.Sprintf("invalid WriteHeader code %v", code))
}
}
// relevantCaller searches the call stack for the first function outside of net/http.
// The purpose of this function is to provide more helpful error messages.
func relevantCaller() runtime.Frame {
pc := make([]uintptr, 16)
n := runtime.Callers(1, pc)
frames := runtime.CallersFrames(pc[:n])
var frame runtime.Frame
for {
frame, more := frames.Next()
if !strings.HasPrefix(frame.Function, "net/http.") {
return frame
}
if !more {
break
}
}
return frame
}

View File

@@ -1,6 +1,7 @@
package handler
import (
"context"
"io/ioutil"
"log"
"net/http"
@@ -39,6 +40,20 @@ func TestWithinTimeout(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.Code)
}
func TestWithTimeoutTimedout(t *testing.T) {
timeoutHandler := TimeoutHandler(time.Millisecond)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Millisecond * 10)
w.Write([]byte(`foo`))
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusServiceUnavailable, resp.Code)
}
func TestWithoutTimeout(t *testing.T) {
timeoutHandler := TimeoutHandler(0)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -50,3 +65,91 @@ func TestWithoutTimeout(t *testing.T) {
handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusOK, resp.Code)
}
func TestTimeoutPanic(t *testing.T) {
timeoutHandler := TimeoutHandler(time.Minute)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
panic("foo")
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
resp := httptest.NewRecorder()
assert.Panics(t, func() {
handler.ServeHTTP(resp, req)
})
}
func TestTimeoutWroteHeaderTwice(t *testing.T) {
timeoutHandler := TimeoutHandler(time.Minute)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`hello`))
w.Header().Set("foo", "bar")
w.WriteHeader(http.StatusOK)
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusOK, resp.Code)
}
func TestTimeoutWriteBadCode(t *testing.T) {
timeoutHandler := TimeoutHandler(time.Minute)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(1000)
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
resp := httptest.NewRecorder()
assert.Panics(t, func() {
handler.ServeHTTP(resp, req)
})
}
func TestTimeoutClientClosed(t *testing.T) {
timeoutHandler := TimeoutHandler(time.Minute)
handler := timeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(1000)
}))
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
ctx, cancel := context.WithCancel(context.Background())
req = req.WithContext(ctx)
cancel()
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, statusClientClosedRequest, resp.Code)
}
func TestTimeoutPusher(t *testing.T) {
handler := &timeoutWriter{
w: mockedPusher{},
}
assert.Panics(t, func() {
handler.Push("any", nil)
})
handler = &timeoutWriter{
w: httptest.NewRecorder(),
}
assert.Equal(t, http.ErrNotSupported, handler.Push("any", nil))
}
type mockedPusher struct{}
func (m mockedPusher) Header() http.Header {
panic("implement me")
}
func (m mockedPusher) Write(bytes []byte) (int, error) {
panic("implement me")
}
func (m mockedPusher) WriteHeader(statusCode int) {
panic("implement me")
}
func (m mockedPusher) Push(target string, opts *http.PushOptions) error {
panic("implement me")
}

View File

@@ -14,7 +14,6 @@ const (
formKey = "form"
pathKey = "path"
headerKey = "header"
emptyJson = "{}"
maxMemory = 32 << 20 // 32MB
maxBodyLen = 8 << 20 // 8MB
separator = ";"
@@ -106,14 +105,12 @@ func ParseHeader(headerValue string) map[string]string {
// ParseJsonBody parses the post request which contains json in body.
func ParseJsonBody(r *http.Request, v interface{}) error {
var reader io.Reader
if withJsonBody(r) {
reader = io.LimitReader(r.Body, maxBodyLen)
} else {
reader = strings.NewReader(emptyJson)
reader := io.LimitReader(r.Body, maxBodyLen)
return mapping.UnmarshalJsonReader(reader, v)
}
return mapping.UnmarshalJsonReader(reader, v)
return mapping.UnmarshalJsonMap(nil, v)
}
// ParsePath parses the symbols reside in url path.

View File

@@ -196,18 +196,32 @@ Content-Disposition: form-data; name="age"
}
func TestParseJsonBody(t *testing.T) {
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
t.Run("has body", func(t *testing.T) {
var v struct {
Name string `json:"name"`
Age int `json:"age"`
}
body := `{"name":"kevin", "age": 18}`
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
r.Header.Set(ContentType, ApplicationJson)
body := `{"name":"kevin", "age": 18}`
r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
r.Header.Set(ContentType, ApplicationJson)
assert.Nil(t, Parse(r, &v))
assert.Equal(t, "kevin", v.Name)
assert.Equal(t, 18, v.Age)
assert.Nil(t, Parse(r, &v))
assert.Equal(t, "kevin", v.Name)
assert.Equal(t, 18, v.Age)
})
t.Run("hasn't body", func(t *testing.T) {
var v struct {
Name string `json:"name,optional"`
Age int `json:"age,optional"`
}
r := httptest.NewRequest(http.MethodGet, "/", nil)
assert.Nil(t, Parse(r, &v))
assert.Equal(t, "", v.Name)
assert.Equal(t, 0, v.Age)
})
}
func TestParseRequired(t *testing.T) {

View File

@@ -14,13 +14,17 @@ var (
)
// Error writes err into w.
func Error(w http.ResponseWriter, err error) {
func Error(w http.ResponseWriter, err error, fns ...func(w http.ResponseWriter, err error)) {
lock.RLock()
handler := errorHandler
lock.RUnlock()
if handler == nil {
http.Error(w, err.Error(), http.StatusBadRequest)
if len(fns) > 0 {
fns[0](w, err)
} else {
http.Error(w, err.Error(), http.StatusBadRequest)
}
return
}

View File

@@ -95,6 +95,18 @@ func TestError(t *testing.T) {
}
}
func TestErrorWithHandler(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
Error(&w, errors.New("foo"), func(w http.ResponseWriter, err error) {
http.Error(w, err.Error(), 499)
})
assert.Equal(t, 499, w.code)
assert.True(t, w.hasBody)
assert.Equal(t, "foo", strings.TrimSpace(w.builder.String()))
}
func TestOk(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),

View File

@@ -1,6 +1,11 @@
package cors
import "net/http"
import (
"bufio"
"errors"
"net"
"net/http"
)
const (
allowOrigin = "Access-Control-Allow-Origin"
@@ -23,23 +28,30 @@ const (
// NotAllowedHandler handles cross domain not allowed requests.
// At most one origin can be specified, other origins are ignored if given, default to be *.
func NotAllowedHandler(origins ...string) http.Handler {
func NotAllowedHandler(fn func(w http.ResponseWriter), origins ...string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
checkAndSetHeaders(w, r, origins)
gw := &guardedResponseWriter{w: w}
checkAndSetHeaders(gw, r, origins)
if fn != nil {
fn(gw)
}
if r.Method != http.MethodOptions {
w.WriteHeader(http.StatusNotFound)
if r.Method == http.MethodOptions {
gw.WriteHeader(http.StatusNoContent)
} else {
w.WriteHeader(http.StatusNoContent)
gw.WriteHeader(http.StatusNotFound)
}
})
}
// Middleware returns a middleware that adds CORS headers to the response.
func Middleware(origins ...string) func(http.HandlerFunc) http.HandlerFunc {
func Middleware(fn func(w http.Header), origins ...string) func(http.HandlerFunc) http.HandlerFunc {
return func(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
checkAndSetHeaders(w, r, origins)
if fn != nil {
fn(w.Header())
}
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
@@ -50,6 +62,44 @@ func Middleware(origins ...string) func(http.HandlerFunc) http.HandlerFunc {
}
}
type guardedResponseWriter struct {
w http.ResponseWriter
wroteHeader bool
}
func (w *guardedResponseWriter) Flush() {
if flusher, ok := w.w.(http.Flusher); ok {
flusher.Flush()
}
}
func (w *guardedResponseWriter) Header() http.Header {
return w.w.Header()
}
// Hijack implements the http.Hijacker interface.
// This expands the Response to fulfill http.Hijacker if the underlying http.ResponseWriter supports it.
func (w *guardedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if hijacked, ok := w.w.(http.Hijacker); ok {
return hijacked.Hijack()
}
return nil, nil, errors.New("server doesn't support hijacking")
}
func (w *guardedResponseWriter) Write(bytes []byte) (int, error) {
return w.w.Write(bytes)
}
func (w *guardedResponseWriter) WriteHeader(code int) {
if w.wroteHeader {
return
}
w.w.WriteHeader(code)
w.wroteHeader = true
}
func checkAndSetHeaders(w http.ResponseWriter, r *http.Request, origins []string) {
setVaryHeaders(w, r)

View File

@@ -1,6 +1,8 @@
package cors
import (
"bufio"
"net"
"net/http"
"net/http/httptest"
"testing"
@@ -62,7 +64,7 @@ func TestCorsHandlerWithOrigins(t *testing.T) {
r := httptest.NewRequest(method, "http://localhost", nil)
r.Header.Set(originHeader, test.reqOrigin)
w := httptest.NewRecorder()
handler := NotAllowedHandler(test.origins...)
handler := NotAllowedHandler(nil, test.origins...)
handler.ServeHTTP(w, r)
if method == http.MethodOptions {
assert.Equal(t, http.StatusNoContent, w.Result().StatusCode)
@@ -71,6 +73,22 @@ func TestCorsHandlerWithOrigins(t *testing.T) {
}
assert.Equal(t, test.expect, w.Header().Get(allowOrigin))
})
t.Run(test.name+"-handler-custom", func(t *testing.T) {
r := httptest.NewRequest(method, "http://localhost", nil)
r.Header.Set(originHeader, test.reqOrigin)
w := httptest.NewRecorder()
handler := NotAllowedHandler(func(w http.ResponseWriter) {
w.Header().Set("foo", "bar")
}, test.origins...)
handler.ServeHTTP(w, r)
if method == http.MethodOptions {
assert.Equal(t, http.StatusNoContent, w.Result().StatusCode)
} else {
assert.Equal(t, http.StatusNotFound, w.Result().StatusCode)
}
assert.Equal(t, test.expect, w.Header().Get(allowOrigin))
assert.Equal(t, "bar", w.Header().Get("foo"))
})
}
}
@@ -81,7 +99,7 @@ func TestCorsHandlerWithOrigins(t *testing.T) {
r := httptest.NewRequest(method, "http://localhost", nil)
r.Header.Set(originHeader, test.reqOrigin)
w := httptest.NewRecorder()
handler := Middleware(test.origins...)(func(w http.ResponseWriter, r *http.Request) {
handler := Middleware(nil, test.origins...)(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
handler.ServeHTTP(w, r)
@@ -92,6 +110,69 @@ func TestCorsHandlerWithOrigins(t *testing.T) {
}
assert.Equal(t, test.expect, w.Header().Get(allowOrigin))
})
t.Run(test.name+"-middleware-custom", func(t *testing.T) {
r := httptest.NewRequest(method, "http://localhost", nil)
r.Header.Set(originHeader, test.reqOrigin)
w := httptest.NewRecorder()
handler := Middleware(func(header http.Header) {
header.Set("foo", "bar")
}, test.origins...)(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
handler.ServeHTTP(w, r)
if method == http.MethodOptions {
assert.Equal(t, http.StatusNoContent, w.Result().StatusCode)
} else {
assert.Equal(t, http.StatusOK, w.Result().StatusCode)
}
assert.Equal(t, test.expect, w.Header().Get(allowOrigin))
assert.Equal(t, "bar", w.Header().Get("foo"))
})
}
}
}
func TestGuardedResponseWriter_Flush(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
handler := NotAllowedHandler(func(w http.ResponseWriter) {
w.Header().Set("X-Test", "test")
w.WriteHeader(http.StatusServiceUnavailable)
_, err := w.Write([]byte("content"))
assert.Nil(t, err)
flusher, ok := w.(http.Flusher)
assert.True(t, ok)
flusher.Flush()
}, "foo.com")
resp := httptest.NewRecorder()
handler.ServeHTTP(resp, req)
assert.Equal(t, http.StatusServiceUnavailable, resp.Code)
assert.Equal(t, "test", resp.Header().Get("X-Test"))
assert.Equal(t, "content", resp.Body.String())
}
func TestGuardedResponseWriter_Hijack(t *testing.T) {
resp := httptest.NewRecorder()
writer := &guardedResponseWriter{
w: resp,
}
assert.NotPanics(t, func() {
writer.Hijack()
})
writer = &guardedResponseWriter{
w: mockedHijackable{resp},
}
assert.NotPanics(t, func() {
writer.Hijack()
})
}
type mockedHijackable struct {
*httptest.ResponseRecorder
}
func (m mockedHijackable) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return nil, nil, nil
}

View File

@@ -119,16 +119,13 @@ func VerifySignature(r *http.Request, securityHeader *ContentSecurityHeader, tol
}, "\n")
actualSignature := codec.HmacBase64(securityHeader.Key, signContent)
passed := securityHeader.Signature == actualSignature
if !passed {
logx.Infof("signature different, expect: %s, actual: %s",
securityHeader.Signature, actualSignature)
}
if passed {
if securityHeader.Signature == actualSignature {
return httpx.CodeSignaturePass
}
logx.Infof("signature different, expect: %s, actual: %s",
securityHeader.Signature, actualSignature)
return httpx.CodeSignatureInvalidToken
}

View File

@@ -1,7 +1,6 @@
package pathvar
import (
"context"
"net/http"
"strings"
"testing"
@@ -16,7 +15,7 @@ func TestVars(t *testing.T) {
}
r, err := http.NewRequest(http.MethodGet, "/", nil)
assert.Nil(t, err)
r = r.WithContext(context.WithValue(context.Background(), pathVars, expect))
r = WithVars(r, expect)
assert.EqualValues(t, expect, Vars(r))
}

View File

@@ -99,8 +99,18 @@ func ToMiddleware(handler func(next http.Handler) http.Handler) Middleware {
// WithCors returns a func to enable CORS for given origin, or default to all origins (*).
func WithCors(origin ...string) RunOption {
return func(server *Server) {
server.router.SetNotAllowedHandler(cors.NotAllowedHandler(origin...))
server.Use(cors.Middleware(origin...))
server.router.SetNotAllowedHandler(cors.NotAllowedHandler(nil, origin...))
server.Use(cors.Middleware(nil, origin...))
}
}
// WithCustomCors returns a func to enable CORS for given origin, or default to all origins (*),
// fn lets caller customizing the response.
func WithCustomCors(middlewareFn func(header http.Header), notAllowedFn func(http.ResponseWriter),
origin ...string) RunOption {
return func(server *Server) {
server.router.SetNotAllowedHandler(cors.NotAllowedHandler(notAllowedFn, origin...))
server.Use(cors.Middleware(middlewareFn, origin...))
}
}

View File

@@ -310,3 +310,22 @@ Port: 54321
opt := WithCors("local")
opt(srv)
}
func TestWithCustomCors(t *testing.T) {
const configYaml = `
Name: foo
Port: 54321
`
var cnf RestConf
assert.Nil(t, conf.LoadConfigFromYamlBytes([]byte(configYaml), &cnf))
rt := router.NewRouter()
srv, err := NewServer(cnf, WithRouter(rt))
assert.Nil(t, err)
opt := WithCustomCors(func(header http.Header) {
header.Set("foo", "bar")
}, func(w http.ResponseWriter) {
w.WriteHeader(http.StatusOK)
}, "local")
opt(srv)
}

View File

@@ -9,6 +9,7 @@ import (
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -46,23 +47,31 @@ func ApiCommand(c *cli.Context) error {
return errors.New("missing -o")
}
fp, err := util.CreateIfNotExist(apiFile)
fp, err := pathx.CreateIfNotExist(apiFile)
if err != nil {
return err
}
defer fp.Close()
home := c.String("home")
if len(home) > 0 {
util.RegisterGoctlHome(home)
remote := c.String("remote")
if len(remote) > 0 {
repo, _ := util.CloneIntoGitHome(remote)
if len(repo) > 0 {
home = repo
}
}
text, err := util.LoadTemplate(category, apiTemplateFile, apiTemplate)
if len(home) > 0 {
pathx.RegisterGoctlHome(home)
}
text, err := pathx.LoadTemplate(category, apiTemplateFile, apiTemplate)
if err != nil {
return err
}
baseName := util.FileNameWithoutExt(filepath.Base(apiFile))
baseName := pathx.FileNameWithoutExt(filepath.Base(apiFile))
if strings.HasSuffix(strings.ToLower(baseName), "-api") {
baseName = baseName[:len(baseName)-4]
} else if strings.HasSuffix(strings.ToLower(baseName), "api") {

View File

@@ -3,7 +3,7 @@ package apigen
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -23,12 +23,12 @@ func Category() string {
// Clean cleans the generated deployment files.
func Clean() error {
return util.Clean(category)
return pathx.Clean(category)
}
// GenTemplates generates api template files.
func GenTemplates(_ *cli.Context) error {
return util.InitTemplates(category, templates)
return pathx.InitTemplates(category, templates)
}
// RevertTemplate reverts the given template file to the default value.
@@ -37,7 +37,7 @@ func RevertTemplate(name string) error {
if !ok {
return fmt.Errorf("%s: no such file name", name)
}
return util.CreateTemplate(category, name, content)
return pathx.CreateTemplate(category, name, content)
}
// Update updates the template files to the templates built in current goctl.
@@ -47,5 +47,5 @@ func Update() error {
return err
}
return util.InitTemplates(category, templates)
return pathx.InitTemplates(category, templates)
}

View File

@@ -8,7 +8,7 @@ import (
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -28,7 +28,7 @@ func DocCommand(c *cli.Context) error {
}
}
if !util.FileExists(dir) {
if !pathx.FileExists(dir) {
return fmt.Errorf("dir %s not exsit", dir)
}

View File

@@ -14,7 +14,7 @@ import (
"github.com/tal-tech/go-zero/core/errorx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -124,7 +124,7 @@ func apiFormat(data string, filename ...string) (string, error) {
newLineCount++
} else {
if preLine == rightBrace {
builder.WriteString(ctlutil.NL)
builder.WriteString(pathx.NL)
}
newLineCount = 0
}
@@ -152,7 +152,7 @@ func apiFormat(data string, filename ...string) (string, error) {
}
}
util.WriteIndent(&builder, tapCount)
builder.WriteString(line + ctlutil.NL)
builder.WriteString(line + pathx.NL)
if strings.HasSuffix(noCommentLine, leftParenthesis) || strings.HasSuffix(noCommentLine, leftBrace) {
tapCount++
}
@@ -168,10 +168,10 @@ func formatGoTypeDef(line string, scanner *bufio.Scanner, builder *strings.Build
if strings.HasPrefix(noCommentLine, "type") && (strings.HasSuffix(noCommentLine, leftParenthesis) ||
strings.HasSuffix(noCommentLine, leftBrace)) {
var typeBuilder strings.Builder
typeBuilder.WriteString(mayInsertStructKeyword(line, &tokenCount) + ctlutil.NL)
typeBuilder.WriteString(mayInsertStructKeyword(line, &tokenCount) + pathx.NL)
for scanner.Scan() {
noCommentLine := util.RemoveComment(scanner.Text())
typeBuilder.WriteString(mayInsertStructKeyword(scanner.Text(), &tokenCount) + ctlutil.NL)
typeBuilder.WriteString(mayInsertStructKeyword(scanner.Text(), &tokenCount) + pathx.NL)
if noCommentLine == rightBrace || noCommentLine == rightParenthesis {
tokenCount--
}

View File

@@ -18,6 +18,7 @@ import (
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -31,9 +32,16 @@ func GoCommand(c *cli.Context) error {
dir := c.String("dir")
namingStyle := c.String("style")
home := c.String("home")
remote := c.String("remote")
if len(remote) > 0 {
repo, _ := util.CloneIntoGitHome(remote)
if len(repo) > 0 {
home = repo
}
}
if len(home) > 0 {
util.RegisterGoctlHome(home)
pathx.RegisterGoctlHome(home)
}
if len(apiFile) == 0 {
return errors.New("missing -api")
@@ -57,7 +65,7 @@ func DoGenProject(apiFile, dir, style string) error {
return err
}
logx.Must(util.MkdirIfNotExist(dir))
logx.Must(pathx.MkdirIfNotExist(dir))
rootPkg, err := getParentPackage(dir)
if err != nil {
return err

View File

@@ -78,7 +78,7 @@ service A-api {
@server(
handler: NoResponseHandler
)
get /greet/get(Request) returns
get /greet/get(Request)
}
`

View File

@@ -10,6 +10,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/internal/version"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
)
@@ -24,7 +25,7 @@ import (
{{.ImportPackages}}
)
func {{.HandlerName}}(ctx *svc.ServiceContext) http.HandlerFunc {
func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
{{if .HasRequest}}var req types.{{.RequestType}}
if err := httpx.Parse(r, &req); err != nil {
@@ -32,7 +33,7 @@ func {{.HandlerName}}(ctx *svc.ServiceContext) http.HandlerFunc {
return
}
{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), ctx)
{{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
{{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}req{{end}})
if err != nil {
httpx.Error(w, err)
@@ -122,10 +123,10 @@ func genHandlers(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) err
func genHandlerImports(group spec.Group, route spec.Route, parentPkg string) string {
var imports []string
imports = append(imports, fmt.Sprintf("\"%s\"",
util.JoinPackages(parentPkg, getLogicFolderPath(group, route))))
imports = append(imports, fmt.Sprintf("\"%s\"", util.JoinPackages(parentPkg, contextDir)))
pathx.JoinPackages(parentPkg, getLogicFolderPath(group, route))))
imports = append(imports, fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, contextDir)))
if len(route.RequestTypeName()) > 0 {
imports = append(imports, fmt.Sprintf("\"%s\"\n", util.JoinPackages(parentPkg, typesDir)))
imports = append(imports, fmt.Sprintf("\"%s\"\n", pathx.JoinPackages(parentPkg, typesDir)))
}
currentVersion := version.GetGoctlVersion()

View File

@@ -3,12 +3,14 @@ package gogen
import (
"fmt"
"path"
"strconv"
"strings"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
)
@@ -64,12 +66,8 @@ func genLogicByRoute(dir, rootPkg string, cfg *config.Config, group spec.Group,
var requestString string
if len(route.ResponseTypeName()) > 0 {
resp := responseGoTypeName(route, typesPacket)
responseString = "(" + resp + ", error)"
if strings.HasPrefix(resp, "*") {
returnString = fmt.Sprintf("return &%s{}, nil", strings.TrimPrefix(resp, "*"))
} else {
returnString = fmt.Sprintf("return %s{}, nil", resp)
}
responseString = "(resp " + resp + ", err error)"
returnString = "return"
} else {
responseString = "error"
returnString = "return nil"
@@ -115,10 +113,48 @@ func getLogicFolderPath(group spec.Group, route spec.Route) string {
func genLogicImports(route spec.Route, parentPkg string) string {
var imports []string
imports = append(imports, `"context"`+"\n")
imports = append(imports, fmt.Sprintf("\"%s\"", ctlutil.JoinPackages(parentPkg, contextDir)))
if len(route.ResponseTypeName()) > 0 || len(route.RequestTypeName()) > 0 {
imports = append(imports, fmt.Sprintf("\"%s\"\n", ctlutil.JoinPackages(parentPkg, typesDir)))
imports = append(imports, fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, contextDir)))
if shallImportTypesPackage(route) {
imports = append(imports, fmt.Sprintf("\"%s\"\n", pathx.JoinPackages(parentPkg, typesDir)))
}
imports = append(imports, fmt.Sprintf("\"%s/core/logx\"", vars.ProjectOpenSourceURL))
return strings.Join(imports, "\n\t")
}
func onlyPrimitiveTypes(val string) bool {
fields := strings.FieldsFunc(val, func(r rune) bool {
return r == '[' || r == ']' || r == ' '
})
for _, field := range fields {
if field == "map" {
continue
}
// ignore array dimension number, like [5]int
if _, err := strconv.Atoi(field); err == nil {
continue
}
if !api.IsBasicType(field) {
return false
}
}
return true
}
func shallImportTypesPackage(route spec.Route) bool {
if len(route.RequestTypeName()) > 0 {
return true
}
respTypeName := route.ResponseTypeName()
if len(respTypeName) == 0 {
return false
}
if onlyPrimitiveTypes(respTypeName) {
return false
}
return true
}

View File

@@ -6,8 +6,8 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
)
@@ -68,9 +68,9 @@ func genMain(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpec) error {
func genMainImports(parentPkg string) string {
var imports []string
imports = append(imports, fmt.Sprintf("\"%s\"", ctlutil.JoinPackages(parentPkg, configDir)))
imports = append(imports, fmt.Sprintf("\"%s\"", ctlutil.JoinPackages(parentPkg, handlerDir)))
imports = append(imports, fmt.Sprintf("\"%s\"\n", ctlutil.JoinPackages(parentPkg, contextDir)))
imports = append(imports, fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, configDir)))
imports = append(imports, fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, handlerDir)))
imports = append(imports, fmt.Sprintf("\"%s\"\n", pathx.JoinPackages(parentPkg, contextDir)))
imports = append(imports, fmt.Sprintf("\"%s/core/conf\"", vars.ProjectOpenSourceURL))
imports = append(imports, fmt.Sprintf("\"%s/rest\"", vars.ProjectOpenSourceURL))
return strings.Join(imports, "\n\t")

View File

@@ -11,8 +11,8 @@ import (
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
)
@@ -39,12 +39,15 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
)
var mapping = map[string]string{
"delete": "http.MethodDelete",
"get": "http.MethodGet",
"head": "http.MethodHead",
"post": "http.MethodPost",
"put": "http.MethodPut",
"patch": "http.MethodPatch",
"delete": "http.MethodDelete",
"get": "http.MethodGet",
"head": "http.MethodHead",
"post": "http.MethodPost",
"put": "http.MethodPut",
"patch": "http.MethodPatch",
"connect": "http.MethodConnect",
"options": "http.MethodOptions",
"trace": "http.MethodTrace",
}
type (
@@ -148,7 +151,7 @@ rest.WithPrefix("%s"),`, g.prefix)
func genRouteImports(parentPkg string, api *spec.ApiSpec) string {
importSet := collection.NewSet()
importSet.AddStr(fmt.Sprintf("\"%s\"", util.JoinPackages(parentPkg, contextDir)))
importSet.AddStr(fmt.Sprintf("\"%s\"", pathx.JoinPackages(parentPkg, contextDir)))
for _, group := range api.Service.Groups {
for _, route := range group.Routes {
folder := route.GetAnnotation(groupProperty)
@@ -158,7 +161,7 @@ func genRouteImports(parentPkg string, api *spec.ApiSpec) string {
continue
}
}
importSet.AddStr(fmt.Sprintf("%s \"%s\"", toPrefix(folder), util.JoinPackages(parentPkg, handlerDir, folder)))
importSet.AddStr(fmt.Sprintf("%s \"%s\"", toPrefix(folder), pathx.JoinPackages(parentPkg, handlerDir, folder)))
}
}
imports := importSet.KeysStr()

View File

@@ -6,8 +6,8 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/config"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/format"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/tal-tech/go-zero/tools/goctl/vars"
)
@@ -50,9 +50,9 @@ func genServiceContext(dir, rootPkg string, cfg *config.Config, api *spec.ApiSpe
fmt.Sprintf("middleware.New%s().%s", strings.Title(name), "Handle"))
}
configImport := "\"" + ctlutil.JoinPackages(rootPkg, configDir) + "\""
configImport := "\"" + pathx.JoinPackages(rootPkg, configDir) + "\""
if len(middlewareStr) > 0 {
configImport += "\n\t\"" + ctlutil.JoinPackages(rootPkg, middlewareDir) + "\""
configImport += "\n\t\"" + pathx.JoinPackages(rootPkg, middlewareDir) + "\""
configImport += fmt.Sprintf("\n\t\"%s/rest\"", vars.ProjectOpenSourceURL)
}

View File

@@ -3,7 +3,7 @@ package gogen
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -33,12 +33,12 @@ func Category() string {
// Clean cleans the generated deployment files.
func Clean() error {
return util.Clean(category)
return pathx.Clean(category)
}
// GenTemplates generates api template files.
func GenTemplates(_ *cli.Context) error {
return util.InitTemplates(category, templates)
return pathx.InitTemplates(category, templates)
}
// RevertTemplate reverts the given template file to the default value.
@@ -47,7 +47,7 @@ func RevertTemplate(name string) error {
if !ok {
return fmt.Errorf("%s: no such file name", name)
}
return util.CreateTemplate(category, name, content)
return pathx.CreateTemplate(category, name, content)
}
// Update updates the template files to the templates built in current goctl.
@@ -57,5 +57,5 @@ func Update() error {
return err
}
return util.InitTemplates(category, templates)
return pathx.InitTemplates(category, templates)
}

View File

@@ -6,13 +6,13 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
)
func TestGenTemplates(t *testing.T) {
err := util.InitTemplates(category, templates)
err := pathx.InitTemplates(category, templates)
assert.Nil(t, err)
dir, err := util.GetTemplateDir(category)
dir, err := pathx.GetTemplateDir(category)
assert.Nil(t, err)
file := filepath.Join(dir, "main.tpl")
data, err := ioutil.ReadFile(file)
@@ -22,10 +22,10 @@ func TestGenTemplates(t *testing.T) {
func TestRevertTemplate(t *testing.T) {
name := "main.tpl"
err := util.InitTemplates(category, templates)
err := pathx.InitTemplates(category, templates)
assert.Nil(t, err)
dir, err := util.GetTemplateDir(category)
dir, err := pathx.GetTemplateDir(category)
assert.Nil(t, err)
file := filepath.Join(dir, name)
@@ -33,7 +33,7 @@ func TestRevertTemplate(t *testing.T) {
assert.Nil(t, err)
modifyData := string(data) + "modify"
err = util.CreateTemplate(category, name, modifyData)
err = pathx.CreateTemplate(category, name, modifyData)
assert.Nil(t, err)
data, err = ioutil.ReadFile(file)
@@ -50,12 +50,12 @@ func TestRevertTemplate(t *testing.T) {
func TestClean(t *testing.T) {
name := "main.tpl"
err := util.InitTemplates(category, templates)
err := pathx.InitTemplates(category, templates)
assert.Nil(t, err)
assert.Nil(t, Clean())
dir, err := util.GetTemplateDir(category)
dir, err := pathx.GetTemplateDir(category)
assert.Nil(t, err)
file := filepath.Join(dir, name)
@@ -65,10 +65,10 @@ func TestClean(t *testing.T) {
func TestUpdate(t *testing.T) {
name := "main.tpl"
err := util.InitTemplates(category, templates)
err := pathx.InitTemplates(category, templates)
assert.Nil(t, err)
dir, err := util.GetTemplateDir(category)
dir, err := pathx.GetTemplateDir(category)
assert.Nil(t, err)
file := filepath.Join(dir, name)
@@ -76,7 +76,7 @@ func TestUpdate(t *testing.T) {
assert.Nil(t, err)
modifyData := string(data) + "modify"
err = util.CreateTemplate(category, name, modifyData)
err = pathx.CreateTemplate(category, name, modifyData)
assert.Nil(t, err)
data, err = ioutil.ReadFile(file)

View File

@@ -12,8 +12,8 @@ import (
"github.com/tal-tech/go-zero/core/collection"
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/api/util"
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
)
type fileGenConfig struct {
@@ -41,7 +41,7 @@ func genFile(c fileGenConfig) error {
if len(c.category) == 0 || len(c.templateFile) == 0 {
text = c.builtinTemplate
} else {
text, err = ctlutil.LoadTemplate(c.category, c.templateFile, c.builtinTemplate)
text, err = pathx.LoadTemplate(c.category, c.templateFile, c.builtinTemplate)
if err != nil {
return err
}
@@ -73,7 +73,7 @@ func getParentPackage(dir string) (string, error) {
// fix https://github.com/zeromicro/go-zero/issues/1058
wd := projectCtx.WorkDir
d := projectCtx.Dir
same, err := ctlutil.SameFile(wd, d)
same, err := pathx.SameFile(wd, d)
if err != nil {
return "", err
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/logrusorgru/aurora"
"github.com/tal-tech/go-zero/core/logx"
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -30,7 +30,7 @@ func JavaCommand(c *cli.Context) error {
api.Service = api.Service.JoinPrefix()
packetName := strings.TrimSuffix(api.Service.Name, "-api")
logx.Must(util.MkdirIfNotExist(dir))
logx.Must(pathx.MkdirIfNotExist(dir))
logx.Must(genPacket(dir, packetName, api))
logx.Must(genComponents(dir, packetName, api))

View File

@@ -14,6 +14,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
apiutil "github.com/tal-tech/go-zero/tools/goctl/api/util"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
)
const (
@@ -110,7 +111,7 @@ func (c *componentsContext) createComponent(dir, packetName string, ty spec.Type
modelFile := util.Title(ty.Name()) + ".java"
filename := path.Join(dir, modelDir, modelFile)
if err := util.RemoveOrQuit(filename); err != nil {
if err := pathx.RemoveOrQuit(filename); err != nil {
return err
}
@@ -270,7 +271,7 @@ func (c *componentsContext) buildConstructor() (string, string, error) {
writeIndent(&constructorSetter, 2)
constructorSetter.WriteString(fmt.Sprintf("this.%s = %s;", pn, util.Untitle(member.Name)))
if index != len(c.members)-1 {
constructorSetter.WriteString(util.NL)
constructorSetter.WriteString(pathx.NL)
}
}
return params.String(), constructorSetter.String(), nil

View File

@@ -8,12 +8,13 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/spec"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
)
func writeProperty(writer io.Writer, member spec.Member, indent int) error {
if len(member.Comment) > 0 {
writeIndent(writer, indent)
fmt.Fprint(writer, member.Comment+util.NL)
fmt.Fprint(writer, member.Comment+pathx.NL)
}
writeIndent(writer, indent)
ty, err := specTypeToJava(member.Type)

View File

@@ -10,6 +10,7 @@ import (
"github.com/tal-tech/go-zero/tools/goctl/api/gogen"
conf "github.com/tal-tech/go-zero/tools/goctl/config"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -36,6 +37,10 @@ func CreateServiceCommand(c *cli.Context) error {
dirName = "greet"
}
dirStyle := c.String("style")
if len(dirStyle) == 0 {
dirStyle = conf.DefaultFormat
}
if strings.Contains(dirName, "-") {
return errors.New("api new command service name not support strikethrough, because this will used by function name")
}
@@ -45,7 +50,7 @@ func CreateServiceCommand(c *cli.Context) error {
return err
}
err = util.MkdirIfNotExist(abs)
err = pathx.MkdirIfNotExist(abs)
if err != nil {
return err
}
@@ -61,11 +66,19 @@ func CreateServiceCommand(c *cli.Context) error {
defer fp.Close()
home := c.String("home")
if len(home) > 0 {
util.RegisterGoctlHome(home)
remote := c.String("remote")
if len(remote) > 0 {
repo, _ := util.CloneIntoGitHome(remote)
if len(repo) > 0 {
home = repo
}
}
text, err := util.LoadTemplate(category, apiTemplateFile, apiTemplate)
if len(home) > 0 {
pathx.RegisterGoctlHome(home)
}
text, err := pathx.LoadTemplate(category, apiTemplateFile, apiTemplate)
if err != nil {
return err
}
@@ -78,6 +91,6 @@ func CreateServiceCommand(c *cli.Context) error {
return err
}
err = gogen.DoGenProject(apiFilePath, abs, conf.DefaultFormat)
err = gogen.DoGenProject(apiFilePath, abs, dirStyle)
return err
}

View File

@@ -3,7 +3,7 @@ package new
import (
"fmt"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/pathx"
"github.com/urfave/cli"
)
@@ -23,12 +23,12 @@ func Category() string {
// Clean cleans the generated deployment files.
func Clean() error {
return util.Clean(category)
return pathx.Clean(category)
}
// GenTemplates generates api template files.
func GenTemplates(_ *cli.Context) error {
return util.InitTemplates(category, templates)
return pathx.InitTemplates(category, templates)
}
// RevertTemplate reverts the given template file to the default value.
@@ -37,7 +37,7 @@ func RevertTemplate(name string) error {
if !ok {
return fmt.Errorf("%s: no such file name", name)
}
return util.CreateTemplate(category, name, content)
return pathx.CreateTemplate(category, name, content)
}
// Update updates the template files to the templates built in current goctl.
@@ -47,5 +47,5 @@ func Update() error {
return err
}
return util.InitTemplates(category, templates)
return pathx.InitTemplates(category, templates)
}

View File

@@ -63,11 +63,11 @@ serviceApi: {match(p,"service")}serviceToken=ID serviceName lbrace='{' servi
serviceRoute: atDoc? (atServer|atHandler) route;
atDoc: ATDOC lp='('? ((kvLit+)|STRING) rp=')'?;
atHandler: ATHANDLER ID;
route: {checkHttpMethod(p)}httpMethod=ID path request=body? returnToken=ID? response=replybody?;
route: {checkHTTPMethod(p)}httpMethod=ID path request=body? response=replybody?;
body: lp='(' (ID)? rp=')';
replybody: lp='(' dataType? rp=')';
replybody: returnToken='returns' lp='(' dataType? rp=')';
// kv
kvLit: key=ID {checkKeyValue(p)}value=LINE_VALUE;
serviceName: (ID '-'?)+;
path: (('/' (ID ('-' ID)*))|('/:' (ID ('-' ID)?)))+;
path: (('/' (ID ('-' ID)*))|('/:' (ID ('-' ID)?)))+ | '/';

View File

@@ -2,11 +2,14 @@ package ast
import (
"fmt"
"path"
"sort"
"github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
)
const prefixKey = "prefix"
// Api describes syntax for api
type Api struct {
LinePrefix string
@@ -49,8 +52,15 @@ func (v *ApiVisitor) acceptService(root, final *Api) {
}
v.duplicateServerItemCheck(service)
var prefix string
if service.AtServer != nil {
p := service.AtServer.Kv.Get(prefixKey)
if p != nil {
prefix = p.Text()
}
}
for _, route := range service.ServiceApi.ServiceRoute {
uniqueRoute := fmt.Sprintf("%s %s", route.Route.Method.Text(), route.Route.Path.Text())
uniqueRoute := fmt.Sprintf("%s %s", route.Route.Method.Text(), path.Join(prefix, route.Route.Path.Text()))
if _, ok := final.routeM[uniqueRoute]; ok {
v.panic(route.Route.Method, fmt.Sprintf("duplicate route '%s'", uniqueRoute))
}

View File

@@ -3,6 +3,7 @@ package ast
import (
"fmt"
"io/ioutil"
"path"
"path/filepath"
"strings"
@@ -113,13 +114,13 @@ func (p *Parser) parse(filename, content string) (*Api, error) {
apiAstList = append(apiAstList, root)
for _, imp := range root.Import {
dir := filepath.Dir(p.src)
path := filepath.Join(dir, imp.Value.Text())
data, err := p.readContent(path)
imp := filepath.Join(dir, imp.Value.Text())
data, err := p.readContent(imp)
if err != nil {
return nil, err
}
nestedApi, err := p.invoke(path, data)
nestedApi, err := p.invoke(imp, data)
if err != nil {
return nil, err
}
@@ -196,8 +197,8 @@ func (p *Parser) valid(mainApi, nestedApi *Api) error {
if handler.IsNotNil() {
handlerName := handler.Text()
handlerMap[handlerName] = Holder
path := fmt.Sprintf("%s://%s", g.Route.Method.Text(), g.Route.Path.Text())
routeMap[path] = Holder
route := fmt.Sprintf("%s://%s", g.Route.Method.Text(), g.Route.Path.Text())
routeMap[route] = Holder
}
}
@@ -239,6 +240,13 @@ func (p *Parser) valid(mainApi, nestedApi *Api) error {
func (p *Parser) duplicateRouteCheck(nestedApi *Api, mainHandlerMap, mainRouteMap map[string]PlaceHolder) error {
for _, each := range nestedApi.Service {
var prefix string
if each.AtServer != nil {
p := each.AtServer.Kv.Get(prefixKey)
if p != nil {
prefix = p.Text()
}
}
for _, r := range each.ServiceApi.ServiceRoute {
handler := r.GetHandler()
if !handler.IsNotNil() {
@@ -250,8 +258,8 @@ func (p *Parser) duplicateRouteCheck(nestedApi *Api, mainHandlerMap, mainRouteMa
nestedApi.LinePrefix, handler.Line(), handler.Column(), handler.Text())
}
path := fmt.Sprintf("%s://%s", r.Route.Method.Text(), r.Route.Path.Text())
if _, ok := mainRouteMap[path]; ok {
p := fmt.Sprintf("%s://%s", r.Route.Method.Text(), path.Join(prefix, r.Route.Path.Text()))
if _, ok := mainRouteMap[p]; ok {
return fmt.Errorf("%s line %d:%d duplicate route '%s'",
nestedApi.LinePrefix, r.Route.Method.Line(), r.Route.Method.Column(), r.Route.Method.Text()+" "+r.Route.Path.Text())
}

View File

@@ -21,7 +21,7 @@ type (
// ApiVisitor wraps api.BaseApiParserVisitor to call methods which has prefix Visit to
// visit node from the api syntax
ApiVisitor struct {
api.BaseApiParserVisitor
*api.BaseApiParserVisitor
debug bool
log console.Console
prefix string

View File

@@ -71,9 +71,10 @@ type Route struct {
// Body describes request,response body ast for api syntax
type Body struct {
Lp Expr
Rp Expr
Name DataType
ReturnExpr Expr
Lp Expr
Rp Expr
Name DataType
}
// VisitServiceSpec implements from api.BaseApiParserVisitor
@@ -175,7 +176,7 @@ func (v *ApiVisitor) VisitAtHandler(ctx *api.AtHandlerContext) interface{} {
return &atHandler
}
// VisitRoute implements from api.BaseApiParserVisitor
// serVisitRoute implements from api.BaseApiParserVisitor
func (v *ApiVisitor) VisitRoute(ctx *api.RouteContext) interface{} {
var route Route
path := ctx.Path()
@@ -193,16 +194,12 @@ func (v *ApiVisitor) VisitRoute(ctx *api.RouteContext) interface{} {
if ctx.GetResponse() != nil {
reply := ctx.GetResponse().Accept(v)
if reply != nil {
route.Reply = reply.(*Body)
resp := reply.(*Body)
route.ReturnToken = resp.ReturnExpr
resp.ReturnExpr = nil
route.Reply = resp
}
}
if ctx.GetReturnToken() != nil {
returnExpr := v.newExprWithToken(ctx.GetReturnToken())
if ctx.GetReturnToken().GetText() != "returns" {
v.panic(returnExpr, fmt.Sprintf("expecting returns, found input '%s'", ctx.GetReturnToken().GetText()))
}
route.ReturnToken = returnExpr
}
route.DocExpr = v.getDoc(ctx)
route.CommentExpr = v.getComment(ctx)
@@ -249,6 +246,14 @@ func (v *ApiVisitor) VisitReplybody(ctx *api.ReplybodyContext) interface{} {
return nil
}
var returnExpr Expr
if ctx.GetReturnToken() != nil {
returnExpr = v.newExprWithToken(ctx.GetReturnToken())
if ctx.GetReturnToken().GetText() != "returns" {
v.panic(returnExpr, fmt.Sprintf("expecting returns, found input '%s'", ctx.GetReturnToken().GetText()))
}
}
dt := ctx.DataType().Accept(v).(DataType)
if dt == nil {
return nil
@@ -267,20 +272,18 @@ func (v *ApiVisitor) VisitReplybody(ctx *api.ReplybodyContext) interface{} {
}
case *Literal:
lit := dataType.Literal.Text()
if api.IsGolangKeyWord(dataType.Literal.Text()) {
v.panic(dataType.Literal, fmt.Sprintf("expecting 'ID', but found golang keyword '%s'", dataType.Literal.Text()))
}
if api.IsBasicType(lit) {
v.panic(dt.Expr(), fmt.Sprintf("unsupport %s", dt.Expr().Text()))
if api.IsGolangKeyWord(lit) {
v.panic(dataType.Literal, fmt.Sprintf("expecting 'ID', but found golang keyword '%s'", lit))
}
default:
v.panic(dt.Expr(), fmt.Sprintf("unsupport %s", dt.Expr().Text()))
}
return &Body{
Lp: v.newExprWithToken(ctx.GetLp()),
Rp: v.newExprWithToken(ctx.GetRp()),
Name: dt,
ReturnExpr: returnExpr,
Lp: v.newExprWithToken(ctx.GetLp()),
Rp: v.newExprWithToken(ctx.GetRp()),
Name: dt,
}
}

View File

@@ -1,5 +1,3 @@
// Code generated from tools/goctl/api/parser/g4/ApiParser.g4 by ANTLR 4.9. DO NOT EDIT.
package api // ApiParser
import "github.com/zeromicro/antlr"

View File

@@ -1,5 +1,3 @@
// Code generated from tools/goctl/api/parser/g4/ApiParser.g4 by ANTLR 4.9. DO NOT EDIT.
package api
import (
@@ -16,132 +14,136 @@ var (
)
var serializedLexerAtn = []uint16{
3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 25, 266,
3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 26, 276,
8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7,
9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12,
4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4,
18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23,
9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9,
28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 3, 2, 3, 2, 3, 3, 3, 3, 3,
4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3,
8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11,
3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3,
15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16,
3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3,
17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 6, 18, 132,
10, 18, 13, 18, 14, 18, 133, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19,
7, 19, 142, 10, 19, 12, 19, 14, 19, 145, 11, 19, 3, 19, 3, 19, 3, 19, 3,
19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 7, 20, 156, 10, 20, 12, 20, 14,
20, 159, 11, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 7, 21, 166, 10, 21,
12, 21, 14, 21, 169, 11, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 6, 22,
176, 10, 22, 13, 22, 14, 22, 177, 3, 22, 3, 22, 3, 23, 3, 23, 7, 23, 184,
10, 23, 12, 23, 14, 23, 187, 11, 23, 3, 23, 3, 23, 7, 23, 191, 10, 23,
12, 23, 14, 23, 194, 11, 23, 5, 23, 196, 10, 23, 3, 24, 3, 24, 7, 24, 200,
10, 24, 12, 24, 14, 24, 203, 11, 24, 3, 25, 3, 25, 5, 25, 207, 10, 25,
3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 5, 26, 215, 10, 26, 3, 26, 5,
26, 218, 10, 26, 3, 26, 3, 26, 3, 26, 6, 26, 223, 10, 26, 13, 26, 14, 26,
224, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 5, 26, 232, 10, 26, 3, 27, 3, 27,
3, 27, 7, 27, 237, 10, 27, 12, 27, 14, 27, 240, 11, 27, 3, 27, 5, 27, 243,
10, 27, 3, 28, 3, 28, 3, 29, 3, 29, 7, 29, 249, 10, 29, 12, 29, 14, 29,
252, 11, 29, 3, 29, 5, 29, 255, 10, 29, 3, 30, 3, 30, 5, 30, 259, 10, 30,
3, 31, 3, 31, 3, 31, 3, 31, 5, 31, 265, 10, 31, 3, 143, 2, 32, 3, 3, 5,
4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25,
14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43,
23, 45, 24, 47, 25, 49, 2, 51, 2, 53, 2, 55, 2, 57, 2, 59, 2, 61, 2, 3,
2, 20, 5, 2, 11, 12, 14, 15, 34, 34, 4, 2, 12, 12, 15, 15, 4, 2, 36, 36,
94, 94, 6, 2, 12, 12, 15, 15, 94, 94, 98, 98, 4, 2, 11, 11, 34, 34, 6,
2, 12, 12, 15, 15, 36, 36, 98, 98, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45,
47, 47, 10, 2, 36, 36, 41, 41, 94, 94, 100, 100, 104, 104, 112, 112, 116,
116, 118, 118, 3, 2, 50, 53, 3, 2, 50, 57, 5, 2, 50, 59, 67, 72, 99, 104,
3, 2, 50, 59, 4, 2, 50, 59, 97, 97, 6, 2, 38, 38, 67, 92, 97, 97, 99, 124,
4, 2, 2, 129, 55298, 56321, 3, 2, 55298, 56321, 3, 2, 56322, 57345, 2,
283, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2,
2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3,
2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25,
3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2,
33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2,
2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2,
2, 3, 63, 3, 2, 2, 2, 5, 65, 3, 2, 2, 2, 7, 67, 3, 2, 2, 2, 9, 69, 3, 2,
2, 2, 11, 71, 3, 2, 2, 2, 13, 73, 3, 2, 2, 2, 15, 75, 3, 2, 2, 2, 17, 85,
3, 2, 2, 2, 19, 87, 3, 2, 2, 2, 21, 89, 3, 2, 2, 2, 23, 91, 3, 2, 2, 2,
25, 93, 3, 2, 2, 2, 27, 96, 3, 2, 2, 2, 29, 101, 3, 2, 2, 2, 31, 110, 3,
2, 2, 2, 33, 122, 3, 2, 2, 2, 35, 131, 3, 2, 2, 2, 37, 137, 3, 2, 2, 2,
39, 151, 3, 2, 2, 2, 41, 162, 3, 2, 2, 2, 43, 172, 3, 2, 2, 2, 45, 181,
3, 2, 2, 2, 47, 197, 3, 2, 2, 2, 49, 204, 3, 2, 2, 2, 51, 231, 3, 2, 2,
2, 53, 233, 3, 2, 2, 2, 55, 244, 3, 2, 2, 2, 57, 246, 3, 2, 2, 2, 59, 258,
3, 2, 2, 2, 61, 264, 3, 2, 2, 2, 63, 64, 7, 63, 2, 2, 64, 4, 3, 2, 2, 2,
65, 66, 7, 42, 2, 2, 66, 6, 3, 2, 2, 2, 67, 68, 7, 43, 2, 2, 68, 8, 3,
2, 2, 2, 69, 70, 7, 125, 2, 2, 70, 10, 3, 2, 2, 2, 71, 72, 7, 127, 2, 2,
72, 12, 3, 2, 2, 2, 73, 74, 7, 44, 2, 2, 74, 14, 3, 2, 2, 2, 75, 76, 7,
118, 2, 2, 76, 77, 7, 107, 2, 2, 77, 78, 7, 111, 2, 2, 78, 79, 7, 103,
2, 2, 79, 80, 7, 48, 2, 2, 80, 81, 7, 86, 2, 2, 81, 82, 7, 107, 2, 2, 82,
83, 7, 111, 2, 2, 83, 84, 7, 103, 2, 2, 84, 16, 3, 2, 2, 2, 85, 86, 7,
93, 2, 2, 86, 18, 3, 2, 2, 2, 87, 88, 7, 95, 2, 2, 88, 20, 3, 2, 2, 2,
89, 90, 7, 47, 2, 2, 90, 22, 3, 2, 2, 2, 91, 92, 7, 49, 2, 2, 92, 24, 3,
2, 2, 2, 93, 94, 7, 49, 2, 2, 94, 95, 7, 60, 2, 2, 95, 26, 3, 2, 2, 2,
96, 97, 7, 66, 2, 2, 97, 98, 7, 102, 2, 2, 98, 99, 7, 113, 2, 2, 99, 100,
7, 101, 2, 2, 100, 28, 3, 2, 2, 2, 101, 102, 7, 66, 2, 2, 102, 103, 7,
106, 2, 2, 103, 104, 7, 99, 2, 2, 104, 105, 7, 112, 2, 2, 105, 106, 7,
102, 2, 2, 106, 107, 7, 110, 2, 2, 107, 108, 7, 103, 2, 2, 108, 109, 7,
116, 2, 2, 109, 30, 3, 2, 2, 2, 110, 111, 7, 107, 2, 2, 111, 112, 7, 112,
2, 2, 112, 113, 7, 118, 2, 2, 113, 114, 7, 103, 2, 2, 114, 115, 7, 116,
2, 2, 115, 116, 7, 104, 2, 2, 116, 117, 7, 99, 2, 2, 117, 118, 7, 101,
2, 2, 118, 119, 7, 103, 2, 2, 119, 120, 7, 125, 2, 2, 120, 121, 7, 127,
2, 2, 121, 32, 3, 2, 2, 2, 122, 123, 7, 66, 2, 2, 123, 124, 7, 117, 2,
2, 124, 125, 7, 103, 2, 2, 125, 126, 7, 116, 2, 2, 126, 127, 7, 120, 2,
2, 127, 128, 7, 103, 2, 2, 128, 129, 7, 116, 2, 2, 129, 34, 3, 2, 2, 2,
130, 132, 9, 2, 2, 2, 131, 130, 3, 2, 2, 2, 132, 133, 3, 2, 2, 2, 133,
131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 136,
8, 18, 2, 2, 136, 36, 3, 2, 2, 2, 137, 138, 7, 49, 2, 2, 138, 139, 7, 44,
2, 2, 139, 143, 3, 2, 2, 2, 140, 142, 11, 2, 2, 2, 141, 140, 3, 2, 2, 2,
142, 145, 3, 2, 2, 2, 143, 144, 3, 2, 2, 2, 143, 141, 3, 2, 2, 2, 144,
146, 3, 2, 2, 2, 145, 143, 3, 2, 2, 2, 146, 147, 7, 44, 2, 2, 147, 148,
7, 49, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 8, 19, 3, 2, 150, 38, 3, 2,
2, 2, 151, 152, 7, 49, 2, 2, 152, 153, 7, 49, 2, 2, 153, 157, 3, 2, 2,
2, 154, 156, 10, 3, 2, 2, 155, 154, 3, 2, 2, 2, 156, 159, 3, 2, 2, 2, 157,
155, 3, 2, 2, 2, 157, 158, 3, 2, 2, 2, 158, 160, 3, 2, 2, 2, 159, 157,
3, 2, 2, 2, 160, 161, 8, 20, 3, 2, 161, 40, 3, 2, 2, 2, 162, 167, 7, 36,
2, 2, 163, 166, 10, 4, 2, 2, 164, 166, 5, 51, 26, 2, 165, 163, 3, 2, 2,
2, 165, 164, 3, 2, 2, 2, 166, 169, 3, 2, 2, 2, 167, 165, 3, 2, 2, 2, 167,
168, 3, 2, 2, 2, 168, 170, 3, 2, 2, 2, 169, 167, 3, 2, 2, 2, 170, 171,
7, 36, 2, 2, 171, 42, 3, 2, 2, 2, 172, 175, 7, 98, 2, 2, 173, 176, 10,
5, 2, 2, 174, 176, 5, 51, 26, 2, 175, 173, 3, 2, 2, 2, 175, 174, 3, 2,
2, 2, 176, 177, 3, 2, 2, 2, 177, 175, 3, 2, 2, 2, 177, 178, 3, 2, 2, 2,
178, 179, 3, 2, 2, 2, 179, 180, 7, 98, 2, 2, 180, 44, 3, 2, 2, 2, 181,
185, 7, 60, 2, 2, 182, 184, 9, 6, 2, 2, 183, 182, 3, 2, 2, 2, 184, 187,
3, 2, 2, 2, 185, 183, 3, 2, 2, 2, 185, 186, 3, 2, 2, 2, 186, 195, 3, 2,
2, 2, 187, 185, 3, 2, 2, 2, 188, 196, 5, 41, 21, 2, 189, 191, 10, 7, 2,
2, 190, 189, 3, 2, 2, 2, 191, 194, 3, 2, 2, 2, 192, 190, 3, 2, 2, 2, 192,
193, 3, 2, 2, 2, 193, 196, 3, 2, 2, 2, 194, 192, 3, 2, 2, 2, 195, 188,
3, 2, 2, 2, 195, 192, 3, 2, 2, 2, 196, 46, 3, 2, 2, 2, 197, 201, 5, 61,
31, 2, 198, 200, 5, 59, 30, 2, 199, 198, 3, 2, 2, 2, 200, 203, 3, 2, 2,
2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 48, 3, 2, 2, 2, 203,
201, 3, 2, 2, 2, 204, 206, 9, 8, 2, 2, 205, 207, 9, 9, 2, 2, 206, 205,
3, 2, 2, 2, 206, 207, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 209, 5, 57,
29, 2, 209, 50, 3, 2, 2, 2, 210, 211, 7, 94, 2, 2, 211, 232, 9, 10, 2,
2, 212, 217, 7, 94, 2, 2, 213, 215, 9, 11, 2, 2, 214, 213, 3, 2, 2, 2,
214, 215, 3, 2, 2, 2, 215, 216, 3, 2, 2, 2, 216, 218, 9, 12, 2, 2, 217,
214, 3, 2, 2, 2, 217, 218, 3, 2, 2, 2, 218, 219, 3, 2, 2, 2, 219, 232,
9, 12, 2, 2, 220, 222, 7, 94, 2, 2, 221, 223, 7, 119, 2, 2, 222, 221, 3,
2, 2, 2, 223, 224, 3, 2, 2, 2, 224, 222, 3, 2, 2, 2, 224, 225, 3, 2, 2,
2, 225, 226, 3, 2, 2, 2, 226, 227, 5, 55, 28, 2, 227, 228, 5, 55, 28, 2,
228, 229, 5, 55, 28, 2, 229, 230, 5, 55, 28, 2, 230, 232, 3, 2, 2, 2, 231,
210, 3, 2, 2, 2, 231, 212, 3, 2, 2, 2, 231, 220, 3, 2, 2, 2, 232, 52, 3,
2, 2, 2, 233, 242, 5, 55, 28, 2, 234, 237, 5, 55, 28, 2, 235, 237, 7, 97,
2, 2, 236, 234, 3, 2, 2, 2, 236, 235, 3, 2, 2, 2, 237, 240, 3, 2, 2, 2,
238, 236, 3, 2, 2, 2, 238, 239, 3, 2, 2, 2, 239, 241, 3, 2, 2, 2, 240,
238, 3, 2, 2, 2, 241, 243, 5, 55, 28, 2, 242, 238, 3, 2, 2, 2, 242, 243,
3, 2, 2, 2, 243, 54, 3, 2, 2, 2, 244, 245, 9, 13, 2, 2, 245, 56, 3, 2,
2, 2, 246, 254, 9, 14, 2, 2, 247, 249, 9, 15, 2, 2, 248, 247, 3, 2, 2,
2, 249, 252, 3, 2, 2, 2, 250, 248, 3, 2, 2, 2, 250, 251, 3, 2, 2, 2, 251,
253, 3, 2, 2, 2, 252, 250, 3, 2, 2, 2, 253, 255, 9, 14, 2, 2, 254, 250,
3, 2, 2, 2, 254, 255, 3, 2, 2, 2, 255, 58, 3, 2, 2, 2, 256, 259, 5, 61,
31, 2, 257, 259, 9, 14, 2, 2, 258, 256, 3, 2, 2, 2, 258, 257, 3, 2, 2,
2, 259, 60, 3, 2, 2, 2, 260, 265, 9, 16, 2, 2, 261, 265, 10, 17, 2, 2,
262, 263, 9, 18, 2, 2, 263, 265, 9, 19, 2, 2, 264, 260, 3, 2, 2, 2, 264,
261, 3, 2, 2, 2, 264, 262, 3, 2, 2, 2, 265, 62, 3, 2, 2, 2, 26, 2, 133,
143, 157, 165, 167, 175, 177, 185, 192, 195, 201, 206, 214, 217, 224, 231,
236, 238, 242, 250, 254, 258, 264, 4, 2, 3, 2, 2, 90, 2,
28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 3, 2, 3, 2,
3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8,
3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10,
3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3,
13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16,
3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3,
17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18,
3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 6, 19, 142, 10,
19, 13, 19, 14, 19, 143, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 7, 20,
152, 10, 20, 12, 20, 14, 20, 155, 11, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3,
20, 3, 21, 3, 21, 3, 21, 3, 21, 7, 21, 166, 10, 21, 12, 21, 14, 21, 169,
11, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 7, 22, 176, 10, 22, 12, 22,
14, 22, 179, 11, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 6, 23, 186, 10,
23, 13, 23, 14, 23, 187, 3, 23, 3, 23, 3, 24, 3, 24, 7, 24, 194, 10, 24,
12, 24, 14, 24, 197, 11, 24, 3, 24, 3, 24, 7, 24, 201, 10, 24, 12, 24,
14, 24, 204, 11, 24, 5, 24, 206, 10, 24, 3, 25, 3, 25, 7, 25, 210, 10,
25, 12, 25, 14, 25, 213, 11, 25, 3, 26, 3, 26, 5, 26, 217, 10, 26, 3, 26,
3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 5, 27, 225, 10, 27, 3, 27, 5, 27, 228,
10, 27, 3, 27, 3, 27, 3, 27, 6, 27, 233, 10, 27, 13, 27, 14, 27, 234, 3,
27, 3, 27, 3, 27, 3, 27, 3, 27, 5, 27, 242, 10, 27, 3, 28, 3, 28, 3, 28,
7, 28, 247, 10, 28, 12, 28, 14, 28, 250, 11, 28, 3, 28, 5, 28, 253, 10,
28, 3, 29, 3, 29, 3, 30, 3, 30, 7, 30, 259, 10, 30, 12, 30, 14, 30, 262,
11, 30, 3, 30, 5, 30, 265, 10, 30, 3, 31, 3, 31, 5, 31, 269, 10, 31, 3,
32, 3, 32, 3, 32, 3, 32, 5, 32, 275, 10, 32, 3, 153, 2, 33, 3, 3, 5, 4,
7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14,
27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23,
45, 24, 47, 25, 49, 26, 51, 2, 53, 2, 55, 2, 57, 2, 59, 2, 61, 2, 63, 2,
3, 2, 20, 5, 2, 11, 12, 14, 15, 34, 34, 4, 2, 12, 12, 15, 15, 4, 2, 36,
36, 94, 94, 6, 2, 12, 12, 15, 15, 94, 94, 98, 98, 4, 2, 11, 11, 34, 34,
6, 2, 12, 12, 15, 15, 36, 36, 98, 98, 4, 2, 71, 71, 103, 103, 4, 2, 45,
45, 47, 47, 10, 2, 36, 36, 41, 41, 94, 94, 100, 100, 104, 104, 112, 112,
116, 116, 118, 118, 3, 2, 50, 53, 3, 2, 50, 57, 5, 2, 50, 59, 67, 72, 99,
104, 3, 2, 50, 59, 4, 2, 50, 59, 97, 97, 6, 2, 38, 38, 67, 92, 97, 97,
99, 124, 4, 2, 2, 129, 55298, 56321, 3, 2, 55298, 56321, 3, 2, 56322, 57345,
2, 293, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3,
2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17,
3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2,
25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2,
2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2,
2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2,
2, 2, 2, 49, 3, 2, 2, 2, 3, 65, 3, 2, 2, 2, 5, 67, 3, 2, 2, 2, 7, 69, 3,
2, 2, 2, 9, 71, 3, 2, 2, 2, 11, 73, 3, 2, 2, 2, 13, 75, 3, 2, 2, 2, 15,
77, 3, 2, 2, 2, 17, 87, 3, 2, 2, 2, 19, 89, 3, 2, 2, 2, 21, 91, 3, 2, 2,
2, 23, 99, 3, 2, 2, 2, 25, 101, 3, 2, 2, 2, 27, 103, 3, 2, 2, 2, 29, 106,
3, 2, 2, 2, 31, 111, 3, 2, 2, 2, 33, 120, 3, 2, 2, 2, 35, 132, 3, 2, 2,
2, 37, 141, 3, 2, 2, 2, 39, 147, 3, 2, 2, 2, 41, 161, 3, 2, 2, 2, 43, 172,
3, 2, 2, 2, 45, 182, 3, 2, 2, 2, 47, 191, 3, 2, 2, 2, 49, 207, 3, 2, 2,
2, 51, 214, 3, 2, 2, 2, 53, 241, 3, 2, 2, 2, 55, 243, 3, 2, 2, 2, 57, 254,
3, 2, 2, 2, 59, 256, 3, 2, 2, 2, 61, 268, 3, 2, 2, 2, 63, 274, 3, 2, 2,
2, 65, 66, 7, 63, 2, 2, 66, 4, 3, 2, 2, 2, 67, 68, 7, 42, 2, 2, 68, 6,
3, 2, 2, 2, 69, 70, 7, 43, 2, 2, 70, 8, 3, 2, 2, 2, 71, 72, 7, 125, 2,
2, 72, 10, 3, 2, 2, 2, 73, 74, 7, 127, 2, 2, 74, 12, 3, 2, 2, 2, 75, 76,
7, 44, 2, 2, 76, 14, 3, 2, 2, 2, 77, 78, 7, 118, 2, 2, 78, 79, 7, 107,
2, 2, 79, 80, 7, 111, 2, 2, 80, 81, 7, 103, 2, 2, 81, 82, 7, 48, 2, 2,
82, 83, 7, 86, 2, 2, 83, 84, 7, 107, 2, 2, 84, 85, 7, 111, 2, 2, 85, 86,
7, 103, 2, 2, 86, 16, 3, 2, 2, 2, 87, 88, 7, 93, 2, 2, 88, 18, 3, 2, 2,
2, 89, 90, 7, 95, 2, 2, 90, 20, 3, 2, 2, 2, 91, 92, 7, 116, 2, 2, 92, 93,
7, 103, 2, 2, 93, 94, 7, 118, 2, 2, 94, 95, 7, 119, 2, 2, 95, 96, 7, 116,
2, 2, 96, 97, 7, 112, 2, 2, 97, 98, 7, 117, 2, 2, 98, 22, 3, 2, 2, 2, 99,
100, 7, 47, 2, 2, 100, 24, 3, 2, 2, 2, 101, 102, 7, 49, 2, 2, 102, 26,
3, 2, 2, 2, 103, 104, 7, 49, 2, 2, 104, 105, 7, 60, 2, 2, 105, 28, 3, 2,
2, 2, 106, 107, 7, 66, 2, 2, 107, 108, 7, 102, 2, 2, 108, 109, 7, 113,
2, 2, 109, 110, 7, 101, 2, 2, 110, 30, 3, 2, 2, 2, 111, 112, 7, 66, 2,
2, 112, 113, 7, 106, 2, 2, 113, 114, 7, 99, 2, 2, 114, 115, 7, 112, 2,
2, 115, 116, 7, 102, 2, 2, 116, 117, 7, 110, 2, 2, 117, 118, 7, 103, 2,
2, 118, 119, 7, 116, 2, 2, 119, 32, 3, 2, 2, 2, 120, 121, 7, 107, 2, 2,
121, 122, 7, 112, 2, 2, 122, 123, 7, 118, 2, 2, 123, 124, 7, 103, 2, 2,
124, 125, 7, 116, 2, 2, 125, 126, 7, 104, 2, 2, 126, 127, 7, 99, 2, 2,
127, 128, 7, 101, 2, 2, 128, 129, 7, 103, 2, 2, 129, 130, 7, 125, 2, 2,
130, 131, 7, 127, 2, 2, 131, 34, 3, 2, 2, 2, 132, 133, 7, 66, 2, 2, 133,
134, 7, 117, 2, 2, 134, 135, 7, 103, 2, 2, 135, 136, 7, 116, 2, 2, 136,
137, 7, 120, 2, 2, 137, 138, 7, 103, 2, 2, 138, 139, 7, 116, 2, 2, 139,
36, 3, 2, 2, 2, 140, 142, 9, 2, 2, 2, 141, 140, 3, 2, 2, 2, 142, 143, 3,
2, 2, 2, 143, 141, 3, 2, 2, 2, 143, 144, 3, 2, 2, 2, 144, 145, 3, 2, 2,
2, 145, 146, 8, 19, 2, 2, 146, 38, 3, 2, 2, 2, 147, 148, 7, 49, 2, 2, 148,
149, 7, 44, 2, 2, 149, 153, 3, 2, 2, 2, 150, 152, 11, 2, 2, 2, 151, 150,
3, 2, 2, 2, 152, 155, 3, 2, 2, 2, 153, 154, 3, 2, 2, 2, 153, 151, 3, 2,
2, 2, 154, 156, 3, 2, 2, 2, 155, 153, 3, 2, 2, 2, 156, 157, 7, 44, 2, 2,
157, 158, 7, 49, 2, 2, 158, 159, 3, 2, 2, 2, 159, 160, 8, 20, 3, 2, 160,
40, 3, 2, 2, 2, 161, 162, 7, 49, 2, 2, 162, 163, 7, 49, 2, 2, 163, 167,
3, 2, 2, 2, 164, 166, 10, 3, 2, 2, 165, 164, 3, 2, 2, 2, 166, 169, 3, 2,
2, 2, 167, 165, 3, 2, 2, 2, 167, 168, 3, 2, 2, 2, 168, 170, 3, 2, 2, 2,
169, 167, 3, 2, 2, 2, 170, 171, 8, 21, 3, 2, 171, 42, 3, 2, 2, 2, 172,
177, 7, 36, 2, 2, 173, 176, 10, 4, 2, 2, 174, 176, 5, 53, 27, 2, 175, 173,
3, 2, 2, 2, 175, 174, 3, 2, 2, 2, 176, 179, 3, 2, 2, 2, 177, 175, 3, 2,
2, 2, 177, 178, 3, 2, 2, 2, 178, 180, 3, 2, 2, 2, 179, 177, 3, 2, 2, 2,
180, 181, 7, 36, 2, 2, 181, 44, 3, 2, 2, 2, 182, 185, 7, 98, 2, 2, 183,
186, 10, 5, 2, 2, 184, 186, 5, 53, 27, 2, 185, 183, 3, 2, 2, 2, 185, 184,
3, 2, 2, 2, 186, 187, 3, 2, 2, 2, 187, 185, 3, 2, 2, 2, 187, 188, 3, 2,
2, 2, 188, 189, 3, 2, 2, 2, 189, 190, 7, 98, 2, 2, 190, 46, 3, 2, 2, 2,
191, 195, 7, 60, 2, 2, 192, 194, 9, 6, 2, 2, 193, 192, 3, 2, 2, 2, 194,
197, 3, 2, 2, 2, 195, 193, 3, 2, 2, 2, 195, 196, 3, 2, 2, 2, 196, 205,
3, 2, 2, 2, 197, 195, 3, 2, 2, 2, 198, 206, 5, 43, 22, 2, 199, 201, 10,
7, 2, 2, 200, 199, 3, 2, 2, 2, 201, 204, 3, 2, 2, 2, 202, 200, 3, 2, 2,
2, 202, 203, 3, 2, 2, 2, 203, 206, 3, 2, 2, 2, 204, 202, 3, 2, 2, 2, 205,
198, 3, 2, 2, 2, 205, 202, 3, 2, 2, 2, 206, 48, 3, 2, 2, 2, 207, 211, 5,
63, 32, 2, 208, 210, 5, 61, 31, 2, 209, 208, 3, 2, 2, 2, 210, 213, 3, 2,
2, 2, 211, 209, 3, 2, 2, 2, 211, 212, 3, 2, 2, 2, 212, 50, 3, 2, 2, 2,
213, 211, 3, 2, 2, 2, 214, 216, 9, 8, 2, 2, 215, 217, 9, 9, 2, 2, 216,
215, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 218, 3, 2, 2, 2, 218, 219,
5, 59, 30, 2, 219, 52, 3, 2, 2, 2, 220, 221, 7, 94, 2, 2, 221, 242, 9,
10, 2, 2, 222, 227, 7, 94, 2, 2, 223, 225, 9, 11, 2, 2, 224, 223, 3, 2,
2, 2, 224, 225, 3, 2, 2, 2, 225, 226, 3, 2, 2, 2, 226, 228, 9, 12, 2, 2,
227, 224, 3, 2, 2, 2, 227, 228, 3, 2, 2, 2, 228, 229, 3, 2, 2, 2, 229,
242, 9, 12, 2, 2, 230, 232, 7, 94, 2, 2, 231, 233, 7, 119, 2, 2, 232, 231,
3, 2, 2, 2, 233, 234, 3, 2, 2, 2, 234, 232, 3, 2, 2, 2, 234, 235, 3, 2,
2, 2, 235, 236, 3, 2, 2, 2, 236, 237, 5, 57, 29, 2, 237, 238, 5, 57, 29,
2, 238, 239, 5, 57, 29, 2, 239, 240, 5, 57, 29, 2, 240, 242, 3, 2, 2, 2,
241, 220, 3, 2, 2, 2, 241, 222, 3, 2, 2, 2, 241, 230, 3, 2, 2, 2, 242,
54, 3, 2, 2, 2, 243, 252, 5, 57, 29, 2, 244, 247, 5, 57, 29, 2, 245, 247,
7, 97, 2, 2, 246, 244, 3, 2, 2, 2, 246, 245, 3, 2, 2, 2, 247, 250, 3, 2,
2, 2, 248, 246, 3, 2, 2, 2, 248, 249, 3, 2, 2, 2, 249, 251, 3, 2, 2, 2,
250, 248, 3, 2, 2, 2, 251, 253, 5, 57, 29, 2, 252, 248, 3, 2, 2, 2, 252,
253, 3, 2, 2, 2, 253, 56, 3, 2, 2, 2, 254, 255, 9, 13, 2, 2, 255, 58, 3,
2, 2, 2, 256, 264, 9, 14, 2, 2, 257, 259, 9, 15, 2, 2, 258, 257, 3, 2,
2, 2, 259, 262, 3, 2, 2, 2, 260, 258, 3, 2, 2, 2, 260, 261, 3, 2, 2, 2,
261, 263, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 263, 265, 9, 14, 2, 2, 264,
260, 3, 2, 2, 2, 264, 265, 3, 2, 2, 2, 265, 60, 3, 2, 2, 2, 266, 269, 5,
63, 32, 2, 267, 269, 9, 14, 2, 2, 268, 266, 3, 2, 2, 2, 268, 267, 3, 2,
2, 2, 269, 62, 3, 2, 2, 2, 270, 275, 9, 16, 2, 2, 271, 275, 10, 17, 2,
2, 272, 273, 9, 18, 2, 2, 273, 275, 9, 19, 2, 2, 274, 270, 3, 2, 2, 2,
274, 271, 3, 2, 2, 2, 274, 272, 3, 2, 2, 2, 275, 64, 3, 2, 2, 2, 26, 2,
143, 153, 167, 175, 177, 185, 187, 195, 202, 205, 211, 216, 224, 227, 234,
241, 246, 248, 252, 260, 264, 268, 274, 4, 2, 3, 2, 2, 90, 2,
}
var lexerChannelNames = []string{
@@ -154,18 +156,19 @@ var lexerModeNames = []string{
var lexerLiteralNames = []string{
"", "'='", "'('", "')'", "'{'", "'}'", "'*'", "'time.Time'", "'['", "']'",
"'-'", "'/'", "'/:'", "'@doc'", "'@handler'", "'interface{}'", "'@server'",
"'returns'", "'-'", "'/'", "'/:'", "'@doc'", "'@handler'", "'interface{}'",
"'@server'",
}
var lexerSymbolicNames = []string{
"", "", "", "", "", "", "", "", "", "", "", "", "", "ATDOC", "ATHANDLER",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "ATDOC", "ATHANDLER",
"INTERFACE", "ATSERVER", "WS", "COMMENT", "LINE_COMMENT", "STRING", "RAW_STRING",
"LINE_VALUE", "ID",
}
var lexerRuleNames = []string{
"T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8",
"T__9", "T__10", "T__11", "ATDOC", "ATHANDLER", "INTERFACE", "ATSERVER",
"T__9", "T__10", "T__11", "T__12", "ATDOC", "ATHANDLER", "INTERFACE", "ATSERVER",
"WS", "COMMENT", "LINE_COMMENT", "STRING", "RAW_STRING", "LINE_VALUE",
"ID", "ExponentPart", "EscapeSequence", "HexDigits", "HexDigit", "Digits",
"LetterOrDigit", "Letter",
@@ -220,17 +223,18 @@ const (
ApiParserLexerT__9 = 10
ApiParserLexerT__10 = 11
ApiParserLexerT__11 = 12
ApiParserLexerATDOC = 13
ApiParserLexerATHANDLER = 14
ApiParserLexerINTERFACE = 15
ApiParserLexerATSERVER = 16
ApiParserLexerWS = 17
ApiParserLexerCOMMENT = 18
ApiParserLexerLINE_COMMENT = 19
ApiParserLexerSTRING = 20
ApiParserLexerRAW_STRING = 21
ApiParserLexerLINE_VALUE = 22
ApiParserLexerID = 23
ApiParserLexerT__12 = 13
ApiParserLexerATDOC = 14
ApiParserLexerATHANDLER = 15
ApiParserLexerINTERFACE = 16
ApiParserLexerATSERVER = 17
ApiParserLexerWS = 18
ApiParserLexerCOMMENT = 19
ApiParserLexerLINE_COMMENT = 20
ApiParserLexerSTRING = 21
ApiParserLexerRAW_STRING = 22
ApiParserLexerLINE_VALUE = 23
ApiParserLexerID = 24
)
const COMEMNTS = 88

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,615 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 1
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
func (s *SyntaxLitContext) GetParser() antlr.Parser { return s.parser }
func (s *SyntaxLitContext) GetSyntaxToken() antlr.Token { return s.syntaxToken }
func (s *SyntaxLitContext) GetAssign() antlr.Token { return s.assign }
func (s *SyntaxLitContext) GetVersion() antlr.Token { return s.version }
func (s *SyntaxLitContext) SetSyntaxToken(v antlr.Token) { s.syntaxToken = v }
func (s *SyntaxLitContext) SetAssign(v antlr.Token) { s.assign = v }
func (s *SyntaxLitContext) SetVersion(v antlr.Token) { s.version = v }
func (s *SyntaxLitContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *SyntaxLitContext) STRING() antlr.TerminalNode {
return s.GetToken(ApiParserParserSTRING, 0)
}
func (s *SyntaxLitContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *SyntaxLitContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *SyntaxLitContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitSyntaxLit(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) SyntaxLit() (localctx ISyntaxLitContext) {
localctx = NewSyntaxLitContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 4, ApiParserParserRULE_syntaxLit)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "syntax")
{
p.SetState(88)
_m := p.Match(ApiParserParserID)
localctx.(*SyntaxLitContext).syntaxToken = _m
}
{
p.SetState(89)
_m := p.Match(ApiParserParserT__0)
localctx.(*SyntaxLitContext).assign = _m
}
checkVersion(p)
{
p.SetState(91)
_m := p.Match(ApiParserParserSTRING)
localctx.(*SyntaxLitContext).version = _m
}
return localctx
}
// IImportSpecContext is an interface to support dynamic dispatch.
type IImportSpecContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsImportSpecContext differentiates from other interfaces.
IsImportSpecContext()
}
type ImportSpecContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyImportSpecContext() *ImportSpecContext {
p := new(ImportSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_importSpec
return p
}
func (*ImportSpecContext) IsImportSpecContext() {}
func NewImportSpecContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ImportSpecContext {
p := new(ImportSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_importSpec
return p
}
func (s *ImportSpecContext) GetParser() antlr.Parser { return s.parser }
func (s *ImportSpecContext) ImportLit() IImportLitContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IImportLitContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IImportLitContext)
}
func (s *ImportSpecContext) ImportBlock() IImportBlockContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IImportBlockContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IImportBlockContext)
}
func (s *ImportSpecContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ImportSpecContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ImportSpecContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitImportSpec(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ImportSpec() (localctx IImportSpecContext) {
localctx = NewImportSpecContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 6, ApiParserParserRULE_importSpec)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.SetState(95)
p.GetErrorHandler().Sync(p)
switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 2, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(93)
p.ImportLit()
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(94)
p.ImportBlock()
}
}
return localctx
}
// IImportLitContext is an interface to support dynamic dispatch.
type IImportLitContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetImportToken returns the importToken token.
GetImportToken() antlr.Token
// SetImportToken sets the importToken token.
SetImportToken(antlr.Token)
// IsImportLitContext differentiates from other interfaces.
IsImportLitContext()
}
type ImportLitContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
importToken antlr.Token
}
func NewEmptyImportLitContext() *ImportLitContext {
p := new(ImportLitContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_importLit
return p
}
func (*ImportLitContext) IsImportLitContext() {}
func NewImportLitContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ImportLitContext {
p := new(ImportLitContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_importLit
return p
}
func (s *ImportLitContext) GetParser() antlr.Parser { return s.parser }
func (s *ImportLitContext) GetImportToken() antlr.Token { return s.importToken }
func (s *ImportLitContext) SetImportToken(v antlr.Token) { s.importToken = v }
func (s *ImportLitContext) ImportValue() IImportValueContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IImportValueContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IImportValueContext)
}
func (s *ImportLitContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *ImportLitContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ImportLitContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ImportLitContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitImportLit(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ImportLit() (localctx IImportLitContext) {
localctx = NewImportLitContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 8, ApiParserParserRULE_importLit)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "import")
{
p.SetState(98)
_m := p.Match(ApiParserParserID)
localctx.(*ImportLitContext).importToken = _m
}
{
p.SetState(99)
p.ImportValue()
}
return localctx
}
// IImportBlockContext is an interface to support dynamic dispatch.
type IImportBlockContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetImportToken returns the importToken token.
GetImportToken() antlr.Token
// SetImportToken sets the importToken token.
SetImportToken(antlr.Token)
// IsImportBlockContext differentiates from other interfaces.
IsImportBlockContext()
}
type ImportBlockContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
importToken antlr.Token
}
func NewEmptyImportBlockContext() *ImportBlockContext {
p := new(ImportBlockContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_importBlock
return p
}
func (*ImportBlockContext) IsImportBlockContext() {}
func NewImportBlockContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ImportBlockContext {
p := new(ImportBlockContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_importBlock
return p
}
func (s *ImportBlockContext) GetParser() antlr.Parser { return s.parser }
func (s *ImportBlockContext) GetImportToken() antlr.Token { return s.importToken }
func (s *ImportBlockContext) SetImportToken(v antlr.Token) { s.importToken = v }
func (s *ImportBlockContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *ImportBlockContext) AllImportBlockValue() []IImportBlockValueContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*IImportBlockValueContext)(nil)).Elem())
tst := make([]IImportBlockValueContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(IImportBlockValueContext)
}
}
return tst
}
func (s *ImportBlockContext) ImportBlockValue(i int) IImportBlockValueContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IImportBlockValueContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(IImportBlockValueContext)
}
func (s *ImportBlockContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ImportBlockContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ImportBlockContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitImportBlock(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ImportBlock() (localctx IImportBlockContext) {
localctx = NewImportBlockContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 10, ApiParserParserRULE_importBlock)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "import")
{
p.SetState(102)
_m := p.Match(ApiParserParserID)
localctx.(*ImportBlockContext).importToken = _m
}
{
p.SetState(103)
p.Match(ApiParserParserT__1)
}
p.SetState(105)
p.GetErrorHandler().Sync(p)
for ok := true; ok; ok = _la == ApiParserParserSTRING {
{
p.SetState(104)
p.ImportBlockValue()
}
p.SetState(107)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(109)
p.Match(ApiParserParserT__2)
}
return localctx
}
// IImportBlockValueContext is an interface to support dynamic dispatch.
type IImportBlockValueContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsImportBlockValueContext differentiates from other interfaces.
IsImportBlockValueContext()
}
type ImportBlockValueContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyImportBlockValueContext() *ImportBlockValueContext {
p := new(ImportBlockValueContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_importBlockValue
return p
}
func (*ImportBlockValueContext) IsImportBlockValueContext() {}
func NewImportBlockValueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ImportBlockValueContext {
p := new(ImportBlockValueContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_importBlockValue
return p
}
func (s *ImportBlockValueContext) GetParser() antlr.Parser { return s.parser }
func (s *ImportBlockValueContext) ImportValue() IImportValueContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IImportValueContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IImportValueContext)
}
func (s *ImportBlockValueContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ImportBlockValueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ImportBlockValueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitImportBlockValue(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ImportBlockValue() (localctx IImportBlockValueContext) {
localctx = NewImportBlockValueContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 12, ApiParserParserRULE_importBlockValue)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(111)
p.ImportValue()
}
return localctx
}
// IImportValueContext is an interface to support dynamic dispatch.
type IImportValueContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsImportValueContext differentiates from other interfaces.
IsImportValueContext()
}
type ImportValueContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyImportValueContext() *ImportValueContext {
p := new(ImportValueContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_importValue
return p
}
func (*ImportValueContext) IsImportValueContext() {}
func NewImportValueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ImportValueContext {
p := new(ImportValueContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_importValue
return p
}

View File

@@ -0,0 +1,656 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 2
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
func (s *ImportValueContext) GetParser() antlr.Parser { return s.parser }
func (s *ImportValueContext) STRING() antlr.TerminalNode {
return s.GetToken(ApiParserParserSTRING, 0)
}
func (s *ImportValueContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ImportValueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ImportValueContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitImportValue(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ImportValue() (localctx IImportValueContext) {
localctx = NewImportValueContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 14, ApiParserParserRULE_importValue)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
checkImportValue(p)
{
p.SetState(114)
p.Match(ApiParserParserSTRING)
}
return localctx
}
// IInfoSpecContext is an interface to support dynamic dispatch.
type IInfoSpecContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetInfoToken returns the infoToken token.
GetInfoToken() antlr.Token
// GetLp returns the lp token.
GetLp() antlr.Token
// GetRp returns the rp token.
GetRp() antlr.Token
// SetInfoToken sets the infoToken token.
SetInfoToken(antlr.Token)
// SetLp sets the lp token.
SetLp(antlr.Token)
// SetRp sets the rp token.
SetRp(antlr.Token)
// IsInfoSpecContext differentiates from other interfaces.
IsInfoSpecContext()
}
type InfoSpecContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
infoToken antlr.Token
lp antlr.Token
rp antlr.Token
}
func NewEmptyInfoSpecContext() *InfoSpecContext {
p := new(InfoSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_infoSpec
return p
}
func (*InfoSpecContext) IsInfoSpecContext() {}
func NewInfoSpecContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *InfoSpecContext {
p := new(InfoSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_infoSpec
return p
}
func (s *InfoSpecContext) GetParser() antlr.Parser { return s.parser }
func (s *InfoSpecContext) GetInfoToken() antlr.Token { return s.infoToken }
func (s *InfoSpecContext) GetLp() antlr.Token { return s.lp }
func (s *InfoSpecContext) GetRp() antlr.Token { return s.rp }
func (s *InfoSpecContext) SetInfoToken(v antlr.Token) { s.infoToken = v }
func (s *InfoSpecContext) SetLp(v antlr.Token) { s.lp = v }
func (s *InfoSpecContext) SetRp(v antlr.Token) { s.rp = v }
func (s *InfoSpecContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *InfoSpecContext) AllKvLit() []IKvLitContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*IKvLitContext)(nil)).Elem())
tst := make([]IKvLitContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(IKvLitContext)
}
}
return tst
}
func (s *InfoSpecContext) KvLit(i int) IKvLitContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IKvLitContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(IKvLitContext)
}
func (s *InfoSpecContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *InfoSpecContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *InfoSpecContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitInfoSpec(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) InfoSpec() (localctx IInfoSpecContext) {
localctx = NewInfoSpecContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 16, ApiParserParserRULE_infoSpec)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "info")
{
p.SetState(117)
_m := p.Match(ApiParserParserID)
localctx.(*InfoSpecContext).infoToken = _m
}
{
p.SetState(118)
_m := p.Match(ApiParserParserT__1)
localctx.(*InfoSpecContext).lp = _m
}
p.SetState(120)
p.GetErrorHandler().Sync(p)
for ok := true; ok; ok = _la == ApiParserParserID {
{
p.SetState(119)
p.KvLit()
}
p.SetState(122)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(124)
_m := p.Match(ApiParserParserT__2)
localctx.(*InfoSpecContext).rp = _m
}
return localctx
}
// ITypeSpecContext is an interface to support dynamic dispatch.
type ITypeSpecContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsTypeSpecContext differentiates from other interfaces.
IsTypeSpecContext()
}
type TypeSpecContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTypeSpecContext() *TypeSpecContext {
p := new(TypeSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeSpec
return p
}
func (*TypeSpecContext) IsTypeSpecContext() {}
func NewTypeSpecContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeSpecContext {
p := new(TypeSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeSpec
return p
}
func (s *TypeSpecContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeSpecContext) TypeLit() ITypeLitContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeLitContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeLitContext)
}
func (s *TypeSpecContext) TypeBlock() ITypeBlockContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeBlockContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeBlockContext)
}
func (s *TypeSpecContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeSpecContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeSpecContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeSpec(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeSpec() (localctx ITypeSpecContext) {
localctx = NewTypeSpecContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 18, ApiParserParserRULE_typeSpec)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.SetState(128)
p.GetErrorHandler().Sync(p)
switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 5, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(126)
p.TypeLit()
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(127)
p.TypeBlock()
}
}
return localctx
}
// ITypeLitContext is an interface to support dynamic dispatch.
type ITypeLitContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetTypeToken returns the typeToken token.
GetTypeToken() antlr.Token
// SetTypeToken sets the typeToken token.
SetTypeToken(antlr.Token)
// IsTypeLitContext differentiates from other interfaces.
IsTypeLitContext()
}
type TypeLitContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
typeToken antlr.Token
}
func NewEmptyTypeLitContext() *TypeLitContext {
p := new(TypeLitContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeLit
return p
}
func (*TypeLitContext) IsTypeLitContext() {}
func NewTypeLitContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeLitContext {
p := new(TypeLitContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeLit
return p
}
func (s *TypeLitContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeLitContext) GetTypeToken() antlr.Token { return s.typeToken }
func (s *TypeLitContext) SetTypeToken(v antlr.Token) { s.typeToken = v }
func (s *TypeLitContext) TypeLitBody() ITypeLitBodyContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeLitBodyContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeLitBodyContext)
}
func (s *TypeLitContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *TypeLitContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeLitContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeLitContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeLit(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeLit() (localctx ITypeLitContext) {
localctx = NewTypeLitContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 20, ApiParserParserRULE_typeLit)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "type")
{
p.SetState(131)
_m := p.Match(ApiParserParserID)
localctx.(*TypeLitContext).typeToken = _m
}
{
p.SetState(132)
p.TypeLitBody()
}
return localctx
}
// ITypeBlockContext is an interface to support dynamic dispatch.
type ITypeBlockContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetTypeToken returns the typeToken token.
GetTypeToken() antlr.Token
// GetLp returns the lp token.
GetLp() antlr.Token
// GetRp returns the rp token.
GetRp() antlr.Token
// SetTypeToken sets the typeToken token.
SetTypeToken(antlr.Token)
// SetLp sets the lp token.
SetLp(antlr.Token)
// SetRp sets the rp token.
SetRp(antlr.Token)
// IsTypeBlockContext differentiates from other interfaces.
IsTypeBlockContext()
}
type TypeBlockContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
typeToken antlr.Token
lp antlr.Token
rp antlr.Token
}
func NewEmptyTypeBlockContext() *TypeBlockContext {
p := new(TypeBlockContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeBlock
return p
}
func (*TypeBlockContext) IsTypeBlockContext() {}
func NewTypeBlockContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeBlockContext {
p := new(TypeBlockContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeBlock
return p
}
func (s *TypeBlockContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeBlockContext) GetTypeToken() antlr.Token { return s.typeToken }
func (s *TypeBlockContext) GetLp() antlr.Token { return s.lp }
func (s *TypeBlockContext) GetRp() antlr.Token { return s.rp }
func (s *TypeBlockContext) SetTypeToken(v antlr.Token) { s.typeToken = v }
func (s *TypeBlockContext) SetLp(v antlr.Token) { s.lp = v }
func (s *TypeBlockContext) SetRp(v antlr.Token) { s.rp = v }
func (s *TypeBlockContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *TypeBlockContext) AllTypeBlockBody() []ITypeBlockBodyContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*ITypeBlockBodyContext)(nil)).Elem())
tst := make([]ITypeBlockBodyContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(ITypeBlockBodyContext)
}
}
return tst
}
func (s *TypeBlockContext) TypeBlockBody(i int) ITypeBlockBodyContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeBlockBodyContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(ITypeBlockBodyContext)
}
func (s *TypeBlockContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeBlockContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeBlockContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeBlock(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeBlock() (localctx ITypeBlockContext) {
localctx = NewTypeBlockContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 22, ApiParserParserRULE_typeBlock)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "type")
{
p.SetState(135)
_m := p.Match(ApiParserParserID)
localctx.(*TypeBlockContext).typeToken = _m
}
{
p.SetState(136)
_m := p.Match(ApiParserParserT__1)
localctx.(*TypeBlockContext).lp = _m
}
p.SetState(140)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
for _la == ApiParserParserID {
{
p.SetState(137)
p.TypeBlockBody()
}
p.SetState(142)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(143)
_m := p.Match(ApiParserParserT__2)
localctx.(*TypeBlockContext).rp = _m
}
return localctx
}

View File

@@ -0,0 +1,634 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 3
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
// ITypeLitBodyContext is an interface to support dynamic dispatch.
type ITypeLitBodyContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsTypeLitBodyContext differentiates from other interfaces.
IsTypeLitBodyContext()
}
type TypeLitBodyContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTypeLitBodyContext() *TypeLitBodyContext {
p := new(TypeLitBodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeLitBody
return p
}
func (*TypeLitBodyContext) IsTypeLitBodyContext() {}
func NewTypeLitBodyContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeLitBodyContext {
p := new(TypeLitBodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeLitBody
return p
}
func (s *TypeLitBodyContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeLitBodyContext) TypeStruct() ITypeStructContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeStructContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeStructContext)
}
func (s *TypeLitBodyContext) TypeAlias() ITypeAliasContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeAliasContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeAliasContext)
}
func (s *TypeLitBodyContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeLitBodyContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeLitBodyContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeLitBody(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeLitBody() (localctx ITypeLitBodyContext) {
localctx = NewTypeLitBodyContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 24, ApiParserParserRULE_typeLitBody)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.SetState(147)
p.GetErrorHandler().Sync(p)
switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 7, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(145)
p.TypeStruct()
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(146)
p.TypeAlias()
}
}
return localctx
}
// ITypeBlockBodyContext is an interface to support dynamic dispatch.
type ITypeBlockBodyContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsTypeBlockBodyContext differentiates from other interfaces.
IsTypeBlockBodyContext()
}
type TypeBlockBodyContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyTypeBlockBodyContext() *TypeBlockBodyContext {
p := new(TypeBlockBodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeBlockBody
return p
}
func (*TypeBlockBodyContext) IsTypeBlockBodyContext() {}
func NewTypeBlockBodyContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeBlockBodyContext {
p := new(TypeBlockBodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeBlockBody
return p
}
func (s *TypeBlockBodyContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeBlockBodyContext) TypeBlockStruct() ITypeBlockStructContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeBlockStructContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeBlockStructContext)
}
func (s *TypeBlockBodyContext) TypeBlockAlias() ITypeBlockAliasContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeBlockAliasContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeBlockAliasContext)
}
func (s *TypeBlockBodyContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeBlockBodyContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeBlockBodyContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeBlockBody(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeBlockBody() (localctx ITypeBlockBodyContext) {
localctx = NewTypeBlockBodyContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 26, ApiParserParserRULE_typeBlockBody)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.SetState(151)
p.GetErrorHandler().Sync(p)
switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 8, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
{
p.SetState(149)
p.TypeBlockStruct()
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(150)
p.TypeBlockAlias()
}
}
return localctx
}
// ITypeStructContext is an interface to support dynamic dispatch.
type ITypeStructContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetStructName returns the structName token.
GetStructName() antlr.Token
// GetStructToken returns the structToken token.
GetStructToken() antlr.Token
// GetLbrace returns the lbrace token.
GetLbrace() antlr.Token
// GetRbrace returns the rbrace token.
GetRbrace() antlr.Token
// SetStructName sets the structName token.
SetStructName(antlr.Token)
// SetStructToken sets the structToken token.
SetStructToken(antlr.Token)
// SetLbrace sets the lbrace token.
SetLbrace(antlr.Token)
// SetRbrace sets the rbrace token.
SetRbrace(antlr.Token)
// IsTypeStructContext differentiates from other interfaces.
IsTypeStructContext()
}
type TypeStructContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
structName antlr.Token
structToken antlr.Token
lbrace antlr.Token
rbrace antlr.Token
}
func NewEmptyTypeStructContext() *TypeStructContext {
p := new(TypeStructContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeStruct
return p
}
func (*TypeStructContext) IsTypeStructContext() {}
func NewTypeStructContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeStructContext {
p := new(TypeStructContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeStruct
return p
}
func (s *TypeStructContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeStructContext) GetStructName() antlr.Token { return s.structName }
func (s *TypeStructContext) GetStructToken() antlr.Token { return s.structToken }
func (s *TypeStructContext) GetLbrace() antlr.Token { return s.lbrace }
func (s *TypeStructContext) GetRbrace() antlr.Token { return s.rbrace }
func (s *TypeStructContext) SetStructName(v antlr.Token) { s.structName = v }
func (s *TypeStructContext) SetStructToken(v antlr.Token) { s.structToken = v }
func (s *TypeStructContext) SetLbrace(v antlr.Token) { s.lbrace = v }
func (s *TypeStructContext) SetRbrace(v antlr.Token) { s.rbrace = v }
func (s *TypeStructContext) AllID() []antlr.TerminalNode {
return s.GetTokens(ApiParserParserID)
}
func (s *TypeStructContext) ID(i int) antlr.TerminalNode {
return s.GetToken(ApiParserParserID, i)
}
func (s *TypeStructContext) AllField() []IFieldContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*IFieldContext)(nil)).Elem())
tst := make([]IFieldContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(IFieldContext)
}
}
return tst
}
func (s *TypeStructContext) Field(i int) IFieldContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IFieldContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(IFieldContext)
}
func (s *TypeStructContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeStructContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeStructContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeStruct(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeStruct() (localctx ITypeStructContext) {
localctx = NewTypeStructContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 28, ApiParserParserRULE_typeStruct)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
var _alt int
p.EnterOuterAlt(localctx, 1)
checkKeyword(p)
{
p.SetState(154)
_m := p.Match(ApiParserParserID)
localctx.(*TypeStructContext).structName = _m
}
p.SetState(156)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserID {
{
p.SetState(155)
_m := p.Match(ApiParserParserID)
localctx.(*TypeStructContext).structToken = _m
}
}
{
p.SetState(158)
_m := p.Match(ApiParserParserT__3)
localctx.(*TypeStructContext).lbrace = _m
}
p.SetState(162)
p.GetErrorHandler().Sync(p)
_alt = p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 10, p.GetParserRuleContext())
for _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
if _alt == 1 {
{
p.SetState(159)
p.Field()
}
}
p.SetState(164)
p.GetErrorHandler().Sync(p)
_alt = p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 10, p.GetParserRuleContext())
}
{
p.SetState(165)
_m := p.Match(ApiParserParserT__4)
localctx.(*TypeStructContext).rbrace = _m
}
return localctx
}
// ITypeAliasContext is an interface to support dynamic dispatch.
type ITypeAliasContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetAlias returns the alias token.
GetAlias() antlr.Token
// GetAssign returns the assign token.
GetAssign() antlr.Token
// SetAlias sets the alias token.
SetAlias(antlr.Token)
// SetAssign sets the assign token.
SetAssign(antlr.Token)
// IsTypeAliasContext differentiates from other interfaces.
IsTypeAliasContext()
}
type TypeAliasContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
alias antlr.Token
assign antlr.Token
}
func NewEmptyTypeAliasContext() *TypeAliasContext {
p := new(TypeAliasContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeAlias
return p
}
func (*TypeAliasContext) IsTypeAliasContext() {}
func NewTypeAliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeAliasContext {
p := new(TypeAliasContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeAlias
return p
}
func (s *TypeAliasContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeAliasContext) GetAlias() antlr.Token { return s.alias }
func (s *TypeAliasContext) GetAssign() antlr.Token { return s.assign }
func (s *TypeAliasContext) SetAlias(v antlr.Token) { s.alias = v }
func (s *TypeAliasContext) SetAssign(v antlr.Token) { s.assign = v }
func (s *TypeAliasContext) DataType() IDataTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IDataTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IDataTypeContext)
}
func (s *TypeAliasContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *TypeAliasContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeAliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeAliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeAlias(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeAlias() (localctx ITypeAliasContext) {
localctx = NewTypeAliasContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 30, ApiParserParserRULE_typeAlias)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
checkKeyword(p)
{
p.SetState(168)
_m := p.Match(ApiParserParserID)
localctx.(*TypeAliasContext).alias = _m
}
p.SetState(170)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__0 {
{
p.SetState(169)
_m := p.Match(ApiParserParserT__0)
localctx.(*TypeAliasContext).assign = _m
}
}
{
p.SetState(172)
p.DataType()
}
return localctx
}
// ITypeBlockStructContext is an interface to support dynamic dispatch.
type ITypeBlockStructContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetStructName returns the structName token.
GetStructName() antlr.Token
// GetStructToken returns the structToken token.
GetStructToken() antlr.Token
// GetLbrace returns the lbrace token.
GetLbrace() antlr.Token
// GetRbrace returns the rbrace token.
GetRbrace() antlr.Token
// SetStructName sets the structName token.
SetStructName(antlr.Token)
// SetStructToken sets the structToken token.
SetStructToken(antlr.Token)
// SetLbrace sets the lbrace token.
SetLbrace(antlr.Token)
// SetRbrace sets the rbrace token.
SetRbrace(antlr.Token)
// IsTypeBlockStructContext differentiates from other interfaces.
IsTypeBlockStructContext()
}

View File

@@ -0,0 +1,613 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 4
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
type TypeBlockStructContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
structName antlr.Token
structToken antlr.Token
lbrace antlr.Token
rbrace antlr.Token
}
func NewEmptyTypeBlockStructContext() *TypeBlockStructContext {
p := new(TypeBlockStructContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeBlockStruct
return p
}
func (*TypeBlockStructContext) IsTypeBlockStructContext() {}
func NewTypeBlockStructContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeBlockStructContext {
p := new(TypeBlockStructContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeBlockStruct
return p
}
func (s *TypeBlockStructContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeBlockStructContext) GetStructName() antlr.Token { return s.structName }
func (s *TypeBlockStructContext) GetStructToken() antlr.Token { return s.structToken }
func (s *TypeBlockStructContext) GetLbrace() antlr.Token { return s.lbrace }
func (s *TypeBlockStructContext) GetRbrace() antlr.Token { return s.rbrace }
func (s *TypeBlockStructContext) SetStructName(v antlr.Token) { s.structName = v }
func (s *TypeBlockStructContext) SetStructToken(v antlr.Token) { s.structToken = v }
func (s *TypeBlockStructContext) SetLbrace(v antlr.Token) { s.lbrace = v }
func (s *TypeBlockStructContext) SetRbrace(v antlr.Token) { s.rbrace = v }
func (s *TypeBlockStructContext) AllID() []antlr.TerminalNode {
return s.GetTokens(ApiParserParserID)
}
func (s *TypeBlockStructContext) ID(i int) antlr.TerminalNode {
return s.GetToken(ApiParserParserID, i)
}
func (s *TypeBlockStructContext) AllField() []IFieldContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*IFieldContext)(nil)).Elem())
tst := make([]IFieldContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(IFieldContext)
}
}
return tst
}
func (s *TypeBlockStructContext) Field(i int) IFieldContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IFieldContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(IFieldContext)
}
func (s *TypeBlockStructContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeBlockStructContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeBlockStructContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeBlockStruct(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeBlockStruct() (localctx ITypeBlockStructContext) {
localctx = NewTypeBlockStructContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 32, ApiParserParserRULE_typeBlockStruct)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
var _alt int
p.EnterOuterAlt(localctx, 1)
checkKeyword(p)
{
p.SetState(175)
_m := p.Match(ApiParserParserID)
localctx.(*TypeBlockStructContext).structName = _m
}
p.SetState(177)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserID {
{
p.SetState(176)
_m := p.Match(ApiParserParserID)
localctx.(*TypeBlockStructContext).structToken = _m
}
}
{
p.SetState(179)
_m := p.Match(ApiParserParserT__3)
localctx.(*TypeBlockStructContext).lbrace = _m
}
p.SetState(183)
p.GetErrorHandler().Sync(p)
_alt = p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 13, p.GetParserRuleContext())
for _alt != 2 && _alt != antlr.ATNInvalidAltNumber {
if _alt == 1 {
{
p.SetState(180)
p.Field()
}
}
p.SetState(185)
p.GetErrorHandler().Sync(p)
_alt = p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 13, p.GetParserRuleContext())
}
{
p.SetState(186)
_m := p.Match(ApiParserParserT__4)
localctx.(*TypeBlockStructContext).rbrace = _m
}
return localctx
}
// ITypeBlockAliasContext is an interface to support dynamic dispatch.
type ITypeBlockAliasContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetAlias returns the alias token.
GetAlias() antlr.Token
// GetAssign returns the assign token.
GetAssign() antlr.Token
// SetAlias sets the alias token.
SetAlias(antlr.Token)
// SetAssign sets the assign token.
SetAssign(antlr.Token)
// IsTypeBlockAliasContext differentiates from other interfaces.
IsTypeBlockAliasContext()
}
type TypeBlockAliasContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
alias antlr.Token
assign antlr.Token
}
func NewEmptyTypeBlockAliasContext() *TypeBlockAliasContext {
p := new(TypeBlockAliasContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_typeBlockAlias
return p
}
func (*TypeBlockAliasContext) IsTypeBlockAliasContext() {}
func NewTypeBlockAliasContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *TypeBlockAliasContext {
p := new(TypeBlockAliasContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_typeBlockAlias
return p
}
func (s *TypeBlockAliasContext) GetParser() antlr.Parser { return s.parser }
func (s *TypeBlockAliasContext) GetAlias() antlr.Token { return s.alias }
func (s *TypeBlockAliasContext) GetAssign() antlr.Token { return s.assign }
func (s *TypeBlockAliasContext) SetAlias(v antlr.Token) { s.alias = v }
func (s *TypeBlockAliasContext) SetAssign(v antlr.Token) { s.assign = v }
func (s *TypeBlockAliasContext) DataType() IDataTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IDataTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IDataTypeContext)
}
func (s *TypeBlockAliasContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *TypeBlockAliasContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *TypeBlockAliasContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *TypeBlockAliasContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitTypeBlockAlias(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) TypeBlockAlias() (localctx ITypeBlockAliasContext) {
localctx = NewTypeBlockAliasContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 34, ApiParserParserRULE_typeBlockAlias)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
checkKeyword(p)
{
p.SetState(189)
_m := p.Match(ApiParserParserID)
localctx.(*TypeBlockAliasContext).alias = _m
}
p.SetState(191)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__0 {
{
p.SetState(190)
_m := p.Match(ApiParserParserT__0)
localctx.(*TypeBlockAliasContext).assign = _m
}
}
{
p.SetState(193)
p.DataType()
}
return localctx
}
// IFieldContext is an interface to support dynamic dispatch.
type IFieldContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsFieldContext differentiates from other interfaces.
IsFieldContext()
}
type FieldContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyFieldContext() *FieldContext {
p := new(FieldContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_field
return p
}
func (*FieldContext) IsFieldContext() {}
func NewFieldContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *FieldContext {
p := new(FieldContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_field
return p
}
func (s *FieldContext) GetParser() antlr.Parser { return s.parser }
func (s *FieldContext) NormalField() INormalFieldContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*INormalFieldContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(INormalFieldContext)
}
func (s *FieldContext) AnonymousFiled() IAnonymousFiledContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IAnonymousFiledContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IAnonymousFiledContext)
}
func (s *FieldContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *FieldContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *FieldContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitField(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) Field() (localctx IFieldContext) {
localctx = NewFieldContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 36, ApiParserParserRULE_field)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.SetState(198)
p.GetErrorHandler().Sync(p)
switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 15, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
p.SetState(195)
if !(isNormal(p)) {
panic(antlr.NewFailedPredicateException(p, "isNormal(p)", ""))
}
{
p.SetState(196)
p.NormalField()
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(197)
p.AnonymousFiled()
}
}
return localctx
}
// INormalFieldContext is an interface to support dynamic dispatch.
type INormalFieldContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetFieldName returns the fieldName token.
GetFieldName() antlr.Token
// GetTag returns the tag token.
GetTag() antlr.Token
// SetFieldName sets the fieldName token.
SetFieldName(antlr.Token)
// SetTag sets the tag token.
SetTag(antlr.Token)
// IsNormalFieldContext differentiates from other interfaces.
IsNormalFieldContext()
}
type NormalFieldContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
fieldName antlr.Token
tag antlr.Token
}
func NewEmptyNormalFieldContext() *NormalFieldContext {
p := new(NormalFieldContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_normalField
return p
}
func (*NormalFieldContext) IsNormalFieldContext() {}
func NewNormalFieldContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *NormalFieldContext {
p := new(NormalFieldContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_normalField
return p
}
func (s *NormalFieldContext) GetParser() antlr.Parser { return s.parser }
func (s *NormalFieldContext) GetFieldName() antlr.Token { return s.fieldName }
func (s *NormalFieldContext) GetTag() antlr.Token { return s.tag }
func (s *NormalFieldContext) SetFieldName(v antlr.Token) { s.fieldName = v }
func (s *NormalFieldContext) SetTag(v antlr.Token) { s.tag = v }
func (s *NormalFieldContext) DataType() IDataTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IDataTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IDataTypeContext)
}
func (s *NormalFieldContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *NormalFieldContext) RAW_STRING() antlr.TerminalNode {
return s.GetToken(ApiParserParserRAW_STRING, 0)
}
func (s *NormalFieldContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *NormalFieldContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *NormalFieldContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitNormalField(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) NormalField() (localctx INormalFieldContext) {
localctx = NewNormalFieldContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 38, ApiParserParserRULE_normalField)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
checkKeyword(p)
{
p.SetState(201)
_m := p.Match(ApiParserParserID)
localctx.(*NormalFieldContext).fieldName = _m
}
{
p.SetState(202)
p.DataType()
}
p.SetState(204)
p.GetErrorHandler().Sync(p)
if p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 16, p.GetParserRuleContext()) == 1 {
{
p.SetState(203)
_m := p.Match(ApiParserParserRAW_STRING)
localctx.(*NormalFieldContext).tag = _m
}
}
return localctx
}
// IAnonymousFiledContext is an interface to support dynamic dispatch.
type IAnonymousFiledContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetStar returns the star token.
GetStar() antlr.Token
// SetStar sets the star token.
SetStar(antlr.Token)
// IsAnonymousFiledContext differentiates from other interfaces.
IsAnonymousFiledContext()
}

View File

@@ -0,0 +1,617 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 5
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
type AnonymousFiledContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
star antlr.Token
}
func NewEmptyAnonymousFiledContext() *AnonymousFiledContext {
p := new(AnonymousFiledContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_anonymousFiled
return p
}
func (*AnonymousFiledContext) IsAnonymousFiledContext() {}
func NewAnonymousFiledContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AnonymousFiledContext {
p := new(AnonymousFiledContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_anonymousFiled
return p
}
func (s *AnonymousFiledContext) GetParser() antlr.Parser { return s.parser }
func (s *AnonymousFiledContext) GetStar() antlr.Token { return s.star }
func (s *AnonymousFiledContext) SetStar(v antlr.Token) { s.star = v }
func (s *AnonymousFiledContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *AnonymousFiledContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *AnonymousFiledContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *AnonymousFiledContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitAnonymousFiled(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) AnonymousFiled() (localctx IAnonymousFiledContext) {
localctx = NewAnonymousFiledContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 40, ApiParserParserRULE_anonymousFiled)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
p.SetState(207)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__5 {
{
p.SetState(206)
_m := p.Match(ApiParserParserT__5)
localctx.(*AnonymousFiledContext).star = _m
}
}
{
p.SetState(209)
p.Match(ApiParserParserID)
}
return localctx
}
// IDataTypeContext is an interface to support dynamic dispatch.
type IDataTypeContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetInter returns the inter token.
GetInter() antlr.Token
// GetTime returns the time token.
GetTime() antlr.Token
// SetInter sets the inter token.
SetInter(antlr.Token)
// SetTime sets the time token.
SetTime(antlr.Token)
// IsDataTypeContext differentiates from other interfaces.
IsDataTypeContext()
}
type DataTypeContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
inter antlr.Token
time antlr.Token
}
func NewEmptyDataTypeContext() *DataTypeContext {
p := new(DataTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_dataType
return p
}
func (*DataTypeContext) IsDataTypeContext() {}
func NewDataTypeContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *DataTypeContext {
p := new(DataTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_dataType
return p
}
func (s *DataTypeContext) GetParser() antlr.Parser { return s.parser }
func (s *DataTypeContext) GetInter() antlr.Token { return s.inter }
func (s *DataTypeContext) GetTime() antlr.Token { return s.time }
func (s *DataTypeContext) SetInter(v antlr.Token) { s.inter = v }
func (s *DataTypeContext) SetTime(v antlr.Token) { s.time = v }
func (s *DataTypeContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *DataTypeContext) MapType() IMapTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IMapTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IMapTypeContext)
}
func (s *DataTypeContext) ArrayType() IArrayTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IArrayTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IArrayTypeContext)
}
func (s *DataTypeContext) INTERFACE() antlr.TerminalNode {
return s.GetToken(ApiParserParserINTERFACE, 0)
}
func (s *DataTypeContext) PointerType() IPointerTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IPointerTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IPointerTypeContext)
}
func (s *DataTypeContext) TypeStruct() ITypeStructContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*ITypeStructContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(ITypeStructContext)
}
func (s *DataTypeContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *DataTypeContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *DataTypeContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitDataType(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) DataType() (localctx IDataTypeContext) {
localctx = NewDataTypeContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 42, ApiParserParserRULE_dataType)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.SetState(219)
p.GetErrorHandler().Sync(p)
switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 18, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
isInterface(p)
{
p.SetState(212)
p.Match(ApiParserParserID)
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(213)
p.MapType()
}
case 3:
p.EnterOuterAlt(localctx, 3)
{
p.SetState(214)
p.ArrayType()
}
case 4:
p.EnterOuterAlt(localctx, 4)
{
p.SetState(215)
_m := p.Match(ApiParserParserINTERFACE)
localctx.(*DataTypeContext).inter = _m
}
case 5:
p.EnterOuterAlt(localctx, 5)
{
p.SetState(216)
_m := p.Match(ApiParserParserT__6)
localctx.(*DataTypeContext).time = _m
}
case 6:
p.EnterOuterAlt(localctx, 6)
{
p.SetState(217)
p.PointerType()
}
case 7:
p.EnterOuterAlt(localctx, 7)
{
p.SetState(218)
p.TypeStruct()
}
}
return localctx
}
// IPointerTypeContext is an interface to support dynamic dispatch.
type IPointerTypeContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetStar returns the star token.
GetStar() antlr.Token
// SetStar sets the star token.
SetStar(antlr.Token)
// IsPointerTypeContext differentiates from other interfaces.
IsPointerTypeContext()
}
type PointerTypeContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
star antlr.Token
}
func NewEmptyPointerTypeContext() *PointerTypeContext {
p := new(PointerTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_pointerType
return p
}
func (*PointerTypeContext) IsPointerTypeContext() {}
func NewPointerTypeContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *PointerTypeContext {
p := new(PointerTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_pointerType
return p
}
func (s *PointerTypeContext) GetParser() antlr.Parser { return s.parser }
func (s *PointerTypeContext) GetStar() antlr.Token { return s.star }
func (s *PointerTypeContext) SetStar(v antlr.Token) { s.star = v }
func (s *PointerTypeContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *PointerTypeContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *PointerTypeContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *PointerTypeContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitPointerType(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) PointerType() (localctx IPointerTypeContext) {
localctx = NewPointerTypeContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 44, ApiParserParserRULE_pointerType)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(221)
_m := p.Match(ApiParserParserT__5)
localctx.(*PointerTypeContext).star = _m
}
checkKeyword(p)
{
p.SetState(223)
p.Match(ApiParserParserID)
}
return localctx
}
// IMapTypeContext is an interface to support dynamic dispatch.
type IMapTypeContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetMapToken returns the mapToken token.
GetMapToken() antlr.Token
// GetLbrack returns the lbrack token.
GetLbrack() antlr.Token
// GetKey returns the key token.
GetKey() antlr.Token
// GetRbrack returns the rbrack token.
GetRbrack() antlr.Token
// SetMapToken sets the mapToken token.
SetMapToken(antlr.Token)
// SetLbrack sets the lbrack token.
SetLbrack(antlr.Token)
// SetKey sets the key token.
SetKey(antlr.Token)
// SetRbrack sets the rbrack token.
SetRbrack(antlr.Token)
// GetValue returns the value rule contexts.
GetValue() IDataTypeContext
// SetValue sets the value rule contexts.
SetValue(IDataTypeContext)
// IsMapTypeContext differentiates from other interfaces.
IsMapTypeContext()
}
type MapTypeContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
mapToken antlr.Token
lbrack antlr.Token
key antlr.Token
rbrack antlr.Token
value IDataTypeContext
}
func NewEmptyMapTypeContext() *MapTypeContext {
p := new(MapTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_mapType
return p
}
func (*MapTypeContext) IsMapTypeContext() {}
func NewMapTypeContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *MapTypeContext {
p := new(MapTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_mapType
return p
}
func (s *MapTypeContext) GetParser() antlr.Parser { return s.parser }
func (s *MapTypeContext) GetMapToken() antlr.Token { return s.mapToken }
func (s *MapTypeContext) GetLbrack() antlr.Token { return s.lbrack }
func (s *MapTypeContext) GetKey() antlr.Token { return s.key }
func (s *MapTypeContext) GetRbrack() antlr.Token { return s.rbrack }
func (s *MapTypeContext) SetMapToken(v antlr.Token) { s.mapToken = v }
func (s *MapTypeContext) SetLbrack(v antlr.Token) { s.lbrack = v }
func (s *MapTypeContext) SetKey(v antlr.Token) { s.key = v }
func (s *MapTypeContext) SetRbrack(v antlr.Token) { s.rbrack = v }
func (s *MapTypeContext) GetValue() IDataTypeContext { return s.value }
func (s *MapTypeContext) SetValue(v IDataTypeContext) { s.value = v }
func (s *MapTypeContext) AllID() []antlr.TerminalNode {
return s.GetTokens(ApiParserParserID)
}
func (s *MapTypeContext) ID(i int) antlr.TerminalNode {
return s.GetToken(ApiParserParserID, i)
}
func (s *MapTypeContext) DataType() IDataTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IDataTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IDataTypeContext)
}
func (s *MapTypeContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *MapTypeContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *MapTypeContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitMapType(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) MapType() (localctx IMapTypeContext) {
localctx = NewMapTypeContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 46, ApiParserParserRULE_mapType)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "map")
{
p.SetState(226)
_m := p.Match(ApiParserParserID)
localctx.(*MapTypeContext).mapToken = _m
}
{
p.SetState(227)
_m := p.Match(ApiParserParserT__7)
localctx.(*MapTypeContext).lbrack = _m
}
checkKey(p)
{
p.SetState(229)
_m := p.Match(ApiParserParserID)
localctx.(*MapTypeContext).key = _m
}
{
p.SetState(230)
_m := p.Match(ApiParserParserT__8)
localctx.(*MapTypeContext).rbrack = _m
}
{
p.SetState(231)
_x := p.DataType()
localctx.(*MapTypeContext).value = _x
}
return localctx
}

View File

@@ -0,0 +1,612 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 6
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
// IArrayTypeContext is an interface to support dynamic dispatch.
type IArrayTypeContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetLbrack returns the lbrack token.
GetLbrack() antlr.Token
// GetRbrack returns the rbrack token.
GetRbrack() antlr.Token
// SetLbrack sets the lbrack token.
SetLbrack(antlr.Token)
// SetRbrack sets the rbrack token.
SetRbrack(antlr.Token)
// IsArrayTypeContext differentiates from other interfaces.
IsArrayTypeContext()
}
type ArrayTypeContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
lbrack antlr.Token
rbrack antlr.Token
}
func NewEmptyArrayTypeContext() *ArrayTypeContext {
p := new(ArrayTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_arrayType
return p
}
func (*ArrayTypeContext) IsArrayTypeContext() {}
func NewArrayTypeContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ArrayTypeContext {
p := new(ArrayTypeContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_arrayType
return p
}
func (s *ArrayTypeContext) GetParser() antlr.Parser { return s.parser }
func (s *ArrayTypeContext) GetLbrack() antlr.Token { return s.lbrack }
func (s *ArrayTypeContext) GetRbrack() antlr.Token { return s.rbrack }
func (s *ArrayTypeContext) SetLbrack(v antlr.Token) { s.lbrack = v }
func (s *ArrayTypeContext) SetRbrack(v antlr.Token) { s.rbrack = v }
func (s *ArrayTypeContext) DataType() IDataTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IDataTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IDataTypeContext)
}
func (s *ArrayTypeContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ArrayTypeContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ArrayTypeContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitArrayType(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ArrayType() (localctx IArrayTypeContext) {
localctx = NewArrayTypeContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 48, ApiParserParserRULE_arrayType)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(233)
_m := p.Match(ApiParserParserT__7)
localctx.(*ArrayTypeContext).lbrack = _m
}
{
p.SetState(234)
_m := p.Match(ApiParserParserT__8)
localctx.(*ArrayTypeContext).rbrack = _m
}
{
p.SetState(235)
p.DataType()
}
return localctx
}
// IServiceSpecContext is an interface to support dynamic dispatch.
type IServiceSpecContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsServiceSpecContext differentiates from other interfaces.
IsServiceSpecContext()
}
type ServiceSpecContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyServiceSpecContext() *ServiceSpecContext {
p := new(ServiceSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_serviceSpec
return p
}
func (*ServiceSpecContext) IsServiceSpecContext() {}
func NewServiceSpecContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ServiceSpecContext {
p := new(ServiceSpecContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_serviceSpec
return p
}
func (s *ServiceSpecContext) GetParser() antlr.Parser { return s.parser }
func (s *ServiceSpecContext) ServiceApi() IServiceApiContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IServiceApiContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IServiceApiContext)
}
func (s *ServiceSpecContext) AtServer() IAtServerContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IAtServerContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IAtServerContext)
}
func (s *ServiceSpecContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ServiceSpecContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ServiceSpecContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitServiceSpec(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ServiceSpec() (localctx IServiceSpecContext) {
localctx = NewServiceSpecContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 50, ApiParserParserRULE_serviceSpec)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
p.SetState(238)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserATSERVER {
{
p.SetState(237)
p.AtServer()
}
}
{
p.SetState(240)
p.ServiceApi()
}
return localctx
}
// IAtServerContext is an interface to support dynamic dispatch.
type IAtServerContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetLp returns the lp token.
GetLp() antlr.Token
// GetRp returns the rp token.
GetRp() antlr.Token
// SetLp sets the lp token.
SetLp(antlr.Token)
// SetRp sets the rp token.
SetRp(antlr.Token)
// IsAtServerContext differentiates from other interfaces.
IsAtServerContext()
}
type AtServerContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
lp antlr.Token
rp antlr.Token
}
func NewEmptyAtServerContext() *AtServerContext {
p := new(AtServerContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_atServer
return p
}
func (*AtServerContext) IsAtServerContext() {}
func NewAtServerContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AtServerContext {
p := new(AtServerContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_atServer
return p
}
func (s *AtServerContext) GetParser() antlr.Parser { return s.parser }
func (s *AtServerContext) GetLp() antlr.Token { return s.lp }
func (s *AtServerContext) GetRp() antlr.Token { return s.rp }
func (s *AtServerContext) SetLp(v antlr.Token) { s.lp = v }
func (s *AtServerContext) SetRp(v antlr.Token) { s.rp = v }
func (s *AtServerContext) ATSERVER() antlr.TerminalNode {
return s.GetToken(ApiParserParserATSERVER, 0)
}
func (s *AtServerContext) AllKvLit() []IKvLitContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*IKvLitContext)(nil)).Elem())
tst := make([]IKvLitContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(IKvLitContext)
}
}
return tst
}
func (s *AtServerContext) KvLit(i int) IKvLitContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IKvLitContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(IKvLitContext)
}
func (s *AtServerContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *AtServerContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *AtServerContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitAtServer(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) AtServer() (localctx IAtServerContext) {
localctx = NewAtServerContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 52, ApiParserParserRULE_atServer)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(242)
p.Match(ApiParserParserATSERVER)
}
{
p.SetState(243)
_m := p.Match(ApiParserParserT__1)
localctx.(*AtServerContext).lp = _m
}
p.SetState(245)
p.GetErrorHandler().Sync(p)
for ok := true; ok; ok = _la == ApiParserParserID {
{
p.SetState(244)
p.KvLit()
}
p.SetState(247)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(249)
_m := p.Match(ApiParserParserT__2)
localctx.(*AtServerContext).rp = _m
}
return localctx
}
// IServiceApiContext is an interface to support dynamic dispatch.
type IServiceApiContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetServiceToken returns the serviceToken token.
GetServiceToken() antlr.Token
// GetLbrace returns the lbrace token.
GetLbrace() antlr.Token
// GetRbrace returns the rbrace token.
GetRbrace() antlr.Token
// SetServiceToken sets the serviceToken token.
SetServiceToken(antlr.Token)
// SetLbrace sets the lbrace token.
SetLbrace(antlr.Token)
// SetRbrace sets the rbrace token.
SetRbrace(antlr.Token)
// IsServiceApiContext differentiates from other interfaces.
IsServiceApiContext()
}
type ServiceApiContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
serviceToken antlr.Token
lbrace antlr.Token
rbrace antlr.Token
}
func NewEmptyServiceApiContext() *ServiceApiContext {
p := new(ServiceApiContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_serviceApi
return p
}
func (*ServiceApiContext) IsServiceApiContext() {}
func NewServiceApiContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ServiceApiContext {
p := new(ServiceApiContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_serviceApi
return p
}
func (s *ServiceApiContext) GetParser() antlr.Parser { return s.parser }
func (s *ServiceApiContext) GetServiceToken() antlr.Token { return s.serviceToken }
func (s *ServiceApiContext) GetLbrace() antlr.Token { return s.lbrace }
func (s *ServiceApiContext) GetRbrace() antlr.Token { return s.rbrace }
func (s *ServiceApiContext) SetServiceToken(v antlr.Token) { s.serviceToken = v }
func (s *ServiceApiContext) SetLbrace(v antlr.Token) { s.lbrace = v }
func (s *ServiceApiContext) SetRbrace(v antlr.Token) { s.rbrace = v }
func (s *ServiceApiContext) ServiceName() IServiceNameContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IServiceNameContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IServiceNameContext)
}
func (s *ServiceApiContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *ServiceApiContext) AllServiceRoute() []IServiceRouteContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*IServiceRouteContext)(nil)).Elem())
tst := make([]IServiceRouteContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(IServiceRouteContext)
}
}
return tst
}
func (s *ServiceApiContext) ServiceRoute(i int) IServiceRouteContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IServiceRouteContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(IServiceRouteContext)
}
func (s *ServiceApiContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ServiceApiContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ServiceApiContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitServiceApi(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ServiceApi() (localctx IServiceApiContext) {
localctx = NewServiceApiContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 54, ApiParserParserRULE_serviceApi)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
match(p, "service")
{
p.SetState(252)
_m := p.Match(ApiParserParserID)
localctx.(*ServiceApiContext).serviceToken = _m
}
{
p.SetState(253)
p.ServiceName()
}
{
p.SetState(254)
_m := p.Match(ApiParserParserT__3)
localctx.(*ServiceApiContext).lbrace = _m
}
p.SetState(258)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
for ((_la)&-(0x1f+1)) == 0 && ((1<<uint(_la))&((1<<ApiParserParserATDOC)|(1<<ApiParserParserATHANDLER)|(1<<ApiParserParserATSERVER))) != 0 {
{
p.SetState(255)
p.ServiceRoute()
}
p.SetState(260)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
{
p.SetState(261)
_m := p.Match(ApiParserParserT__4)
localctx.(*ServiceApiContext).rbrace = _m
}
return localctx
}

View File

@@ -0,0 +1,643 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 7
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
// IServiceRouteContext is an interface to support dynamic dispatch.
type IServiceRouteContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsServiceRouteContext differentiates from other interfaces.
IsServiceRouteContext()
}
type ServiceRouteContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyServiceRouteContext() *ServiceRouteContext {
p := new(ServiceRouteContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_serviceRoute
return p
}
func (*ServiceRouteContext) IsServiceRouteContext() {}
func NewServiceRouteContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ServiceRouteContext {
p := new(ServiceRouteContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_serviceRoute
return p
}
func (s *ServiceRouteContext) GetParser() antlr.Parser { return s.parser }
func (s *ServiceRouteContext) Route() IRouteContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IRouteContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IRouteContext)
}
func (s *ServiceRouteContext) AtServer() IAtServerContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IAtServerContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IAtServerContext)
}
func (s *ServiceRouteContext) AtHandler() IAtHandlerContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IAtHandlerContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IAtHandlerContext)
}
func (s *ServiceRouteContext) AtDoc() IAtDocContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IAtDocContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IAtDocContext)
}
func (s *ServiceRouteContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ServiceRouteContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ServiceRouteContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitServiceRoute(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ServiceRoute() (localctx IServiceRouteContext) {
localctx = NewServiceRouteContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 56, ApiParserParserRULE_serviceRoute)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
p.SetState(264)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserATDOC {
{
p.SetState(263)
p.AtDoc()
}
}
p.SetState(268)
p.GetErrorHandler().Sync(p)
switch p.GetTokenStream().LA(1) {
case ApiParserParserATSERVER:
{
p.SetState(266)
p.AtServer()
}
case ApiParserParserATHANDLER:
{
p.SetState(267)
p.AtHandler()
}
default:
panic(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
}
{
p.SetState(270)
p.Route()
}
return localctx
}
// IAtDocContext is an interface to support dynamic dispatch.
type IAtDocContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetLp returns the lp token.
GetLp() antlr.Token
// GetRp returns the rp token.
GetRp() antlr.Token
// SetLp sets the lp token.
SetLp(antlr.Token)
// SetRp sets the rp token.
SetRp(antlr.Token)
// IsAtDocContext differentiates from other interfaces.
IsAtDocContext()
}
type AtDocContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
lp antlr.Token
rp antlr.Token
}
func NewEmptyAtDocContext() *AtDocContext {
p := new(AtDocContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_atDoc
return p
}
func (*AtDocContext) IsAtDocContext() {}
func NewAtDocContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AtDocContext {
p := new(AtDocContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_atDoc
return p
}
func (s *AtDocContext) GetParser() antlr.Parser { return s.parser }
func (s *AtDocContext) GetLp() antlr.Token { return s.lp }
func (s *AtDocContext) GetRp() antlr.Token { return s.rp }
func (s *AtDocContext) SetLp(v antlr.Token) { s.lp = v }
func (s *AtDocContext) SetRp(v antlr.Token) { s.rp = v }
func (s *AtDocContext) ATDOC() antlr.TerminalNode {
return s.GetToken(ApiParserParserATDOC, 0)
}
func (s *AtDocContext) STRING() antlr.TerminalNode {
return s.GetToken(ApiParserParserSTRING, 0)
}
func (s *AtDocContext) AllKvLit() []IKvLitContext {
ts := s.GetTypedRuleContexts(reflect.TypeOf((*IKvLitContext)(nil)).Elem())
tst := make([]IKvLitContext, len(ts))
for i, t := range ts {
if t != nil {
tst[i] = t.(IKvLitContext)
}
}
return tst
}
func (s *AtDocContext) KvLit(i int) IKvLitContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IKvLitContext)(nil)).Elem(), i)
if t == nil {
return nil
}
return t.(IKvLitContext)
}
func (s *AtDocContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *AtDocContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *AtDocContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitAtDoc(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) AtDoc() (localctx IAtDocContext) {
localctx = NewAtDocContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 58, ApiParserParserRULE_atDoc)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(272)
p.Match(ApiParserParserATDOC)
}
p.SetState(274)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__1 {
{
p.SetState(273)
_m := p.Match(ApiParserParserT__1)
localctx.(*AtDocContext).lp = _m
}
}
p.SetState(282)
p.GetErrorHandler().Sync(p)
switch p.GetTokenStream().LA(1) {
case ApiParserParserID:
p.SetState(277)
p.GetErrorHandler().Sync(p)
for ok := true; ok; ok = _la == ApiParserParserID {
{
p.SetState(276)
p.KvLit()
}
p.SetState(279)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
case ApiParserParserSTRING:
{
p.SetState(281)
p.Match(ApiParserParserSTRING)
}
default:
panic(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
}
p.SetState(285)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__2 {
{
p.SetState(284)
_m := p.Match(ApiParserParserT__2)
localctx.(*AtDocContext).rp = _m
}
}
return localctx
}
// IAtHandlerContext is an interface to support dynamic dispatch.
type IAtHandlerContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsAtHandlerContext differentiates from other interfaces.
IsAtHandlerContext()
}
type AtHandlerContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyAtHandlerContext() *AtHandlerContext {
p := new(AtHandlerContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_atHandler
return p
}
func (*AtHandlerContext) IsAtHandlerContext() {}
func NewAtHandlerContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *AtHandlerContext {
p := new(AtHandlerContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_atHandler
return p
}
func (s *AtHandlerContext) GetParser() antlr.Parser { return s.parser }
func (s *AtHandlerContext) ATHANDLER() antlr.TerminalNode {
return s.GetToken(ApiParserParserATHANDLER, 0)
}
func (s *AtHandlerContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *AtHandlerContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *AtHandlerContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *AtHandlerContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitAtHandler(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) AtHandler() (localctx IAtHandlerContext) {
localctx = NewAtHandlerContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 60, ApiParserParserRULE_atHandler)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(287)
p.Match(ApiParserParserATHANDLER)
}
{
p.SetState(288)
p.Match(ApiParserParserID)
}
return localctx
}
// IRouteContext is an interface to support dynamic dispatch.
type IRouteContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetHttpMethod returns the httpMethod token.
GetHttpMethod() antlr.Token
// SetHttpMethod sets the httpMethod token.
SetHttpMethod(antlr.Token)
// GetRequest returns the request rule contexts.
GetRequest() IBodyContext
// GetResponse returns the response rule contexts.
GetResponse() IReplybodyContext
// SetRequest sets the request rule contexts.
SetRequest(IBodyContext)
// SetResponse sets the response rule contexts.
SetResponse(IReplybodyContext)
// IsRouteContext differentiates from other interfaces.
IsRouteContext()
}
type RouteContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
httpMethod antlr.Token
request IBodyContext
response IReplybodyContext
}
func NewEmptyRouteContext() *RouteContext {
p := new(RouteContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_route
return p
}
func (*RouteContext) IsRouteContext() {}
func NewRouteContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *RouteContext {
p := new(RouteContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_route
return p
}
func (s *RouteContext) GetParser() antlr.Parser { return s.parser }
func (s *RouteContext) GetHttpMethod() antlr.Token { return s.httpMethod }
func (s *RouteContext) SetHttpMethod(v antlr.Token) { s.httpMethod = v }
func (s *RouteContext) GetRequest() IBodyContext { return s.request }
func (s *RouteContext) GetResponse() IReplybodyContext { return s.response }
func (s *RouteContext) SetRequest(v IBodyContext) { s.request = v }
func (s *RouteContext) SetResponse(v IReplybodyContext) { s.response = v }
func (s *RouteContext) Path() IPathContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IPathContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IPathContext)
}
func (s *RouteContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *RouteContext) Body() IBodyContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IBodyContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IBodyContext)
}
func (s *RouteContext) Replybody() IReplybodyContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IReplybodyContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IReplybodyContext)
}
func (s *RouteContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *RouteContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *RouteContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitRoute(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) Route() (localctx IRouteContext) {
localctx = NewRouteContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 62, ApiParserParserRULE_route)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
checkHTTPMethod(p)
{
p.SetState(291)
_m := p.Match(ApiParserParserID)
localctx.(*RouteContext).httpMethod = _m
}
{
p.SetState(292)
p.Path()
}
p.SetState(294)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__1 {
{
p.SetState(293)
_x := p.Body()
localctx.(*RouteContext).request = _x
}
}
p.SetState(297)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__9 {
{
p.SetState(296)
_x := p.Replybody()
localctx.(*RouteContext).response = _x
}
}
return localctx
}

View File

@@ -0,0 +1,712 @@
package api
import (
"reflect"
"github.com/zeromicro/antlr"
)
// Part 8
// The apiparser_parser.go file was split into multiple files because it
// was too large and caused a possible memory overflow during goctl installation.
// IBodyContext is an interface to support dynamic dispatch.
type IBodyContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetLp returns the lp token.
GetLp() antlr.Token
// GetRp returns the rp token.
GetRp() antlr.Token
// SetLp sets the lp token.
SetLp(antlr.Token)
// SetRp sets the rp token.
SetRp(antlr.Token)
// IsBodyContext differentiates from other interfaces.
IsBodyContext()
}
type BodyContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
lp antlr.Token
rp antlr.Token
}
func NewEmptyBodyContext() *BodyContext {
p := new(BodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_body
return p
}
func (*BodyContext) IsBodyContext() {}
func NewBodyContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *BodyContext {
p := new(BodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_body
return p
}
func (s *BodyContext) GetParser() antlr.Parser { return s.parser }
func (s *BodyContext) GetLp() antlr.Token { return s.lp }
func (s *BodyContext) GetRp() antlr.Token { return s.rp }
func (s *BodyContext) SetLp(v antlr.Token) { s.lp = v }
func (s *BodyContext) SetRp(v antlr.Token) { s.rp = v }
func (s *BodyContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *BodyContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *BodyContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *BodyContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitBody(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) Body() (localctx IBodyContext) {
localctx = NewBodyContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 64, ApiParserParserRULE_body)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(299)
_m := p.Match(ApiParserParserT__1)
localctx.(*BodyContext).lp = _m
}
p.SetState(301)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserID {
{
p.SetState(300)
p.Match(ApiParserParserID)
}
}
{
p.SetState(303)
_m := p.Match(ApiParserParserT__2)
localctx.(*BodyContext).rp = _m
}
return localctx
}
// IReplybodyContext is an interface to support dynamic dispatch.
type IReplybodyContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetReturnToken returns the returnToken token.
GetReturnToken() antlr.Token
// GetLp returns the lp token.
GetLp() antlr.Token
// GetRp returns the rp token.
GetRp() antlr.Token
// SetReturnToken sets the returnToken token.
SetReturnToken(antlr.Token)
// SetLp sets the lp token.
SetLp(antlr.Token)
// SetRp sets the rp token.
SetRp(antlr.Token)
// IsReplybodyContext differentiates from other interfaces.
IsReplybodyContext()
}
type ReplybodyContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
returnToken antlr.Token
lp antlr.Token
rp antlr.Token
}
func NewEmptyReplybodyContext() *ReplybodyContext {
p := new(ReplybodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_replybody
return p
}
func (*ReplybodyContext) IsReplybodyContext() {}
func NewReplybodyContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ReplybodyContext {
p := new(ReplybodyContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_replybody
return p
}
func (s *ReplybodyContext) GetParser() antlr.Parser { return s.parser }
func (s *ReplybodyContext) GetReturnToken() antlr.Token { return s.returnToken }
func (s *ReplybodyContext) GetLp() antlr.Token { return s.lp }
func (s *ReplybodyContext) GetRp() antlr.Token { return s.rp }
func (s *ReplybodyContext) SetReturnToken(v antlr.Token) { s.returnToken = v }
func (s *ReplybodyContext) SetLp(v antlr.Token) { s.lp = v }
func (s *ReplybodyContext) SetRp(v antlr.Token) { s.rp = v }
func (s *ReplybodyContext) DataType() IDataTypeContext {
t := s.GetTypedRuleContext(reflect.TypeOf((*IDataTypeContext)(nil)).Elem(), 0)
if t == nil {
return nil
}
return t.(IDataTypeContext)
}
func (s *ReplybodyContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ReplybodyContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ReplybodyContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitReplybody(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) Replybody() (localctx IReplybodyContext) {
localctx = NewReplybodyContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 66, ApiParserParserRULE_replybody)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(305)
_m := p.Match(ApiParserParserT__9)
localctx.(*ReplybodyContext).returnToken = _m
}
{
p.SetState(306)
_m := p.Match(ApiParserParserT__1)
localctx.(*ReplybodyContext).lp = _m
}
p.SetState(308)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if ((_la)&-(0x1f+1)) == 0 && ((1<<uint(_la))&((1<<ApiParserParserT__5)|(1<<ApiParserParserT__6)|(1<<ApiParserParserT__7)|(1<<ApiParserParserINTERFACE)|(1<<ApiParserParserID))) != 0 {
{
p.SetState(307)
p.DataType()
}
}
{
p.SetState(310)
_m := p.Match(ApiParserParserT__2)
localctx.(*ReplybodyContext).rp = _m
}
return localctx
}
// IKvLitContext is an interface to support dynamic dispatch.
type IKvLitContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// GetKey returns the key token.
GetKey() antlr.Token
// GetValue returns the value token.
GetValue() antlr.Token
// SetKey sets the key token.
SetKey(antlr.Token)
// SetValue sets the value token.
SetValue(antlr.Token)
// IsKvLitContext differentiates from other interfaces.
IsKvLitContext()
}
type KvLitContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
key antlr.Token
value antlr.Token
}
func NewEmptyKvLitContext() *KvLitContext {
p := new(KvLitContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_kvLit
return p
}
func (*KvLitContext) IsKvLitContext() {}
func NewKvLitContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *KvLitContext {
p := new(KvLitContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_kvLit
return p
}
func (s *KvLitContext) GetParser() antlr.Parser { return s.parser }
func (s *KvLitContext) GetKey() antlr.Token { return s.key }
func (s *KvLitContext) GetValue() antlr.Token { return s.value }
func (s *KvLitContext) SetKey(v antlr.Token) { s.key = v }
func (s *KvLitContext) SetValue(v antlr.Token) { s.value = v }
func (s *KvLitContext) ID() antlr.TerminalNode {
return s.GetToken(ApiParserParserID, 0)
}
func (s *KvLitContext) LINE_VALUE() antlr.TerminalNode {
return s.GetToken(ApiParserParserLINE_VALUE, 0)
}
func (s *KvLitContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *KvLitContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *KvLitContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitKvLit(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) KvLit() (localctx IKvLitContext) {
localctx = NewKvLitContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 68, ApiParserParserRULE_kvLit)
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
{
p.SetState(312)
_m := p.Match(ApiParserParserID)
localctx.(*KvLitContext).key = _m
}
checkKeyValue(p)
{
p.SetState(314)
_m := p.Match(ApiParserParserLINE_VALUE)
localctx.(*KvLitContext).value = _m
}
return localctx
}
// IServiceNameContext is an interface to support dynamic dispatch.
type IServiceNameContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsServiceNameContext differentiates from other interfaces.
IsServiceNameContext()
}
type ServiceNameContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyServiceNameContext() *ServiceNameContext {
p := new(ServiceNameContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_serviceName
return p
}
func (*ServiceNameContext) IsServiceNameContext() {}
func NewServiceNameContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ServiceNameContext {
p := new(ServiceNameContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_serviceName
return p
}
func (s *ServiceNameContext) GetParser() antlr.Parser { return s.parser }
func (s *ServiceNameContext) AllID() []antlr.TerminalNode {
return s.GetTokens(ApiParserParserID)
}
func (s *ServiceNameContext) ID(i int) antlr.TerminalNode {
return s.GetToken(ApiParserParserID, i)
}
func (s *ServiceNameContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *ServiceNameContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *ServiceNameContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitServiceName(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) ServiceName() (localctx IServiceNameContext) {
localctx = NewServiceNameContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 70, ApiParserParserRULE_serviceName)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.EnterOuterAlt(localctx, 1)
p.SetState(320)
p.GetErrorHandler().Sync(p)
for ok := true; ok; ok = _la == ApiParserParserID {
{
p.SetState(316)
p.Match(ApiParserParserID)
}
p.SetState(318)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__10 {
{
p.SetState(317)
p.Match(ApiParserParserT__10)
}
}
p.SetState(322)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
return localctx
}
// IPathContext is an interface to support dynamic dispatch.
type IPathContext interface {
antlr.ParserRuleContext
// GetParser returns the parser.
GetParser() antlr.Parser
// IsPathContext differentiates from other interfaces.
IsPathContext()
}
type PathContext struct {
*antlr.BaseParserRuleContext
parser antlr.Parser
}
func NewEmptyPathContext() *PathContext {
p := new(PathContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(nil, -1)
p.RuleIndex = ApiParserParserRULE_path
return p
}
func (*PathContext) IsPathContext() {}
func NewPathContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *PathContext {
p := new(PathContext)
p.BaseParserRuleContext = antlr.NewBaseParserRuleContext(parent, invokingState)
p.parser = parser
p.RuleIndex = ApiParserParserRULE_path
return p
}
func (s *PathContext) GetParser() antlr.Parser { return s.parser }
func (s *PathContext) AllID() []antlr.TerminalNode {
return s.GetTokens(ApiParserParserID)
}
func (s *PathContext) ID(i int) antlr.TerminalNode {
return s.GetToken(ApiParserParserID, i)
}
func (s *PathContext) GetRuleContext() antlr.RuleContext {
return s
}
func (s *PathContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string {
return antlr.TreesStringTree(s, ruleNames, recog)
}
func (s *PathContext) Accept(visitor antlr.ParseTreeVisitor) interface{} {
switch t := visitor.(type) {
case ApiParserVisitor:
return t.VisitPath(s)
default:
return t.VisitChildren(s)
}
}
func (p *ApiParserParser) Path() (localctx IPathContext) {
localctx = NewPathContext(p, p.GetParserRuleContext(), p.GetState())
p.EnterRule(localctx, 72, ApiParserParserRULE_path)
var _la int
defer func() {
p.ExitRule()
}()
defer func() {
if err := recover(); err != nil {
if v, ok := err.(antlr.RecognitionException); ok {
localctx.SetException(v)
p.GetErrorHandler().ReportError(p, v)
p.GetErrorHandler().Recover(p, v)
} else {
panic(err)
}
}
}()
p.SetState(344)
p.GetErrorHandler().Sync(p)
switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 38, p.GetParserRuleContext()) {
case 1:
p.EnterOuterAlt(localctx, 1)
p.SetState(339)
p.GetErrorHandler().Sync(p)
for ok := true; ok; ok = _la == ApiParserParserT__11 || _la == ApiParserParserT__12 {
p.SetState(339)
p.GetErrorHandler().Sync(p)
switch p.GetTokenStream().LA(1) {
case ApiParserParserT__11:
{
p.SetState(324)
p.Match(ApiParserParserT__11)
}
{
p.SetState(325)
p.Match(ApiParserParserID)
}
p.SetState(330)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
for _la == ApiParserParserT__10 {
{
p.SetState(326)
p.Match(ApiParserParserT__10)
}
{
p.SetState(327)
p.Match(ApiParserParserID)
}
p.SetState(332)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
case ApiParserParserT__12:
{
p.SetState(333)
p.Match(ApiParserParserT__12)
}
{
p.SetState(334)
p.Match(ApiParserParserID)
}
p.SetState(337)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
if _la == ApiParserParserT__10 {
{
p.SetState(335)
p.Match(ApiParserParserT__10)
}
{
p.SetState(336)
p.Match(ApiParserParserID)
}
}
default:
panic(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil))
}
p.SetState(341)
p.GetErrorHandler().Sync(p)
_la = p.GetTokenStream().LA(1)
}
case 2:
p.EnterOuterAlt(localctx, 2)
{
p.SetState(343)
p.Match(ApiParserParserT__11)
}
}
return localctx
}

Some files were not shown because too many files have changed in this diff Show More