forked from x/ContextOS
mac add yac 添加了yac模块,重构了cli模块,可以随时修改语法规则
This commit is contained in:
parent
2375806ff9
commit
2b0d7e9777
54
etc/init.shy
54
etc/init.shy
@ -1,58 +1,4 @@
|
|||||||
@lex lex
|
|
||||||
~cli
|
~cli
|
||||||
@lex lex
|
|
||||||
~aaa login root root
|
~aaa login root root
|
||||||
~ssh dial chat.shylinux.com:9090 true
|
|
||||||
sleep 1
|
|
||||||
~host1
|
|
||||||
~aaa login root root
|
|
||||||
~web serve
|
|
||||||
~nfs load usr/sess.txt
|
|
||||||
var sessid = $result
|
|
||||||
if -n $sessid
|
|
||||||
~host1 remote context mpa register $sessid
|
|
||||||
else
|
|
||||||
~host1 remote context mpa register terminal shhylinux term term term 1
|
|
||||||
let sessid $result
|
|
||||||
end
|
|
||||||
|
|
||||||
~host1 cache sessid $sessid
|
|
||||||
~host1 remote cache sessid $sessid
|
|
||||||
~nfs save usr/sess.txt $sessid
|
|
||||||
~nfs genqr usr/sess.png "terminal: " $sessid
|
|
||||||
return
|
|
||||||
|
|
||||||
return
|
return
|
||||||
return
|
|
||||||
# ~ssh dial chat.shylinux.com:9090 true
|
|
||||||
# ~cli
|
|
||||||
# remote slaver listen ":9393" tcp
|
|
||||||
# ~ssh
|
|
||||||
# listen :9191
|
|
||||||
~tcp
|
|
||||||
listen :9393
|
|
||||||
|
|
||||||
# ~tcp dial ":9393"
|
|
||||||
# @debug on
|
|
||||||
# ~aaa
|
|
||||||
# login shy shy
|
|
||||||
# ~mdb
|
|
||||||
# open chat:chat@/chat mysql
|
|
||||||
# ~web listen
|
|
||||||
# @debug on
|
|
||||||
# ~nfs
|
|
||||||
# open hi.txt
|
|
||||||
|
|
||||||
|
|
||||||
@debug
|
|
||||||
~web spawn hi he ./
|
|
||||||
route template /tpl ./usr/msg.tpl
|
|
||||||
route script /php ./usr/msg.php
|
|
||||||
route script /who who
|
|
||||||
~hi listen ./ ":9494"
|
|
||||||
master nice
|
|
||||||
return
|
|
||||||
|
|
||||||
login shy shy
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,11 +20,12 @@ import ( // {{{
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
type CLI struct {
|
type CLI struct { // {{{
|
||||||
out io.WriteCloser
|
out io.WriteCloser
|
||||||
bio *bufio.Reader
|
bio *bufio.Reader
|
||||||
lines []string
|
lines []string
|
||||||
|
|
||||||
|
yac *ctx.Message
|
||||||
lex *ctx.Message
|
lex *ctx.Message
|
||||||
target *ctx.Context
|
target *ctx.Context
|
||||||
alias map[string][]string
|
alias map[string][]string
|
||||||
@ -32,6 +33,8 @@ type CLI struct {
|
|||||||
*ctx.Context
|
*ctx.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
func (cli *CLI) print(str string, arg ...interface{}) bool { // {{{
|
func (cli *CLI) print(str string, arg ...interface{}) bool { // {{{
|
||||||
if cli.out != nil {
|
if cli.out != nil {
|
||||||
fmt.Fprintf(cli.out, str, arg...)
|
fmt.Fprintf(cli.out, str, arg...)
|
||||||
@ -45,17 +48,27 @@ func (cli *CLI) parse(m *ctx.Message) (cmd []string) { // {{{
|
|||||||
|
|
||||||
line := m.Cap("next")
|
line := m.Cap("next")
|
||||||
if m.Cap("next", ""); line == "" {
|
if m.Cap("next", ""); line == "" {
|
||||||
|
|
||||||
if cli.bio == nil {
|
if cli.bio == nil {
|
||||||
line = cli.lines[m.Capi("pos")]
|
line = cli.lines[m.Capi("pos", 1)-1]
|
||||||
m.Capi("pos", 1)
|
|
||||||
} else {
|
} else {
|
||||||
cli.print(m.Conf("PS1"))
|
cli.print(m.Conf("PS1"))
|
||||||
l, e := cli.bio.ReadString('\n')
|
if l, e := cli.bio.ReadString('\n'); m.Assert(e) {
|
||||||
m.Assert(e)
|
|
||||||
line = l
|
line = l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cli.yac != nil {
|
||||||
|
if line == "\n" && cli.out != nil {
|
||||||
|
line = m.Cap("back")
|
||||||
|
m.Cap("back", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
yac := m.Spawn(cli.yac.Target())
|
||||||
|
yac.Cmd("parse", "line", "void", line+"\n")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if line = strings.TrimSpace(line); len(line) == 0 && cli.out != nil {
|
if line = strings.TrimSpace(line); len(line) == 0 && cli.out != nil {
|
||||||
line = m.Cap("back")
|
line = m.Cap("back")
|
||||||
@ -66,7 +79,18 @@ func (cli *CLI) parse(m *ctx.Message) (cmd []string) { // {{{
|
|||||||
}
|
}
|
||||||
|
|
||||||
ls := []string{}
|
ls := []string{}
|
||||||
if cli.lex == nil {
|
if cli.lex != nil {
|
||||||
|
rest := line
|
||||||
|
for len(rest) > 0 {
|
||||||
|
lex := m.Spawn(cli.lex.Target())
|
||||||
|
lex.Cmd("split", rest, "word", "void")
|
||||||
|
if !lex.Gets("result") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ls = append(ls, lex.Meta["result"][1])
|
||||||
|
rest = lex.Meta["result"][2]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
ls = strings.Split(line, " ")
|
ls = strings.Split(line, " ")
|
||||||
cs := []string{}
|
cs := []string{}
|
||||||
for i := 0; i < len(ls); i++ {
|
for i := 0; i < len(ls); i++ {
|
||||||
@ -79,10 +103,6 @@ func (cli *CLI) parse(m *ctx.Message) (cmd []string) { // {{{
|
|||||||
cs = append(cs, ls[i])
|
cs = append(cs, ls[i])
|
||||||
}
|
}
|
||||||
ls = cs
|
ls = cs
|
||||||
} else {
|
|
||||||
lex := m.Spawn(cli.lex.Target())
|
|
||||||
m.Assert(lex.Cmd("split", line, "void"))
|
|
||||||
ls = lex.Meta["result"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cli.Has("skip") || !cli.Pulse.Caps("skip") {
|
if !cli.Has("skip") || !cli.Pulse.Caps("skip") {
|
||||||
@ -277,7 +297,7 @@ func (cli *CLI) check(arg []string) bool { // {{{
|
|||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
|
func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
||||||
c.Caches = map[string]*ctx.Cache{}
|
c.Caches = map[string]*ctx.Cache{}
|
||||||
c.Configs = map[string]*ctx.Config{}
|
c.Configs = map[string]*ctx.Config{}
|
||||||
c.Caches["skip"] = &ctx.Cache{Name: "跳过执行", Value: cli.Pulse.Cap("skip"), Help: "命令只解析不执行"}
|
c.Caches["skip"] = &ctx.Cache{Name: "跳过执行", Value: cli.Pulse.Cap("skip"), Help: "命令只解析不执行"}
|
||||||
@ -285,6 +305,7 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
|
|||||||
s := new(CLI)
|
s := new(CLI)
|
||||||
s.Context = c
|
s.Context = c
|
||||||
s.lex = cli.lex
|
s.lex = cli.lex
|
||||||
|
s.yac = cli.yac
|
||||||
if m.Has("for") {
|
if m.Has("for") {
|
||||||
s.lines = append(s.lines, cli.lines[cli.Pulse.Capi("pos")-1:]...)
|
s.lines = append(s.lines, cli.lines[cli.Pulse.Capi("pos")-1:]...)
|
||||||
} else {
|
} else {
|
||||||
@ -293,7 +314,8 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
// }}}
|
||||||
|
func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||||
cli.Caches["target"] = &ctx.Cache{Name: "操作目标", Value: cli.Name, Help: "命令操作的目标"}
|
cli.Caches["target"] = &ctx.Cache{Name: "操作目标", Value: cli.Name, Help: "命令操作的目标"}
|
||||||
cli.Caches["result"] = &ctx.Cache{Name: "执行结果", Value: "", Help: "前一条命令的执行结果"}
|
cli.Caches["result"] = &ctx.Cache{Name: "执行结果", Value: "", Help: "前一条命令的执行结果"}
|
||||||
cli.Caches["back"] = &ctx.Cache{Name: "前一条指令", Value: "", Help: "前一条指令"}
|
cli.Caches["back"] = &ctx.Cache{Name: "前一条指令", Value: "", Help: "前一条指令"}
|
||||||
@ -314,11 +336,11 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
|||||||
m.Assert(lex != nil, "词法解析模块不存在")
|
m.Assert(lex != nil, "词法解析模块不存在")
|
||||||
if lex.Cap("status") != "start" {
|
if lex.Cap("status") != "start" {
|
||||||
lex.Target().Start(lex)
|
lex.Target().Start(lex)
|
||||||
m.Spawn(lex.Target()).Cmd("train", "'[^']*'")
|
m.Spawn(lex.Target()).Cmd("train", "'[^']*'", "word", "word")
|
||||||
m.Spawn(lex.Target()).Cmd("train", "\"[^\"]*\"")
|
m.Spawn(lex.Target()).Cmd("train", "\"[^\"]*\"", "word", "word")
|
||||||
m.Spawn(lex.Target()).Cmd("train", "[^ \t\n]+")
|
m.Spawn(lex.Target()).Cmd("train", "[^\t \n]+", "word", "word")
|
||||||
m.Spawn(lex.Target()).Cmd("train", "[ \n\t]+", "void", "void")
|
m.Spawn(lex.Target()).Cmd("train", "[\t \n]+", "void", "void")
|
||||||
m.Spawn(lex.Target()).Cmd("train", "#[^\n]*\n", "void", "void")
|
m.Spawn(lex.Target()).Cmd("train", "#[^\n]*\n", "help", "void")
|
||||||
}
|
}
|
||||||
cli.lex = lex
|
cli.lex = lex
|
||||||
return arg[0]
|
return arg[0]
|
||||||
@ -326,6 +348,27 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
|||||||
return x.Value
|
return x.Value
|
||||||
// }}}
|
// }}}
|
||||||
}}
|
}}
|
||||||
|
cli.Configs["yac"] = &ctx.Config{Name: "词法解析器", Value: "", Help: "命令行词法解析器", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
|
||||||
|
if len(arg) > 0 && len(arg[0]) > 0 { // {{{
|
||||||
|
cli, ok := m.Target().Server.(*CLI)
|
||||||
|
m.Assert(ok, "模块类型错误")
|
||||||
|
|
||||||
|
yac := m.Find(arg[0], true)
|
||||||
|
m.Assert(yac != nil, "词法解析模块不存在")
|
||||||
|
if yac.Cap("status") != "start" {
|
||||||
|
yac.Target().Start(yac)
|
||||||
|
m.Spawn(yac.Target()).Cmd("train", "void", "void", "[\t ]+")
|
||||||
|
m.Spawn(yac.Target()).Cmd("train", "tran", "tran", "mul{", "@", "$", "}", "opt{", "[a-zA-Z0-9]+", "}")
|
||||||
|
m.Spawn(yac.Target()).Cmd("train", "word", "word", "rep{", "mul{", "~", "!", "tran", "\"[^\"]*\"", "'[^']*'", "[a-zA-Z0-9_/.]+", "}", "}")
|
||||||
|
m.Spawn(yac.Target()).Cmd("train", "tran", "tran", "$", "(", "word", ")")
|
||||||
|
m.Spawn(yac.Target()).Cmd("train", "line", "line", "opt{", "word", "}", "mul{", ";", "\n", "#[^\n]*\n", "}")
|
||||||
|
}
|
||||||
|
cli.yac = yac
|
||||||
|
return arg[0]
|
||||||
|
}
|
||||||
|
return x.Value
|
||||||
|
// }}}
|
||||||
|
}}
|
||||||
cli.Configs["PS1"] = &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
|
cli.Configs["PS1"] = &ctx.Config{Name: "命令行提示符(target/detail)", Value: "target", Help: "命令行提示符,target:显示当前模块,detail:显示详细信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
|
||||||
if len(arg) > 0 { // {{{
|
if len(arg) > 0 { // {{{
|
||||||
return arg[0]
|
return arg[0]
|
||||||
@ -383,7 +426,8 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
|||||||
return cli
|
return cli
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
|
// }}}
|
||||||
|
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
cli.Caches["#"] = &ctx.Cache{Name: "参数个数", Value: fmt.Sprintf("%d", len(arg)), Help: "参数个数"}
|
cli.Caches["#"] = &ctx.Cache{Name: "参数个数", Value: fmt.Sprintf("%d", len(arg)), Help: "参数个数"}
|
||||||
for i, v := range arg {
|
for i, v := range arg {
|
||||||
cli.Caches[fmt.Sprintf("%d", i)] = &ctx.Cache{Name: "执行参数", Value: v, Help: "执行参数"}
|
cli.Caches[fmt.Sprintf("%d", i)] = &ctx.Cache{Name: "执行参数", Value: v, Help: "执行参数"}
|
||||||
@ -404,10 +448,11 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
|
|||||||
m.Cap("init.shy", arg[0])
|
m.Cap("init.shy", arg[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Cap("next", "source "+m.Cap("init.shy"))
|
m.Cap("next", fmt.Sprintf("source %s\n", m.Cap("init.shy")))
|
||||||
cli.bio = bufio.NewReader(os.Stdin)
|
cli.bio = bufio.NewReader(os.Stdin)
|
||||||
cli.out = os.Stdout
|
cli.out = os.Stdout
|
||||||
m.Conf("lex", "lex")
|
// m.Conf("lex", "lex")
|
||||||
|
m.Conf("yac", "yac")
|
||||||
m.Cap("stream", "stdout")
|
m.Cap("stream", "stdout")
|
||||||
} else if stream, ok := m.Data["file"]; ok {
|
} else if stream, ok := m.Data["file"]; ok {
|
||||||
if bio, ok := stream.(*bufio.Reader); ok {
|
if bio, ok := stream.(*bufio.Reader); ok {
|
||||||
@ -427,7 +472,8 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
|
|||||||
go m.AssertOne(m, true, func(m *ctx.Message) {
|
go m.AssertOne(m, true, func(m *ctx.Message) {
|
||||||
for !m.Caps("exit") {
|
for !m.Caps("exit") {
|
||||||
if cmd := cli.parse(m); cmd != nil {
|
if cmd := cli.parse(m); cmd != nil {
|
||||||
m.Spawn(cli.target).Set("detail", cmd...).Post(cli.Context)
|
msg := m.Spawn(cli.target).Set("detail", cmd...)
|
||||||
|
msg.Post(cli.Context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, func(m *ctx.Message) {
|
}, func(m *ctx.Message) {
|
||||||
@ -443,7 +489,8 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
|
|||||||
return !m.Caps("exit")
|
return !m.Caps("exit")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !msg.Has("result") && cli.Owner == ctx.Index.Owner {
|
if !msg.Hand && cli.Owner == ctx.Index.Owner {
|
||||||
|
msg.Hand = true
|
||||||
msg.Log("system", nil, "%v", msg.Meta["detail"])
|
msg.Log("system", nil, "%v", msg.Meta["detail"])
|
||||||
|
|
||||||
msg.Set("result").Set("append")
|
msg.Set("result").Set("append")
|
||||||
@ -468,11 +515,6 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result := strings.TrimRight(strings.Join(msg.Meta["result"], ""), "\n")
|
|
||||||
if m.Cap("result", result); len(result) > 0 {
|
|
||||||
cli.print(result + "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.Target().Context() != nil || msg.Target() == ctx.Index {
|
if msg.Target().Context() != nil || msg.Target() == ctx.Index {
|
||||||
cli.target = msg.Target()
|
cli.target = msg.Target()
|
||||||
}
|
}
|
||||||
@ -489,7 +531,8 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
|
|||||||
return !cli.Pulse.Has("save")
|
return !cli.Pulse.Has("save")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *CLI) Close(m *ctx.Message, arg ...string) bool {
|
// }}}
|
||||||
|
func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
switch cli.Context {
|
switch cli.Context {
|
||||||
case m.Target():
|
case m.Target():
|
||||||
if p, ok := cli.Context.Context().Server.(*CLI); ok {
|
if p, ok := cli.Context.Context().Server.(*CLI); ok {
|
||||||
@ -519,6 +562,8 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
var Pulse *ctx.Message
|
var Pulse *ctx.Message
|
||||||
var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
||||||
Caches: map[string]*ctx.Cache{
|
Caches: map[string]*ctx.Cache{
|
||||||
@ -526,8 +571,57 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
|||||||
},
|
},
|
||||||
Configs: map[string]*ctx.Config{},
|
Configs: map[string]*ctx.Config{},
|
||||||
Commands: map[string]*ctx.Command{
|
Commands: map[string]*ctx.Command{
|
||||||
|
"tran": &ctx.Command{Name: "tran word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
|
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
|
switch len(arg) {
|
||||||
|
case 2:
|
||||||
|
switch arg[0] {
|
||||||
|
case "$":
|
||||||
|
m.Echo(m.Cap(arg[1]))
|
||||||
|
case "@":
|
||||||
|
m.Echo(m.Conf(arg[1]))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
m.Set("result", arg[2:len(arg)-1]...)
|
||||||
|
}
|
||||||
|
} // }}}
|
||||||
|
}},
|
||||||
|
"word": &ctx.Command{Name: "word word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
|
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
|
|
||||||
|
msg := m.Spawn(cli.target)
|
||||||
|
if a, ok := cli.alias[arg[0]]; ok {
|
||||||
|
msg.Set("detail", a...)
|
||||||
|
msg.Meta["detail"] = append(msg.Meta["detail"], arg[1:]...)
|
||||||
|
} else {
|
||||||
|
msg.Set("detail", arg...)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Post(cli.Context)
|
||||||
|
if m.Hand = false; msg.Hand {
|
||||||
|
m.Hand = true
|
||||||
|
m.Meta["result"] = msg.Meta["result"]
|
||||||
|
}
|
||||||
|
} // }}}
|
||||||
|
}},
|
||||||
|
"line": &ctx.Command{Name: "line word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
|
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
|
arg = arg[:len(arg)-1]
|
||||||
|
|
||||||
|
result := strings.TrimRight(strings.Join(arg, ""), "\n")
|
||||||
|
if m.Cap("result", result); len(result) > 0 {
|
||||||
|
cli.print(result + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Cap("back", ""); cli.bio != nil {
|
||||||
|
cli.lines = append(cli.lines, strings.Join(arg, " "))
|
||||||
|
m.Capi("nline", 1)
|
||||||
|
m.Capi("pos", 1)
|
||||||
|
}
|
||||||
|
} // }}}
|
||||||
|
}},
|
||||||
"alias": &ctx.Command{Name: "alias [short [long]]|[delete short]", Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"alias": &ctx.Command{Name: "alias [short [long]]|[delete short]", Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) {
|
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{
|
||||||
switch len(arg) {
|
switch len(arg) {
|
||||||
case 0:
|
case 0:
|
||||||
for k, v := range cli.alias {
|
for k, v := range cli.alias {
|
||||||
@ -544,49 +638,49 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
|||||||
m.Echo("%s: %v\n", arg[0], cli.alias[arg[0]])
|
m.Echo("%s: %v\n", arg[0], cli.alias[arg[0]])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{
|
||||||
if d, e := time.ParseDuration(arg[0]); m.Assert(e) {
|
if d, e := time.ParseDuration(arg[0]); m.Assert(e) {
|
||||||
m.Log("info", nil, "sleep %v", d)
|
m.Log("info", nil, "sleep %v", d)
|
||||||
time.Sleep(d)
|
time.Sleep(d)
|
||||||
m.Log("info", nil, "sleep %v done", d)
|
m.Log("info", nil, "sleep %v done", d)
|
||||||
}
|
}
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{
|
||||||
val := ""
|
val := ""
|
||||||
if len(arg) > 2 {
|
if len(arg) > 2 {
|
||||||
val = cli.express(arg[2:])
|
val = cli.express(arg[2:])
|
||||||
}
|
}
|
||||||
cli.Pulse.Cap(arg[0], arg[0], val, "临时变量")
|
cli.Pulse.Cap(arg[0], arg[0], val, "临时变量")
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{
|
||||||
m.Echo(cli.Pulse.Cap(arg[0], cli.express(arg[2:])))
|
m.Echo(cli.Pulse.Cap(arg[0], cli.express(arg[2:])))
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"source": &ctx.Command{Name: "source file", Help: "运行脚本, file: 脚本文件名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"source": &ctx.Command{Name: "source file", Help: "运行脚本, file: 脚本文件名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{
|
||||||
if f, e := os.Open(arg[0]); m.Assert(e) {
|
if f, e := os.Open(arg[0]); m.Assert(e) {
|
||||||
m.Put("option", "file", f).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "脚本文件")
|
m.Put("option", "file", f).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "脚本文件")
|
||||||
<-m.Target().Exit
|
<-m.Target().Exit
|
||||||
Pulse.Capi("level", -1)
|
Pulse.Capi("level", -1)
|
||||||
}
|
}
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"return": &ctx.Command{Name: "return result...", Help: "结束脚本, rusult: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"return": &ctx.Command{Name: "return result...", Help: "结束脚本, rusult: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) && (!cli.Has("skip") || !cli.Pulse.Caps("skip")) { // {{{
|
||||||
call := cli.Requests[len(cli.Requests)-1]
|
call := cli.Requests[len(cli.Requests)-1]
|
||||||
call.Set("result", arg...)
|
call.Set("result", arg...)
|
||||||
cli.Pulse.Caps("exit", true)
|
cli.Pulse.Caps("exit", true)
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
if m.Target(m.Source()); (cli.Has("skip") && cli.Pulse.Caps("skip")) || !cli.check(arg) {
|
if m.Target(m.Source()); (cli.Has("skip") && cli.Pulse.Caps("skip")) || !cli.check(arg) {
|
||||||
m.Add("option", "skip")
|
m.Add("option", "skip")
|
||||||
}
|
}
|
||||||
@ -594,33 +688,33 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
|||||||
m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "条件语句")
|
m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "条件语句")
|
||||||
<-m.Target().Exit
|
<-m.Target().Exit
|
||||||
Pulse.Capi("level", -1)
|
Pulse.Capi("level", -1)
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"elif": &ctx.Command{Name: "elif exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"elif": &ctx.Command{Name: "elif exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
if cli.Pulse.Caps("skip", !cli.Pulse.Caps("else")) {
|
if cli.Pulse.Caps("skip", !cli.Pulse.Caps("else")) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cli.Pulse.Caps("else", cli.Pulse.Caps("skip", !cli.check(arg)))
|
cli.Pulse.Caps("else", cli.Pulse.Caps("skip", !cli.check(arg)))
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
cli.Pulse.Caps("skip", !cli.Pulse.Caps("else"))
|
cli.Pulse.Caps("skip", !cli.Pulse.Caps("else"))
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
if cli.Pulse.Caps("exit", true); cli.Pulse.Has("for") && !cli.Pulse.Caps("skip") {
|
if cli.Pulse.Caps("exit", true); cli.Pulse.Has("for") && !cli.Pulse.Caps("skip") {
|
||||||
cli.Pulse.Caps("exit", false)
|
cli.Pulse.Caps("exit", false)
|
||||||
cli.Pulse.Cap("pos", "0")
|
cli.Pulse.Cap("pos", "0")
|
||||||
|
|
||||||
}
|
}
|
||||||
cli.bio = nil
|
cli.bio = nil
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"for": &ctx.Command{Name: "for exp", Help: "循环语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"for": &ctx.Command{Name: "for exp", Help: "循环语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
if cli.Pulse.Has("for") && cli.Pulse.Capi("pos") == 1 {
|
if cli.Pulse.Has("for") && cli.Pulse.Capi("pos") == 1 {
|
||||||
cli.Pulse.Caps("skip", !cli.check(arg))
|
cli.Pulse.Caps("skip", !cli.check(arg))
|
||||||
return
|
return
|
||||||
@ -632,10 +726,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
|||||||
m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "循环语句")
|
m.Put("option", "file", cli.bio).Start(fmt.Sprintf("%s%d", key, Pulse.Capi("level", 1)), "循环语句")
|
||||||
<-m.Target().Exit
|
<-m.Target().Exit
|
||||||
Pulse.Capi("level", -1)
|
Pulse.Capi("level", -1)
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"function": &ctx.Command{Name: "function name", Help: "函数定义, name: 函数名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"function": &ctx.Command{Name: "function name", Help: "函数定义, name: 函数名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) {
|
if cli, ok := m.Source().Server.(*CLI); m.Assert(ok) { // {{{
|
||||||
if _, ok := cli.Context.Context().Server.(*CLI); ok {
|
if _, ok := cli.Context.Context().Server.(*CLI); ok {
|
||||||
m.Target(m.Source().Context())
|
m.Target(m.Source().Context())
|
||||||
} else {
|
} else {
|
||||||
@ -645,10 +739,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
|||||||
m.Add("option", "skip").Add("option", "save")
|
m.Add("option", "skip").Add("option", "save")
|
||||||
m.Put("option", "file", cli.bio).Start(arg[0], "函数定义")
|
m.Put("option", "file", cli.bio).Start(arg[0], "函数定义")
|
||||||
<-m.Target().Exit
|
<-m.Target().Exit
|
||||||
}
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"call": &ctx.Command{Name: "call name arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"call": &ctx.Command{Name: "call name arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
m.Target(m.Source())
|
m.Target(m.Source()) // {{{
|
||||||
m.BackTrace(func(msg *ctx.Message) bool {
|
m.BackTrace(func(msg *ctx.Message) bool {
|
||||||
if fun := msg.Find(arg[0], false); fun != nil {
|
if fun := msg.Find(arg[0], false); fun != nil {
|
||||||
fun.Add("detail", arg[0], arg[1:]...).Target().Start(fun)
|
fun.Add("detail", arg[0], arg[1:]...).Target().Start(fun)
|
||||||
@ -657,7 +751,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
}) // }}}
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -443,6 +443,7 @@ func (c *Context) Del(arg ...string) { // {{{
|
|||||||
type Message struct {
|
type Message struct {
|
||||||
code int
|
code int
|
||||||
time time.Time
|
time time.Time
|
||||||
|
Hand bool
|
||||||
|
|
||||||
Recv chan bool
|
Recv chan bool
|
||||||
Wait chan bool
|
Wait chan bool
|
||||||
@ -973,10 +974,8 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{
|
|||||||
arg = m.Meta["args"]
|
arg = m.Meta["args"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.Hand = true
|
||||||
x.Hand(m.Set("result").Set("append"), s, key, arg...)
|
x.Hand(m.Set("result").Set("append"), s, key, arg...)
|
||||||
if !m.Has("result") {
|
|
||||||
m.Meta["result"] = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if x.Appends != nil {
|
if x.Appends != nil {
|
||||||
for _, v := range m.Meta["append"] {
|
for _, v := range m.Meta["append"] {
|
||||||
@ -1112,7 +1111,7 @@ func (m *Message) Conf(key string, arg ...string) string { // {{{
|
|||||||
} else {
|
} else {
|
||||||
x.Value = arg[0]
|
x.Value = arg[0]
|
||||||
}
|
}
|
||||||
m.Log("conf", s, "%s %v", x.Name, x.Value)
|
// m.Log("conf", s, "%s %v", x.Name, x.Value)
|
||||||
return x.Value
|
return x.Value
|
||||||
case 0:
|
case 0:
|
||||||
if x.Hand != nil {
|
if x.Hand != nil {
|
||||||
@ -1190,10 +1189,10 @@ func (m *Message) Cap(key string, arg ...string) string { // {{{
|
|||||||
} else {
|
} else {
|
||||||
x.Value = arg[0]
|
x.Value = arg[0]
|
||||||
}
|
}
|
||||||
m.Log("debug", s, "%s %s", x.Name, x.Value)
|
// m.Log("debug", s, "%s %s", x.Name, x.Value)
|
||||||
return x.Value
|
return x.Value
|
||||||
case 0:
|
case 0:
|
||||||
m.Log("debug", s, "%s %s", x.Name, x.Value)
|
// m.Log("debug", s, "%s %s", x.Name, x.Value)
|
||||||
if x.Hand != nil {
|
if x.Hand != nil {
|
||||||
return x.Hand(m, x)
|
return x.Hand(m, x)
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
package lex
|
package lex // {{{
|
||||||
|
// }}}
|
||||||
import (
|
import ( // {{{
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type State struct {
|
// }}}
|
||||||
star bool
|
|
||||||
next int
|
|
||||||
hash int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Seed struct {
|
type Seed struct { // {{{
|
||||||
page int
|
page int
|
||||||
hash int
|
hash int
|
||||||
word string
|
word string
|
||||||
}
|
}
|
||||||
|
|
||||||
type LEX struct {
|
// }}}
|
||||||
|
type State struct { // {{{
|
||||||
|
star bool
|
||||||
|
next int
|
||||||
|
hash int
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
type LEX struct { // {{{
|
||||||
seed []*Seed
|
seed []*Seed
|
||||||
page map[string]int
|
page map[string]int
|
||||||
hash map[string]int
|
hash map[string]int
|
||||||
@ -29,52 +34,71 @@ type LEX struct {
|
|||||||
*ctx.Context
|
*ctx.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lex *LEX) train(seed []byte, arg ...string) {
|
// }}}
|
||||||
cell, page, hash := 128, 1, 1
|
|
||||||
if len(arg) > 0 {
|
|
||||||
if x, ok := lex.hash[arg[0]]; ok {
|
|
||||||
hash = x
|
|
||||||
} else {
|
|
||||||
hash = lex.Capi("nhash", 1)
|
|
||||||
lex.hash[arg[0]] = hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(arg) > 1 {
|
|
||||||
if x, ok := lex.page[arg[1]]; ok {
|
|
||||||
page = x
|
|
||||||
} else {
|
|
||||||
lex.mat = append(lex.mat, make(map[byte]*State))
|
|
||||||
page = lex.Capi("nline", 1)
|
|
||||||
lex.page[arg[1]] = page
|
|
||||||
lex.Capi("npage", 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lex.Log("debug", nil, "%d %d %v", page, hash, seed)
|
|
||||||
lex.seed = append(lex.seed, &Seed{page, hash, string(seed)})
|
|
||||||
lex.Capi("nseed", 1)
|
|
||||||
lex.Cap("stream", fmt.Sprintf("%s,%s,%s", lex.Cap("nseed"), lex.Cap("npage"), lex.Cap("nhash")))
|
|
||||||
|
|
||||||
|
func (lex *LEX) index(hash string, h string) int { // {{{
|
||||||
|
if x, e := strconv.Atoi(h); e == nil {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
which := lex.page
|
||||||
|
switch hash {
|
||||||
|
case "npage":
|
||||||
|
which = lex.page
|
||||||
|
case "nhash":
|
||||||
|
which = lex.hash
|
||||||
|
}
|
||||||
|
|
||||||
|
if x, ok := which[h]; ok {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
x := lex.Capi(hash, 1)
|
||||||
|
which[h] = x
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
func (lex *LEX) charset(c byte) []byte { // {{{
|
||||||
|
switch c {
|
||||||
|
case 't':
|
||||||
|
return []byte{'\t'}
|
||||||
|
case 'n':
|
||||||
|
return []byte{'\n'}
|
||||||
|
case 's':
|
||||||
|
return []byte{'\t', ' ', '\n'}
|
||||||
|
case 'd':
|
||||||
|
return []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
|
||||||
|
case 'x':
|
||||||
|
return []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'}
|
||||||
|
}
|
||||||
|
return []byte{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
func (lex *LEX) train(page int, hash int, seed []byte) int { // {{{
|
||||||
|
|
||||||
|
cn := make([]bool, lex.Capi("ncell"))
|
||||||
|
c := make([]byte, 0, lex.Capi("ncell"))
|
||||||
|
sn := make([]bool, lex.Capi("nline"))
|
||||||
s := []int{page}
|
s := []int{page}
|
||||||
c := make([]byte, 0, cell)
|
|
||||||
sn := make([]bool, len(lex.mat))
|
|
||||||
cn := make([]bool, cell)
|
|
||||||
|
|
||||||
ends := make([]*State, 0, len(seed))
|
ends := []*State{}
|
||||||
|
|
||||||
|
for p, set := 0, true; p < len(seed); p++ {
|
||||||
|
|
||||||
for p := 0; p < len(seed); p++ {
|
|
||||||
switch seed[p] {
|
switch seed[p] {
|
||||||
case '[':
|
case '[':
|
||||||
p++
|
if p++; seed[p] == '^' {
|
||||||
set := true
|
set, p = false, p+1
|
||||||
if seed[p] == '^' {
|
|
||||||
set = false
|
|
||||||
p++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for ; seed[p] != ']'; p++ {
|
for ; seed[p] != ']'; p++ {
|
||||||
if seed[p] == '\\' {
|
if seed[p] == '\\' {
|
||||||
p++
|
p++
|
||||||
cn[seed[p]] = true
|
for _, s := range lex.charset(seed[p]) {
|
||||||
|
cn[s] = true
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +111,7 @@ func (lex *LEX) train(seed []byte, arg ...string) {
|
|||||||
cn[i] = true
|
cn[i] = true
|
||||||
}
|
}
|
||||||
p += 2
|
p += 2
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
cn[seed[p]] = true
|
cn[seed[p]] = true
|
||||||
@ -100,18 +125,21 @@ func (lex *LEX) train(seed []byte, arg ...string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
for i := 0; i < cell; i++ {
|
for i := 0; i < len(cn); i++ {
|
||||||
c = append(c, byte(i))
|
c = append(c, byte(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
case '\\':
|
case '\\':
|
||||||
p++
|
p++
|
||||||
fallthrough
|
for _, s := range lex.charset(seed[p]) {
|
||||||
|
c = append(c, s)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
c = append(c, seed[p])
|
c = append(c, seed[p])
|
||||||
}
|
}
|
||||||
|
|
||||||
lex.Log("debug", nil, "page: \033[31m%v\033[0m", s)
|
lex.Log("debug", nil, "page: \033[31m%d %v\033[0m", len(s), s)
|
||||||
lex.Log("debug", nil, "cell: \033[32m%v\033[0m", c)
|
lex.Log("debug", nil, "cell: \033[32m%d %v\033[0m", len(c), c)
|
||||||
|
|
||||||
flag := '\000'
|
flag := '\000'
|
||||||
if p+1 < len(seed) {
|
if p+1 < len(seed) {
|
||||||
@ -125,11 +153,11 @@ func (lex *LEX) train(seed []byte, arg ...string) {
|
|||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
for line, j := 0, byte(0); int(j) < len(c); j++ {
|
for line, j := 0, byte(0); int(j) < len(c); j++ {
|
||||||
state := lex.mat[s[i]][c[j]]
|
state := lex.mat[s[i]][c[j]]
|
||||||
|
lex.Log("debug", nil, "GET(%d,%d): %v", s[i], c[j], state)
|
||||||
if state == nil {
|
if state == nil {
|
||||||
state = new(State)
|
state = &State{}
|
||||||
lex.Capi("nnode", 1)
|
lex.Capi("nnode", 1)
|
||||||
}
|
}
|
||||||
lex.Log("debug", nil, "GET(%d,%d): %v", s[i], c[j], state)
|
|
||||||
|
|
||||||
switch flag {
|
switch flag {
|
||||||
case '+':
|
case '+':
|
||||||
@ -140,7 +168,7 @@ func (lex *LEX) train(seed []byte, arg ...string) {
|
|||||||
case '?':
|
case '?':
|
||||||
if sn[s[i]] = true; p == len(seed)-1 {
|
if sn[s[i]] = true; p == len(seed)-1 {
|
||||||
for _, n := range ends {
|
for _, n := range ends {
|
||||||
if n.next == s[i] && n.hash == 0 {
|
if n.next == s[i] {
|
||||||
lex.Log("debug", nil, "GET() state:%v", n)
|
lex.Log("debug", nil, "GET() state:%v", n)
|
||||||
n.hash = hash
|
n.hash = hash
|
||||||
lex.Log("debug", nil, "END() state:%v", n)
|
lex.Log("debug", nil, "END() state:%v", n)
|
||||||
@ -153,25 +181,26 @@ func (lex *LEX) train(seed []byte, arg ...string) {
|
|||||||
state.hash = hash
|
state.hash = hash
|
||||||
} else {
|
} else {
|
||||||
if state.next == 0 {
|
if state.next == 0 {
|
||||||
if line == 0 {
|
if line == 0 || !lex.Caps("compact") {
|
||||||
line = len(lex.mat)
|
|
||||||
sn = append(sn, false)
|
|
||||||
lex.mat = append(lex.mat, make(map[byte]*State))
|
lex.mat = append(lex.mat, make(map[byte]*State))
|
||||||
lex.Capi("nline", 1)
|
line = lex.Capi("nline", 1) - 1
|
||||||
|
sn = append(sn, false)
|
||||||
}
|
}
|
||||||
state.next = line
|
state.next = line
|
||||||
}
|
}
|
||||||
sn[state.next] = true
|
sn[state.next] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if s, ok := lex.state[*state]; ok {
|
if s, ok := lex.state[*state]; !ok {
|
||||||
|
lex.state[*state] = state
|
||||||
|
lex.Capi("nreal", 1)
|
||||||
|
} else {
|
||||||
state = s
|
state = s
|
||||||
}
|
}
|
||||||
|
|
||||||
lex.state[*state] = state
|
|
||||||
lex.mat[s[i]][c[j]] = state
|
lex.mat[s[i]][c[j]] = state
|
||||||
|
|
||||||
lex.Log("debug", nil, "SET(%d,%d): %v", s[i], c[j], state)
|
lex.Log("debug", nil, "SET(%d,%d): %v(%s,%s)", s[i], c[j], state, lex.Cap("nnode"), lex.Cap("nreal"))
|
||||||
ends = append(ends, state)
|
ends = append(ends, state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,25 +213,20 @@ func (lex *LEX) train(seed []byte, arg ...string) {
|
|||||||
sn[i] = false
|
sn[i] = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lex *LEX) parse(line []byte, arg ...string) (word []byte, hash int, rest []byte) {
|
// }}}
|
||||||
page, begin, end := 1, 0, 0
|
func (lex *LEX) parse(page int, line []byte) (hash int, word []byte, rest []byte) { // {{{
|
||||||
if len(arg) > 0 {
|
|
||||||
if x, ok := lex.page[arg[0]]; ok {
|
|
||||||
page = x
|
|
||||||
} else {
|
|
||||||
return line, 0, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for star, s, i := 0, page, 0; s != 0 && i < len(line); i++ {
|
pos := 0
|
||||||
|
|
||||||
c := line[i]
|
for star, s := 0, page; s != 0 && pos < len(line); pos++ {
|
||||||
if c == '\\' && i < len(line)-1 {
|
|
||||||
c = 'a'
|
c := line[pos]
|
||||||
end++
|
if c == '\\' && pos < len(line)-1 {
|
||||||
i++
|
pos++
|
||||||
|
c = lex.charset(line[pos])[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
state := lex.mat[s][c]
|
state := lex.mat[s][c]
|
||||||
@ -216,27 +240,31 @@ func (lex *LEX) parse(line []byte, arg ...string) (word []byte, hash int, rest [
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if state, ok := lex.mat[star][c]; star == 0 || !ok || state == nil || !state.star {
|
if state, ok := lex.mat[star][c]; !ok || state == nil || !state.star {
|
||||||
star = 0
|
star = 0
|
||||||
}
|
}
|
||||||
if end++; state.star {
|
if state.star {
|
||||||
star = s
|
star = s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
word = append(word, c)
|
||||||
if s, hash = state.next, state.hash; s == 0 {
|
if s, hash = state.next, state.hash; s == 0 {
|
||||||
s, star = star, 0
|
s, star = star, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hash == 0 {
|
if hash == 0 {
|
||||||
begin, end = 0, 0
|
pos, word = 0, word[:0]
|
||||||
}
|
}
|
||||||
|
rest = line[pos:]
|
||||||
|
|
||||||
word, rest = line[begin:end], line[end:]
|
|
||||||
lex.Log("debug", nil, "\033[31m[%v]\033[0m %d [%v]", string(word), hash, string(rest))
|
lex.Log("debug", nil, "\033[31m[%v]\033[0m %d [%v]", string(word), hash, string(rest))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lex *LEX) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
|
// }}}
|
||||||
|
|
||||||
|
func (lex *LEX) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
||||||
c.Caches = map[string]*ctx.Cache{}
|
c.Caches = map[string]*ctx.Cache{}
|
||||||
c.Configs = map[string]*ctx.Config{}
|
c.Configs = map[string]*ctx.Config{}
|
||||||
|
|
||||||
@ -245,37 +273,42 @@ func (lex *LEX) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lex *LEX) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
// }}}
|
||||||
lex.Message = m
|
func (lex *LEX) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||||
|
if lex.Context == Index {
|
||||||
|
Pulse = m
|
||||||
|
}
|
||||||
|
|
||||||
|
lex.Caches["ncell"] = &ctx.Cache{Name: "字符上限", Value: "128", Help: "字符上限"}
|
||||||
|
lex.Caches["nlang"] = &ctx.Cache{Name: "集合上限", Value: "16", Help: "集合上限"}
|
||||||
|
|
||||||
lex.Caches["nseed"] = &ctx.Cache{Name: "种子数量", Value: "0", Help: "种子数量"}
|
lex.Caches["nseed"] = &ctx.Cache{Name: "种子数量", Value: "0", Help: "种子数量"}
|
||||||
lex.Caches["npage"] = &ctx.Cache{Name: "集合数量", Value: "1", Help: "集合数量"}
|
lex.Caches["npage"] = &ctx.Cache{Name: "集合数量", Value: "0", Help: "集合数量"}
|
||||||
lex.Caches["nhash"] = &ctx.Cache{Name: "类型数量", Value: "1", Help: "类型数量"}
|
lex.Caches["nhash"] = &ctx.Cache{Name: "类型数量", Value: "0", Help: "类型数量"}
|
||||||
|
|
||||||
lex.Caches["nline"] = &ctx.Cache{Name: "状态数量", Value: "1", Help: "状态数量"}
|
lex.Caches["nline"] = &ctx.Cache{Name: "状态数量", Value: "16", Help: "状态数量"}
|
||||||
lex.Caches["nnode"] = &ctx.Cache{Name: "节点数量", Value: "0", Help: "节点数量"}
|
lex.Caches["nnode"] = &ctx.Cache{Name: "节点数量", Value: "0", Help: "节点数量"}
|
||||||
lex.Caches["npush"] = &ctx.Cache{Name: "节点数量", Value: "0", Help: "节点数量", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string {
|
lex.Caches["nreal"] = &ctx.Cache{Name: "实点数量", Value: "0", Help: "实点数量"}
|
||||||
return fmt.Sprintf("%d", len(m.Target().Server.(*LEX).state))
|
|
||||||
}}
|
|
||||||
|
|
||||||
|
lex.Caches["compact"] = &ctx.Cache{Name: "紧凑模式", Value: "true", Help: "实点数量"}
|
||||||
return lex
|
return lex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lex *LEX) Start(m *ctx.Message, arg ...string) bool {
|
// }}}
|
||||||
lex.seed = make([]*Seed, 0, 10)
|
func (lex *LEX) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
|
lex.Message = m
|
||||||
|
|
||||||
|
lex.seed = make([]*Seed, 0, 9)
|
||||||
lex.page = map[string]int{"nil": 0}
|
lex.page = map[string]int{"nil": 0}
|
||||||
lex.hash = map[string]int{"nil": 0}
|
lex.hash = map[string]int{"nil": 0}
|
||||||
|
|
||||||
|
lex.mat = make([]map[byte]*State, lex.Capi("nlang"))
|
||||||
lex.state = make(map[State]*State)
|
lex.state = make(map[State]*State)
|
||||||
lex.mat = make([]map[byte]*State, 2, 10)
|
|
||||||
for i := 0; i < len(lex.mat); i++ {
|
|
||||||
lex.mat[i] = make(map[byte]*State)
|
|
||||||
}
|
|
||||||
|
|
||||||
lex.Message = m
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lex *LEX) Close(m *ctx.Message, arg ...string) bool {
|
// }}}
|
||||||
|
func (lex *LEX) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
switch lex.Context {
|
switch lex.Context {
|
||||||
case m.Target():
|
case m.Target():
|
||||||
case m.Source():
|
case m.Source():
|
||||||
@ -283,54 +316,71 @@ func (lex *LEX) Close(m *ctx.Message, arg ...string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var Index = &ctx.Context{Name: "lex", Help: "词法解析",
|
// }}}
|
||||||
|
|
||||||
|
var Pulse *ctx.Message
|
||||||
|
var Index = &ctx.Context{Name: "lex", Help: "词法中心",
|
||||||
Caches: map[string]*ctx.Cache{},
|
Caches: map[string]*ctx.Cache{},
|
||||||
Configs: map[string]*ctx.Config{},
|
Configs: map[string]*ctx.Config{},
|
||||||
Commands: map[string]*ctx.Command{
|
Commands: map[string]*ctx.Command{
|
||||||
"train": &ctx.Command{Name: "train seed [hash [page]", Help: "添加词法规则", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"train": &ctx.Command{Name: "train seed [hash [page]", Help: "添加词法规则", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
lex, ok := m.Target().Server.(*LEX)
|
if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{
|
||||||
m.Assert(ok, "模块类型错误")
|
page, hash := 1, 1
|
||||||
m.Assert(len(arg) > 0, "参数错误")
|
if len(arg) > 2 {
|
||||||
|
page = lex.index("npage", arg[2])
|
||||||
|
}
|
||||||
|
if len(arg) > 1 {
|
||||||
|
hash = lex.index("nhash", arg[1])
|
||||||
|
}
|
||||||
|
|
||||||
lex.train([]byte(arg[0]), arg[1:]...)
|
if lex.mat[page] == nil {
|
||||||
|
lex.mat[page] = map[byte]*State{}
|
||||||
|
}
|
||||||
|
|
||||||
|
lex.seed = append(lex.seed, &Seed{page, hash, string(arg[0])})
|
||||||
|
lex.Log("info", nil, "%d %d %d %v", page, hash, lex.Capi("nseed", 1), arg[0])
|
||||||
|
lex.Cap("stream", fmt.Sprintf("%s,%s,%s", lex.Cap("nseed"), lex.Cap("npage"), lex.Cap("nhash")))
|
||||||
|
|
||||||
|
m.Echo("%d", lex.train(page, hash, []byte(arg[0])))
|
||||||
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"parse": &ctx.Command{Name: "parse line [page]", Help: "解析单词", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"parse": &ctx.Command{Name: "parse line [page]", Help: "解析单词", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
lex, ok := m.Target().Server.(*LEX)
|
if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{
|
||||||
m.Assert(ok, "模块类型错误")
|
page := 1
|
||||||
m.Assert(len(arg) > 0, "参数错误")
|
if len(arg) > 1 {
|
||||||
|
page = lex.index("npage", arg[1])
|
||||||
|
}
|
||||||
|
|
||||||
word, hash, rest := lex.parse([]byte(arg[0]), arg[1:]...)
|
hash, word, rest := lex.parse(page, []byte(arg[0]))
|
||||||
m.Add("result", string(word), fmt.Sprintf("%d", hash), string(rest))
|
m.Add("result", fmt.Sprintf("%d", hash), string(word), string(rest))
|
||||||
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"split": &ctx.Command{Name: "split line page1 [page2]", Help: "分割语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"split": &ctx.Command{Name: "split line page void help", Help: "分割语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
lex, ok := m.Target().Server.(*LEX)
|
if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{
|
||||||
m.Assert(ok, "模块类型错误")
|
page := 1
|
||||||
m.Assert(len(arg) > 1, "参数错误")
|
if len(arg) > 1 {
|
||||||
|
page = lex.index("npage", arg[1])
|
||||||
for line := arg[0]; len(line) > 0; {
|
|
||||||
word, hash, rest := lex.parse([]byte(line), arg[1:]...)
|
|
||||||
line = string(rest)
|
|
||||||
word, hash, rest = lex.parse([]byte(line), arg[2:]...)
|
|
||||||
line = string(rest)
|
|
||||||
|
|
||||||
if hash == 0 {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(word) > 1 {
|
void := 2
|
||||||
switch word[0] {
|
if len(arg) > 2 {
|
||||||
case '"', '\'':
|
void = lex.index("npage", arg[2])
|
||||||
word = word[1 : len(word)-1]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Add("result", string(word))
|
help := 2
|
||||||
|
if len(arg) > 3 {
|
||||||
|
help = lex.index("npage", arg[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rest := []byte(arg[0])
|
||||||
|
_, _, rest = lex.parse(help, []byte(rest))
|
||||||
|
_, _, rest = lex.parse(void, []byte(rest))
|
||||||
|
hash, word, rest := lex.parse(page, []byte(rest))
|
||||||
|
m.Add("result", fmt.Sprintf("%d", hash), string(word), string(rest))
|
||||||
|
} // }}}
|
||||||
}},
|
}},
|
||||||
"cache": &ctx.Command{Name: "cache", Help: "显示缓存", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
"info": &ctx.Command{Name: "info", Help: "显示缓存", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
lex, ok := m.Target().Server.(*LEX)
|
if lex, ok := m.Target().Server.(*LEX); m.Assert(ok) { // {{{
|
||||||
m.Assert(ok, "模块类型错误")
|
|
||||||
for i, v := range lex.seed {
|
for i, v := range lex.seed {
|
||||||
m.Echo("seed: %d %v\n", i, v)
|
m.Echo("seed: %d %v\n", i, v)
|
||||||
}
|
}
|
||||||
@ -348,13 +398,9 @@ var Index = &ctx.Context{Name: "lex", Help: "词法解析",
|
|||||||
m.Echo("node: %v %v %v\n", i, k, v)
|
m.Echo("node: %v %v %v\n", i, k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // }}}
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
Index: map[string]*ctx.Context{
|
|
||||||
"void": &ctx.Context{Name: "void",
|
|
||||||
Commands: map[string]*ctx.Command{"split": &ctx.Command{}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
371
src/context/yac/yac.go
Normal file
371
src/context/yac/yac.go
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
package yac // {{{
|
||||||
|
// }}}
|
||||||
|
import ( // {{{
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
type Seed struct { // {{{
|
||||||
|
page int
|
||||||
|
hash int
|
||||||
|
word []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
type State struct { // {{{
|
||||||
|
star int
|
||||||
|
next int
|
||||||
|
hash int
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
type YAC struct { // {{{
|
||||||
|
seed []*Seed
|
||||||
|
page map[string]int
|
||||||
|
hash map[string]int
|
||||||
|
hand map[int]string
|
||||||
|
|
||||||
|
state map[State]*State
|
||||||
|
mat []map[byte]*State
|
||||||
|
|
||||||
|
lex *ctx.Message
|
||||||
|
*ctx.Message
|
||||||
|
*ctx.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
func (yac *YAC) train(page, hash int, word []string) ([]*State, int) { // {{{
|
||||||
|
|
||||||
|
if yac.mat[page] == nil {
|
||||||
|
yac.mat[page] = map[byte]*State{}
|
||||||
|
for i := 0; i < yac.Capi("nlang"); i++ {
|
||||||
|
yac.mat[page][byte(i)] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sn := make([]bool, yac.Capi("nline"))
|
||||||
|
ss := []int{page}
|
||||||
|
|
||||||
|
begin := page
|
||||||
|
point := []*State{}
|
||||||
|
ends := []*State{}
|
||||||
|
state := []*State{}
|
||||||
|
mul := false
|
||||||
|
skip := len(word)
|
||||||
|
|
||||||
|
for i, n := 0, 1; i < len(word); i += n {
|
||||||
|
if !mul {
|
||||||
|
if hash <= 0 && word[i] == "}" {
|
||||||
|
if skip = i + 2; hash == -1 {
|
||||||
|
hash = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return ends, skip
|
||||||
|
} else {
|
||||||
|
ends = ends[:0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range ss {
|
||||||
|
switch word[i] {
|
||||||
|
case "opt{":
|
||||||
|
sn[s] = true
|
||||||
|
state, n = yac.train(s, 0, word[i+1:])
|
||||||
|
for _, x := range state {
|
||||||
|
for i := len(sn); i <= x.next; i++ {
|
||||||
|
sn = append(sn, false)
|
||||||
|
}
|
||||||
|
sn[x.next] = true
|
||||||
|
point = append(point, x)
|
||||||
|
}
|
||||||
|
case "rep{":
|
||||||
|
sn[s] = true
|
||||||
|
state, n = yac.train(s, -1, word[i+1:])
|
||||||
|
for _, x := range state {
|
||||||
|
x.star = s
|
||||||
|
sn[x.next] = true
|
||||||
|
point = append(point, x)
|
||||||
|
yac.Pulse.Log("info", nil, "END: %v", x)
|
||||||
|
}
|
||||||
|
case "mul{":
|
||||||
|
mul, n = true, 1
|
||||||
|
goto next
|
||||||
|
case "}":
|
||||||
|
if mul {
|
||||||
|
mul = false
|
||||||
|
goto next
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
c := byte(0)
|
||||||
|
if x, ok := yac.page[word[i]]; !ok {
|
||||||
|
lex := yac.lex.Spawn(yac.lex.Target())
|
||||||
|
lex.Cmd("parse", word[i], fmt.Sprintf("yac%d", s))
|
||||||
|
if lex.Gets("result") {
|
||||||
|
x = lex.Geti("result")
|
||||||
|
} else {
|
||||||
|
x = len(yac.mat[s])
|
||||||
|
lex = yac.lex.Spawn(yac.lex.Target())
|
||||||
|
lex.Cmd("train", word[i], fmt.Sprintf("%d", x), fmt.Sprintf("yac%d", s))
|
||||||
|
}
|
||||||
|
c = byte(x)
|
||||||
|
} else {
|
||||||
|
c = byte(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
state := yac.mat[s][c]
|
||||||
|
yac.Pulse.Log("info", nil, "GET(%d, %d): %v", s, c, state)
|
||||||
|
if state == nil {
|
||||||
|
state = &State{}
|
||||||
|
yac.Pulse.Capi("nnode", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.next == 0 {
|
||||||
|
yac.mat = append(yac.mat, map[byte]*State{})
|
||||||
|
state.next = yac.Pulse.Capi("nline", 1) - 1
|
||||||
|
for i := 0; i < yac.Capi("nlang"); i++ {
|
||||||
|
yac.mat[state.next][byte(i)] = nil
|
||||||
|
}
|
||||||
|
sn = append(sn, false)
|
||||||
|
}
|
||||||
|
sn[state.next] = true
|
||||||
|
|
||||||
|
if x, ok := yac.state[*state]; !ok {
|
||||||
|
yac.Pulse.Capi("nreal", 1)
|
||||||
|
yac.state[*state] = state
|
||||||
|
} else {
|
||||||
|
yac.mat[s][c] = x
|
||||||
|
}
|
||||||
|
yac.mat[s][c] = state
|
||||||
|
|
||||||
|
yac.Pulse.Log("info", nil, "SET(%d, %d): %v", s, c, state)
|
||||||
|
ends = append(ends, state)
|
||||||
|
point = append(point, state)
|
||||||
|
if s > begin {
|
||||||
|
begin = s
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next:
|
||||||
|
if !mul {
|
||||||
|
ss = ss[:0]
|
||||||
|
for s, b := range sn {
|
||||||
|
if sn[s] = false; b {
|
||||||
|
ss = append(ss, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, n := range ss {
|
||||||
|
if n < yac.Pulse.Capi("nlang") || n >= len(yac.mat) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
void := true
|
||||||
|
for _, x := range yac.mat[n] {
|
||||||
|
if x != nil {
|
||||||
|
void = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if void {
|
||||||
|
yac.Pulse.Log("info", nil, "DEL: %d %d", yac.Pulse.Capi("nline"), n)
|
||||||
|
yac.Pulse.Capi("nline", 0, n)
|
||||||
|
yac.mat = yac.mat[:n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, n := range ss {
|
||||||
|
for _, s := range point {
|
||||||
|
if s.next == n {
|
||||||
|
yac.Pulse.Log("info", nil, "GET: %v", s)
|
||||||
|
if s.next >= len(yac.mat) {
|
||||||
|
s.next = 0
|
||||||
|
}
|
||||||
|
if hash > 0 {
|
||||||
|
s.hash = hash
|
||||||
|
}
|
||||||
|
yac.Pulse.Log("info", nil, "SET: %v", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ends, skip
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
func (yac *YAC) parse(m *ctx.Message, page, void int, line string) ([]string, string) { // {{{
|
||||||
|
|
||||||
|
level := m.Capi("level", 1)
|
||||||
|
m.Log("info", nil, ">>>%s%d", m.Cap("label")[0:level], level)
|
||||||
|
|
||||||
|
hash, word := 0, []string{}
|
||||||
|
for star, s := 0, page; s != 0 && len(line) > 0; {
|
||||||
|
|
||||||
|
lex := yac.lex.Spawn(yac.lex.Target())
|
||||||
|
lex.Cmd("parse", line, fmt.Sprintf("yac%d", void))
|
||||||
|
line = lex.Meta["result"][2]
|
||||||
|
|
||||||
|
lex = yac.lex.Spawn(yac.lex.Target())
|
||||||
|
lex.Cmd("parse", line, fmt.Sprintf("yac%d", s))
|
||||||
|
line = lex.Meta["result"][2]
|
||||||
|
|
||||||
|
c := byte(lex.Geti("result"))
|
||||||
|
state := yac.mat[s][c]
|
||||||
|
m.Log("info", nil, "get(%d,%d): %s %v", s, c, lex.Meta["result"][1], state)
|
||||||
|
if state == nil {
|
||||||
|
for i, x := range yac.mat[s] {
|
||||||
|
if int(i) >= m.Capi("nlang") || x == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m.Log("info", nil, "try(%d,%d): %v", s, i, x)
|
||||||
|
if w, l := yac.parse(m, int(i), void, line); l != line {
|
||||||
|
word = append(word, w...)
|
||||||
|
state = x
|
||||||
|
line = l
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
word = append(word, lex.Meta["result"][1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if state == nil {
|
||||||
|
s, star = star, 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
star, s, hash = state.star, state.next, state.hash
|
||||||
|
if s == 0 {
|
||||||
|
s, star = star, 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hash == 0 {
|
||||||
|
word = word[:0]
|
||||||
|
} else {
|
||||||
|
m.Log("info", nil, "%s(%d,%d): %d %v %v", yac.hand[page], page, hash, len(word), word, line)
|
||||||
|
msg := m.Spawn(m.Source()).Add("detail", yac.hand[page], word...)
|
||||||
|
if msg.Cmd(); msg.Hand {
|
||||||
|
word = msg.Meta["result"]
|
||||||
|
}
|
||||||
|
m.Log("info", nil, "end(%d,%d): %d %v %v", page, hash, len(word), word, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Log("info", nil, "<<<%s%d", m.Cap("label")[0:level], level)
|
||||||
|
level = m.Capi("level", -1)
|
||||||
|
return word, line
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
func (yac *YAC) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
||||||
|
c.Caches = map[string]*ctx.Cache{}
|
||||||
|
c.Configs = map[string]*ctx.Config{}
|
||||||
|
|
||||||
|
s := new(YAC)
|
||||||
|
s.Context = c
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
func (yac *YAC) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
||||||
|
yac.Message = m
|
||||||
|
if yac.Context == Index {
|
||||||
|
Pulse = m
|
||||||
|
}
|
||||||
|
|
||||||
|
yac.Caches["ncell"] = &ctx.Cache{Name: "单词上限", Value: "128", Help: "单词上限"}
|
||||||
|
yac.Caches["nlang"] = &ctx.Cache{Name: "集合上限", Value: "16", Help: "集合上限"}
|
||||||
|
|
||||||
|
yac.Caches["nseed"] = &ctx.Cache{Name: "种子数量", Value: "0", Help: "种子数量"}
|
||||||
|
yac.Caches["npage"] = &ctx.Cache{Name: "集合数量", Value: "0", Help: "集合数量"}
|
||||||
|
yac.Caches["nhash"] = &ctx.Cache{Name: "类型数量", Value: "0", Help: "类型数量"}
|
||||||
|
|
||||||
|
yac.Caches["nline"] = &ctx.Cache{Name: "状态数量", Value: "16", Help: "状态数量"}
|
||||||
|
yac.Caches["nnode"] = &ctx.Cache{Name: "节点数量", Value: "0", Help: "节点数量"}
|
||||||
|
yac.Caches["nreal"] = &ctx.Cache{Name: "实点数量", Value: "0", Help: "实点数量"}
|
||||||
|
|
||||||
|
yac.Caches["level"] = &ctx.Cache{Name: "嵌套层级", Value: "0", Help: "嵌套层级"}
|
||||||
|
yac.Caches["label"] = &ctx.Cache{Name: "嵌套标记", Value: "####################", Help: "嵌套层级"}
|
||||||
|
|
||||||
|
yac.page = map[string]int{"nil": 0}
|
||||||
|
yac.hash = map[string]int{"nil": 0}
|
||||||
|
yac.hand = map[int]string{0: "nil"}
|
||||||
|
|
||||||
|
yac.mat = make([]map[byte]*State, m.Capi("nlang"))
|
||||||
|
yac.state = map[State]*State{}
|
||||||
|
return yac
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
func (yac *YAC) Start(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
|
yac.Message = m
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
func (yac *YAC) Close(m *ctx.Message, arg ...string) bool { // {{{
|
||||||
|
switch yac.Context {
|
||||||
|
case m.Target():
|
||||||
|
case m.Source():
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
var Pulse *ctx.Message
|
||||||
|
var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||||
|
Caches: map[string]*ctx.Cache{},
|
||||||
|
Configs: map[string]*ctx.Config{},
|
||||||
|
Commands: map[string]*ctx.Command{
|
||||||
|
"train": &ctx.Command{Name: "train page hash word...", Help: "添加语法规则, page: 语法集合, hash: 语句类型, word: 语法模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
|
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) { // {{{
|
||||||
|
page, ok := yac.page[arg[0]]
|
||||||
|
if !ok {
|
||||||
|
page = m.Capi("npage", 1)
|
||||||
|
yac.page[arg[0]] = page
|
||||||
|
}
|
||||||
|
|
||||||
|
hash, ok := yac.hash[arg[1]]
|
||||||
|
if !ok {
|
||||||
|
hash = m.Capi("nhash", 1)
|
||||||
|
yac.hash[arg[0]] = hash
|
||||||
|
yac.hand[hash] = arg[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if yac.lex == nil {
|
||||||
|
lex := m.Find("lex", true)
|
||||||
|
lex.Start("lyacc", "语法词法")
|
||||||
|
yac.lex = lex
|
||||||
|
}
|
||||||
|
yac.seed = append(yac.seed, &Seed{page, hash, arg[2:]})
|
||||||
|
yac.Capi("nseed", 1)
|
||||||
|
yac.train(page, hash, arg[2:])
|
||||||
|
} // }}}
|
||||||
|
}},
|
||||||
|
"parse": &ctx.Command{Name: "parse page void word...", Help: "解析语句, page: 语法集合, void: 空白语法集合, word: 语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
||||||
|
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) { // {{{
|
||||||
|
page, ok := yac.page[arg[0]]
|
||||||
|
m.Assert(ok)
|
||||||
|
void, ok := yac.page[arg[1]]
|
||||||
|
m.Assert(ok)
|
||||||
|
word, rest := yac.parse(m, page, void, strings.Join(arg[2:], " "))
|
||||||
|
m.Add("result", rest, word...)
|
||||||
|
} // }}}
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
yac := &YAC{}
|
||||||
|
yac.Context = Index
|
||||||
|
ctx.Index.Register(Index, yac)
|
||||||
|
}
|
@ -12,6 +12,7 @@ import (
|
|||||||
_ "context/web"
|
_ "context/web"
|
||||||
|
|
||||||
_ "context/lex"
|
_ "context/lex"
|
||||||
|
_ "context/yac"
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user