github.com/rajeev159/opa@v0.45.0/ast/index.go (about) 1 // Copyright 2017 The OPA Authors. All rights reserved. 2 // Use of this source code is governed by an Apache2 3 // license that can be found in the LICENSE file. 4 5 package ast 6 7 import ( 8 "fmt" 9 "sort" 10 "strings" 11 12 "github.com/open-policy-agent/opa/util" 13 ) 14 15 // RuleIndex defines the interface for rule indices. 16 type RuleIndex interface { 17 18 // Build tries to construct an index for the given rules. If the index was 19 // constructed, it returns true, otherwise false. 20 Build(rules []*Rule) bool 21 22 // Lookup searches the index for rules that will match the provided 23 // resolver. If the resolver returns an error, it is returned via err. 24 Lookup(resolver ValueResolver) (*IndexResult, error) 25 26 // AllRules traverses the index and returns all rules that will match 27 // the provided resolver without any optimizations (effectively with 28 // indexing disabled). If the resolver returns an error, it is returned 29 // via err. 30 AllRules(resolver ValueResolver) (*IndexResult, error) 31 } 32 33 // IndexResult contains the result of an index lookup. 34 type IndexResult struct { 35 Kind DocKind 36 Rules []*Rule 37 Else map[*Rule][]*Rule 38 Default *Rule 39 EarlyExit bool 40 } 41 42 // NewIndexResult returns a new IndexResult object. 43 func NewIndexResult(kind DocKind) *IndexResult { 44 return &IndexResult{ 45 Kind: kind, 46 Else: map[*Rule][]*Rule{}, 47 } 48 } 49 50 // Empty returns true if there are no rules to evaluate. 51 func (ir *IndexResult) Empty() bool { 52 return len(ir.Rules) == 0 && ir.Default == nil 53 } 54 55 type baseDocEqIndex struct { 56 skipIndexing Set 57 isVirtual func(Ref) bool 58 root *trieNode 59 defaultRule *Rule 60 kind DocKind 61 } 62 63 func newBaseDocEqIndex(isVirtual func(Ref) bool) *baseDocEqIndex { 64 return &baseDocEqIndex{ 65 skipIndexing: NewSet(NewTerm(InternalPrint.Ref())), 66 isVirtual: isVirtual, 67 root: newTrieNodeImpl(), 68 } 69 } 70 71 func (i *baseDocEqIndex) Build(rules []*Rule) bool { 72 if len(rules) == 0 { 73 return false 74 } 75 76 i.kind = rules[0].Head.DocKind() 77 indices := newrefindices(i.isVirtual) 78 79 // build indices for each rule. 80 for idx := range rules { 81 WalkRules(rules[idx], func(rule *Rule) bool { 82 if rule.Default { 83 i.defaultRule = rule 84 return false 85 } 86 var skip bool 87 for _, expr := range rule.Body { 88 if op := expr.OperatorTerm(); op != nil && i.skipIndexing.Contains(op) { 89 skip = true 90 break 91 } 92 } 93 if !skip { 94 for _, expr := range rule.Body { 95 indices.Update(rule, expr) 96 } 97 } 98 return false 99 }) 100 } 101 102 // build trie out of indices. 103 for idx := range rules { 104 var prio int 105 WalkRules(rules[idx], func(rule *Rule) bool { 106 if rule.Default { 107 return false 108 } 109 node := i.root 110 if indices.Indexed(rule) { 111 for _, ref := range indices.Sorted() { 112 node = node.Insert(ref, indices.Value(rule, ref), indices.Mapper(rule, ref)) 113 } 114 } 115 // Insert rule into trie with (insertion order, priority order) 116 // tuple. Retaining the insertion order allows us to return rules 117 // in the order they were passed to this function. 118 node.append([...]int{idx, prio}, rule) 119 prio++ 120 return false 121 }) 122 } 123 return true 124 } 125 126 func (i *baseDocEqIndex) Lookup(resolver ValueResolver) (*IndexResult, error) { 127 128 tr := newTrieTraversalResult() 129 130 err := i.root.Traverse(resolver, tr) 131 if err != nil { 132 return nil, err 133 } 134 135 result := NewIndexResult(i.kind) 136 result.Default = i.defaultRule 137 result.Rules = make([]*Rule, 0, len(tr.ordering)) 138 139 for _, pos := range tr.ordering { 140 sort.Slice(tr.unordered[pos], func(i, j int) bool { 141 return tr.unordered[pos][i].prio[1] < tr.unordered[pos][j].prio[1] 142 }) 143 nodes := tr.unordered[pos] 144 root := nodes[0].rule 145 146 result.Rules = append(result.Rules, root) 147 if len(nodes) > 1 { 148 result.Else[root] = make([]*Rule, len(nodes)-1) 149 for i := 1; i < len(nodes); i++ { 150 result.Else[root][i-1] = nodes[i].rule 151 } 152 } 153 } 154 155 result.EarlyExit = tr.values.Len() == 1 && tr.values.Slice()[0].IsGround() 156 157 return result, nil 158 } 159 160 func (i *baseDocEqIndex) AllRules(resolver ValueResolver) (*IndexResult, error) { 161 tr := newTrieTraversalResult() 162 163 // Walk over the rule trie and accumulate _all_ rules 164 rw := &ruleWalker{result: tr} 165 i.root.Do(rw) 166 167 result := NewIndexResult(i.kind) 168 result.Default = i.defaultRule 169 result.Rules = make([]*Rule, 0, len(tr.ordering)) 170 171 for _, pos := range tr.ordering { 172 sort.Slice(tr.unordered[pos], func(i, j int) bool { 173 return tr.unordered[pos][i].prio[1] < tr.unordered[pos][j].prio[1] 174 }) 175 nodes := tr.unordered[pos] 176 root := nodes[0].rule 177 result.Rules = append(result.Rules, root) 178 if len(nodes) > 1 { 179 result.Else[root] = make([]*Rule, len(nodes)-1) 180 for i := 1; i < len(nodes); i++ { 181 result.Else[root][i-1] = nodes[i].rule 182 } 183 } 184 } 185 186 result.EarlyExit = tr.values.Len() == 1 && tr.values.Slice()[0].IsGround() 187 188 return result, nil 189 } 190 191 type ruleWalker struct { 192 result *trieTraversalResult 193 } 194 195 func (r *ruleWalker) Do(x interface{}) trieWalker { 196 tn := x.(*trieNode) 197 r.result.Add(tn) 198 return r 199 } 200 201 type valueMapper struct { 202 Key string 203 MapValue func(Value) Value 204 } 205 206 type refindex struct { 207 Ref Ref 208 Value Value 209 Mapper *valueMapper 210 } 211 212 type refindices struct { 213 isVirtual func(Ref) bool 214 rules map[*Rule][]*refindex 215 frequency *util.HashMap 216 sorted []Ref 217 } 218 219 func newrefindices(isVirtual func(Ref) bool) *refindices { 220 return &refindices{ 221 isVirtual: isVirtual, 222 rules: map[*Rule][]*refindex{}, 223 frequency: util.NewHashMap(func(a, b util.T) bool { 224 r1, r2 := a.(Ref), b.(Ref) 225 return r1.Equal(r2) 226 }, func(x util.T) int { 227 return x.(Ref).Hash() 228 }), 229 } 230 } 231 232 // Update attempts to update the refindices for the given expression in the 233 // given rule. If the expression cannot be indexed the update does not affect 234 // the indices. 235 func (i *refindices) Update(rule *Rule, expr *Expr) { 236 237 if expr.Negated { 238 return 239 } 240 241 if len(expr.With) > 0 { 242 // NOTE(tsandall): In the future, we may need to consider expressions 243 // that have with statements applied to them. 244 return 245 } 246 247 op := expr.Operator() 248 249 if op.Equal(Equality.Ref()) { 250 i.updateEq(rule, expr) 251 } else if op.Equal(Equal.Ref()) && len(expr.Operands()) == 2 { 252 // NOTE(tsandall): if equal() is called with more than two arguments the 253 // output value is being captured in which case the indexer cannot 254 // exclude the rule if the equal() call would return false (because the 255 // false value must still be produced.) 256 i.updateEq(rule, expr) 257 } else if op.Equal(GlobMatch.Ref()) { 258 i.updateGlobMatch(rule, expr) 259 } 260 } 261 262 // Sorted returns a sorted list of references that the indices were built from. 263 // References that appear more frequently in the indexed rules are ordered 264 // before less frequently appearing references. 265 func (i *refindices) Sorted() []Ref { 266 267 if i.sorted == nil { 268 counts := make([]int, 0, i.frequency.Len()) 269 i.sorted = make([]Ref, 0, i.frequency.Len()) 270 271 i.frequency.Iter(func(k, v util.T) bool { 272 counts = append(counts, v.(int)) 273 i.sorted = append(i.sorted, k.(Ref)) 274 return false 275 }) 276 277 sort.Slice(i.sorted, func(a, b int) bool { 278 if counts[a] > counts[b] { 279 return true 280 } else if counts[b] > counts[a] { 281 return false 282 } 283 return i.sorted[a][0].Loc().Compare(i.sorted[b][0].Loc()) < 0 284 }) 285 } 286 287 return i.sorted 288 } 289 290 func (i *refindices) Indexed(rule *Rule) bool { 291 return len(i.rules[rule]) > 0 292 } 293 294 func (i *refindices) Value(rule *Rule, ref Ref) Value { 295 if index := i.index(rule, ref); index != nil { 296 return index.Value 297 } 298 return nil 299 } 300 301 func (i *refindices) Mapper(rule *Rule, ref Ref) *valueMapper { 302 if index := i.index(rule, ref); index != nil { 303 return index.Mapper 304 } 305 return nil 306 } 307 308 func (i *refindices) updateEq(rule *Rule, expr *Expr) { 309 a, b := expr.Operand(0), expr.Operand(1) 310 args := rule.Head.Args 311 if idx, ok := eqOperandsToRefAndValue(i.isVirtual, args, a, b); ok { 312 i.insert(rule, idx) 313 return 314 } 315 if idx, ok := eqOperandsToRefAndValue(i.isVirtual, args, b, a); ok { 316 i.insert(rule, idx) 317 return 318 } 319 } 320 321 func (i *refindices) updateGlobMatch(rule *Rule, expr *Expr) { 322 args := rule.Head.Args 323 324 delim, ok := globDelimiterToString(expr.Operand(1)) 325 if !ok { 326 return 327 } 328 329 if arr := globPatternToArray(expr.Operand(0), delim); arr != nil { 330 // The 3rd operand of glob.match is the value to match. We assume the 331 // 3rd operand was a reference that has been rewritten and bound to a 332 // variable earlier in the query OR a function argument variable. 333 match := expr.Operand(2) 334 if _, ok := match.Value.(Var); ok { 335 var ref Ref 336 for _, other := range i.rules[rule] { 337 if _, ok := other.Value.(Var); ok && other.Value.Compare(match.Value) == 0 { 338 ref = other.Ref 339 } 340 } 341 if ref == nil { 342 for j, arg := range args { 343 if arg.Equal(match) { 344 ref = Ref{FunctionArgRootDocument, IntNumberTerm(j)} 345 } 346 } 347 } 348 if ref != nil { 349 i.insert(rule, &refindex{ 350 Ref: ref, 351 Value: arr.Value, 352 Mapper: &valueMapper{ 353 Key: delim, 354 MapValue: func(v Value) Value { 355 if s, ok := v.(String); ok { 356 return stringSliceToArray(splitStringEscaped(string(s), delim)) 357 } 358 return v 359 }, 360 }, 361 }) 362 } 363 } 364 } 365 } 366 367 func (i *refindices) insert(rule *Rule, index *refindex) { 368 369 count, ok := i.frequency.Get(index.Ref) 370 if !ok { 371 count = 0 372 } 373 374 i.frequency.Put(index.Ref, count.(int)+1) 375 376 for pos, other := range i.rules[rule] { 377 if other.Ref.Equal(index.Ref) { 378 i.rules[rule][pos] = index 379 return 380 } 381 } 382 383 i.rules[rule] = append(i.rules[rule], index) 384 } 385 386 func (i *refindices) index(rule *Rule, ref Ref) *refindex { 387 for _, index := range i.rules[rule] { 388 if index.Ref.Equal(ref) { 389 return index 390 } 391 } 392 return nil 393 } 394 395 type trieWalker interface { 396 Do(x interface{}) trieWalker 397 } 398 399 type trieTraversalResult struct { 400 unordered map[int][]*ruleNode 401 ordering []int 402 values Set 403 } 404 405 func newTrieTraversalResult() *trieTraversalResult { 406 return &trieTraversalResult{ 407 unordered: map[int][]*ruleNode{}, 408 values: NewSet(), 409 } 410 } 411 412 func (tr *trieTraversalResult) Add(t *trieNode) { 413 for _, node := range t.rules { 414 root := node.prio[0] 415 nodes, ok := tr.unordered[root] 416 if !ok { 417 tr.ordering = append(tr.ordering, root) 418 } 419 tr.unordered[root] = append(nodes, node) 420 } 421 if t.values != nil { 422 t.values.Foreach(func(v *Term) { tr.values.Add(v) }) 423 } 424 } 425 426 type trieNode struct { 427 ref Ref 428 values Set 429 mappers []*valueMapper 430 next *trieNode 431 any *trieNode 432 undefined *trieNode 433 scalars map[Value]*trieNode 434 array *trieNode 435 rules []*ruleNode 436 } 437 438 func (node *trieNode) String() string { 439 var flags []string 440 flags = append(flags, fmt.Sprintf("self:%p", node)) 441 if len(node.ref) > 0 { 442 flags = append(flags, node.ref.String()) 443 } 444 if node.next != nil { 445 flags = append(flags, fmt.Sprintf("next:%p", node.next)) 446 } 447 if node.any != nil { 448 flags = append(flags, fmt.Sprintf("any:%p", node.any)) 449 } 450 if node.undefined != nil { 451 flags = append(flags, fmt.Sprintf("undefined:%p", node.undefined)) 452 } 453 if node.array != nil { 454 flags = append(flags, fmt.Sprintf("array:%p", node.array)) 455 } 456 if len(node.scalars) > 0 { 457 buf := make([]string, 0, len(node.scalars)) 458 for k, v := range node.scalars { 459 buf = append(buf, fmt.Sprintf("scalar(%v):%p", k, v)) 460 } 461 sort.Strings(buf) 462 flags = append(flags, strings.Join(buf, " ")) 463 } 464 if len(node.rules) > 0 { 465 flags = append(flags, fmt.Sprintf("%d rule(s)", len(node.rules))) 466 } 467 if len(node.mappers) > 0 { 468 flags = append(flags, fmt.Sprintf("%d mapper(s)", len(node.mappers))) 469 } 470 if l := node.values.Len(); l > 0 { 471 flags = append(flags, fmt.Sprintf("%d value(s)", l)) 472 } 473 return strings.Join(flags, " ") 474 } 475 476 func (node *trieNode) append(prio [2]int, rule *Rule) { 477 node.rules = append(node.rules, &ruleNode{prio, rule}) 478 479 if node.values != nil { 480 node.values.Add(rule.Head.Value) 481 return 482 } 483 484 if node.values == nil && rule.Head.DocKind() == CompleteDoc { 485 node.values = NewSet(rule.Head.Value) 486 } 487 } 488 489 type ruleNode struct { 490 prio [2]int 491 rule *Rule 492 } 493 494 func newTrieNodeImpl() *trieNode { 495 return &trieNode{ 496 scalars: map[Value]*trieNode{}, 497 } 498 } 499 500 func (node *trieNode) Do(walker trieWalker) { 501 next := walker.Do(node) 502 if next == nil { 503 return 504 } 505 if node.any != nil { 506 node.any.Do(next) 507 } 508 if node.undefined != nil { 509 node.undefined.Do(next) 510 } 511 for _, child := range node.scalars { 512 child.Do(next) 513 } 514 if node.array != nil { 515 node.array.Do(next) 516 } 517 if node.next != nil { 518 node.next.Do(next) 519 } 520 } 521 522 func (node *trieNode) Insert(ref Ref, value Value, mapper *valueMapper) *trieNode { 523 524 if node.next == nil { 525 node.next = newTrieNodeImpl() 526 node.next.ref = ref 527 } 528 529 if mapper != nil { 530 node.next.addMapper(mapper) 531 } 532 533 return node.next.insertValue(value) 534 } 535 536 func (node *trieNode) Traverse(resolver ValueResolver, tr *trieTraversalResult) error { 537 538 if node == nil { 539 return nil 540 } 541 542 tr.Add(node) 543 544 return node.next.traverse(resolver, tr) 545 } 546 547 func (node *trieNode) addMapper(mapper *valueMapper) { 548 for i := range node.mappers { 549 if node.mappers[i].Key == mapper.Key { 550 return 551 } 552 } 553 node.mappers = append(node.mappers, mapper) 554 } 555 556 func (node *trieNode) insertValue(value Value) *trieNode { 557 558 switch value := value.(type) { 559 case nil: 560 if node.undefined == nil { 561 node.undefined = newTrieNodeImpl() 562 } 563 return node.undefined 564 case Var: 565 if node.any == nil { 566 node.any = newTrieNodeImpl() 567 } 568 return node.any 569 case Null, Boolean, Number, String: 570 child, ok := node.scalars[value] 571 if !ok { 572 child = newTrieNodeImpl() 573 node.scalars[value] = child 574 } 575 return child 576 case *Array: 577 if node.array == nil { 578 node.array = newTrieNodeImpl() 579 } 580 return node.array.insertArray(value) 581 } 582 583 panic("illegal value") 584 } 585 586 func (node *trieNode) insertArray(arr *Array) *trieNode { 587 588 if arr.Len() == 0 { 589 return node 590 } 591 592 switch head := arr.Elem(0).Value.(type) { 593 case Var: 594 if node.any == nil { 595 node.any = newTrieNodeImpl() 596 } 597 return node.any.insertArray(arr.Slice(1, -1)) 598 case Null, Boolean, Number, String: 599 child, ok := node.scalars[head] 600 if !ok { 601 child = newTrieNodeImpl() 602 node.scalars[head] = child 603 } 604 return child.insertArray(arr.Slice(1, -1)) 605 } 606 607 panic("illegal value") 608 } 609 610 func (node *trieNode) traverse(resolver ValueResolver, tr *trieTraversalResult) error { 611 612 if node == nil { 613 return nil 614 } 615 616 v, err := resolver.Resolve(node.ref) 617 if err != nil { 618 if IsUnknownValueErr(err) { 619 return node.traverseUnknown(resolver, tr) 620 } 621 return err 622 } 623 624 if node.undefined != nil { 625 err = node.undefined.Traverse(resolver, tr) 626 if err != nil { 627 return err 628 } 629 } 630 631 if v == nil { 632 return nil 633 } 634 635 if node.any != nil { 636 err = node.any.Traverse(resolver, tr) 637 if err != nil { 638 return err 639 } 640 } 641 642 if err := node.traverseValue(resolver, tr, v); err != nil { 643 return err 644 } 645 646 for i := range node.mappers { 647 if err := node.traverseValue(resolver, tr, node.mappers[i].MapValue(v)); err != nil { 648 return err 649 } 650 } 651 652 return nil 653 } 654 655 func (node *trieNode) traverseValue(resolver ValueResolver, tr *trieTraversalResult, value Value) error { 656 657 switch value := value.(type) { 658 case *Array: 659 if node.array == nil { 660 return nil 661 } 662 return node.array.traverseArray(resolver, tr, value) 663 664 case Null, Boolean, Number, String: 665 child, ok := node.scalars[value] 666 if !ok { 667 return nil 668 } 669 return child.Traverse(resolver, tr) 670 } 671 672 return nil 673 } 674 675 func (node *trieNode) traverseArray(resolver ValueResolver, tr *trieTraversalResult, arr *Array) error { 676 677 if arr.Len() == 0 { 678 return node.Traverse(resolver, tr) 679 } 680 681 head := arr.Elem(0).Value 682 683 if !IsScalar(head) { 684 return nil 685 } 686 687 if node.any != nil { 688 err := node.any.traverseArray(resolver, tr, arr.Slice(1, -1)) 689 if err != nil { 690 return err 691 } 692 } 693 694 child, ok := node.scalars[head] 695 if !ok { 696 return nil 697 } 698 699 return child.traverseArray(resolver, tr, arr.Slice(1, -1)) 700 } 701 702 func (node *trieNode) traverseUnknown(resolver ValueResolver, tr *trieTraversalResult) error { 703 704 if node == nil { 705 return nil 706 } 707 708 if err := node.Traverse(resolver, tr); err != nil { 709 return err 710 } 711 712 if err := node.undefined.traverseUnknown(resolver, tr); err != nil { 713 return err 714 } 715 716 if err := node.any.traverseUnknown(resolver, tr); err != nil { 717 return err 718 } 719 720 if err := node.array.traverseUnknown(resolver, tr); err != nil { 721 return err 722 } 723 724 for _, child := range node.scalars { 725 if err := child.traverseUnknown(resolver, tr); err != nil { 726 return err 727 } 728 } 729 730 return nil 731 } 732 733 // If term `a` is one of the function's operands, we store a Ref: `args[0]` 734 // for the argument number. So for `f(x, y) { x = 10; y = 12 }`, we'll 735 // bind `args[0]` and `args[1]` to this rule when called for (x=10) and 736 // (y=12) respectively. 737 func eqOperandsToRefAndValue(isVirtual func(Ref) bool, args []*Term, a, b *Term) (*refindex, bool) { 738 switch v := a.Value.(type) { 739 case Var: 740 for i, arg := range args { 741 if arg.Value.Compare(v) == 0 { 742 if bval, ok := indexValue(b); ok { 743 return &refindex{Ref: Ref{FunctionArgRootDocument, IntNumberTerm(i)}, Value: bval}, true 744 } 745 } 746 } 747 case Ref: 748 if !RootDocumentNames.Contains(v[0]) { 749 return nil, false 750 } 751 if isVirtual(v) { 752 return nil, false 753 } 754 if v.IsNested() || !v.IsGround() { 755 return nil, false 756 } 757 if bval, ok := indexValue(b); ok { 758 return &refindex{Ref: v, Value: bval}, true 759 } 760 } 761 return nil, false 762 } 763 764 func indexValue(b *Term) (Value, bool) { 765 switch b := b.Value.(type) { 766 case Null, Boolean, Number, String, Var: 767 return b, true 768 case *Array: 769 stop := false 770 first := true 771 vis := NewGenericVisitor(func(x interface{}) bool { 772 if first { 773 first = false 774 return false 775 } 776 switch x.(type) { 777 // No nested structures or values that require evaluation (other than var). 778 case *Array, Object, Set, *ArrayComprehension, *ObjectComprehension, *SetComprehension, Ref: 779 stop = true 780 } 781 return stop 782 }) 783 vis.Walk(b) 784 if !stop { 785 return b, true 786 } 787 } 788 789 return nil, false 790 } 791 792 func globDelimiterToString(delim *Term) (string, bool) { 793 794 arr, ok := delim.Value.(*Array) 795 if !ok { 796 return "", false 797 } 798 799 var result string 800 801 if arr.Len() == 0 { 802 result = "." 803 } else { 804 for i := 0; i < arr.Len(); i++ { 805 term := arr.Elem(i) 806 s, ok := term.Value.(String) 807 if !ok { 808 return "", false 809 } 810 result += string(s) 811 } 812 } 813 814 return result, true 815 } 816 817 func globPatternToArray(pattern *Term, delim string) *Term { 818 819 s, ok := pattern.Value.(String) 820 if !ok { 821 return nil 822 } 823 824 parts := splitStringEscaped(string(s), delim) 825 arr := make([]*Term, len(parts)) 826 827 for i := range parts { 828 if parts[i] == "*" { 829 arr[i] = VarTerm("$globwildcard") 830 } else { 831 var escaped bool 832 for _, c := range parts[i] { 833 if c == '\\' { 834 escaped = !escaped 835 continue 836 } 837 if !escaped { 838 switch c { 839 case '[', '?', '{', '*': 840 // TODO(tsandall): super glob and character pattern 841 // matching not supported yet. 842 return nil 843 } 844 } 845 escaped = false 846 } 847 arr[i] = StringTerm(parts[i]) 848 } 849 } 850 851 return NewTerm(NewArray(arr...)) 852 } 853 854 // splits s on characters in delim except if delim characters have been escaped 855 // with reverse solidus. 856 func splitStringEscaped(s string, delim string) []string { 857 858 var last, curr int 859 var escaped bool 860 var result []string 861 862 for ; curr < len(s); curr++ { 863 if s[curr] == '\\' || escaped { 864 escaped = !escaped 865 continue 866 } 867 if strings.ContainsRune(delim, rune(s[curr])) { 868 result = append(result, s[last:curr]) 869 last = curr + 1 870 } 871 } 872 873 result = append(result, s[last:]) 874 875 return result 876 } 877 878 func stringSliceToArray(s []string) *Array { 879 arr := make([]*Term, len(s)) 880 for i, v := range s { 881 arr[i] = StringTerm(v) 882 } 883 return NewArray(arr...) 884 }