package yac import ( "strings" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/nfs" kit "shylinux.com/x/toolkits" ) const ( IF = "if" ELSE = "else" FOR = "for" RANGE = "range" BREAK = "break" CONTINUE = "continue" SWITCH = "switch" CASE = "case" DEFAULT = "default" FUNC = "func" DEFER = "defer" RETURN = "return" CALL = "call" INIT = "init" MAIN = "main" INFO = "info" ) const ( KEYWORD = "keyword" FUNCTION = "function" ) func init() { Index.MergeCommands(ice.Commands{ IF: {Name: "if a = 1; a > 1 {", Hand: func(m *ice.Message, arg ...string) { s, f := _parse_frame(m) res := s.expr(m) kit.If(s.token() == SPLIT, func() { res = s.expr(m) }) kit.If(res == ice.FALSE, func() { s.status_disable(f) }) }}, ELSE: {Name: "else if a = 1; a > 1 {", Hand: func(m *ice.Message, arg ...string) { s, f := _parse_frame(m) if s.last.status == STATUS_DISABLE { s.status_normal(f) } else { f.status, f.defers = STATUS_DISABLE, append(f.defers, func() { s.status_normal(f) }) } if s.next(m) == IF { res := s.expr(m) kit.If(s.token() == SPLIT, func() { res = s.expr(m) }) kit.If(res == ice.FALSE, func() { s.status_disable(f) }) } }}, FOR: {Name: "for a = 1; a < 10; a++ {", Hand: func(m *ice.Message, arg ...string) { s, f := _parse_frame(m) if strings.Contains(s.list[s.line], RANGE) { pos, key, list := s.Position, []string{}, []Any{} kit.If(s.last != nil && s.last.line == s.line, func() { list, _ = s.last.value["_range"].([]Any) }) for s.next(m) != BEGIN { switch s.token() { case RANGE: if obj, ok := s.cals(m).(Operater); ok { if list, ok := obj.Operate(RANGE, list).([]Any); ok { kit.For(key, func(i int, k string) { f.value[k] = list[i] }) f.defers = append(f.defers, func() { kit.If(s.runable(), func() { s.pos(m, pos, -1) }) }) f.value["_range"] = list return } } s.status_disable(f) return case ASSIGN: case DEFS: case FIELD: default: key = append(key, s.token()) } } return } list, status := []Position{s.Position}, f.status for s.status_disable(f); s.token() != BEGIN; list = append(list, s.Position) { s.expr(m) } f.status = status res := ice.TRUE if len(list) == 1 { } else if len(list) == 2 { res = s.expr(m, list[0]) } else { if s.last == nil || s.last.line != s.line { res = s.expr(m, list[0]) } else { kit.For(s.last.value, func(k string, v Any) { f.value[k] = v }) } res = s.expr(m, list[1]) } kit.If(res == ice.FALSE, func() { s.status_disable(f) }) s.Position, f.defers = list[len(list)-1], append(f.defers, func() { if s.runable() { kit.If(len(list) > 3, func() { s.expr(m, list[2]) }) s.pos(m, list[0], -1) } }) }}, BREAK: {Name: "break", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) if !s.runable() { return } s.stack(func(f *Frame, i int) bool { switch s.status_disable(f); f.key { case FOR, SWITCH: return true default: return false } }) }}, CONTINUE: {Name: "continue", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) if !s.runable() { return } s.stack(func(f *Frame, i int) bool { switch s.status_disable(f); f.key { case FOR: f.defers = append(f.defers, func() { s.status_normal(f) }) return true default: return false } }) }}, SWITCH: {Name: "switch a = 1; a {", Hand: func(m *ice.Message, arg ...string) { s, f := _parse_frame(m) res := s.cals(m) kit.If(s.token() == SPLIT, func() { res = s.cals(m) }) f.value["_switch"], f.value["_case"] = res, "" }}, CASE: {Name: "case b:", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) f := s.peekf() s.status_normal(f) v := s.cals(m) if s.status_disable(f); f.value["_case"] == "done" { return } if res, ok := v.(Operater); ok { if res, ok := res.Operate("==", Trans(s.value(m, "_switch"))).(Boolean); ok && res.value { f.value["_case"] = "done" s.status_normal(f) } } }}, DEFAULT: {Name: "default:", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) f := s.peekf() if s.status_normal(f); f.value["_case"] == "done" { s.status_disable(f) } s.skip++ }}, FUNC: {Name: "func show(a, b) (c, d)", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) field, list := Field{}, []Field{} if s.next(m) == OPEN { for s.next(m) != CLOSE { kit.If(field.name == "", func() { field.name = s.token() }, func() { field.types = s.token() }) } kit.If(field.types == nil, func() { field.types = field.name }) list = append(list, field) s.next(m) } name := s.token() list = append(list, Field{name: name}) s.rest[s.skip] = FUNC v := s.funcs(m, name) if v.obj = list; field.types != nil { if t, ok := s.value(m, kit.Format(field.types)).(Struct); ok { m.Debug("value %s set %s.%s %s", Format(s), field.types, name, Format(v)) t.index[name] = v } } else if !kit.IsIn(name, INIT, MAIN) { s.value(m, name, v) } }}, DEFER: {Name: "defer func() {} ()", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) obj, k := Any(nil), "" obj, k = s, s.next(m) kit.If(k == FUNC, func() { obj, k = s.funcs(m, ""), "" }) s.skip++ args := _parse_res(m, s.cals(m)) if !s.runable() { return } s.stack(func(f *Frame, i int) bool { if f.key == CALL { f.defers = append(f.defers, func() { s.calls(m, obj, k, nil, args...) }) return true } return false }) }}, RETURN: {Name: "return show", Hand: func(m *ice.Message, arg ...string) { s := _parse_stack(m) args := _parse_res(m, s.cals(m)) s.stack(func(f *Frame, i int) bool { switch s.status_disable(f); f.key { case FUNC: case CALL: switch cb := f.value["_return"].(type) { case func(...Any): cb(args...) } case STACK: s.input = nil default: return false } return true }) }}, INFO: {Name: "info", Actions: ice.Actions{ ERROR: {Hand: func(m *ice.Message, arg ...string) { for _, e := range _parse_stack(m).Error { m.EchoLine(" %s%s %s %s", e.key, e.detail, _parse_link(m, Format(e.Position)), _parse_link(m, e.fileline)) } }}, STACK: {Hand: func(m *ice.Message, arg ...string) { _parse_stack(m).stack(func(f *Frame, i int) bool { m.EchoLine("frame: %s %v:%v:%v", f.key, f.name, f.line, f.skip) show := func(p string) string { return _parse_link(m, p) } kit.For(f.value, func(k string, v Any) { switch v := v.(type) { case func(*ice.Message, string, ...Any) Any: m.EchoLine(" %s: %v", k, show(kit.FileLine(v, 100))) case Message: m.EchoLine(" %s: %v", k, show(kit.FileLine(v.Call, 100))) case Function: m.EchoLine(" %s: %v", k, show(v.Position.name+nfs.DF+kit.Format(v.Position.line+1))) case Struct: m.EchoLine(" %s: %s", k, show(v.Position.name+nfs.DF+kit.Format(v.Position.line+1))) break kit.For(v.index, func(k string, v Any) { switch v := v.(type) { case Function: m.EchoLine(" %s: %v", k, show(v.Position.name+nfs.DF+kit.Format(v.Position.line+1))) case Field: m.EchoLine(" %s: %v", k, v.Format()) } }) case string: m.EchoLine(" %s: %v", k, v) default: m.EchoLine(" %s: %v", k, Format(v)) } }) return false }) }}, ctx.CONFIG: {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(ctx.CONFIG, m.Option("__index")).EchoLine("") }}, ctx.COMMAND: {Hand: func(m *ice.Message, arg ...string) { msg := m.Cmd(ctx.COMMAND, m.Option("__index")) m.EchoLine(msg.Append(mdb.LIST)) m.EchoLine(msg.Append(mdb.META)) }}, }, Hand: func(m *ice.Message, arg ...string) { kit.For([]string{ERROR, STACK, ctx.CONFIG, ctx.COMMAND}, func(k string) { m.EchoLine("%s: %s", k, arg[0]).Cmdy("", k) }) }}, }) }