// Package engine 依据已发布规则和持久化快照计算有限推进命令;不调用业务处理器或外部系统。 package engine import ( "bytes" "encoding/json" "errors" "math/big" "strings" "git.yuntuo.hk/k2safe/orbit/internal/jsonwire" "git.yuntuo.hk/k2safe/orbit/weave/definition" ) type values map[string]json.RawMessage func copyJSON(raw json.RawMessage) json.RawMessage { return append(json.RawMessage(nil), raw...) } func copyValues(in values) values { out := make(values, len(in)+8) for k, v := range in { out[k] = v } return out } // 表达式来自已验证且由Program持有的不可变定义;每个值仍按运行数据上限检查。 func resolve(v definition.Value, expected definition.Type, env values) (json.RawMessage, error) { raw, err := evaluate(v, env, 0) if err != nil { return nil, err } if err := definition.ValidateData(expected, raw); err != nil { return nil, err } return raw, nil } func evaluate(v definition.Value, env values, depth int) (json.RawMessage, error) { if depth > 8 { return nil, errors.New("expression depth exceeded") } var out json.RawMessage switch v.Kind { case "LITERAL": out = copyJSON(v.Literal) case "REFERENCE": if v.Reference == nil { return nil, errors.New("reference required") } raw, ok := env[v.Reference.Source] if !ok { return nil, errors.New("reference unavailable") } for _, key := range v.Reference.Path { var object map[string]json.RawMessage if json.Unmarshal(raw, &object) != nil { return nil, errors.New("reference is not an object") } raw, ok = object[key] if !ok { return nil, errors.New("reference field missing") } } out = copyJSON(raw) case "OBJECT": object := make(map[string]json.RawMessage, len(v.Fields)) size := 0 for k, child := range v.Fields { raw, err := evaluate(child, env, depth+1) if err != nil { return nil, err } size += len(raw) if size > definition.MaxSpecificationBytes { return nil, errors.New("resolved object exceeds bounds") } object[k] = raw } raw, err := jsonwire.Marshal(object) if err != nil { return nil, err } out = raw case "ARRAY": array := make([]json.RawMessage, len(v.Items)) size := 0 for i, child := range v.Items { raw, err := evaluate(child, env, depth+1) if err != nil { return nil, err } size += len(raw) if size > definition.MaxSpecificationBytes { return nil, errors.New("resolved array exceeds bounds") } array[i] = raw } raw, err := jsonwire.Marshal(array) if err != nil { return nil, err } out = raw default: return nil, errors.New("unknown expression") } if len(out) == 0 || len(out) > definition.MaxSpecificationBytes { return nil, errors.New("resolved value exceeds bounds") } return out, nil } func compare(p definition.Predicate, env values) (bool, error) { switch p.Op { case "AND", "OR", "NOT": for _, child := range p.Arguments { ok, err := compare(child, env) if err != nil { return false, err } if p.Op == "NOT" { return !ok, nil } if p.Op == "AND" && !ok { return false, nil } if p.Op == "OR" && ok { return true, nil } } return p.Op == "AND", nil } if p.Left == nil || p.Right == nil { return false, errors.New("comparison operands missing") } left, err := resolve(*p.Left, definition.Type{Kind: "JSON"}, env) if err != nil { return false, err } right, err := resolve(*p.Right, definition.Type{Kind: "JSON"}, env) if err != nil { return false, err } decode := func(raw []byte) (any, error) { var v any d := json.NewDecoder(bytes.NewReader(raw)) d.UseNumber() err := d.Decode(&v) return v, err } a, err := decode(left) if err != nil { return false, err } b, err := decode(right) if err != nil { return false, err } var order int switch v := a.(type) { case string: w, ok := b.(string) if !ok { return false, errors.New("comparison type mismatch") } order = strings.Compare(v, w) case json.Number: w, ok := b.(json.Number) if !ok { return false, errors.New("comparison type mismatch") } x, ok := new(big.Rat).SetString(string(v)) if !ok { return false, errors.New("invalid exact number") } y, ok := new(big.Rat).SetString(string(w)) if !ok { return false, errors.New("invalid exact number") } order = x.Cmp(y) case bool: w, ok := b.(bool) if !ok || p.Op != "EQ" && p.Op != "NE" { return false, errors.New("comparison type mismatch") } if v != w { order = 1 } case nil: if b != nil || p.Op != "EQ" && p.Op != "NE" { return false, errors.New("comparison type mismatch") } default: return false, errors.New("comparison requires scalars") } switch p.Op { case "EQ": return order == 0, nil case "NE": return order != 0, nil case "LT": return order < 0, nil case "LE": return order <= 0, nil case "GT": return order > 0, nil case "GE": return order >= 0, nil } return false, errors.New("unknown comparison") }