You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

387 lines
8.3 KiB

package expression
import (
"errors"
"strconv"
"strings"
"unicode"
)
// Deprecated: 待优化, 简单表达式解析与求值器,支持变量、比较运算符和逻辑运算符
type Parser struct {
expr string
pos int
}
type Node interface {
Eval(vars map[string]interface{}) (bool, error)
}
type numberNode struct{ val float64 }
type boolNode struct{ val bool }
type varNode struct{ name string }
type binaryNode struct {
op string
left, right Node
}
type compareNode struct {
op string
left, right Node
}
type logicNode struct {
op string
left, right Node
}
type unaryNode struct {
op string
operand Node
}
// NewParser 创建解析器
func Parse(expr string) (*Parser, error) {
expr = strings.ReplaceAll(expr, " ", "") // 去除空格
if expr == "" {
return nil, errors.New("表达式为空")
}
return &Parser{expr: expr}, nil
}
// 解析并返回 AST 根节点
func (p *Parser) Parse() (Node, error) {
node, err := p.parseLogicOr()
if err != nil {
return nil, err
}
if p.pos != len(p.expr) {
return nil, errors.New("表达式末尾有多余字符")
}
return node, nil
}
// ====================== 解析层级 ======================
func (p *Parser) parseLogicOr() (Node, error) {
left, err := p.parseLogicAnd()
if err != nil {
return nil, err
}
for p.pos < len(p.expr) && p.substr(p.pos, 2) == "||" {
p.pos += 2
right, err := p.parseLogicAnd()
if err != nil {
return nil, err
}
left = &logicNode{op: "||", left: left, right: right}
}
return left, nil
}
func (p *Parser) parseLogicAnd() (Node, error) {
left, err := p.parseComparison()
if err != nil {
return nil, err
}
for p.pos < len(p.expr) && p.substr(p.pos, 2) == "&&" {
p.pos += 2
right, err := p.parseComparison()
if err != nil {
return nil, err
}
left = &logicNode{op: "&&", left: left, right: right}
}
return left, nil
}
func (p *Parser) parseComparison() (Node, error) {
left, err := p.parseExpression()
if err != nil {
return nil, err
}
ops := []string{">=", "<=", "==", "!=", ">", "<"}
var op string
for _, candidate := range ops {
if p.substr(p.pos, len(candidate)) == candidate {
op = candidate
p.pos += len(candidate)
break
}
}
if op != "" {
right, err := p.parseExpression()
if err != nil {
return nil, err
}
return &compareNode{op: op, left: left, right: right}, nil
}
return left, nil
}
func (p *Parser) parseExpression() (Node, error) {
left, err := p.parseTerm()
if err != nil {
return nil, err
}
for p.pos < len(p.expr) && (p.current() == '+' || p.current() == '-') {
op := string(p.current())
p.pos++
right, err := p.parseTerm()
if err != nil {
return nil, err
}
left = &binaryNode{op: op, left: left, right: right}
}
return left, nil
}
func (p *Parser) parseTerm() (Node, error) {
left, err := p.parseUnary()
if err != nil {
return nil, err
}
for p.pos < len(p.expr) && (p.current() == '*' || p.current() == '/') {
op := string(p.current())
p.pos++
right, err := p.parseUnary()
if err != nil {
return nil, err
}
left = &binaryNode{op: op, left: left, right: right}
}
return left, nil
}
func (p *Parser) parseUnary() (Node, error) {
if p.current() == '!' {
p.pos++
operand, err := p.parseUnary()
if err != nil {
return nil, err
}
return &unaryNode{op: "!", operand: operand}, nil
}
return p.parseAtom()
}
func (p *Parser) parseAtom() (Node, error) {
ch := p.current()
if ch == '(' {
p.pos++
node, err := p.parseLogicOr()
if err != nil {
return nil, err
}
if p.current() != ')' {
return nil, errors.New("缺少右括号")
}
p.pos++
return node, nil
}
if unicode.IsDigit(rune(ch)) || ch == '.' || ch == '-' && p.pos+1 < len(p.expr) && (unicode.IsDigit(rune(p.expr[p.pos+1])) || p.expr[p.pos+1] == '.') {
return p.parseNumber()
}
if unicode.IsLetter(rune(ch)) || ch == '_' {
return p.parseIdentifierOrBool()
}
return nil, errors.New("无效字符: " + string(ch))
}
func (p *Parser) parseNumber() (Node, error) {
start := p.pos
if p.current() == '-' {
p.pos++
}
for p.pos < len(p.expr) && (unicode.IsDigit(rune(p.expr[p.pos])) || p.expr[p.pos] == '.') {
p.pos++
}
val, err := strconv.ParseFloat(p.expr[start:p.pos], 64)
if err != nil {
return nil, err
}
return &numberNode{val: val}, nil
}
func (p *Parser) parseIdentifierOrBool() (Node, error) {
start := p.pos
for p.pos < len(p.expr) && (unicode.IsLetter(rune(p.expr[p.pos])) || unicode.IsDigit(rune(p.expr[p.pos])) || p.expr[p.pos] == '_') {
p.pos++
}
name := p.expr[start:p.pos]
if name == "true" {
return &boolNode{val: true}, nil
}
if name == "false" {
return &boolNode{val: false}, nil
}
return &varNode{name: name}, nil
}
// ====================== 辅助函数 ======================
func (p *Parser) current() byte {
if p.pos >= len(p.expr) {
return 0
}
return p.expr[p.pos]
}
func (p *Parser) substr(start, length int) string {
if start+length > len(p.expr) {
return ""
}
return p.expr[start : start+length]
}
// ====================== 求值 ======================
func (n *numberNode) Eval(_ map[string]interface{}) (bool, error) {
return false, errors.New("数字节点不能直接作为布尔表达式")
}
func (n *boolNode) Eval(_ map[string]interface{}) (bool, error) {
return n.val, nil
}
func (n *varNode) Eval(vars map[string]interface{}) (bool, error) {
val, exists := vars[n.name]
if !exists {
return false, errors.New("未定义的变量: " + n.name)
}
switch v := val.(type) {
case float64:
return v != 0, nil // 数字非零视为 true(可选逻辑)
case bool:
return v, nil
default:
return false, errors.New("变量必须是 float64 或 bool")
}
}
func (n *binaryNode) Eval(vars map[string]interface{}) (bool, error) {
_, err := evalToFloat(n.left, vars)
if err != nil {
return false, err
}
r, err := evalToFloat(n.right, vars)
if err != nil {
return false, err
}
switch n.op {
case "+":
return false, errors.New("二元运算不能直接返回 bool")
case "-":
return false, errors.New("二元运算不能直接返回 bool")
case "*":
return false, errors.New("二元运算不能直接返回 bool")
case "/":
if r == 0 {
return false, errors.New("除以零")
}
return false, errors.New("二元运算不能直接返回 bool")
}
return false, errors.New("未知运算符")
}
func (n *compareNode) Eval(vars map[string]interface{}) (bool, error) {
l, err := evalToFloat(n.left, vars)
if err != nil {
return false, err
}
r, err := evalToFloat(n.right, vars)
if err != nil {
return false, err
}
switch n.op {
case ">":
return l > r, nil
case "<":
return l < r, nil
case "==":
return l == r, nil
case ">=":
return l >= r, nil
case "<=":
return l <= r, nil
case "!=":
return l != r, nil
}
return false, errors.New("未知比较符")
}
func (n *logicNode) Eval(vars map[string]interface{}) (bool, error) {
l, err := evalToBool(n.left, vars)
if err != nil {
return false, err
}
r, err := evalToBool(n.right, vars)
if err != nil {
return false, err
}
if n.op == "&&" {
return l && r, nil
}
return l || r, nil
}
func (n *unaryNode) Eval(vars map[string]interface{}) (bool, error) {
val, err := evalToBool(n.operand, vars)
if err != nil {
return false, err
}
return !val, nil
}
// 辅助求值函数
func evalToFloat(node Node, vars map[string]interface{}) (float64, error) {
// 简化实现:这里假设算术表达式最终求值后用于比较
// 实际项目中可扩展返回 interface{}
switch n := node.(type) {
case *numberNode:
return n.val, nil
case *varNode:
if v, ok := vars[n.name].(float64); ok {
return v, nil
}
return 0, errors.New("变量不是数字")
case *binaryNode:
l, _ := evalToFloat(n.left, vars)
r, _ := evalToFloat(n.right, vars)
switch n.op {
case "+":
return l + r, nil
case "-":
return l - r, nil
case "*":
return l * r, nil
case "/":
if r == 0 {
return 0, errors.New("除以零")
}
return l / r, nil
}
}
return 0, errors.New("无法求值为数字")
}
func evalToBool(node Node, vars map[string]interface{}) (bool, error) {
return node.Eval(vars)
}
// ====================== 使用示例 ======================
func Evaluate(expr string, vars map[string]interface{}) (bool, error) {
p, err := Parse(expr)
if err != nil {
return false, err
}
ast, err := p.Parse()
if err != nil {
return false, err
}
return ast.Eval(vars)
}