forked from x/ContextOS
1241 lines
38 KiB
Go
1241 lines
38 KiB
Go
package yac
|
|
|
|
import (
|
|
"contexts/ctx"
|
|
"sort"
|
|
kit "toolkit"
|
|
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Seed struct {
|
|
page int
|
|
hash int
|
|
word []string
|
|
}
|
|
type Point struct {
|
|
s int
|
|
c byte
|
|
}
|
|
type State struct {
|
|
star int
|
|
next int
|
|
hash int
|
|
}
|
|
type YAC struct {
|
|
seed []*Seed
|
|
page map[string]int
|
|
word map[int]string
|
|
hand map[int]string
|
|
hash map[string]int
|
|
|
|
state map[State]*State
|
|
mat []map[byte]*State
|
|
|
|
lex *ctx.Message
|
|
|
|
label map[string]string
|
|
*ctx.Context
|
|
}
|
|
type Parser interface {
|
|
Parse(m *ctx.Message, line []byte, page string) (hash int, rest []byte, word []byte)
|
|
}
|
|
|
|
func (yac *YAC) name(page int) string {
|
|
if name, ok := yac.word[page]; ok {
|
|
return name
|
|
}
|
|
return fmt.Sprintf("yac%d", page)
|
|
}
|
|
func (yac *YAC) index(m *ctx.Message, hash string, h string) int {
|
|
which, names := yac.page, yac.word
|
|
if hash == "nhash" {
|
|
which, names = yac.hash, yac.hand
|
|
}
|
|
|
|
if x, ok := which[h]; ok {
|
|
return x
|
|
}
|
|
|
|
which[h] = m.Capi(hash, 1)
|
|
names[which[h]] = h
|
|
m.Assert(hash != "npage" || m.Capi("npage") < m.Confi("meta", "nlang"), "语法集合超过上限")
|
|
return which[h]
|
|
}
|
|
func (yac *YAC) train(m *ctx.Message, page, hash int, word []string, level int) (int, []*Point, []*Point) {
|
|
m.Log("debug", "%s %s\\%d page: %v hash: %v word: %v", "train", strings.Repeat("#", level), level, page, hash, word)
|
|
|
|
ss := []int{page}
|
|
sn := make([]bool, m.Capi("nline"))
|
|
points, ends := []*Point{}, []*Point{}
|
|
|
|
for i, n, mul := 0, 1, false; i < len(word); i += n {
|
|
if !mul {
|
|
if hash <= 0 && word[i] == "}" {
|
|
return i + 2, points, ends
|
|
}
|
|
ends = ends[:0]
|
|
}
|
|
|
|
for _, s := range ss {
|
|
switch word[i] {
|
|
case "opt{", "rep{":
|
|
sn[s] = true
|
|
num, point, end := yac.train(m, s, 0, word[i+1:], level+1)
|
|
n, points = num, append(points, point...)
|
|
|
|
for _, x := range end {
|
|
state := &State{}
|
|
*state = *yac.mat[x.s][x.c]
|
|
for i := len(sn); i <= state.next; i++ {
|
|
sn = append(sn, false)
|
|
}
|
|
sn[state.next] = true
|
|
|
|
points = append(points, x)
|
|
if word[i] == "rep{" {
|
|
state.star = s
|
|
yac.mat[x.s][x.c] = state
|
|
m.Log("debug", "REP(%d, %d): %v", x.s, x.c, state)
|
|
}
|
|
}
|
|
case "mul{":
|
|
mul, n = true, 1
|
|
goto next
|
|
case "}":
|
|
if mul {
|
|
mul = false
|
|
goto next
|
|
}
|
|
fallthrough
|
|
default:
|
|
x, ok := yac.page[word[i]]
|
|
if !ok {
|
|
if x = kit.Int(yac.lex.Spawn().Cmdx("parse", word[i], yac.name(s))); x == 0 {
|
|
x = kit.Int(yac.lex.Spawn().Cmdx("train", word[i], len(yac.mat[s]), yac.name(s)))
|
|
}
|
|
}
|
|
|
|
c := byte(x)
|
|
state := &State{}
|
|
if yac.mat[s][c] != nil {
|
|
*state = *yac.mat[s][c]
|
|
} else {
|
|
m.Capi("nnode", 1)
|
|
}
|
|
if state.next == 0 {
|
|
state.next = m.Capi("nline", 1) - 1
|
|
yac.mat = append(yac.mat, map[byte]*State{})
|
|
for i := 0; i < m.Capi("nline"); i++ {
|
|
yac.mat[state.next][byte(i)] = nil
|
|
}
|
|
sn = append(sn, false)
|
|
}
|
|
sn[state.next] = true
|
|
yac.mat[s][c] = state
|
|
ends = append(ends, &Point{s, c})
|
|
points = append(points, &Point{s, c})
|
|
}
|
|
}
|
|
next:
|
|
if !mul {
|
|
ss = ss[:0]
|
|
for s, b := range sn {
|
|
if sn[s] = false; b {
|
|
ss = append(ss, s)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for _, s := range ss {
|
|
if s < m.Confi("meta", "nlang") || s >= len(yac.mat) {
|
|
continue
|
|
}
|
|
void := true
|
|
for _, x := range yac.mat[s] {
|
|
if x != nil {
|
|
void = false
|
|
break
|
|
}
|
|
}
|
|
if void {
|
|
last := m.Capi("nline") - 1
|
|
m.Cap("nline", "0")
|
|
m.Log("debug", "DEL: %d-%d", last, m.Capi("nline", s))
|
|
yac.mat = yac.mat[:s]
|
|
}
|
|
}
|
|
for _, s := range ss {
|
|
for _, p := range points {
|
|
state := &State{}
|
|
*state = *yac.mat[p.s][p.c]
|
|
if state.next == s {
|
|
m.Log("debug", "GET(%d, %d): %v", p.s, p.c, state)
|
|
if state.next >= len(yac.mat) {
|
|
state.next = 0
|
|
}
|
|
if hash > 0 {
|
|
state.hash = hash
|
|
}
|
|
yac.mat[p.s][p.c] = state
|
|
m.Log("debug", "SET(%d, %d): %v", p.s, p.c, state)
|
|
}
|
|
if x, ok := yac.state[*state]; !ok {
|
|
yac.state[*state] = yac.mat[p.s][p.c]
|
|
m.Capi("nreal", 1)
|
|
} else {
|
|
yac.mat[p.s][p.c] = x
|
|
}
|
|
}
|
|
}
|
|
|
|
m.Log("debug", "%s %s/%d word: %d point: %d end: %d", "train", strings.Repeat("#", level), level, len(word), len(points), len(ends))
|
|
return len(word), points, ends
|
|
}
|
|
func (yac *YAC) parse(m *ctx.Message, msg *ctx.Message, stack *kit.Stack, page int, void int, line []byte, level int) (rest []byte, word []string, hash int) {
|
|
m.Log("debug", "%s %s\\%d %s(%d): %s", "parse", strings.Repeat("#", level), level, yac.name(page), page, string(line))
|
|
|
|
h, r, w := 0, []byte{}, []byte{}
|
|
p, _ := yac.lex.Target().Server.(Parser)
|
|
|
|
for star, s := 0, page; s != 0 && len(line) > 0; {
|
|
//解析空白
|
|
if h, r, _ = p.Parse(m, line, yac.name(void)); h == -1 {
|
|
break
|
|
}
|
|
//解析单词
|
|
if h, r, w = p.Parse(m, r, yac.name(s)); h == -1 {
|
|
break
|
|
}
|
|
|
|
//解析状态
|
|
state := yac.mat[s][byte(h)]
|
|
|
|
//全局语法检查
|
|
if state != nil {
|
|
if hh, _, ww := p.Parse(m, line, "key"); hh == 0 || len(ww) <= len(w) {
|
|
line, word = r, append(word, string(w))
|
|
} else {
|
|
state = nil
|
|
}
|
|
}
|
|
//嵌套语法递归解析
|
|
if state == nil {
|
|
for i := 0; i < m.Confi("meta", "ncell"); i++ {
|
|
if x := yac.mat[s][byte(i)]; i < m.Confi("meta", "nlang") && x != nil {
|
|
if l, w, _ := yac.parse(m, msg, stack, i, void, line, level+1); len(l) != len(line) {
|
|
line, word, state = l, append(word, w...), x
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//语法切换
|
|
if state == nil {
|
|
s, star = star, 0
|
|
} else if s, star, hash = state.next, state.star, state.hash; s == 0 {
|
|
s, star = star, 0
|
|
}
|
|
}
|
|
|
|
if hash == 0 {
|
|
word = word[:0]
|
|
|
|
} else if !m.Confs("exec", []string{"disable", yac.hand[hash]}) {
|
|
if stack == nil || stack.Peek().Run || m.Confs("exec", []string{"always", yac.hand[hash]}) {
|
|
//执行命令
|
|
cmd := msg.Spawn(m.Optionv("bio.ctx"))
|
|
if cmd.Cmd(yac.hand[hash], word); cmd.Hand {
|
|
word = cmd.Meta["result"]
|
|
}
|
|
//切换模块
|
|
if v := cmd.Optionv("bio.ctx"); v != nil {
|
|
m.Optionv("bio.ctx", v)
|
|
}
|
|
}
|
|
}
|
|
|
|
m.Log("debug", "%s %s/%d %s(%d): %v", "parse", strings.Repeat("#", level), level, yac.hand[hash], hash, word)
|
|
return line, word, hash
|
|
}
|
|
|
|
func (yac *YAC) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
|
|
return &YAC{Context: c}
|
|
}
|
|
func (yac *YAC) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
|
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: m.Conf("meta", "nlang"), 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: "level", Value: "0", Help: "嵌套层级"}
|
|
yac.Caches["parse"] = &ctx.Cache{Name: "parse(true/false)", Value: "true", Help: "命令解析"}
|
|
|
|
yac.page = map[string]int{"nil": 0}
|
|
yac.word = map[int]string{0: "nil"}
|
|
yac.hash = map[string]int{"nil": 0}
|
|
yac.hand = map[int]string{0: "nil"}
|
|
|
|
yac.state = map[State]*State{}
|
|
yac.mat = make([]map[byte]*State, m.Capi("nline"))
|
|
return yac
|
|
}
|
|
func (yac *YAC) Start(m *ctx.Message, arg ...string) (close bool) {
|
|
return true
|
|
}
|
|
func (yac *YAC) Close(m *ctx.Message, arg ...string) bool {
|
|
return false
|
|
}
|
|
|
|
var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
|
Caches: map[string]*ctx.Cache{
|
|
"nshy": &ctx.Cache{Name: "nshy", Value: "0", Help: "引擎数量"},
|
|
},
|
|
Configs: map[string]*ctx.Config{
|
|
"nline": &ctx.Config{Name: "nline", Value: "line", Help: "默认页"},
|
|
"nvoid": &ctx.Config{Name: "nvoid", Value: "void", Help: "默认值"},
|
|
"meta": &ctx.Config{Name: "meta", Value: map[string]interface{}{
|
|
"ncell": 128, "nlang": 64, "compact": true,
|
|
"name": "shy%d", "help": "engine",
|
|
}, Help: "初始参数"},
|
|
"seed": &ctx.Config{Name: "seed", Value: []interface{}{
|
|
map[string]interface{}{"page": "void", "hash": "void", "word": []interface{}{"[\t ]+"}},
|
|
|
|
// 数据类型
|
|
map[string]interface{}{"page": "num", "hash": "num", "word": []interface{}{"mul{", "0", "-?[1-9][0-9]*", "0[0-9]+", "0x[0-9]+", "}"}},
|
|
map[string]interface{}{"page": "key", "hash": "key", "word": []interface{}{"[A-Za-z_][A-Za-z_0-9]*"}},
|
|
map[string]interface{}{"page": "str", "hash": "str", "word": []interface{}{"mul{", "\"[^\"]*\"", "'[^']*'", "}"}},
|
|
map[string]interface{}{"page": "exe", "hash": "exe", "word": []interface{}{"mul{", "$", "@", "}", "opt{", "key", "}"}},
|
|
map[string]interface{}{"page": "exe", "hash": "exe", "word": []interface{}{"mul{", "$", "@", "}", "opt{", "num", "}"}},
|
|
|
|
// 表达式语句
|
|
map[string]interface{}{"page": "op1", "hash": "op1", "word": []interface{}{"mul{", "-", "+", "}"}},
|
|
map[string]interface{}{"page": "op2", "hash": "op2", "word": []interface{}{"mul{", "~", "!~", "}"}},
|
|
map[string]interface{}{"page": "op2", "hash": "op2", "word": []interface{}{"mul{", "+", "-", "*", "/", "%", "}"}},
|
|
map[string]interface{}{"page": "op2", "hash": "op2", "word": []interface{}{"mul{", "<", "<=", ">", ">=", "==", "!=", "}"}},
|
|
map[string]interface{}{"page": "val", "hash": "val", "word": []interface{}{"opt{", "op1", "}", "mul{", "num", "key", "str", "exe", "}"}},
|
|
map[string]interface{}{"page": "exp", "hash": "exp", "word": []interface{}{"val", "rep{", "op2", "val", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "return", "word": []interface{}{"return", "rep{", "exp", "}"}},
|
|
|
|
// 命令语句
|
|
map[string]interface{}{"page": "word", "hash": "word", "word": []interface{}{"mul{", "~", "!", "\\?", "\\?\\?", "exe", "str", "[\\-a-zA-Z0-9_:/.%*]+", "=", "<", ">$", ">@", ">", "\\|", "}"}},
|
|
map[string]interface{}{"page": "cmd", "hash": "cmd", "word": []interface{}{"rep{", "word", "}"}},
|
|
map[string]interface{}{"page": "com", "hash": "com", "word": []interface{}{"mul{", ";", "#[^\n]*\n?", "\n", "}"}},
|
|
map[string]interface{}{"page": "line", "hash": "line", "word": []interface{}{"opt{", "mul{", "stm", "cmd", "}", "}", "com"}},
|
|
|
|
// 复合语句
|
|
map[string]interface{}{"page": "op1", "hash": "op1", "word": []interface{}{"mul{", "!", "}"}},
|
|
map[string]interface{}{"page": "op2", "hash": "op2", "word": []interface{}{"mul{", "&&", "||", "}"}},
|
|
map[string]interface{}{"page": "exe", "hash": "exe", "word": []interface{}{"(", "exp", ")"}},
|
|
map[string]interface{}{"page": "exe", "hash": "exe", "word": []interface{}{"$", "(", "cmd", ")"}},
|
|
map[string]interface{}{"page": "stm", "hash": "var", "word": []interface{}{"var", "key", "opt{", "=", "exp", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "let", "word": []interface{}{"let", "key", "opt{", "=", "exp", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "let", "word": []interface{}{"let", "key", "=", "\\[", "rep{", "exp", "}", "\\]"}},
|
|
map[string]interface{}{"page": "stm", "hash": "let", "word": []interface{}{"let", "key", "=", "\\{", "rep{", "exp", "}", "\\}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "if", "word": []interface{}{"if", "exp"}},
|
|
map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "rep{", "key", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "rep{", "exp", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "fun", "word": []interface{}{"fun", "key", "rep{", "exp", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "kit", "word": []interface{}{"kit", "rep{", "exp", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "else", "word": []interface{}{"else", "opt{", "if", "exp", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "end", "word": []interface{}{"end"}},
|
|
|
|
map[string]interface{}{"page": "stm", "hash": "label", "word": []interface{}{"label", "key"}},
|
|
map[string]interface{}{"page": "stm", "hash": "goto", "word": []interface{}{"goto", "key"}},
|
|
/*
|
|
|
|
map[string]interface{}{"page": "op1", "hash": "op1", "word": []interface{}{"mul{", "-z", "-n", "}"}},
|
|
map[string]interface{}{"page": "op1", "hash": "op1", "word": []interface{}{"mul{", "-e", "-f", "-d", "}"}},
|
|
map[string]interface{}{"page": "op2", "hash": "op2", "word": []interface{}{"mul{", ":=", "=", "+=", "}"}},
|
|
|
|
map[string]interface{}{"page": "exp", "hash": "exp", "word": []interface{}{"\\{", "rep{", "map", "}", "\\}"}},
|
|
map[string]interface{}{"page": "val", "hash": "val", "word": []interface{}{"opt{", "op1", "}", "(", "exp", ")"}},
|
|
|
|
map[string]interface{}{"page": "stm", "hash": "var", "word": []interface{}{"var", "key", "<-"}},
|
|
map[string]interface{}{"page": "stm", "hash": "var", "word": []interface{}{"var", "key", "<-", "opt{", "exe", "}"}},
|
|
map[string]interface{}{"page": "stm", "hash": "let", "word": []interface{}{"let", "key", "<-", "opt{", "exe", "}"}},
|
|
|
|
map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "opt{", "exp", ";", "}", "exp"}},
|
|
map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "index", "exp", "opt{", "exp", "}", "exp"}},
|
|
|
|
*/
|
|
|
|
}, Help: "语法集合的最大数量"},
|
|
"input": &ctx.Config{Name: "input", Value: map[string]interface{}{
|
|
"text": true,
|
|
"select": true,
|
|
"button": true,
|
|
"textarea": true,
|
|
"exports": true,
|
|
"feature": true,
|
|
}, Help: "控件类型"},
|
|
"exec": &ctx.Config{Name: "info", Value: map[string]interface{}{
|
|
"disable": map[string]interface{}{
|
|
"void": true,
|
|
"num": true,
|
|
"key": true,
|
|
"op1": true,
|
|
"op2": true,
|
|
"word": true,
|
|
"line": true,
|
|
},
|
|
"always": map[string]interface{}{
|
|
"if": true,
|
|
"else": true,
|
|
"end": true,
|
|
"for": true,
|
|
},
|
|
}, Help: "嵌套层级日志的标记"},
|
|
|
|
"alias": &ctx.Config{Name: "alias", Value: map[string]interface{}{
|
|
"~": []string{"context"},
|
|
"!": []string{"message"},
|
|
":": []string{"command"},
|
|
"::": []string{"command", "list"},
|
|
|
|
"note": []string{"mdb.note"},
|
|
"pwd": []string{"nfs.pwd"},
|
|
"path": []string{"nfs.path"},
|
|
"dir": []string{"nfs.dir"},
|
|
"git": []string{"nfs.git"},
|
|
"brow": []string{"web.brow"},
|
|
"ifconfig": []string{"tcp.ifconfig"},
|
|
}, Help: "启动脚本"},
|
|
},
|
|
Commands: map[string]*ctx.Command{
|
|
"_init": &ctx.Command{Name: "_init", Help: "添加语法规则, page: 语法集合, hash: 语句类型, word: 语法模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) {
|
|
yac.lex = m.Cmd("lex.spawn")
|
|
m.Confm("seed", func(line int, seed map[string]interface{}) {
|
|
m.Spawn().Cmd("train", seed["page"], seed["hash"], seed["word"])
|
|
})
|
|
}
|
|
return
|
|
}},
|
|
"train": &ctx.Command{Name: "train page hash word...", Help: "添加语法规则, page: 语法集合, hash: 语句类型, word: 语法模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) {
|
|
page := yac.index(m, "npage", arg[0])
|
|
hash := yac.index(m, "nhash", arg[1])
|
|
if yac.mat[page] == nil {
|
|
yac.mat[page] = map[byte]*State{}
|
|
for i := 0; i < m.Confi("meta", "nlang"); i++ {
|
|
yac.mat[page][byte(i)] = nil
|
|
}
|
|
}
|
|
yac.train(m, page, hash, arg[2:], 1)
|
|
|
|
yac.seed = append(yac.seed, &Seed{page, hash, arg[2:]})
|
|
m.Cap("stream", fmt.Sprintf("%d,%s,%s", m.Cap("nseed", len(yac.seed)),
|
|
m.Cap("npage"), m.Cap("nhash", len(yac.hash)-1)))
|
|
}
|
|
return
|
|
}},
|
|
"parse": &ctx.Command{Name: "parse line", Help: "解析语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) {
|
|
stack, _ := m.Optionv("bio.stack").(*kit.Stack)
|
|
m.Optioni("yac.page", yac.page[m.Conf("nline")])
|
|
m.Optioni("yac.void", yac.page[m.Conf("nvoid")])
|
|
|
|
_, word, _ := yac.parse(m, m, stack, m.Optioni("yac.page"), m.Optioni("yac.void"), []byte(arg[0]), 1)
|
|
m.Result(word)
|
|
}
|
|
return
|
|
}},
|
|
"show": &ctx.Command{Name: "show seed|page|hash|mat", Help: "查看信息", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) {
|
|
if len(arg) == 0 {
|
|
m.Push("seed", len(yac.seed))
|
|
m.Push("page", len(yac.page))
|
|
m.Push("hash", len(yac.hash))
|
|
m.Push("nmat", len(yac.mat))
|
|
m.Push("node", len(yac.state))
|
|
m.Table()
|
|
return
|
|
}
|
|
|
|
switch arg[0] {
|
|
case "seed":
|
|
for _, v := range yac.seed {
|
|
m.Push("page", yac.hand[v.page])
|
|
m.Push("word", strings.Replace(strings.Replace(fmt.Sprint(v.word), "\n", "\\n", -1), "\t", "\\t", -1))
|
|
m.Push("hash", yac.word[v.hash])
|
|
}
|
|
m.Sort("page", "int").Table()
|
|
|
|
case "page":
|
|
for k, v := range yac.page {
|
|
m.Add("append", "page", k)
|
|
m.Add("append", "code", v)
|
|
}
|
|
m.Sort("code", "int").Table()
|
|
|
|
case "hash":
|
|
for k, v := range yac.hash {
|
|
m.Add("append", "hash", k)
|
|
m.Add("append", "code", v)
|
|
m.Add("append", "hand", yac.hand[v])
|
|
}
|
|
m.Sort("code", "int").Table()
|
|
|
|
case "node":
|
|
for _, v := range yac.state {
|
|
m.Push("star", v.star)
|
|
m.Push("next", v.next)
|
|
m.Push("hash", v.hash)
|
|
}
|
|
m.Table()
|
|
|
|
case "mat":
|
|
for i, v := range yac.mat {
|
|
if i <= m.Capi("npage") {
|
|
m.Push("index", yac.hand[i])
|
|
} else if i < m.Confi("meta", "nlang") {
|
|
continue
|
|
} else {
|
|
m.Push("index", i)
|
|
}
|
|
|
|
for j := byte(0); j < byte(m.Confi("meta", "ncell")); j++ {
|
|
c := fmt.Sprintf("%d", j)
|
|
if s := v[j]; s == nil {
|
|
m.Push(c, "")
|
|
} else {
|
|
m.Push(c, fmt.Sprintf("%d,%d,%d", s.star, s.next, s.hash))
|
|
}
|
|
}
|
|
}
|
|
|
|
ncol := len(m.Meta["append"])
|
|
nrow := len(m.Meta[m.Meta["append"][0]])
|
|
for i := 0; i < ncol-1; i++ {
|
|
for j := i + 1; j < ncol; j++ {
|
|
same := true
|
|
void := true
|
|
for n := 0; n < nrow; n++ {
|
|
if m.Meta[m.Meta["append"][i]][n] != "" {
|
|
void = false
|
|
}
|
|
|
|
if m.Meta[m.Meta["append"][i]][n] != m.Meta[m.Meta["append"][j]][n] {
|
|
same = false
|
|
break
|
|
}
|
|
}
|
|
|
|
if same {
|
|
if !void {
|
|
key = m.Meta["append"][i] + "," + m.Meta["append"][j]
|
|
m.Meta[key] = m.Meta[m.Meta["append"][i]]
|
|
m.Meta["append"][i] = key
|
|
}
|
|
|
|
for k := j; k < ncol-1; k++ {
|
|
m.Meta["append"][k] = m.Meta["append"][k+1]
|
|
}
|
|
ncol--
|
|
j--
|
|
}
|
|
}
|
|
}
|
|
m.Meta["append"] = m.Meta["append"][:ncol]
|
|
m.Table()
|
|
}
|
|
}
|
|
return
|
|
}},
|
|
|
|
"str": &ctx.Command{Name: "str word", Help: "解析字符串", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
m.Echo(arg[0][1 : len(arg[0])-1])
|
|
return
|
|
}},
|
|
"exe": &ctx.Command{Name: "exe $ ( cmd )", Help: "解析嵌套命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
switch len(arg) {
|
|
case 1:
|
|
m.Echo(arg[0])
|
|
case 2:
|
|
bio := m.Optionv("bio.msg").(*ctx.Message)
|
|
msg := m.Spawn(m.Optionv("bio.ctx"))
|
|
switch arg[0] {
|
|
case "$":
|
|
// 局部变量
|
|
if stack, ok := m.Optionv("bio.stack").(*kit.Stack); ok {
|
|
if v, ok := stack.Hash(arg[1]); ok {
|
|
m.Echo("%v", v)
|
|
break
|
|
}
|
|
}
|
|
|
|
// 函数参数
|
|
if i, e := strconv.Atoi(arg[1]); e == nil {
|
|
m.Echo(bio.Detail(i))
|
|
break
|
|
}
|
|
// 函数选项
|
|
m.Echo(kit.Select(msg.Cap(arg[1]), bio.Option(arg[1])))
|
|
|
|
case "@":
|
|
// 局部变量
|
|
if stack, ok := m.Optionv("bio.stack").(*kit.Stack); ok {
|
|
if v, ok := stack.Hash(arg[1]); ok {
|
|
m.Echo("%v", v)
|
|
break
|
|
}
|
|
}
|
|
|
|
// 函数参数
|
|
if i, e := strconv.Atoi(arg[1]); e == nil {
|
|
m.Echo(bio.Detail(i))
|
|
break
|
|
}
|
|
// 函数配置
|
|
m.Echo(kit.Select(msg.Conf(arg[1]), bio.Option(arg[1])))
|
|
|
|
default:
|
|
m.Echo(arg[0]).Echo(arg[1])
|
|
}
|
|
default:
|
|
switch arg[0] {
|
|
case "$", "@":
|
|
m.Result(0, arg[2:len(arg)-1])
|
|
case "(":
|
|
m.Echo(arg[1])
|
|
}
|
|
}
|
|
return
|
|
}},
|
|
"val": &ctx.Command{Name: "val exp", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
result := "false"
|
|
switch len(arg) {
|
|
case 0:
|
|
result = ""
|
|
case 1:
|
|
result = arg[0]
|
|
case 2:
|
|
switch arg[0] {
|
|
case "-z":
|
|
if arg[1] == "" {
|
|
result = "true"
|
|
}
|
|
case "-n":
|
|
if arg[1] != "" {
|
|
result = "true"
|
|
}
|
|
|
|
case "-e":
|
|
if _, e := os.Stat(arg[1]); e == nil {
|
|
result = "true"
|
|
}
|
|
case "-f":
|
|
if info, e := os.Stat(arg[1]); e == nil && !info.IsDir() {
|
|
result = "true"
|
|
}
|
|
case "-d":
|
|
if info, e := os.Stat(arg[1]); e == nil && info.IsDir() {
|
|
result = "true"
|
|
}
|
|
case "!":
|
|
result = kit.Format(!kit.Right(arg[1]))
|
|
case "+":
|
|
result = arg[1]
|
|
case "-":
|
|
result = arg[1]
|
|
if i, e := strconv.Atoi(arg[1]); e == nil {
|
|
result = fmt.Sprintf("%d", -i)
|
|
}
|
|
}
|
|
case 3:
|
|
v1, e1 := strconv.Atoi(arg[0])
|
|
v2, e2 := strconv.Atoi(arg[2])
|
|
switch arg[1] {
|
|
case "=":
|
|
result = m.Cap(arg[0], arg[2])
|
|
case "+=":
|
|
if i, e := strconv.Atoi(m.Cap(arg[0])); e == nil && e2 == nil {
|
|
result = m.Cap(arg[0], fmt.Sprintf("%d", v2+i))
|
|
} else {
|
|
result = m.Cap(arg[0], m.Cap(arg[0])+arg[2])
|
|
}
|
|
case "+":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%d", v1+v2)
|
|
} else {
|
|
result = arg[0] + arg[2]
|
|
}
|
|
case "-":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%d", v1-v2)
|
|
} else {
|
|
result = strings.Replace(arg[0], arg[1], "", -1)
|
|
}
|
|
case "*":
|
|
result = arg[0]
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%d", v1*v2)
|
|
}
|
|
case "/":
|
|
result = arg[0]
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%d", v1/v2)
|
|
}
|
|
case "%":
|
|
result = arg[0]
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%d", v1%v2)
|
|
}
|
|
|
|
case "<":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%t", v1 < v2)
|
|
} else {
|
|
result = fmt.Sprintf("%t", arg[0] < arg[2])
|
|
}
|
|
case "<=":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%t", v1 <= v2)
|
|
} else {
|
|
result = fmt.Sprintf("%t", arg[0] <= arg[2])
|
|
}
|
|
case ">":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%t", v1 > v2)
|
|
} else {
|
|
result = fmt.Sprintf("%t", arg[0] > arg[2])
|
|
}
|
|
case ">=":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%t", v1 >= v2)
|
|
} else {
|
|
result = fmt.Sprintf("%t", arg[0] >= arg[2])
|
|
}
|
|
case "==":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%t", v1 == v2)
|
|
} else {
|
|
result = fmt.Sprintf("%t", arg[0] == arg[2])
|
|
}
|
|
case "!=":
|
|
if e1 == nil && e2 == nil {
|
|
result = fmt.Sprintf("%t", v1 != v2)
|
|
} else {
|
|
result = fmt.Sprintf("%t", arg[0] != arg[2])
|
|
}
|
|
case "&&":
|
|
if kit.Right(arg[0]) {
|
|
result = arg[2]
|
|
} else {
|
|
result = arg[0]
|
|
}
|
|
case "||":
|
|
if kit.Right(arg[0]) {
|
|
result = arg[0]
|
|
} else {
|
|
result = arg[2]
|
|
}
|
|
|
|
case "~":
|
|
if m, e := regexp.MatchString(arg[2], arg[0]); m && e == nil {
|
|
result = "true"
|
|
}
|
|
case "!~":
|
|
if m, e := regexp.MatchString(arg[2], arg[0]); !m || e != nil {
|
|
result = "true"
|
|
}
|
|
}
|
|
}
|
|
m.Echo(result)
|
|
|
|
return
|
|
}},
|
|
"exp": &ctx.Command{Name: "exp word", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
if len(arg) > 0 && arg[0] == "{" {
|
|
msg := m.Spawn()
|
|
for i := 1; i < len(arg); i++ {
|
|
key := arg[i]
|
|
for i += 3; i < len(arg); i++ {
|
|
if arg[i] == "]" {
|
|
break
|
|
}
|
|
msg.Add("append", key, arg[i])
|
|
}
|
|
}
|
|
m.Echo("%d", msg.Code())
|
|
return
|
|
}
|
|
|
|
pre := map[string]int{
|
|
"=": -1,
|
|
"||": 0,
|
|
"==": 1, "~": 1,
|
|
"+": 2, "-": 2,
|
|
"*": 3, "/": 3, "%": 3,
|
|
}
|
|
num, op := []string{arg[0]}, []string{}
|
|
|
|
for i := 1; i < len(arg); i += 2 {
|
|
if len(op) > 0 && pre[op[len(op)-1]] >= pre[arg[i]] {
|
|
num[len(op)-1] = m.Cmdx("yac.val", num[len(op)-1], op[len(op)-1], num[len(op)])
|
|
num, op = num[:len(num)-1], op[:len(op)-1]
|
|
}
|
|
num, op = append(num, arg[i+1]), append(op, arg[i])
|
|
}
|
|
|
|
for i := len(op) - 1; i >= 0; i-- {
|
|
num[i] = m.Cmdx("yac.val", num[i], op[i], num[i+1])
|
|
}
|
|
|
|
m.Echo("%s", num[0])
|
|
return
|
|
}},
|
|
"return": &ctx.Command{Name: "return result...", Help: "结束脚本, result: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
m.Appends("bio.end", true)
|
|
m.Result(arg[1:])
|
|
return
|
|
}},
|
|
"com": &ctx.Command{Name: "com", Help: "解析注释", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
return
|
|
}},
|
|
"cmd": &ctx.Command{Name: "cmd word", Help: "解析命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
// 解析别名
|
|
detail := []string{}
|
|
if alias, ok := m.Confv("alias", arg[0]).([]string); ok {
|
|
detail, arg = append(detail, alias...), arg[1:]
|
|
}
|
|
detail = append(detail, arg...)
|
|
|
|
// 目标切换
|
|
target := m.Optionv("bio.ctx")
|
|
if detail[0] != "context" {
|
|
defer func() { m.Optionv("bio.ctx", target) }()
|
|
}
|
|
|
|
// 解析脚本
|
|
msg := m
|
|
for k, v := range m.Confv("system", "script").(map[string]interface{}) {
|
|
if strings.HasSuffix(detail[0], "."+k) {
|
|
msg = m.Spawn(m.Optionv("bio.ctx"))
|
|
detail[0] = m.Cmdx("nfs.path", detail[0])
|
|
detail = append([]string{v.(string)}, detail...)
|
|
break
|
|
}
|
|
}
|
|
|
|
// 解析路由
|
|
if msg == m {
|
|
if routes := strings.Split(detail[0], "."); len(routes) > 1 && !strings.Contains(detail[0], ":") {
|
|
route := strings.Join(routes[:len(routes)-1], ".")
|
|
if msg = m.Find(route, false); msg == nil {
|
|
msg = m.Find(route, true)
|
|
}
|
|
|
|
if msg == nil {
|
|
m.Echo("%s not exist", route)
|
|
return
|
|
}
|
|
detail[0] = routes[len(routes)-1]
|
|
} else {
|
|
msg = m.Spawn(m.Optionv("bio.ctx"))
|
|
}
|
|
}
|
|
msg.Copy(m, "option").Copy(m, "append")
|
|
|
|
// 解析命令
|
|
args, rest := []string{}, []string{}
|
|
exports := []map[string]string{}
|
|
exec, execexec := true, false
|
|
for i := 0; i < len(detail); i++ {
|
|
switch detail[i] {
|
|
case "?":
|
|
if !kit.Right(detail[i+1]) {
|
|
return
|
|
}
|
|
i++
|
|
case "??":
|
|
exec = false
|
|
execexec = execexec || kit.Right(detail[i+1])
|
|
i++
|
|
case "<":
|
|
m.Cmdy("nfs.import", detail[i+1])
|
|
i++
|
|
case ">":
|
|
exports = append(exports, map[string]string{"file": detail[i+1]})
|
|
i++
|
|
case ">$":
|
|
if i == len(detail)-2 {
|
|
exports = append(exports, map[string]string{"cache": detail[i+1], "index": "result"})
|
|
i += 1
|
|
break
|
|
}
|
|
exports = append(exports, map[string]string{"cache": detail[i+1], "index": detail[i+2]})
|
|
i += 2
|
|
case ">@":
|
|
if i == len(detail)-2 {
|
|
exports = append(exports, map[string]string{"config": detail[i+1], "index": "result"})
|
|
i += 1
|
|
break
|
|
}
|
|
exports = append(exports, map[string]string{"config": detail[i+1], "index": detail[i+2]})
|
|
i += 2
|
|
case "|":
|
|
detail, rest = detail[:i], detail[i+1:]
|
|
case "%":
|
|
rest = append(rest, "select")
|
|
detail, rest = detail[:i], append(rest, detail[i+1:]...)
|
|
default:
|
|
args = append(args, detail[i])
|
|
}
|
|
}
|
|
if !exec && !execexec {
|
|
return
|
|
}
|
|
|
|
// 执行命令
|
|
if msg.Set("detail", args).Cmd(); !msg.Hand {
|
|
msg.Cmd("system", args)
|
|
}
|
|
if msg.Appends("bio.ctx1") {
|
|
target = msg.Target()
|
|
}
|
|
|
|
// 管道命令
|
|
if len(rest) > 0 {
|
|
pipe := msg.Spawn()
|
|
pipe.Copy(msg, "append").Copy(msg, "result").Cmd("cmd", rest)
|
|
msg.Set("append").Copy(pipe, "append")
|
|
msg.Set("result").Copy(pipe, "result")
|
|
}
|
|
|
|
// 导出结果
|
|
for _, v := range exports {
|
|
if v["file"] != "" {
|
|
m.Sess("nfs").Copy(msg, "option").Copy(msg, "append").Copy(msg, "result").Cmd("export", v["file"])
|
|
msg.Set("result")
|
|
}
|
|
if v["cache"] != "" {
|
|
if v["index"] == "result" {
|
|
m.Cap(v["cache"], strings.Join(msg.Meta["result"], ""))
|
|
} else {
|
|
m.Cap(v["cache"], msg.Append(v["index"]))
|
|
}
|
|
}
|
|
if v["config"] != "" {
|
|
if v["index"] == "result" {
|
|
m.Conf(v["config"], strings.Join(msg.Meta["result"], ""))
|
|
} else {
|
|
m.Conf(v["config"], msg.Append(v["index"]))
|
|
}
|
|
}
|
|
}
|
|
|
|
// 返回结果
|
|
m.Optionv("bio.ctx", msg.Target())
|
|
m.Set("append").Copy(msg, "append")
|
|
m.Set("result").Copy(msg, "result")
|
|
return
|
|
}},
|
|
"alias": &ctx.Command{Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]",
|
|
Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令",
|
|
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
switch len(arg) {
|
|
case 0:
|
|
m.Cmdy("ctx.config", "alias")
|
|
case 1:
|
|
m.Cmdy("ctx.config", "alias", arg[0])
|
|
default:
|
|
switch arg[0] {
|
|
case "delete":
|
|
alias := m.Confm("alias")
|
|
m.Echo("delete: %s %v\n", arg[1], alias[arg[1]])
|
|
delete(alias, arg[1])
|
|
case "import":
|
|
msg := m.Find(arg[1], false)
|
|
if msg == nil {
|
|
msg = m.Find(arg[1], true)
|
|
}
|
|
if msg == nil {
|
|
m.Echo("%s not exist", arg[1])
|
|
return
|
|
}
|
|
|
|
module := msg.Cap("module")
|
|
for k, _ := range msg.Target().Commands {
|
|
if len(k) > 0 && k[0] == '/' {
|
|
continue
|
|
}
|
|
|
|
if len(arg) == 2 {
|
|
m.Confv("alias", k, []string{module + "." + k})
|
|
m.Log("info", "import %s.%s", module, k)
|
|
continue
|
|
}
|
|
|
|
if key := k; k == arg[2] {
|
|
if len(arg) > 3 {
|
|
key = arg[3]
|
|
}
|
|
m.Confv("alias", key, []string{module + "." + k})
|
|
m.Log("info", "import %s.%s as %s", module, k, key)
|
|
break
|
|
}
|
|
}
|
|
default:
|
|
m.Confv("alias", arg[0], arg[1:])
|
|
m.Log("info", "%s: %v", arg[0], arg[1:])
|
|
}
|
|
}
|
|
return
|
|
}},
|
|
|
|
"var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
if stack, ok := m.Optionv("bio.stack").(*kit.Stack); ok {
|
|
m.Log("stack", "%v = %v", arg[1], arg[3])
|
|
stack.Peek().Hash[arg[1]] = arg[3]
|
|
}
|
|
return
|
|
}},
|
|
"let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
if stack, ok := m.Optionv("bio.stack").(*kit.Stack); ok {
|
|
switch arg[3] {
|
|
case "[":
|
|
list := []interface{}{}
|
|
for i := 4; i < len(arg)-1; i++ {
|
|
list = append(list, arg[i])
|
|
}
|
|
m.Log("stack", "%v = %v", arg[1], list)
|
|
stack.Hash(arg[1], list)
|
|
|
|
case "{":
|
|
list := map[string]interface{}{}
|
|
for i := 4; i < len(arg)-2; i += 2 {
|
|
list[arg[i]] = arg[i+1]
|
|
}
|
|
m.Log("stack", "%v = %v", arg[1], list)
|
|
stack.Hash(arg[1], list)
|
|
|
|
default:
|
|
m.Log("stack", "%v = %v", arg[1], arg[3])
|
|
stack.Hash(arg[1], arg[3])
|
|
}
|
|
}
|
|
return
|
|
}},
|
|
"if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
stack := m.Optionv("bio.stack").(*kit.Stack)
|
|
o := stack.Peek()
|
|
p := stack.Push(arg[0], o.Run && kit.Right(arg[1]), m.Optioni("stack.pos"))
|
|
m.Log("stack", "push %v", p.String("\\"))
|
|
if !o.Run || p.Run {
|
|
p.Done = true
|
|
}
|
|
return
|
|
}},
|
|
"for": &ctx.Command{Name: "for exp | for index val... in list", Help: "循环语句",
|
|
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
stack := m.Optionv("bio.stack").(*kit.Stack)
|
|
m.Log("stack", "push %v", stack.Push(arg[0], stack.Peek().Run && kit.Right(arg[1]), m.Optioni("stack.pos")).String("\\"))
|
|
|
|
val, _ := stack.Hash(arg[len(arg)-1])
|
|
index := kit.Int(stack.FS[len(stack.FS)-2].Hash["_index"])
|
|
switch val := val.(type) {
|
|
case map[string]interface{}:
|
|
list := make([]string, 0, len(val))
|
|
for k, _ := range val {
|
|
list = append(list, k)
|
|
}
|
|
sort.Strings(list)
|
|
|
|
if index < len(list) {
|
|
stack.Hash(arg[1], list[index])
|
|
}
|
|
stack.Peek().Run = false
|
|
for i, j := 2, index; i < len(arg)-2 && j < len(list); i, j = i+1, j+1 {
|
|
stack.Peek().Run = true
|
|
stack.Hash(arg[i], val[list[j]])
|
|
stack.FS[len(stack.FS)-2].Hash["_index"] = j + 1
|
|
}
|
|
|
|
case []interface{}:
|
|
stack.Hash(arg[1], index)
|
|
stack.Peek().Run = false
|
|
for i, j := 2, index; i < len(arg)-2 && j < len(val); i, j = i+1, j+1 {
|
|
stack.Peek().Run = true
|
|
stack.Hash(arg[i], val[j])
|
|
stack.FS[len(stack.FS)-2].Hash["_index"] = j + 1
|
|
}
|
|
default:
|
|
}
|
|
if !stack.Peek().Run {
|
|
stack.FS[len(stack.FS)-2].Hash["_index"] = 0
|
|
}
|
|
return
|
|
}},
|
|
"fun": &ctx.Command{Name: "fun name help", Help: "小函数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
p := m.Optionv("bio.stack").(*kit.Stack).Push(arg[0], false, m.Optioni("stack.pos"))
|
|
m.Log("stack", "push %v", p.String("\\"))
|
|
|
|
if len(arg) > 2 {
|
|
m.Cmd("kit", "kit", arg[1:])
|
|
}
|
|
self := &ctx.Command{Name: strings.Join(arg[1:], " "), Help: []string{"pwd", "ls"}}
|
|
self.Hand = func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
m.Goshy(self.Help.([]string), 0, nil, nil)
|
|
m.Log("time", "parse: %v", m.Format("cost"))
|
|
return
|
|
}
|
|
m.Target().Commands[arg[1]] = self
|
|
m.Log("info", "fun: %v %v", arg[1], arg)
|
|
p.Data = self
|
|
return
|
|
}},
|
|
"kit": &ctx.Command{Name: "kit name help [init [view]] [public|protected|private] cmd arg... [input value [key val]...]...", Help: "小功能", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
m.Log("info", "_index: %v", arg)
|
|
|
|
args := []interface{}{}
|
|
inputs := []interface{}{}
|
|
exports := []interface{}{}
|
|
feature := map[string]interface{}{}
|
|
|
|
init, view, right, cmd := "", "", "", ""
|
|
begin := 3
|
|
|
|
switch arg[3] {
|
|
case "private", "protected", "public":
|
|
begin, right, cmd = 5, arg[3], arg[4]
|
|
default:
|
|
switch arg[4] {
|
|
case "private", "protected", "public":
|
|
begin, init, right, cmd = 6, arg[3], arg[4], arg[5]
|
|
default:
|
|
begin, init, view, right, cmd = 7, arg[3], arg[4], arg[5], arg[6]
|
|
}
|
|
}
|
|
|
|
if m.Confs("input", cmd) {
|
|
cmd, begin = arg[1], begin-1
|
|
}
|
|
|
|
for i := begin; i < len(arg); i++ {
|
|
if !m.Confs("input", arg[i]) {
|
|
args = append(args, arg[i])
|
|
continue
|
|
}
|
|
for j := i; j < len(arg); j++ {
|
|
if j < len(arg)-1 && !m.Confs("input", arg[j+1]) {
|
|
continue
|
|
}
|
|
args := arg[i : j+1]
|
|
if arg[i] == "feature" {
|
|
feature[arg[i+1]] = arg[i+2]
|
|
|
|
} else if arg[i] == "exports" {
|
|
for k := 1; k < len(args); k += 1 {
|
|
exports = append(exports, args[k])
|
|
}
|
|
} else {
|
|
input := map[string]interface{}{
|
|
"type": kit.Select("", args, 0),
|
|
"value": kit.Select("", args, 1),
|
|
}
|
|
for k := 2; k < len(args)-1; k += 2 {
|
|
switch val := input[args[k]].(type) {
|
|
case nil:
|
|
input[args[k]] = args[k+1]
|
|
case string:
|
|
input[args[k]] = []interface{}{input[args[k]], args[k+1]}
|
|
case []interface{}:
|
|
input[args[k]] = append(val, args[k+1])
|
|
}
|
|
}
|
|
inputs = append(inputs, input)
|
|
}
|
|
i = j
|
|
break
|
|
}
|
|
}
|
|
|
|
if len(inputs) == 0 {
|
|
inputs = []interface{}{
|
|
map[string]interface{}{"type": "text", "name": "arg"},
|
|
map[string]interface{}{"type": "button", "value": "执行"},
|
|
}
|
|
}
|
|
|
|
m.Confv("_index", []interface{}{-2}, map[string]interface{}{
|
|
"name": kit.Select("", arg, 1),
|
|
"help": kit.Select("", arg, 2),
|
|
"view": view,
|
|
"init": init,
|
|
"type": right,
|
|
|
|
"ctx": m.Cap("module"),
|
|
"cmd": cmd,
|
|
"args": args,
|
|
"inputs": inputs,
|
|
"exports": exports,
|
|
"feature": feature,
|
|
})
|
|
return
|
|
}},
|
|
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
p := m.Optionv("bio.stack").(*kit.Stack).Peek()
|
|
p.Run = !p.Done && !p.Run && (len(arg) == 1 || kit.Right(arg[2]))
|
|
m.Log("stack", "set: %v", p.String("|"))
|
|
if p.Run {
|
|
p.Done = true
|
|
}
|
|
return
|
|
}},
|
|
"end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
p := m.Optionv("bio.stack").(*kit.Stack).Pop()
|
|
m.Log("stack", "pop: %v", p.String("/"))
|
|
switch p.Key {
|
|
case "for":
|
|
if p.Run {
|
|
m.Appendi("bio.pos0", p.Pos)
|
|
}
|
|
case "fun":
|
|
end := m.Optioni("stack.pos")
|
|
self := p.Data.(*ctx.Command)
|
|
help := []string{}
|
|
for i, v := range m.Optionv("bio.input").([]string) {
|
|
if p.Pos < i && i < end {
|
|
help = append(help, v)
|
|
}
|
|
}
|
|
self.Help = help
|
|
}
|
|
|
|
return
|
|
}},
|
|
|
|
"label": &ctx.Command{Name: "label name", Help: "记录当前脚本的位置, name: 位置名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
p := m.Optionv("bio.stack").(*kit.Stack).Peek()
|
|
if p.Label == nil {
|
|
p.Label = map[string]int{}
|
|
}
|
|
m.Log("stack", "%v <= %v", arg[1], m.Optioni("stack.pos")+1)
|
|
p.Label[arg[1]] = m.Optioni("stack.pos") + 1
|
|
return
|
|
}},
|
|
"goto": &ctx.Command{Name: "goto label [exp] condition", Help: "向上跳转到指定位置, label: 跳转位置, condition: 跳转条件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
|
stack := m.Optionv("bio.stack").(*kit.Stack)
|
|
if i, ok := stack.Label(arg[1]); ok {
|
|
m.Log("stack", "%v => %v", arg[1], i)
|
|
m.Append("bio.pos0", i)
|
|
}
|
|
return
|
|
}},
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
ctx.Index.Register(Index, &YAC{Context: Index})
|
|
}
|