1
0
forked from x/icebergs
icebergs/base/yac/stack.go
2023-04-07 00:25:24 +08:00

562 lines
15 KiB
Go

package yac
import (
"bufio"
"io"
"path"
"strconv"
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs"
kit "shylinux.com/x/toolkits"
)
type Function struct {
obj []Field
arg []Field
res []Field
Position
object Object
}
type Frame struct {
key string
value ice.Map
defers []func()
status int
Position
}
type Stack struct {
last *Frame
frame []*Frame
Position
}
type Position struct {
rest []string
skip int
line int
*Buffer
}
type Buffer struct {
name string
list []string
input *bufio.Scanner
}
func (s *Stack) peekf() *Frame { return s.frame[len(s.frame)-1] }
func (s *Stack) pushf(m *ice.Message, key string) *Frame {
f := &Frame{key: kit.Select(m.CommandKey(), key), value: kit.Dict(), Position: s.Position}
kit.If(len(s.frame) > 0, func() { f.status = s.peekf().status })
m.Debug("stack %d push %s %s", len(s.frame), f.key, s.show())
s.frame = append(s.frame, f)
return f
}
func (s *Stack) popf(m *ice.Message) *Frame {
f := s.peekf()
for i := len(f.defers) - 1; i >= 0; i-- {
f.defers[i]()
}
m.Debug("stack %d pop %s %s", len(s.frame)-1, f.key, s.show())
kit.If(len(s.frame) > 0, func() { s.frame = s.frame[:len(s.frame)-1] })
s.last = f
return f
}
func (s *Stack) stack(cb func(*Frame, int) bool) {
for i := len(s.frame) - 1; i >= 0; i-- {
if cb(s.frame[i], i) {
return
}
}
}
func (s *Stack) value(m *ice.Message, key string, arg ...Any) Any {
f, n := s.peekf(), len(s.frame)-1
if len(arg) < 2 || arg[1] != DEFINE {
s.stack(func(_f *Frame, i int) bool {
if _f.value[key] != nil {
f, n = _f, i
return true
}
return false
})
}
keys := strings.Split(key, ice.PT)
kit.If(strings.Contains(key, ice.PS), func() { keys = []string{key} })
kit.If(len(arg) > 0, func() {
var v Any = Dict{f.value}
for i := 0; i < len(keys); i++ {
switch k := keys[i]; _v := v.(type) {
case Operater:
if i == len(keys)-1 {
m.Debug("value %d:%s set %v %#v", n, f.key, key, arg[0])
_v.Operate(k, arg[0])
} else {
if v = _v.Operate(SUBS, k); v == nil {
if _, e := strconv.ParseInt(keys[i+1], 10, 32); e == nil {
v = _v.Operate(k, List{})
} else {
v = _v.Operate(k, Dict{kit.Dict()})
}
}
}
default:
v = nil
}
}
})
v, ok := f.value[key]
if ok {
return v
} else {
if s.stack(func(_f *Frame, i int) bool {
v, ok = _f.value[key]
return ok
}); ok {
return v
}
}
v = s
kit.For(keys, func(k string) {
m.Debug("what %#v %v", v, k)
switch _v := v.(type) {
case Operater:
v = _v.Operate(SUBS, k)
case *Stack:
v = nil
_v.stack(func(_f *Frame, i int) bool {
v, ok = _f.value[k]
return ok
})
default:
v = nil
}
})
if v != nil {
return v
}
return _parse_const(m, key)
}
func (s *Stack) runable() bool { return s.peekf().status > STATUS_DISABLE }
func (s *Stack) token() string { return kit.Select("", s.rest, s.skip) }
func (s *Stack) show() string {
if s.Buffer == nil {
return ""
} else if s.skip == -1 {
return kit.Format("%s:%d", s.name, s.line+1)
} else {
return kit.Format("%s:%d:%d", s.name, s.line+1, s.skip)
}
}
func (s *Stack) read(m *ice.Message) (text string, ok bool) {
isvoid := func(text string) bool {
return strings.TrimSpace(text) == "" || strings.HasPrefix(strings.TrimSpace(text), "#")
}
for s.line++; s.line < len(s.list); s.line++ {
if isvoid(s.list[s.line]) {
continue
}
return s.list[s.line], true
}
for s.input != nil && s.input.Scan() {
text = s.input.Text()
if s.line, s.list = len(s.list), append(s.list, text); isvoid(text) {
continue
}
m.Debug("input %d read \"%s\" %s", len(s.list), text, s.show())
return text, true
}
return
}
func (s *Stack) reads(m *ice.Message, cb func(k string) bool) {
block, last := []string{}, 0
for {
if s.skip++; s.skip < len(s.rest) {
if k := s.rest[s.skip]; k == "`" {
if len(block) > 0 {
kit.If(s.line != last, func() { block, last = append(block, ice.NL), s.line })
block = append(block, k)
cb(strings.Join(block, ice.SP))
block = block[:0]
} else {
block = append(block, k)
}
continue
} else if len(block) > 0 {
kit.If(s.line != last, func() { block, last = append(block, ice.NL), s.line })
block = append(block, k)
continue
}
if s.rest[s.skip] == ice.PS && kit.Select("", s.rest, s.skip+1) == ice.PS {
s.skip = len(s.rest)
continue
}
if cb(s.rest[s.skip]) {
break
}
} else if text, ok := s.read(m); ok {
s.rest, s.skip = kit.Split(text, SPACE, BLOCK, QUOTE, TRANS, ice.TRUE), -1
} else {
cb(SPLIT)
break
}
}
}
func (s *Stack) nextLine(m *ice.Message) []string {
s.skip = len(s.rest)
s.reads(m, func(string) bool { return true })
return s.rest
}
func (s *Stack) next(m *ice.Message) string {
s.reads(m, func(k string) bool { return true })
return s.token()
}
func (s *Stack) peek(m *ice.Message) string {
pos := s.Position
defer func() { s.Position = pos }()
s.reads(m, func(k string) bool { return true })
return s.token()
}
func (s *Stack) pos(m *ice.Message, pos Position, n int) {
s.Position = pos
s.skip += n
}
func (s *Stack) run(m *ice.Message) {
begin := len(s.frame)
s.reads(m, func(k string) bool {
if k == SPLIT {
} else if k == END {
if s.last = s.popf(m); len(s.frame) < begin {
return true
}
} else if _, ok := m.Source().Commands[k]; ok {
m.Cmdy(k, kit.Slice(s.rest, s.skip+1))
} else if _, ok := m.Target().Commands[k]; ok {
m.Cmdy(k, kit.Slice(s.rest, s.skip+1))
} else {
if s.skip--; s.skip == -1 {
m.Cmd(EXPR, s.rest, ice.SP, s.show())
} else {
m.Cmd(EXPR, kit.Slice(s.rest, s.skip), ice.SP, s.show())
}
}
return false
})
}
func (s *Stack) expr(m *ice.Message, pos ...Position) string {
kit.If(len(pos) > 0, func() { s.Position = pos[0] })
return m.Cmdx(EXPR, kit.Slice(s.rest, s.skip))
}
func (s *Stack) cals(m *ice.Message, arg ...string) Any {
sub := NewExpr(s)
return sub.cals(m, arg...)
}
func (s *Stack) cals0(m *ice.Message, arg ...string) string {
sub := NewExpr(s)
sub.cals(m, arg...)
return sub.gets(0)
}
func (s *Stack) types(m *ice.Message) Any {
for ; s.skip < len(s.rest); s.skip++ {
switch s.token() {
case "*":
case MAP:
s.skip += 2
key := s.types(m)
s.skip += 2
return Map{key: key, value: s.types(m)}
case SUBS:
s.skip += 2
return Slice{value: s.types(m)}
case STRUCT:
key, t := []string{}, Struct{index: map[string]Any{}}
for s.next(m); s.next(m) != END; {
if key = append(key, s.token()); s.next(m) == FIELD {
continue
}
types := s.types(m)
kit.For(key, func(key string) {
field := Field{key, types}
t.field = append(t.field, field)
t.index[key] = field
})
key, s.skip = key[:0], len(s.rest)
}
return t
case INTERFACE:
t := Interface{index: map[string]Function{}}
for s.next(m); s.next(m) != END; {
name := s.token()
field, list := Field{}, [][]Field{}
for s.skip++; s.skip < len(s.rest); s.skip++ {
switch s.token() {
case OPEN:
list = append(list, []Field{})
case "*":
case FIELD, CLOSE:
list[len(list)-1] = append(list[len(list)-1], field)
field = Field{}
default:
switch t := s.types(m).(type) {
case string:
kit.If(field.name == "", func() { field.name = t }, func() { field.kind = t })
default:
field.kind = s.types(m)
}
}
}
kit.If(len(list) == 1, func() { list = append(list, []Field{}) })
t.index[name] = Function{arg: list[0], res: list[1]}
s.skip = len(s.rest)
}
return t
case FUNC:
field, list := Field{}, [][]Field{}
for s.skip++; s.skip < len(s.rest); s.skip++ {
switch s.token() {
case OPEN:
list = append(list, []Field{})
case "*":
case FIELD, CLOSE:
list[len(list)-1] = append(list[len(list)-1], field)
field = Field{}
default:
switch t := s.types(m).(type) {
case string:
kit.If(field.name == "", func() { field.name = t }, func() { field.kind = t })
default:
field.kind = s.types(m)
}
}
}
kit.If(len(list) == 1, func() { list = append(list, []Field{}) })
return Function{arg: list[0], res: list[1]}
default:
// if t := s.value(m, s.token()); t != nil && t != "" {
// return t
// }
return s.token()
}
}
return ""
}
func (s *Stack) funcs(m *ice.Message) string {
name := s.show()
s.rest[s.skip], s.skip = name, s.skip-1
m.Cmd(FUNC, name)
f := s.peekf()
status := f.status
defer func() { f.status = status }()
f.status = STATUS_DISABLE
s.run(m)
return name
}
func (s *Stack) calls(m *ice.Message, obj Any, key Any, cb func(*Frame, Function), arg ...Any) Any {
m.Debug("stack %d call %T %s %#v", len(s.frame)-1, obj, key, arg)
if _k, ok := key.(string); ok && _k != "" {
kit.For(kit.Split(_k, ice.PT), func(k string) {
switch v := obj.(type) {
case Operater:
obj = v.Operate(SUBS, k)
case *Stack:
if _v := v.value(m, _k); _v != nil && _v != "" {
obj, key = _v, ""
} else {
obj, key = v.value(m, k), strings.TrimPrefix(_k, k+ice.PT)
}
}
})
}
switch obj := obj.(type) {
case Function:
m.Debug("stack %d call %T %s %#v", len(s.frame)-1, obj, kit.Select("", obj.obj, -1), arg)
f := s.pushf(m, CALL)
for _, field := range obj.res {
f.value[field.name] = nil
}
for i, field := range obj.arg {
kit.If(i < len(arg), func() { f.value[field.name] = arg[i] }, func() { f.value[field.name] = nil })
}
kit.If(len(obj.obj) > 1, func() { f.value[obj.obj[0].name] = obj.object })
value, pos := Value{list: kit.List()}, s.Position
f.value["_return"] = func(arg ...Any) {
if len(obj.res) > 0 {
for i, field := range obj.res {
kit.If(i < len(arg), func() { value.list = append(value.list, f.value[field.name]) }, func() { value.list = append(value.list, nil) })
}
} else {
value.list = arg
}
}
s.Position, f.defers = obj.Position, append(f.defers, func() {
if len(obj.res) > 0 && len(value.list) == 0 {
for _, field := range obj.res {
value.list = append(value.list, f.value[field.name])
}
}
s.Position = pos
})
kit.If(cb != nil, func() { cb(f, obj) })
s.run(m.Options(ice.YAC_STACK, s))
return value
case Caller:
m.Debug("stack %d call %T %s %#v", len(s.frame)-1, obj, key, arg)
kit.For(arg, func(i int, v Any) { arg[i] = Trans(arg[i]) })
return wrap(obj.Call(kit.Format(key), arg...))
case func(*ice.Message, string, ...Any) Any:
m.Debug("stack %d call %s %s %#v", len(s.frame)-1, kit.FileLine(obj, 3), key, arg)
kit.For(arg, func(i int, v Any) { arg[i] = Trans(arg[i]) })
return wrap(obj(m, kit.Format(key), arg...))
case func():
obj()
return nil
default:
if key == "" {
return nil
}
m.Debug("stack %d call %T %s %#v", len(s.frame)-1, obj, key, arg)
args := kit.List(key)
kit.For(arg, func(i int, v Any) { args = append(args, Trans(v)) })
return Message{m.Cmd(args...)}
}
}
func (s *Stack) Handler(obj Any) ice.Handler {
return func(m *ice.Message, arg ...string) {
m.Copy(s.Action(m.Spawn(Index).Spawn(m.Target()), obj, nil, arg...))
}
}
func (s *Stack) Action(m *ice.Message, obj Any, key Any, arg ...string) *ice.Message {
s.calls(m, obj, key, func(f *Frame, v Function) {
i := 0
for _, field := range v.arg {
switch field.name {
case "m", "msg":
f.value[field.name] = Message{m}
case ice.ARG:
list := kit.List()
kit.For(arg, func(v string) { list = append(list, String{v}) })
f.value[field.name] = Value{list}
default:
f.value[field.name], i = String{m.Option(field.name, kit.Select(m.Option(field.name), arg, i))}, i+1
}
}
})
return m
}
func (s *Stack) parse(m *ice.Message, name string, r io.Reader) *Stack {
pos := s.Position
defer func() { s.Position = pos }()
s.Position = Position{Buffer: &Buffer{name: name, input: bufio.NewScanner(r)}}
s.peekf().Position = s.Position
m.Debug("stack %d parse %s", len(s.frame)-1, s.show())
s.run(m)
return s
}
func NewStack(m *ice.Message, cb func(*Frame)) *Stack {
s := &Stack{}
s.pushf(m.Options(ice.YAC_STACK, s), STACK)
s.load(m, cb)
return s
}
func _parse_stack(m *ice.Message) *Stack { return m.Optionv(ice.YAC_STACK).(*Stack) }
func _parse_frame(m *ice.Message) (*Stack, *Frame) {
return _parse_stack(m), _parse_stack(m).pushf(m, "")
}
func _parse_const(m *ice.Message, key string) string {
if k := kit.Select(key, strings.Split(key, ice.PT), -1); kit.IsUpper(k) {
// if c, ok := ice.Info.Index[strings.ToLower(k)].(*ice.Context); ok && (key == k || key == c.Prefix(k)) {
return strings.ToLower(k)
// }
}
return ""
}
func _parse_res(m *ice.Message, v Any) []Any {
switch v := v.(type) {
case nil:
return nil
case Value:
return v.list
default:
return []Any{v}
}
}
const (
STATUS_NORMAL = 0
STATUS_DISABLE = -1
)
const STACK = "stack"
func init() {
Index.MergeCommands(ice.Commands{
STACK: {Name: "stack path auto parse", Actions: ice.Actions{
"start": {Hand: func(m *ice.Message, arg ...string) {}},
ice.CMD: {Hand: func(m *ice.Message, arg ...string) {}},
ice.RUN: {Hand: func(m *ice.Message, arg ...string) {}},
}, Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 || strings.HasSuffix(arg[0], ice.PS) {
m.Options(nfs.DIR_ROOT, nfs.SRC).Cmdy(nfs.CAT, arg)
return
}
nfs.Open(m, path.Join(nfs.SRC, strings.TrimPrefix(path.Join(arg...), nfs.SRC)), func(r io.Reader, p string) {
if NewStack(m, nil).parse(m, p, r); m.Option(ice.DEBUG) == ice.TRUE {
m.Cmdy(INFO, arg)
}
})
}},
})
loaded := kit.Dict()
ice.AddMergeAction(func(c *ice.Context, key string, cmd *ice.Command, sub string, action *ice.Action) (init ice.Handler) {
kit.IfNoKey(loaded, ice.SRC_SCRIPT+c.Prefix(key)+ice.PS, func(p string) { kit.If(nfs.Exists(ice.Pulse, p), func() { init = StackHandler }) })
return
})
}
func StackHandler(m *ice.Message, arg ...string) {
s := NewStack(m, nil)
script := []string{}
nfs.Open(m, ice.SRC_SCRIPT+m.PrefixKey()+ice.PS, func(r io.Reader, p string) {
kit.If(kit.Ext(p) == nfs.SHY, func() {
if strings.HasPrefix(path.Base(p), "on") {
script = append(script, kit.Format("Volcanos(\"%s\", {", kit.TrimExt(path.Base(p), nfs.SHY)))
kit.For(r, func(s string) {
if strings.HasPrefix(s, FUNC) {
script = append(script, ice.TB+strings.Replace(strings.TrimPrefix(s, FUNC+ice.SP), "(", ": function(", 1))
} else if strings.HasPrefix(s, END) {
script = append(script, ice.TB+"},")
} else {
script = append(script, ice.TB+s)
}
})
script = append(script, "})")
} else {
s.parse(m.Spawn(Index).Spawn(m.Target()), p, r)
}
})
})
if len(script) > 0 {
p := ice.USR_SCRIPT + m.PrefixKey() + ice.PS + "list.js"
s.value(m, "_script", "/require/"+p)
m.Cmd(nfs.SAVE, p, kit.Dict(nfs.CONTENT, strings.Join(script, ice.NL)))
}
cmd := m.Commands("")
kit.For(s.peekf().value, func(k string, v Any) {
switch v := v.(type) {
case Function:
list := kit.List()
for _, field := range v.arg {
kit.If(!kit.IsIn(field.name, "m", "msg", ice.ARG), func() { list = append(list, kit.Dict(mdb.NAME, field.name, mdb.TYPE, mdb.TEXT, mdb.VALUE, "")) })
}
kit.If(k == mdb.LIST, func() { list = append(list, kit.Dict(mdb.NAME, mdb.LIST, mdb.TYPE, "button", mdb.ACTION, ice.AUTO)) })
h := func(m *ice.Message, arg ...string) { m.Copy(s.Action(m.Spawn(Index).Spawn(m.Target()), s, k, arg...)) }
if k == mdb.LIST {
cmd.Hand, cmd.List = h, list
} else {
cmd.Actions[k], cmd.Meta[k] = &ice.Action{Hand: h}, list
}
}
})
}
func StackAction() ice.Actions { return ice.Actions{ice.CTX_INIT: {Hand: StackHandler}} }