package yac import ( "regexp" "strings" ice "shylinux.com/x/icebergs" kit "shylinux.com/x/toolkits" ) const ( SPACE = "\t " QUOTE = "\"" TRANS = " " BLOCK = "[:](,){;}*/+-<>!=&|" DEFINE = ":=" ASSIGN = "=" SUBS = "[" DEFS = ":" SUPS = "]" OPEN = "(" FIELD = "," CLOSE = ")" BEGIN = "{" SPLIT = ";" END = "}" DISABLE = -1 ) var level = map[string]int{ "//": 200, "/*": 200, "*/": 200, "!": 100, "++": 100, "--": 100, "[": 100, "]": 100, "*": 40, "/": 40, "+": 30, "-": 30, "<": 20, ">": 20, ">=": 20, "<=": 20, "!=": 20, "==": 20, "&&": 10, "||": 10, DEFINE: 2, ASSIGN: 2, FIELD: 2, OPEN: 1, CLOSE: 1, } type Expr struct { list ice.List s *Stack m *ice.Message n int } func (s *Expr) push(v Any) *Expr { s.list = append(s.list, v) return s } func (s *Expr) pop(n int) *Expr { s.list = s.list[:len(s.list)-n] return s } func (s *Expr) get(p int) (v Any) { kit.If(0 <= p+len(s.list) && p+len(s.list) < len(s.list), func() { v = s.list[p+len(s.list)] }) kit.If(0 <= p && p < len(s.list), func() { v = s.list[p] }) return } func (s *Expr) gets(p int) string { return kit.Format(s.get(p)) } func (s *Expr) getl(p int) int { return level[s.gets(p)] } func (s *Expr) getv(m *ice.Message, p int) (v Any) { switch v := s.get(p); v := v.(type) { case string: return s.s.value(m, v) default: return v } } func (s *Expr) setv(m *ice.Message, p int, op string, v Any) Any { k := s.gets(p) kit.If(s.s.runable(), func() { switch v := v.(type) { case string: s.s.value(m, k, s.s.value(m, v), op) case Value: s.s.value(m, k, v.list[0], op) default: s.s.value(m, k, v, op) } }) return s.s.value(m, k) } func (s *Expr) opv(m *ice.Message, p int, op string, v Any) Any { if s.n++; s.n > 100 { panic(s.n) } if !s.s.runable() { return s.getv(m, p) } if obj, ok := s.getv(m, p).(Operater); ok { return obj.Operate(op, trans(v)) } return s.getv(m, p) } func (s *Expr) ops(m *ice.Message) { if !s.s.runable() || s.getl(-2) < 10 { return } v := s.opv(m, -3, s.gets(-2), s.getv(m, -1)) s.pop(3).push(v) } func (s *Expr) end(m *ice.Message) Any { if !s.s.runable() || len(s.list) == 0 { return nil } m.Debug("expr ops %v", s.list) for len(s.list) > 1 { switch s.ops(m); s.gets(-2) { case FIELD: list := kit.List() for i := len(s.list) - 2; i > 0; i -= 2 { if s.gets(i) == ASSIGN || s.gets(i) == DEFINE { for j := 0; j < i; j += 2 { list = append(list, s.setv(m, j, s.gets(i), s.getv(m, j+i+1))) } s.list = kit.List(Value{list: list}) break } else if i == 1 { for i := 0; i < len(s.list); i += 2 { list = append(list, s.getv(m, i)) } s.list = kit.List(Value{list: list}) break } } case ASSIGN, DEFINE: list := kit.List() switch v := s.getv(m, -1).(type) { case Value: for i := 0; i < len(s.list)-1; i += 2 { if i/2 < len(v.list) { list = append(list, s.setv(m, i, s.gets(-2), v.list[i/2])) } } default: s.setv(m, -3, s.gets(-2), s.getv(m, -1)) } s.list = kit.List(Value{list}) } } m.Debug("expr ops %v", s.list) return s.getv(m, 0) } func (s *Expr) cals(m *ice.Message) Any { if s.s.skip == -1 { m.Debug("expr calcs %v %s:%d", s.s.rest, s.s.name, s.s.line) } else { m.Debug("expr calcs %v %s:%d", s.s.rest[s.s.skip:], s.s.name, s.s.line) } s.s.reads(m, func(k string) bool { if op := s.gets(-1) + k; level[op] > 0 && s.getl(-1) > 0 { s.pop(1) k = op } switch k { case DEFS, SUPS, BEGIN, SPLIT: return true case END: s.s.skip-- return true } if len(s.list) > 0 && s.getl(-1) == 0 { switch k { case "++": v := s.opv(m, -1, "+", 1) s.setv(m, -1, ASSIGN, v) s.pop(1).push(v) return false case "--": v := s.opv(m, -1, "-", 1) s.setv(m, -1, ASSIGN, v) s.pop(1).push(v) return false case SUBS: v := s.opv(m, -1, SUBS, s.s.cals(m)) s.pop(1).push(v) return false case OPEN: if s.gets(-1) == FUNC { name := kit.Format("%s:%d:%d", s.s.name, s.s.line, s.s.skip) s.s.skip-- s.s.rest[s.s.skip] = name s.s.skip-- m.Cmd(FUNC, name) s.s.skip++ sub := NewStack() sub.Position = s.s.Position sub.pushf(m, FUNC).status = DISABLE sub.run(m.Options(STACK, sub)) s.s.Position = sub.Position m.Options(STACK, s.s) s.s.popf(m) s.pop(1).push(s.s.value(m, name)) } else { v := s.call(m, s.s, s.gets(-1)) s.pop(1).push(v) } return false case CLOSE: if s.gets(-2) == OPEN { v := s.get(-1) s.pop(2).push(v) return false } m.Debug("what %v", k) return true } if level[k] == 0 { if strings.HasPrefix(k, ice.PT) && kit.Select("", s.s.rest, s.s.skip+1) == OPEN { s.s.skip++ v := s.call(m, s.getv(m, -1), strings.TrimPrefix(k, ice.PT)) s.pop(1).push(v) return false } else { s.s.skip-- return true } } } if level[k] > 0 { for level[k] >= 9 && level[k] <= s.getl(-2) { s.ops(m) } s.push(k) } else { if strings.HasPrefix(k, "\"") { s.push(String{value: k[1 : len(k)-1]}) } else if k == ice.TRUE { s.push(Boolean{value: true}) } else if k == ice.FALSE { s.push(Boolean{value: false}) } else if b, e := regexp.MatchString("[_a-zA-Z][_a-zA-Z0-9]*", k); e == nil && b { s.push(k) } else { s.push(Number{value: k}) } } return false }) return s.end(m) } func (s *Expr) call(m *ice.Message, obj Any, key string) Any { list := kit.List() switch v := s.s.cals(m).(type) { case Value: list = append(list, v.list...) default: list = append(list, v) } if !s.s.runable() { return nil } kit.For(kit.Slice(kit.Split(key, ice.PT), 0, -1), func(k string) { switch v := obj.(type) { case *Stack: obj, key = v.value(m, k), strings.TrimPrefix(key, k+ice.PT) } }) m.Debug("expr call %T %s %v", obj, key, kit.Format(list)) switch obj := obj.(type) { case *Stack: return obj.call(m, obj.value(m, key), nil, list...) case Caller: return obj.Call(key, list...) case func(string, ...Any) Any: return obj(key, list...) default: args := kit.List(key) for _, v := range list { switch v := v.(type) { case Value: args = append(args, v.list...) default: args = append(args, trans(v)) } } return Message{m.Cmd(args...)} } } func NewExpr(m *ice.Message, s *Stack) *Expr { return &Expr{kit.List(), s, m, 0} } const EXPR = "expr" func init() { Index.MergeCommands(ice.Commands{ EXPR: {Name: "expr a = 1", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) arg = s.rest m.Debug("what %v %d %d", s.rest[:], s.skip, s.line) if v := s.cals(m); !s.runable() { return } else if v != nil { m.Echo(kit.Format(trans(v))) } else if s.token() == BEGIN { m.Echo(ice.TRUE) } m.Debug("expr value %s %v %s:%d", m.Result(), arg, s.name, s.line) }}, }) }