diff --git a/base/yac/script.go b/base/yac/script.go new file mode 100644 index 00000000..241ee726 --- /dev/null +++ b/base/yac/script.go @@ -0,0 +1,197 @@ +package yac + +import ( + "strconv" + "strings" + + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/cli" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" +) + +type frame struct { + key string + skip bool + data map[string]string +} + +type stack struct { + fs []*frame + res []string +} + +func (s *stack) push(f *frame) *stack { + f.data = map[string]string{} + s.fs = append(s.fs, f) + return s +} +func (s *stack) define(key, value string) { + if len(s.fs) > 0 { + s.fs[len(s.fs)-1].data[key] = value + } +} +func (s *stack) value(key string) string { + for i := len(s.fs) - 1; i >= 0; i-- { + if value, ok := s.fs[i].data[key]; ok { + return value + } + } + return "" +} + +func _script_push_stack(m *ice.Message, f *frame) { + stack := m.Optionv("stack").(*stack) + stack.push(f) +} +func _script_define(m *ice.Message, key, value string) { + stack := m.Optionv("stack").(*stack) + stack.define(key, value) +} +func _script_runing(m *ice.Message, nhash string) bool { + switch nhash { + case "if", "for", "end": + return true + } + + stack := m.Optionv("stack").(*stack) + return !stack.fs[len(stack.fs)-1].skip +} +func _script_pop_stack(m *ice.Message) { + stack := m.Optionv("stack").(*stack) + stack.fs = stack.fs[:len(stack.fs)-1] +} +func _script_res(m *ice.Message, arg ...interface{}) { + stack := m.Optionv("stack").(*stack) + stack.res = append(stack.res, kit.Simple(arg...)...) +} + +const SCRIPT = "script" + +func init() { + Index.Merge(&ice.Context{Commands: map[string]*ice.Command{ + SCRIPT: {Name: "script name npage text:textarea auto create", Help: "脚本解析", Action: map[string]*ice.Action{ + mdb.CREATE: {Name: "create name=shy", Help: "创建", Hand: func(m *ice.Message, arg ...string) { + m.Cmd(MATRIX, mdb.CREATE, m.Option(kit.MDB_NAME)) + for _, p := range [][]string{ + []string{"num", "num", "[0-9]+"}, + []string{"key", "key", "[abc]+"}, + []string{"op2", "op2", "[+\\\\-*/%]"}, + []string{"op2", "op2", "[>=<]"}, + []string{"val", "val", "mul{ num key }"}, + []string{"exp", "exp", "val"}, + []string{"exp", "exp", "val op2 val"}, + []string{"stm", "var", "var key = exp"}, + []string{"stm", "for", "for exp"}, + []string{"stm", "if", "if exp"}, + []string{"stm", "cmd", "pwd"}, + []string{"stm", "end", "end"}, + []string{"script", "script", "rep{ stm }"}, + } { + m.Cmdx(MATRIX, mdb.INSERT, m.Option(kit.MDB_NAME), p) + } + }}, + "exp": {Name: "exp num op2 num", Help: "创建", Hand: func(m *ice.Message, arg ...string) { + stack := m.Optionv("stack").(*stack) + + arg[0] = kit.Select(arg[0], stack.value(arg[0])) + if len(arg) == 1 { + m.Echo(arg[0]) + return + } + arg[2] = kit.Select(arg[2], stack.value(arg[2])) + + m.Debug(" %v %v %v", arg[0], arg[1], arg[2]) + n1, e1 := strconv.ParseInt(arg[0], 10, 64) + n2, e2 := strconv.ParseInt(arg[2], 10, 64) + m.Debug(" %v %v %v", n1, arg[1], n2) + switch arg[1] { + case ">": + if e1 == nil && e2 == nil { + m.Echo("%t", n1 > n2) + } else { + m.Echo("%t", arg[0] > arg[2]) + } + case "+": + if e1 == nil && e2 == nil { + m.Echo("%d", n1+n2) + } else { + m.Echo("%s", arg[0]+arg[2]) + } + case "-": + if e1 == nil && e2 == nil { + m.Echo("%d", n1-n2) + } else { + m.Echo("%s", strings.ReplaceAll(arg[0], arg[2], "")) + } + case "*": + if e1 == nil && e2 == nil { + m.Echo("%d", n1*n2) + } else { + m.Echo(arg[0]) + } + case "/": + if e1 == nil && e2 == nil { + m.Echo("%d", n1/n2) + } else { + m.Echo("%s", strings.ReplaceAll(arg[0], arg[2], "")) + } + case "%": + if e1 == nil && e2 == nil { + m.Echo("%d", n1%n2) + } else { + m.Echo(arg[0]) + } + default: + m.Echo(arg[0], arg[1], arg[2]) + } + }}, + "if": {Name: "if exp", Help: "判断", Hand: func(m *ice.Message, arg ...string) { + if arg[1] == "true" { + _script_push_stack(m, &frame{key: arg[0], skip: false}) + return + } + if arg[1] == "false" { + _script_push_stack(m, &frame{key: arg[0], skip: true}) + return + } + if n1, e1 := strconv.ParseInt(arg[1], 10, 64); e1 == nil { + _script_push_stack(m, &frame{key: arg[0], skip: n1 == 0}) + m.Echo("%t", n1 != 0) + } else { + _script_push_stack(m, &frame{skip: len(arg[1]) == 0}) + m.Echo("%t", len(arg[1]) > 0) + } + }}, + "var": {Name: "var key = exp", Help: "变量", Hand: func(m *ice.Message, arg ...string) { + _script_define(m, arg[1], arg[3]) + }}, + "for": {Name: "for exp", Help: "循环", Hand: func(m *ice.Message, arg ...string) { + }}, + "cmd": {Name: "cmd", Help: "命令", Hand: func(m *ice.Message, arg ...string) { + _script_res(m, m.Cmdx(cli.SYSTEM, arg)) + }}, + "end": {Name: "end", Help: "结束", Hand: func(m *ice.Message, arg ...string) { + _script_pop_stack(m) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) < 2 { + m.Cmdy(MATRIX, arg) + return + } + + stack := &stack{} + stack.push(&frame{}) + m.Option("stack", stack) + m.Cmdy(MATRIX, PARSE, arg[0], arg[1], arg[2], func(nhash string, hash int, word []string, rest []byte) (int, []string, []byte) { + m.Debug("script %v %v", nhash, word) + if _, ok := c.Commands[SCRIPT].Action[nhash]; ok && _script_runing(m, nhash) { + msg := m.Cmd(SCRIPT, nhash, word) + return hash, msg.Resultv(), rest + } + return hash, word, rest + }) + m.Resultv(stack.res) + }}, + }}) +}