mirror of
https://shylinux.com/x/icebergs
synced 2025-04-25 17:18:05 +08:00
300 lines
6.8 KiB
Go
300 lines
6.8 KiB
Go
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)
|
|
}},
|
|
})
|
|
}
|