1
0
forked from x/icebergs
icebergs/base/yac/expr.go
2023-04-02 15:39:58 +08:00

252 lines
5.7 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 = "}"
)
var keyword = regexp.MustCompile("[_a-zA-Z][_a-zA-Z0-9]*")
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
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) pops(n int, v Any) *Expr { return s.pop(n).push(v) }
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 {
if !s.s.runable() {
return nil
}
switch k := s.gets(p); v := v.(type) {
case string:
return s.s.value(m, k, s.s.value(m, v), op)
case Value:
return s.s.value(m, k, v.list[0], op)
default:
return s.s.value(m, k, v, op)
}
}
func (s *Expr) opv(m *ice.Message, p int, op string, v Any) Any {
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
}
if s.n++; s.n > 100 {
panic(s.n)
}
s.pops(3, s.opv(m, -3, s.gets(-2), s.getv(m, -1)))
}
func (s *Expr) end(m *ice.Message) Any {
if !s.s.runable() || len(s.list) == 0 {
return nil
} else if len(s.list) == 1 {
return s.getv(m, 0)
}
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 {
kit.If(i/2 < len(v.list), func() { 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
case CLOSE:
if s.gets(-2) == OPEN {
s.pops(2, s.get(-1))
return false
}
return true
}
if len(s.list) > 0 && s.getl(-1) == 0 {
switch k {
case "++", "--":
s.pops(1, s.setv(m, -1, ASSIGN, s.opv(m, -1, k, nil)))
return false
case SUBS:
s.pops(1, s.opv(m, -1, SUBS, s.s.cals(m)))
return false
case OPEN:
if s.gets(-1) == FUNC && s.s.skip > 1 {
s.s.skip--
s.pops(1, s.s.value(m, s.s.funcs(m)))
} else {
s.pops(1, s.call(m, s.s, s.gets(-1)))
}
return false
}
if level[k] == 0 {
if strings.HasPrefix(k, ice.PT) && kit.Select("", s.s.rest, s.s.skip+1) == OPEN {
s.s.skip++
s.pops(1, s.call(m, s.getv(m, -1), strings.TrimPrefix(k, ice.PT)))
return false
} else {
s.s.skip--
return true
}
}
}
if level[k] > 0 {
for level[k] >= 9 && level[k] <= s.getl(-2) && level[k] < 100 {
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 keyword.MatchString(k) {
s.push(k)
} else {
s.push(Number{value: k})
}
if s.gets(-2) == "!" {
s.pops(2, s.opv(-1, "!"))
}
}
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 list
}
return s.s.call(m, obj, key, nil, list...)
}
func NewExpr(s *Stack) *Expr { return &Expr{kit.List(), s, 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
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)
}},
})
}