github.com/rajeev159/opa@v0.45.0/ast/parser_test.go (about)

     1  // Copyright 2016 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  	"bytes"
     9  	"encoding/json"
    10  	"fmt"
    11  	"reflect"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/open-policy-agent/opa/ast/internal/tokens"
    16  )
    17  
    18  const (
    19  	testModule = `
    20  # This policy module belongs the opa.example package.
    21  package opa.examples
    22  
    23  # Refer to data.servers as servers.
    24  import data.servers
    25  # Refer to the data.networks as networks.
    26  import data.networks
    27  # Refer to the data.ports as ports.
    28  import data.ports
    29  
    30  # A server exists in the violations set if...
    31  violations[server] {
    32      # ...the server exists
    33      server = servers[i]
    34      # ...and any of the server’s protocols is HTTP
    35      server.protocols[j] = "http"
    36      # ...and the server is public.
    37      public_servers[server]
    38  }
    39  
    40  # A server exists in the public_servers set if...
    41  public_servers[server] {
    42  	# Semicolons are optional. Can group expressions onto one line.
    43      server = servers[i]; server.ports[j] = ports[k].id 	# ...and the server is connected to a port
    44      ports[k].networks[l] = networks[m].id; 				# ...and the port is connected to a network
    45      networks[m].public = true							# ...and the network is public.
    46  }`
    47  )
    48  
    49  func TestNumberTerms(t *testing.T) {
    50  
    51  	tests := []struct {
    52  		input    string
    53  		expected string
    54  	}{
    55  		{"0", "0"},
    56  		{"100", "100"},
    57  		{"-1", "-1"},
    58  		{"1e6", "1e6"},
    59  		{"1.1e6", "1.1e6"},
    60  		{"-1e-6", "-1e-6"},
    61  		{"1E6", "1E6"},
    62  		{"0.1", "0.1"},
    63  		{".1", "0.1"},
    64  		{".0001", "0.0001"},
    65  		{"-.1", "-0.1"},
    66  		{"-0.0001", "-0.0001"},
    67  		{"1e1000", "1e1000"},
    68  		{"0e1", "0"},
    69  		{"-0.1", "-0.1"},
    70  	}
    71  
    72  	for _, tc := range tests {
    73  		result, err := ParseTerm(tc.input)
    74  		if err != nil {
    75  			t.Errorf("Unexpected error for %v: %v", tc.input, err)
    76  		} else {
    77  			e := NumberTerm(json.Number(tc.expected))
    78  			if !result.Equal(e) {
    79  				t.Errorf("Expected %v for %v but got: %v", e, tc.input, result)
    80  			}
    81  		}
    82  	}
    83  }
    84  
    85  func TestStringTerms(t *testing.T) {
    86  	tests := []struct {
    87  		input    string
    88  		expected string
    89  	}{
    90  		{`""`, ""},                   // empty
    91  		{`" "`, " "},                 // whitespace
    92  		{`"\""`, `"`},                // escaped quote
    93  		{`"http:\/\/"`, `http://`},   // escaped solidus
    94  		{`"\u0001"`, "\x01"},         // control code
    95  		{`"foo\u005C"`, "foo\u005c"}, // unicode (upper hex)
    96  		{`"foo\u005c"`, "foo\u005C"}, // unicode (lower hex)
    97  		{`"\uD834\uDD1E"`, `𝄞`},      // g-clef
    98  		{"`hi\\there`", `hi\there`},  // basic raw string
    99  		{"`foo\nbar\n    baz`", `foo
   100  bar
   101      baz`}, // multi-line raw string
   102  	}
   103  
   104  	for _, tc := range tests {
   105  		result, err := ParseTerm(tc.input)
   106  		if err != nil {
   107  			t.Errorf("Unexpected error for %v: %v", tc.input, err)
   108  		} else {
   109  			s := StringTerm(tc.expected)
   110  			if !result.Equal(s) {
   111  				t.Errorf("Expected %v for %v but got: %v", s, tc.input, result)
   112  			}
   113  		}
   114  	}
   115  }
   116  
   117  func TestScalarTerms(t *testing.T) {
   118  	assertParseOneTerm(t, "null", "null", NullTerm())
   119  	assertParseOneTerm(t, "true", "true", BooleanTerm(true))
   120  	assertParseOneTerm(t, "false", "false", BooleanTerm(false))
   121  	assertParseOneTerm(t, "integer", "53", IntNumberTerm(53))
   122  	assertParseOneTerm(t, "integer2", "-53", IntNumberTerm(-53))
   123  	assertParseOneTerm(t, "float", "16.7", FloatNumberTerm(16.7))
   124  	assertParseOneTerm(t, "float2", "-16.7", FloatNumberTerm(-16.7))
   125  	assertParseOneTerm(t, "exponent", "6e7", FloatNumberTerm(6e7))
   126  	assertParseOneTerm(t, "string", "\"a string\"", StringTerm("a string"))
   127  	assertParseOneTerm(t, "string", "\"a string u6abc7def8abc0def with unicode\"", StringTerm("a string u6abc7def8abc0def with unicode"))
   128  	assertParseErrorContains(t, "hex", "6abc", "illegal number format")
   129  	assertParseErrorContains(t, "non-terminated", "\"foo", "non-terminated string")
   130  	assertParseErrorContains(t, "non-terminated-raw", "`foo", "non-terminated string")
   131  	assertParseErrorContains(t, "non-string", "'a string'", "illegal token")
   132  	assertParseErrorContains(t, "non-number", "6zxy", "illegal number format")
   133  	assertParseErrorContains(t, "non-number2", "6d7", "illegal number format")
   134  	assertParseErrorContains(t, "non-number3", "6\"foo\"", "expected exactly one statement") // ??
   135  	assertParseErrorContains(t, "non-number4", "6true", "illegal number format")
   136  	assertParseErrorContains(t, "non-number5", "6false", "illegal number format")
   137  	assertParseErrorContains(t, "non-number6", "6[null, null]", "illegal ref (head cannot be number)") // ??
   138  	assertParseErrorContains(t, "non-number7", "6{\"foo\": \"bar\"}", "expected exactly one statement")
   139  	assertParseErrorContains(t, "non-number8", ".0.", "expected fraction")
   140  	assertParseErrorContains(t, "non-number9", "0e", "expected exponent")
   141  	assertParseErrorContains(t, "non-number10", "0e.", "expected exponent")
   142  	assertParseErrorContains(t, "non-number11", "0F", "illegal number format")
   143  	assertParseErrorContains(t, "non-number12", "00", "expected number")
   144  	assertParseErrorContains(t, "non-number13", "00.1", "expected number")
   145  	assertParseErrorContains(t, "non-number14", "-00", "expected number")
   146  	assertParseErrorContains(t, "non-number15", "-00.1", "expected number")
   147  	assertParseErrorContains(t, "non-number16", "-00.01", "expected number")
   148  	assertParseErrorContains(t, "non-number17", "00e1", "expected number")
   149  	assertParseErrorContains(t, "non-number18", "-00e1", "expected number")
   150  	assertParseErrorContains(t, "parsing float fails", "7e3000000000", "invalid float")
   151  	assertParseErrorContains(t, "float is +inf", "10245423601e680507880", "number too big")
   152  	assertParseErrorContains(t, "float is -inf", "-10245423601e680507880", "number too big")
   153  
   154  	// f := big.NewFloat(1); f.SetMantExp(f, -1e6); f.String() // => 1.010034059e-301030 (this takes ~9s)
   155  	assertParseErrorContains(t, "float exp < -1e5", "1.010034059e-301030", "number too big")
   156  
   157  	// g := big.NewFloat(1); g.SetMantExp(g, 1e6); g.String() // => 9.900656229e+301029
   158  	assertParseErrorContains(t, "float exp > 1e5", "9.900656229e+301029", "number too big")
   159  }
   160  
   161  func TestVarTerms(t *testing.T) {
   162  	assertParseOneTerm(t, "var", "foo", VarTerm("foo"))
   163  	assertParseOneTerm(t, "var", "foo_bar", VarTerm("foo_bar"))
   164  	assertParseOneTerm(t, "var", "foo0", VarTerm("foo0"))
   165  	assertParseOneTerm(t, "import prefix", "imports", VarTerm("imports"))
   166  	assertParseOneTerm(t, "not prefix", "not_foo", VarTerm("not_foo"))
   167  	assertParseOneTerm(t, `package prefix`, "packages", VarTerm("packages"))
   168  	assertParseOneTerm(t, `true prefix`, "trueish", VarTerm("trueish"))
   169  	assertParseOneTerm(t, `false prefix`, "false_flag", VarTerm("false_flag"))
   170  	assertParseOneTerm(t, `null prefix`, "nullable", VarTerm("nullable"))
   171  	assertParseError(t, "illegal token", `墳`)
   172  	assertParseError(t, "not keyword", "not")
   173  	assertParseError(t, `package keyword`, "package")
   174  	assertParseError(t, "import keyword", "import")
   175  	assertParseError(t, "import invalid path", "import x.")
   176  }
   177  
   178  func TestRefTerms(t *testing.T) {
   179  	assertParseOneTerm(t, "constants", "foo.bar.baz", RefTerm(VarTerm("foo"), StringTerm("bar"), StringTerm("baz")))
   180  	assertParseOneTerm(t, "constants 2", "foo.bar[0].baz", RefTerm(VarTerm("foo"), StringTerm("bar"), IntNumberTerm(0), StringTerm("baz")))
   181  	assertParseOneTerm(t, "variables", "foo.bar[0].baz[i]", RefTerm(VarTerm("foo"), StringTerm("bar"), IntNumberTerm(0), StringTerm("baz"), VarTerm("i")))
   182  	assertParseOneTerm(t, "spaces", "foo[\"white space\"].bar", RefTerm(VarTerm("foo"), StringTerm("white space"), StringTerm("bar")))
   183  	assertParseOneTerm(t, "nested", "foo[baz[1][borge[i]]].bar", RefTerm(
   184  		VarTerm("foo"),
   185  		RefTerm(
   186  			VarTerm("baz"), IntNumberTerm(1), RefTerm(
   187  				VarTerm("borge"), VarTerm("i"),
   188  			),
   189  		),
   190  		StringTerm("bar"),
   191  	))
   192  	assertParseOneTerm(t, "composite operand 1", "foo[[1,2,3]].bar", RefTerm(VarTerm("foo"), ArrayTerm(NumberTerm("1"), NumberTerm("2"), NumberTerm("3")), StringTerm("bar")))
   193  	assertParseOneTerm(t, "composite operand 2", `foo[{"foo": 2}].bar`, RefTerm(VarTerm("foo"), ObjectTerm(Item(StringTerm("foo"), NumberTerm("2"))), StringTerm("bar")))
   194  
   195  	assertParseError(t, "missing component 1", "foo.")
   196  	assertParseError(t, "missing component 2", "foo[].bar")
   197  	assertParseError(t, "invalid composite operand", "foo[1,2]")
   198  	assertParseError(t, "invalid call", "bar(..")
   199  	assertParseError(t, "invalid ref", "bar[..")
   200  	assertParseError(t, "invalid ref head type number", "0[0]")
   201  	assertParseError(t, "invalid ref head type boolean", "true[0]")
   202  	assertParseError(t, "invalid ref head type string", `"foo"[0]`)
   203  	assertParseError(t, "invalid ref head type null", `null[0]`)
   204  }
   205  
   206  func TestObjectWithScalars(t *testing.T) {
   207  	assertParseOneTerm(t, "number", "{\"abc\": 7, \"def\": 8}", ObjectTerm(Item(StringTerm("abc"), IntNumberTerm(7)), Item(StringTerm("def"), IntNumberTerm(8))))
   208  	assertParseOneTerm(t, "bool", "{\"abc\": false, \"def\": true}", ObjectTerm(Item(StringTerm("abc"), BooleanTerm(false)), Item(StringTerm("def"), BooleanTerm(true))))
   209  	assertParseOneTerm(t, "string", "{\"abc\": \"foo\", \"def\": \"bar\"}", ObjectTerm(Item(StringTerm("abc"), StringTerm("foo")), Item(StringTerm("def"), StringTerm("bar"))))
   210  	assertParseOneTerm(t, "mixed", "{\"abc\": 7, \"def\": null}", ObjectTerm(Item(StringTerm("abc"), IntNumberTerm(7)), Item(StringTerm("def"), NullTerm())))
   211  	assertParseOneTerm(t, "number key", "{8: 7, \"def\": null}", ObjectTerm(Item(IntNumberTerm(8), IntNumberTerm(7)), Item(StringTerm("def"), NullTerm())))
   212  	assertParseOneTerm(t, "number key 2", "{8.5: 7, \"def\": null}", ObjectTerm(Item(FloatNumberTerm(8.5), IntNumberTerm(7)), Item(StringTerm("def"), NullTerm())))
   213  	assertParseOneTerm(t, "bool key", "{true: false}", ObjectTerm(Item(BooleanTerm(true), BooleanTerm(false))))
   214  	assertParseOneTerm(t, "trailing comma", `{"a": "bar", "b": 64, }`, ObjectTerm(Item(StringTerm("a"), StringTerm("bar")), Item(StringTerm("b"), IntNumberTerm(64))))
   215  	assertParseOneTerm(t, "leading comma", `{, "a": "bar", "b": 64 }`, ObjectTerm(Item(StringTerm("a"), StringTerm("bar")), Item(StringTerm("b"), IntNumberTerm(64))))
   216  	assertParseOneTerm(t, "leading comma not comprehension", `{, 1 | 1: "bar"}`, ObjectTerm(Item(CallTerm(RefTerm(VarTerm("or")), NumberTerm("1"), NumberTerm("1")), StringTerm("bar"))))
   217  }
   218  
   219  func TestObjectWithVars(t *testing.T) {
   220  	assertParseOneTerm(t, "var keys", "{foo: \"bar\", bar: 64}", ObjectTerm(Item(VarTerm("foo"), StringTerm("bar")), Item(VarTerm("bar"), IntNumberTerm(64))))
   221  	assertParseOneTerm(t, "nested var keys", "{baz: {foo: \"bar\", bar: qux}}", ObjectTerm(Item(VarTerm("baz"), ObjectTerm(Item(VarTerm("foo"), StringTerm("bar")), Item(VarTerm("bar"), VarTerm("qux"))))))
   222  	assertParseOneTerm(t, "ambiguous or", `{ a: b+c | d }`, ObjectTerm(Item(VarTerm("a"), CallTerm(RefTerm(VarTerm("or")), CallTerm(RefTerm(VarTerm("plus")), VarTerm("b"), VarTerm("c")), VarTerm("d")))))
   223  }
   224  
   225  func TestObjectWithRelation(t *testing.T) {
   226  	assertParseOneTerm(t, "relation term value", `{"x": 1+1}`, ObjectTerm(
   227  		Item(StringTerm("x"), CallTerm(RefTerm(VarTerm("plus")), IntNumberTerm(1), IntNumberTerm(1))),
   228  	))
   229  	assertParseError(t, "invalid relation term value", `{"x": 0= }`)
   230  }
   231  
   232  func TestObjectFail(t *testing.T) {
   233  	assertParseError(t, "non-terminated 1", "{foo: bar, baz: [], qux: corge")
   234  	assertParseError(t, "non-terminated 2", "{foo: bar, baz: [], qux: ")
   235  	assertParseError(t, "non-terminated 3", "{foo: bar, baz: [], qux ")
   236  	assertParseError(t, "non-terminated 4", "{foo: bar, baz: [], ")
   237  	assertParseError(t, "missing separator", "{foo: bar baz: []}")
   238  	assertParseError(t, "missing start", "foo: bar, baz: [], qux: corge}")
   239  	assertParseError(t, "double comma", "{a:1,,b:2}")
   240  	assertParseError(t, "leading double comma", "{,,a:1}")
   241  	assertParseError(t, "trailing double comma", "{a:1,,}")
   242  }
   243  
   244  func TestArrayWithScalars(t *testing.T) {
   245  	assertParseOneTerm(t, "number", "[1,2,3,4.5]", ArrayTerm(IntNumberTerm(1), IntNumberTerm(2), IntNumberTerm(3), FloatNumberTerm(4.5)))
   246  	assertParseOneTerm(t, "bool", "[true, false, true]", ArrayTerm(BooleanTerm(true), BooleanTerm(false), BooleanTerm(true)))
   247  	assertParseOneTerm(t, "string", "[\"foo\", \"bar\"]", ArrayTerm(StringTerm("foo"), StringTerm("bar")))
   248  	assertParseOneTerm(t, "mixed", "[null, true, 42]", ArrayTerm(NullTerm(), BooleanTerm(true), IntNumberTerm(42)))
   249  	assertParseOneTerm(t, "trailing comma - one element", "[null, ]", ArrayTerm(NullTerm()))
   250  	assertParseOneTerm(t, "trailing comma", "[null, true, ]", ArrayTerm(NullTerm(), BooleanTerm(true)))
   251  	assertParseOneTerm(t, "leading comma", "[, null, true]", ArrayTerm(NullTerm(), BooleanTerm(true)))
   252  	assertParseOneTerm(t, "leading comma not comprehension", "[, 1 | 1]", ArrayTerm(CallTerm(RefTerm(VarTerm("or")), NumberTerm("1"), NumberTerm("1"))))
   253  	assertParseOneTerm(t, "ambiguous or", "[ 1 + 2 | 3 ]", ArrayTerm(CallTerm(RefTerm(VarTerm("or")), CallTerm(RefTerm(VarTerm("plus")), NumberTerm("1"), NumberTerm("2")), NumberTerm("3"))))
   254  }
   255  
   256  func TestArrayWithVars(t *testing.T) {
   257  	assertParseOneTerm(t, "var elements", "[foo, bar, 42]", ArrayTerm(VarTerm("foo"), VarTerm("bar"), IntNumberTerm(42)))
   258  	assertParseOneTerm(t, "nested var elements", "[[foo, true], [null, bar], 42]", ArrayTerm(ArrayTerm(VarTerm("foo"), BooleanTerm(true)), ArrayTerm(NullTerm(), VarTerm("bar")), IntNumberTerm(42)))
   259  }
   260  
   261  func TestArrayFail(t *testing.T) {
   262  	assertParseError(t, "non-terminated 1", "[foo, bar")
   263  	assertParseError(t, "non-terminated 2", "[foo, bar, ")
   264  	assertParseError(t, "missing separator", "[foo bar]")
   265  	assertParseError(t, "missing start", "foo, bar, baz]")
   266  	assertParseError(t, "bad term", "[!!!]")
   267  	assertParseError(t, "double comma", "[a,,b]")
   268  	assertParseError(t, "leading double comma", "[,,a]")
   269  	assertParseError(t, "trailing double comma", "[a,,]")
   270  }
   271  
   272  func TestSetWithScalars(t *testing.T) {
   273  	assertParseOneTerm(t, "number", "{1,2,3,4.5}", SetTerm(IntNumberTerm(1), IntNumberTerm(2), IntNumberTerm(3), FloatNumberTerm(4.5)))
   274  	assertParseOneTerm(t, "bool", "{true, false, true}", SetTerm(BooleanTerm(true), BooleanTerm(false), BooleanTerm(true)))
   275  	assertParseOneTerm(t, "string", "{\"foo\", \"bar\"}", SetTerm(StringTerm("foo"), StringTerm("bar")))
   276  	assertParseOneTerm(t, "mixed", "{null, true, 42}", SetTerm(NullTerm(), BooleanTerm(true), IntNumberTerm(42)))
   277  	assertParseOneTerm(t, "trailing comma", "{null, true,}", SetTerm(NullTerm(), BooleanTerm(true)))
   278  	assertParseOneTerm(t, "leading comma", "{, null, true}", SetTerm(NullTerm(), BooleanTerm(true)))
   279  	assertParseOneTerm(t, "leading comma not comprehension", "{, 1 | 1}", SetTerm(CallTerm(RefTerm(VarTerm("or")), NumberTerm("1"), NumberTerm("1"))))
   280  	assertParseOneTerm(t, "ambiguous or", "{ 1 + 2 | 3}", SetTerm(CallTerm(RefTerm(VarTerm("or")), CallTerm(RefTerm(VarTerm("plus")), NumberTerm("1"), NumberTerm("2")), NumberTerm("3"))))
   281  }
   282  
   283  func TestSetWithVars(t *testing.T) {
   284  	assertParseOneTerm(t, "var elements", "{foo, bar, 42}", SetTerm(VarTerm("foo"), VarTerm("bar"), IntNumberTerm(42)))
   285  	assertParseOneTerm(t, "nested var elements", "{[foo, true], {null, bar}, set()}", SetTerm(ArrayTerm(VarTerm("foo"), BooleanTerm(true)), SetTerm(NullTerm(), VarTerm("bar")), SetTerm()))
   286  }
   287  
   288  func TestSetFail(t *testing.T) {
   289  	assertParseError(t, "non-terminated 1", "set(")
   290  	assertParseError(t, "non-terminated 2", "{foo, bar")
   291  	assertParseError(t, "non-terminated 3", "{foo, bar, ")
   292  	assertParseError(t, "missing separator", "{foo bar}")
   293  	assertParseError(t, "missing start", "foo, bar, baz}")
   294  	assertParseError(t, "bad term", "{!!!}")
   295  	assertParseError(t, "double comma", "{a,,b}")
   296  	assertParseError(t, "leading double comma", "{,,a}")
   297  	assertParseError(t, "trailing double comma", "{a,,}")
   298  }
   299  
   300  func TestEmptyComposites(t *testing.T) {
   301  	assertParseOneTerm(t, "empty object", "{}", ObjectTerm())
   302  	assertParseOneTerm(t, "empty array", "[]", ArrayTerm())
   303  	assertParseOneTerm(t, "empty set", "set()", SetTerm())
   304  }
   305  
   306  func TestNestedComposites(t *testing.T) {
   307  	assertParseOneTerm(t, "nested composites", "[{foo: [\"bar\", {baz}]}]", ArrayTerm(ObjectTerm(Item(VarTerm("foo"), ArrayTerm(StringTerm("bar"), SetTerm(VarTerm("baz")))))))
   308  }
   309  
   310  func TestCompositesWithRefs(t *testing.T) {
   311  	ref1 := RefTerm(VarTerm("a"), VarTerm("i"), StringTerm("b"))
   312  	ref2 := RefTerm(VarTerm("c"), IntNumberTerm(0), StringTerm("d"), StringTerm("e"), VarTerm("j"))
   313  	assertParseOneTerm(t, "ref keys", "[{a[i].b: 8, c[0][\"d\"].e[j]: f}]", ArrayTerm(ObjectTerm(Item(ref1, IntNumberTerm(8)), Item(ref2, VarTerm("f")))))
   314  	assertParseOneTerm(t, "ref values", "[{8: a[i].b, f: c[0][\"d\"].e[j]}]", ArrayTerm(ObjectTerm(Item(IntNumberTerm(8), ref1), Item(VarTerm("f"), ref2))))
   315  	assertParseOneTerm(t, "ref values (sets)", `{a[i].b, {c[0]["d"].e[j]}}`, SetTerm(ref1, SetTerm(ref2)))
   316  }
   317  
   318  func TestArrayComprehensions(t *testing.T) {
   319  
   320  	nestedTerm := `[{"x": [a[i] | xs = [{"a": ["baz", j]} | q[p]; p.a != "bar"; j = "foo"]; xs[j].a[k] = "foo"]}]`
   321  	nestedExpected := ArrayTerm(
   322  		ObjectTerm(Item(
   323  			StringTerm("x"),
   324  			ArrayComprehensionTerm(
   325  				RefTerm(VarTerm("a"), VarTerm("i")),
   326  				NewBody(
   327  					Equality.Expr(
   328  						VarTerm("xs"),
   329  						ArrayComprehensionTerm(
   330  							ObjectTerm(Item(StringTerm("a"), ArrayTerm(StringTerm("baz"), VarTerm("j")))),
   331  							NewBody(
   332  								NewExpr(RefTerm(VarTerm("q"), VarTerm("p"))),
   333  								NotEqual.Expr(RefTerm(VarTerm("p"), StringTerm("a")), StringTerm("bar")),
   334  								Equality.Expr(VarTerm("j"), StringTerm("foo")),
   335  							),
   336  						),
   337  					),
   338  					Equality.Expr(
   339  						RefTerm(VarTerm("xs"), VarTerm("j"), StringTerm("a"), VarTerm("k")),
   340  						StringTerm("foo"),
   341  					),
   342  				),
   343  			),
   344  		)),
   345  	)
   346  	assertParseOneTerm(t, "nested", nestedTerm, nestedExpected)
   347  	assertParseOneTerm(t, "ambiguous or", "[ a | b ]", ArrayComprehensionTerm(
   348  		VarTerm("a"),
   349  		MustParseBody("b"),
   350  	))
   351  }
   352  
   353  func TestObjectComprehensions(t *testing.T) {
   354  	nestedTerm := `[{"x": {a[i]: b[i] | xs = {"foo":{"a": ["baz", j]} | q[p]; p.a != "bar"; j = "foo"}; xs[j].a[k] = "foo"}}]`
   355  	nestedExpected := ArrayTerm(
   356  		ObjectTerm(Item(
   357  			StringTerm("x"),
   358  			ObjectComprehensionTerm(
   359  				RefTerm(VarTerm("a"), VarTerm("i")),
   360  				RefTerm(VarTerm("b"), VarTerm("i")),
   361  				NewBody(
   362  					Equality.Expr(
   363  						VarTerm("xs"),
   364  						ObjectComprehensionTerm(
   365  							StringTerm("foo"),
   366  							ObjectTerm(Item(StringTerm("a"), ArrayTerm(StringTerm("baz"), VarTerm("j")))),
   367  							NewBody(
   368  								NewExpr(RefTerm(VarTerm("q"), VarTerm("p"))),
   369  								NotEqual.Expr(RefTerm(VarTerm("p"), StringTerm("a")), StringTerm("bar")),
   370  								Equality.Expr(VarTerm("j"), StringTerm("foo")),
   371  							),
   372  						),
   373  					),
   374  					Equality.Expr(
   375  						RefTerm(VarTerm("xs"), VarTerm("j"), StringTerm("a"), VarTerm("k")),
   376  						StringTerm("foo"),
   377  					),
   378  				),
   379  			),
   380  		)),
   381  	)
   382  	assertParseOneTerm(t, "nested", nestedTerm, nestedExpected)
   383  	assertParseOneTerm(t, "ambiguous or", "{ 1+2: 3 | 4}", ObjectComprehensionTerm(
   384  		CallTerm(RefTerm(VarTerm("plus")), NumberTerm("1"), NumberTerm("2")),
   385  		NumberTerm("3"),
   386  		MustParseBody("4"),
   387  	))
   388  }
   389  
   390  func TestObjectComprehensionError(t *testing.T) {
   391  	assertParseError(t, "bad body", "{x: y|!!!}")
   392  }
   393  
   394  func TestSetComprehensions(t *testing.T) {
   395  	nestedTerm := `[{"x": {a[i] | xs = {{"a": ["baz", j]} | q[p]; p.a != "bar"; j = "foo"}; xs[j].a[k] = "foo"}}]`
   396  	nestedExpected := ArrayTerm(
   397  		ObjectTerm(Item(
   398  			StringTerm("x"),
   399  			SetComprehensionTerm(
   400  				RefTerm(VarTerm("a"), VarTerm("i")),
   401  				NewBody(
   402  					Equality.Expr(
   403  						VarTerm("xs"),
   404  						SetComprehensionTerm(
   405  							ObjectTerm(Item(StringTerm("a"), ArrayTerm(StringTerm("baz"), VarTerm("j")))),
   406  							NewBody(
   407  								NewExpr(RefTerm(VarTerm("q"), VarTerm("p"))),
   408  								NotEqual.Expr(RefTerm(VarTerm("p"), StringTerm("a")), StringTerm("bar")),
   409  								Equality.Expr(VarTerm("j"), StringTerm("foo")),
   410  							),
   411  						),
   412  					),
   413  					Equality.Expr(
   414  						RefTerm(VarTerm("xs"), VarTerm("j"), StringTerm("a"), VarTerm("k")),
   415  						StringTerm("foo"),
   416  					),
   417  				),
   418  			),
   419  		)),
   420  	)
   421  
   422  	assertParseOneTerm(t, "nested", nestedTerm, nestedExpected)
   423  	assertParseOneTerm(t, "ambiguous or", "{ a | b }", SetComprehensionTerm(
   424  		VarTerm("a"),
   425  		MustParseBody("b"),
   426  	))
   427  }
   428  
   429  func TestSetComprehensionError(t *testing.T) {
   430  	assertParseError(t, "bad body", "{x|!!!}")
   431  }
   432  
   433  func TestSetComprehensionsAlone(t *testing.T) {
   434  	input := `{k | a = [1,2,3]; a[k]}`
   435  
   436  	expected := SetComprehensionTerm(
   437  		VarTerm("k"),
   438  		NewBody(
   439  			Equality.Expr(
   440  				VarTerm("a"),
   441  				ArrayTerm(NumberTerm("1"), NumberTerm("2"), NumberTerm("3")),
   442  			),
   443  			&Expr{
   444  				Terms: RefTerm(VarTerm("a"), VarTerm("k")),
   445  			},
   446  		),
   447  	)
   448  
   449  	assertParseOneTerm(t, "alone", input, expected)
   450  }
   451  
   452  func TestCalls(t *testing.T) {
   453  
   454  	assertParseOneExpr(t, "ne", "100 != 200", NotEqual.Expr(IntNumberTerm(100), IntNumberTerm(200)))
   455  	assertParseOneExpr(t, "gt", "17.4 > \"hello\"", GreaterThan.Expr(FloatNumberTerm(17.4), StringTerm("hello")))
   456  	assertParseOneExpr(t, "lt", "17.4 < \"hello\"", LessThan.Expr(FloatNumberTerm(17.4), StringTerm("hello")))
   457  	assertParseOneExpr(t, "gte", "17.4 >= \"hello\"", GreaterThanEq.Expr(FloatNumberTerm(17.4), StringTerm("hello")))
   458  	assertParseOneExpr(t, "lte", "17.4 <= \"hello\"", LessThanEq.Expr(FloatNumberTerm(17.4), StringTerm("hello")))
   459  
   460  	left2 := ArrayTerm(ObjectTerm(Item(FloatNumberTerm(14.2), BooleanTerm(true)), Item(StringTerm("a"), NullTerm())))
   461  	right2 := ObjectTerm(Item(VarTerm("foo"), ObjectTerm(Item(RefTerm(VarTerm("a"), StringTerm("b"), IntNumberTerm(0)), ArrayTerm(IntNumberTerm(10))))))
   462  	assertParseOneExpr(t, "composites", "[{14.2: true, \"a\": null}] != {foo: {a.b[0]: [10]}}", NotEqual.Expr(left2, right2))
   463  
   464  	assertParseOneExpr(t, "plus", "1 + 2", Plus.Expr(IntNumberTerm(1), IntNumberTerm(2)))
   465  	assertParseOneExpr(t, "minus", "1 - 2", Minus.Expr(IntNumberTerm(1), IntNumberTerm(2)))
   466  	assertParseOneExpr(t, "mul", "1 * 2", Multiply.Expr(IntNumberTerm(1), IntNumberTerm(2)))
   467  	assertParseOneExpr(t, "div", "1 / 2", Divide.Expr(IntNumberTerm(1), IntNumberTerm(2)))
   468  	assertParseOneExpr(t, "rem", "3 % 2", Rem.Expr(IntNumberTerm(3), IntNumberTerm(2)))
   469  	assertParseOneExpr(t, "and", "{1,2,3} & {2,3,4}", And.Expr(SetTerm(IntNumberTerm(1), IntNumberTerm(2), IntNumberTerm(3)), SetTerm(IntNumberTerm(2), IntNumberTerm(3), IntNumberTerm(4))))
   470  	assertParseOneExpr(t, "or", "{1,2,3} | {3,4,5}", Or.Expr(SetTerm(IntNumberTerm(1), IntNumberTerm(2), IntNumberTerm(3)), SetTerm(IntNumberTerm(3), IntNumberTerm(4), IntNumberTerm(5))))
   471  
   472  	assertParseOneExpr(t, "call", "count([true, false])", Count.Expr(ArrayTerm(BooleanTerm(true), BooleanTerm(false))))
   473  	assertParseOneExpr(t, "call-ref", "foo.bar(1)", NewExpr(
   474  		[]*Term{RefTerm(VarTerm("foo"), StringTerm("bar")),
   475  			IntNumberTerm(1)}))
   476  	assertParseOneExpr(t, "call-void", "foo()", NewExpr(
   477  		[]*Term{RefTerm(VarTerm("foo"))}))
   478  
   479  	opts := ParserOptions{FutureKeywords: []string{"in"}}
   480  	assertParseOneExpr(t, "internal.member_2", "x in xs", Member.Expr(VarTerm("x"), VarTerm("xs")), opts)
   481  	assertParseOneExpr(t, "internal.member_3", "x, y in xs", MemberWithKey.Expr(VarTerm("x"), VarTerm("y"), VarTerm("xs")), opts)
   482  }
   483  
   484  func TestInfixExpr(t *testing.T) {
   485  	assertParseOneExpr(t, "scalars 1", "true = false", Equality.Expr(BooleanTerm(true), BooleanTerm(false)))
   486  	assertParseOneExpr(t, "scalars 2", "3.14 = null", Equality.Expr(FloatNumberTerm(3.14), NullTerm()))
   487  	assertParseOneExpr(t, "scalars 3", "42 = \"hello world\"", Equality.Expr(IntNumberTerm(42), StringTerm("hello world")))
   488  	assertParseOneExpr(t, "vars 1", "hello = world", Equality.Expr(VarTerm("hello"), VarTerm("world")))
   489  	assertParseOneExpr(t, "vars 2", "42 = hello", Equality.Expr(IntNumberTerm(42), VarTerm("hello")))
   490  
   491  	ref1 := RefTerm(VarTerm("foo"), IntNumberTerm(0), StringTerm("bar"), VarTerm("x"))
   492  	ref2 := RefTerm(VarTerm("baz"), BooleanTerm(false), StringTerm("qux"), StringTerm("hello"))
   493  	assertParseOneExpr(t, "refs 1", "foo[0].bar[x] = baz[false].qux[\"hello\"]", Equality.Expr(ref1, ref2))
   494  
   495  	left1 := ObjectTerm(Item(VarTerm("a"), ArrayTerm(ref1)))
   496  	right1 := ArrayTerm(ObjectTerm(Item(IntNumberTerm(42), BooleanTerm(true))))
   497  	assertParseOneExpr(t, "composites", "{a: [foo[0].bar[x]]} = [{42: true}]", Equality.Expr(left1, right1))
   498  
   499  	assertParseOneExpr(t, "plus", "x = 1 + 2", Equality.Expr(VarTerm("x"), Plus.Call(IntNumberTerm(1), IntNumberTerm(2))))
   500  	assertParseOneExpr(t, "plus reverse", "1 + 2 = x", Equality.Expr(Plus.Call(IntNumberTerm(1), IntNumberTerm(2)), VarTerm("x")))
   501  
   502  	assertParseOneExpr(t, "call", "count([true, false]) = x", Equality.Expr(Count.Call(ArrayTerm(BooleanTerm(true), BooleanTerm(false))), VarTerm("x")))
   503  	assertParseOneExpr(t, "call-reverse", "x = count([true, false])", Equality.Expr(VarTerm("x"), Count.Call(ArrayTerm(BooleanTerm(true), BooleanTerm(false)))))
   504  }
   505  
   506  func TestNegatedExpr(t *testing.T) {
   507  	assertParseOneTermNegated(t, "scalars 1", "not true", BooleanTerm(true))
   508  	assertParseOneTermNegated(t, "scalars 2", "not \"hello\"", StringTerm("hello"))
   509  	assertParseOneTermNegated(t, "scalars 3", "not 100", IntNumberTerm(100))
   510  	assertParseOneTermNegated(t, "scalars 4", "not null", NullTerm())
   511  	assertParseOneTermNegated(t, "var", "not x", VarTerm("x"))
   512  	assertParseOneTermNegated(t, "ref", "not x[y].z", RefTerm(VarTerm("x"), VarTerm("y"), StringTerm("z")))
   513  	assertParseOneExprNegated(t, "vars", "not x = y", Equality.Expr(VarTerm("x"), VarTerm("y")))
   514  
   515  	ref1 := RefTerm(VarTerm("x"), VarTerm("y"), StringTerm("z"), VarTerm("a"))
   516  
   517  	assertParseOneExprNegated(t, "membership", "not x[y].z[a] = \"b\"", Equality.Expr(ref1, StringTerm("b")))
   518  	assertParseOneExprNegated(t, "misc. builtin", "not sorted(x[y].z[a])", NewExpr([]*Term{RefTerm(VarTerm("sorted")), ref1}))
   519  }
   520  
   521  func TestExprWith(t *testing.T) {
   522  	assertParseOneExpr(t, "input", "data.foo with input as baz", &Expr{
   523  		Terms: MustParseTerm("data.foo"),
   524  		With: []*With{
   525  			{
   526  				Target: NewTerm(InputRootRef),
   527  				Value:  VarTerm("baz"),
   528  			},
   529  		},
   530  	})
   531  
   532  	assertParseOneExpr(t, "builtin/ref target/composites", `plus(data.foo, 1, x) with input.com.acmecorp.obj as {"count": [{1,2,3}]}`, &Expr{
   533  		Terms: MustParseExpr("plus(data.foo, 1, x)").Terms,
   534  		With: []*With{
   535  			{
   536  				Target: MustParseTerm("input.com.acmecorp.obj"),
   537  				Value:  MustParseTerm(`{"count": [{1,2,3}]}`),
   538  			},
   539  		},
   540  	})
   541  
   542  	assertParseOneExpr(t, "multiple", `data.foo with input.obj as baz with input.com.acmecorp.obj as {"count": [{1,2,3}]}`, &Expr{
   543  		Terms: MustParseTerm("data.foo"),
   544  		With: []*With{
   545  			{
   546  				Target: MustParseTerm("input.obj"),
   547  				Value:  VarTerm("baz"),
   548  			},
   549  			{
   550  				Target: MustParseTerm("input.com.acmecorp.obj"),
   551  				Value:  MustParseTerm(`{"count": [{1,2,3}]}`),
   552  			},
   553  		},
   554  	})
   555  
   556  	assertParseOneExpr(t, "variable target", "true with x as 1", &Expr{
   557  		Terms: BooleanTerm(true),
   558  		With: []*With{
   559  			{
   560  				Target: VarTerm("x"),
   561  				Value:  IntNumberTerm(1),
   562  			},
   563  		},
   564  	})
   565  }
   566  
   567  func TestExprWithLocation(t *testing.T) {
   568  	cases := []struct {
   569  		note     string
   570  		input    string
   571  		expected []*Location
   572  	}{
   573  		{
   574  			note:  "base",
   575  			input: "a with b as c",
   576  			expected: []*Location{
   577  				{
   578  					Row:    1,
   579  					Col:    3,
   580  					Offset: 2,
   581  					Text:   []byte("with b as c"),
   582  				},
   583  			},
   584  		},
   585  		{
   586  			note:  "with line break",
   587  			input: "a with b\nas c",
   588  			expected: []*Location{
   589  				{
   590  					Row:    1,
   591  					Col:    3,
   592  					Offset: 2,
   593  					Text:   []byte("with b\nas c"),
   594  				},
   595  			},
   596  		},
   597  		{
   598  			note:  "multiple withs on single line",
   599  			input: "a with b as c with d as e",
   600  			expected: []*Location{
   601  				{
   602  					Row:    1,
   603  					Col:    3,
   604  					Offset: 2,
   605  					Text:   []byte("with b as c"),
   606  				},
   607  				{
   608  					Row:    1,
   609  					Col:    15,
   610  					Offset: 14,
   611  					Text:   []byte("with d as e"),
   612  				},
   613  			},
   614  		},
   615  		{
   616  			note:  "multiple withs on multiple line",
   617  			input: "a with b as c\n\t\twith d as e",
   618  			expected: []*Location{
   619  				{
   620  					Row:    1,
   621  					Col:    3,
   622  					Offset: 2,
   623  					Text:   []byte("with b as c"),
   624  				},
   625  				{
   626  					Row:    2,
   627  					Col:    3,
   628  					Offset: 16,
   629  					Text:   []byte("with d as e"),
   630  				},
   631  			},
   632  		},
   633  	}
   634  
   635  	for _, tc := range cases {
   636  		t.Run(tc.note, func(t *testing.T) {
   637  			parsed, err := ParseStatement(tc.input)
   638  			if err != nil {
   639  				t.Errorf("Unexpected error on %s: %s", tc.input, err)
   640  				return
   641  			}
   642  
   643  			body := parsed.(Body)
   644  			if len(body) != 1 {
   645  				t.Errorf("Parser returned multiple expressions: %v", body)
   646  				return
   647  			}
   648  			expr := body[0]
   649  			if len(expr.With) != len(tc.expected) {
   650  				t.Fatalf("Expected %d with statements, got %d", len(expr.With), len(tc.expected))
   651  			}
   652  			for i, with := range expr.With {
   653  				if !with.Location.Equal(tc.expected[i]) {
   654  					t.Errorf("Expected location %+v for '%v' but got %+v ", *(tc.expected[i]), with.String(), *with.Location)
   655  				}
   656  			}
   657  		})
   658  	}
   659  }
   660  
   661  func TestSomeDeclExpr(t *testing.T) {
   662  	opts := ParserOptions{FutureKeywords: []string{"in"}}
   663  
   664  	assertParseOneExpr(t, "one", "some x", &Expr{
   665  		Terms: &SomeDecl{
   666  			Symbols: []*Term{
   667  				VarTerm("x"),
   668  			},
   669  		},
   670  	})
   671  
   672  	assertParseOneExpr(t, "internal.member_2", "some x in xs", &Expr{
   673  		Terms: &SomeDecl{
   674  			Symbols: []*Term{
   675  				Member.Call(
   676  					VarTerm("x"),
   677  					VarTerm("xs"),
   678  				),
   679  			},
   680  		},
   681  	}, opts)
   682  
   683  	assertParseOneExpr(t, "internal.member_3", "some x, y in xs", &Expr{
   684  		Terms: &SomeDecl{
   685  			Symbols: []*Term{
   686  				MemberWithKey.Call(
   687  					VarTerm("x"),
   688  					VarTerm("y"),
   689  					VarTerm("xs"),
   690  				),
   691  			},
   692  		},
   693  	}, opts)
   694  
   695  	assertParseErrorContains(t, "not some", "not some x, y in xs",
   696  		"unexpected some keyword: illegal negation of 'some'",
   697  		opts)
   698  
   699  	assertParseErrorContains(t, "some + function call", "some f(x)",
   700  		"expected `x in xs` or `x, y in xs` expression")
   701  
   702  	assertParseOneExpr(t, "multiple", "some x, y", &Expr{
   703  		Terms: &SomeDecl{
   704  			Symbols: []*Term{
   705  				VarTerm("x"),
   706  				VarTerm("y"),
   707  			},
   708  		},
   709  	}, opts)
   710  
   711  	assertParseOneExpr(t, "multiple split across lines", `some x, y,
   712  		z`, &Expr{
   713  		Terms: &SomeDecl{
   714  			Symbols: []*Term{
   715  				VarTerm("x"),
   716  				VarTerm("y"),
   717  				VarTerm("z"),
   718  			},
   719  		},
   720  	})
   721  
   722  	assertParseRule(t, "whitespace separated", `
   723  
   724  		p[x] {
   725  			some x
   726  			q[x]
   727  		}
   728  	`, &Rule{
   729  		Head: NewHead(Var("p"), VarTerm("x")),
   730  		Body: NewBody(
   731  			NewExpr(&SomeDecl{Symbols: []*Term{VarTerm("x")}}),
   732  			NewExpr(RefTerm(VarTerm("q"), VarTerm("x"))),
   733  		),
   734  	})
   735  
   736  	assertParseRule(t, "whitespace separated, following `in` rule ref", `
   737  	p[x] {
   738  		some x
   739  		in[x]
   740  	}
   741  `, &Rule{
   742  		Head: NewHead(Var("p"), VarTerm("x")),
   743  		Body: NewBody(
   744  			NewExpr(&SomeDecl{Symbols: []*Term{VarTerm("x")}}),
   745  			NewExpr(RefTerm(VarTerm("in"), VarTerm("x"))),
   746  		),
   747  	})
   748  
   749  	assertParseErrorContains(t, "some x in ... usage is hinted properly", `
   750  	p[x] {
   751  		some x in {"foo": "bar"}
   752  	}`,
   753  		"unexpected ident token: expected \\n or ; or } (hint: `import future.keywords.in` for `some x in xs` expressions)")
   754  
   755  	assertParseErrorContains(t, "some x, y in ... usage is hinted properly", `
   756  	p[y] = x {
   757  		some x, y in {"foo": "bar"}
   758  	}`,
   759  		"unexpected ident token: expected \\n or ; or } (hint: `import future.keywords.in` for `some x in xs` expressions)")
   760  
   761  	assertParseRule(t, "whitespace terminated", `
   762  
   763  	p[x] {
   764  		some x
   765  		x
   766  	}
   767  `, &Rule{
   768  		Head: NewHead(Var("p"), VarTerm("x")),
   769  		Body: NewBody(
   770  			NewExpr(&SomeDecl{Symbols: []*Term{VarTerm("x")}}),
   771  			NewExpr(VarTerm("x")),
   772  		),
   773  	})
   774  
   775  	assertParseOneExpr(t, "with modifier on expr", "some x, y in input with input as []",
   776  		&Expr{
   777  			Terms: &SomeDecl{
   778  				Symbols: []*Term{
   779  					MemberWithKey.Call(
   780  						VarTerm("x"),
   781  						VarTerm("y"),
   782  						NewTerm(MustParseRef("input")),
   783  					),
   784  				},
   785  			},
   786  			With: []*With{{Value: ArrayTerm(), Target: NewTerm(MustParseRef("input"))}},
   787  		}, opts)
   788  
   789  	assertParseErrorContains(t, "invalid domain (internal.member_2)", "some internal.member_2()", "illegal domain", opts)
   790  	assertParseErrorContains(t, "invalid domain (internal.member_3)", "some internal.member_3()", "illegal domain", opts)
   791  
   792  }
   793  
   794  func TestEvery(t *testing.T) {
   795  	opts := ParserOptions{unreleasedKeywords: true, FutureKeywords: []string{"every"}}
   796  	assertParseOneExpr(t, "simple", "every x in xs { true }",
   797  		&Expr{
   798  			Terms: &Every{
   799  				Value:  VarTerm("x"),
   800  				Domain: VarTerm("xs"),
   801  				Body: []*Expr{
   802  					NewExpr(BooleanTerm(true)),
   803  				},
   804  			},
   805  		},
   806  		opts)
   807  
   808  	assertParseOneExpr(t, "with key", "every k, v in [1,2] { true }",
   809  		&Expr{
   810  			Terms: &Every{
   811  				Key:    VarTerm("k"),
   812  				Value:  VarTerm("v"),
   813  				Domain: ArrayTerm(IntNumberTerm(1), IntNumberTerm(2)),
   814  				Body: []*Expr{
   815  					NewExpr(BooleanTerm(true)),
   816  				},
   817  			},
   818  		}, opts)
   819  
   820  	assertParseErrorContains(t, "arbitrary term", "every 10", "expected `x[, y] in xs { ... }` expression", opts)
   821  	assertParseErrorContains(t, "non-var value", "every 10 in xs { true }", "unexpected { token: expected value to be a variable", opts)
   822  	assertParseErrorContains(t, "non-var key", "every 10, x in xs { true }", "unexpected { token: expected key to be a variable", opts)
   823  	assertParseErrorContains(t, "arbitrary call", "every f(10)", "expected `x[, y] in xs { ... }` expression", opts)
   824  	assertParseErrorContains(t, "no body", "every x in xs", "missing body", opts)
   825  	assertParseErrorContains(t, "invalid body", "every x in xs { + }", "unexpected plus token", opts)
   826  	assertParseErrorContains(t, "not every", "not every x in xs { true }", "unexpected every keyword: illegal negation of 'every'", opts)
   827  
   828  	assertParseOneExpr(t, `"every" kw implies "in" kw`, "x in xs", Member.Expr(
   829  		VarTerm("x"),
   830  		VarTerm("xs"),
   831  	), opts)
   832  
   833  	assertParseOneExpr(t, "with modifier on expr", "every x in input { x } with input as []",
   834  		&Expr{
   835  			Terms: &Every{
   836  				Value:  VarTerm("x"),
   837  				Domain: NewTerm(MustParseRef("input")),
   838  				Body: []*Expr{
   839  					NewExpr(VarTerm("x")),
   840  				},
   841  			},
   842  			With: []*With{{Value: ArrayTerm(), Target: NewTerm(MustParseRef("input"))}},
   843  		}, opts)
   844  
   845  	assertParseErrorContains(t, "every x, y in ... usage is hinted properly", `
   846  	p {
   847  		every x, y in {"foo": "bar"} { is_string(x); is_string(y) }
   848  	}`,
   849  		"unexpected ident token: expected \\n or ; or } (hint: `import future.keywords.every` for `every x in xs { ... }` expressions)")
   850  
   851  	assertParseErrorContains(t, "not every 'every' gets a hint", `
   852  	p {
   853  		every x
   854  	}`,
   855  		"unexpected ident token: expected \\n or ; or }\n\tevery x\n", // this asserts that the tail of the error message doesn't contain a hint
   856  	)
   857  
   858  	assertParseErrorContains(t, "invalid domain (internal.member_2)", "every internal.member_2()", "illegal domain", opts)
   859  	assertParseErrorContains(t, "invalid domain (internal.member_3)", "every internal.member_3()", "illegal domain", opts)
   860  }
   861  
   862  func TestNestedExpressions(t *testing.T) {
   863  
   864  	n1 := IntNumberTerm(1)
   865  	n2 := IntNumberTerm(2)
   866  	n3 := IntNumberTerm(3)
   867  	n4 := IntNumberTerm(4)
   868  	n6 := IntNumberTerm(6)
   869  	x := VarTerm("x")
   870  	y := VarTerm("y")
   871  	z := VarTerm("z")
   872  	w := VarTerm("w")
   873  	f := RefTerm(VarTerm("f"))
   874  	g := RefTerm(VarTerm("g"))
   875  
   876  	tests := []struct {
   877  		note     string
   878  		input    string
   879  		expected *Expr
   880  	}{
   881  		{"associativity", "1 + 2 * 6 / 3",
   882  			Plus.Expr(
   883  				n1,
   884  				Divide.Call(
   885  					Multiply.Call(
   886  						n2,
   887  						n6),
   888  					n3))},
   889  		{"associativity - factors", "x * y / z % w",
   890  			Rem.Expr(Divide.Call(Multiply.Call(x, y), z), w)},
   891  		{"associativity - factors", "w % z / x * y",
   892  			Multiply.Expr(Divide.Call(Rem.Call(w, z), x), y)},
   893  		{"associativity - arithetic", "x + y - z",
   894  			Minus.Expr(Plus.Call(x, y), z)},
   895  		{"associativity - arithmetic", "z - x + y",
   896  			Plus.Expr(Minus.Call(z, x), y)},
   897  		{"associativity - and", "z & x & y",
   898  			And.Expr(And.Call(z, x), y)},
   899  		{"associativity - or", "z | x | y",
   900  			Or.Expr(Or.Call(z, x), y)},
   901  		{"associativity - relations", "x == y != z",
   902  			NotEqual.Expr(Equal.Call(x, y), z)},
   903  		{"grouping", "(1 + 2 * 6 / 3) > 4",
   904  			GreaterThan.Expr(
   905  				Plus.Call(
   906  					n1,
   907  					Divide.Call(
   908  						Multiply.Call(
   909  							n2,
   910  							n6),
   911  						n3)),
   912  				n4)},
   913  		{"nested parens", "(((1 + 2) * (6 / (3))) > 4) != false",
   914  			NotEqual.Expr(
   915  				GreaterThan.Call(
   916  					Multiply.Call(
   917  						Plus.Call(
   918  							n1,
   919  							n2),
   920  						Divide.Call(
   921  							n6,
   922  							n3)),
   923  					n4,
   924  				),
   925  				BooleanTerm(false))},
   926  		{"bitwise or", "x + 1 | 2", Or.Expr(Plus.Call(x, n1), n2)},
   927  		{"bitwise and", "x + 1 | 2 & 3", Or.Expr(Plus.Call(x, n1), And.Call(n2, n3))},
   928  		{"array", "[x + 1, y > 2, z]", NewExpr(ArrayTerm(Plus.Call(x, n1), GreaterThan.Call(y, n2), z))},
   929  		{"object", "{x * 2: y < 2, z[3]: 1 + 6/2}", NewExpr(
   930  			ObjectTerm(
   931  				Item(Multiply.Call(x, n2), LessThan.Call(y, n2)),
   932  				Item(RefTerm(z, n3), Plus.Call(n1, Divide.Call(n6, n2))),
   933  			),
   934  		)},
   935  		{"set", "{x + 1, y + 2, set()}", NewExpr(
   936  			SetTerm(
   937  				Plus.Call(x, n1),
   938  				Plus.Call(y, n2),
   939  				SetTerm(),
   940  			),
   941  		)},
   942  		{"ref", `x[1][y + z[w + 1]].b`, NewExpr(
   943  			RefTerm(
   944  				x,
   945  				n1,
   946  				Plus.Call(
   947  					y,
   948  					RefTerm(
   949  						z,
   950  						Plus.Call(w, n1))),
   951  				StringTerm("b"),
   952  			),
   953  		)},
   954  		{"call void", "f()", NewExpr([]*Term{f})},
   955  		{"call unary", "f(x)", NewExpr([]*Term{f, x})},
   956  		{"call binary", "f(x, y)", NewExpr([]*Term{f, x, y})},
   957  		{"call embedded", "f([g(x), y+1])", NewExpr([]*Term{
   958  			f,
   959  			ArrayTerm(
   960  				CallTerm(g, x),
   961  				Plus.Call(y, n1))})},
   962  		{"call fqn", "foo.bar(1)", NewExpr([]*Term{
   963  			RefTerm(VarTerm("foo"), StringTerm("bar")),
   964  			n1,
   965  		})},
   966  		{"unify", "x = 1", Equality.Expr(x, n1)},
   967  		{"unify embedded", "1 + x = 2 - y", Equality.Expr(Plus.Call(n1, x), Minus.Call(n2, y))},
   968  		{"not keyword", "not x = y", Equality.Expr(x, y).Complement()},
   969  		{"with keyword", "x with p[q] as f([x+1])", NewExpr(x).IncludeWith(
   970  			RefTerm(VarTerm("p"), VarTerm("q")),
   971  			CallTerm(f, ArrayTerm(Plus.Call(x, n1))),
   972  		)},
   973  	}
   974  	for _, tc := range tests {
   975  		t.Run(tc.note, func(t *testing.T) {
   976  			expr, err := ParseExpr(tc.input)
   977  			if err != nil {
   978  				t.Fatal(err)
   979  			}
   980  			if !expr.Equal(tc.expected) {
   981  				t.Fatalf("Expected %v but got %v", tc.expected, expr)
   982  			}
   983  		})
   984  	}
   985  }
   986  
   987  func TestChainedCall(t *testing.T) {
   988  	result, err := ParseExpr("foo.bar(1)[0](1).baz")
   989  	if err != nil {
   990  		t.Fatal(err)
   991  	}
   992  
   993  	exp := NewExpr(RefTerm(
   994  		CallTerm(
   995  			RefTerm(
   996  				CallTerm(
   997  					RefTerm(VarTerm("foo"), StringTerm("bar")),
   998  					IntNumberTerm(1)),
   999  				IntNumberTerm(0)),
  1000  			IntNumberTerm(1)),
  1001  		StringTerm("baz")))
  1002  
  1003  	if !result.Equal(exp) {
  1004  		t.Fatalf("expected %v but got: %v", exp, result)
  1005  	}
  1006  }
  1007  
  1008  func TestMultiLineBody(t *testing.T) {
  1009  
  1010  	input1 := `
  1011  		x = 1
  1012  		y = 2
  1013  		z = [ i | [x,y] = arr
  1014  				   arr[_] = i]
  1015  	`
  1016  
  1017  	body1, err := ParseBody(input1)
  1018  	if err != nil {
  1019  		t.Fatalf("Unexpected parse error on enclosed body: %v", err)
  1020  	}
  1021  
  1022  	expected1 := MustParseBody(`x = 1; y = 2; z = [i | [x,y] = arr; arr[_] = i]`)
  1023  
  1024  	if !body1.Equal(expected1) {
  1025  		t.Errorf("Expected enclosed body to equal %v but got: %v", expected1, body1)
  1026  	}
  1027  
  1028  	// Check that parser can handle multiple expressions w/o enclosing braces.
  1029  	input2 := `
  1030  		x = 1 ; # comment after semicolon
  1031  		y = 2   # comment without semicolon
  1032  		z = [ i | [x,y] = arr  # comment in comprehension
  1033  				   arr[_] = i]
  1034  	`
  1035  
  1036  	body2, err := ParseBody(input2)
  1037  	if err != nil {
  1038  		t.Fatalf("Unexpected parse error on enclosed body: %v", err)
  1039  	}
  1040  
  1041  	if !body2.Equal(expected1) {
  1042  		t.Errorf("Expected unenclosed body to equal %v but got: %v", expected1, body1)
  1043  	}
  1044  
  1045  	assertParseOneBody(t, "whitespace following call", "f(x)\t\n [1]", NewBody(
  1046  		NewExpr(
  1047  			[]*Term{
  1048  				RefTerm(VarTerm("f")),
  1049  				VarTerm("x"),
  1050  			},
  1051  		),
  1052  		NewExpr(
  1053  			ArrayTerm(IntNumberTerm(1)),
  1054  		),
  1055  	))
  1056  
  1057  	assertParseOneBody(t, "whitespace following array", "[1]\t\n [2]", NewBody(
  1058  		NewExpr(
  1059  			ArrayTerm(IntNumberTerm(1)),
  1060  		),
  1061  		NewExpr(
  1062  			ArrayTerm(IntNumberTerm(2)),
  1063  		),
  1064  	))
  1065  
  1066  	assertParseOneBody(t, "whitespace following set", "{1}\t\n {2}", NewBody(
  1067  		NewExpr(
  1068  			SetTerm(IntNumberTerm(1)),
  1069  		),
  1070  		NewExpr(
  1071  			SetTerm(IntNumberTerm(2)),
  1072  		),
  1073  	))
  1074  }
  1075  
  1076  func TestBitwiseOrVsComprehension(t *testing.T) {
  1077  
  1078  	x := VarTerm("x")
  1079  	y := VarTerm("y")
  1080  	z := VarTerm("z")
  1081  	a := VarTerm("a")
  1082  	b := VarTerm("b")
  1083  
  1084  	tests := []struct {
  1085  		note  string
  1086  		input string
  1087  		exp   *Term
  1088  	}{
  1089  		{
  1090  			note:  "array containing bitwise or",
  1091  			input: "[x|y,z]",
  1092  			exp:   ArrayTerm(Or.Call(x, y), z),
  1093  		},
  1094  		{
  1095  			note:  "array containing bitwise or - last element",
  1096  			input: "[z,x|y]",
  1097  			exp:   ArrayTerm(z, Or.Call(x, y)),
  1098  		},
  1099  		{
  1100  			note:  "array containing bitwise or - middle",
  1101  			input: "[z,x|y,a]",
  1102  			exp:   ArrayTerm(z, Or.Call(x, y), a),
  1103  		},
  1104  		{
  1105  			note:  "array containing single bitwise or",
  1106  			input: "[x|y,]",
  1107  			exp:   ArrayTerm(Or.Call(x, y)),
  1108  		},
  1109  		{
  1110  			note:  "set containing bitwise or",
  1111  			input: "{x|y,z}",
  1112  			exp:   SetTerm(Or.Call(x, y), z),
  1113  		},
  1114  		{
  1115  			note:  "set containing bitwise or - last element",
  1116  			input: "{z,x|y}",
  1117  			exp:   SetTerm(z, Or.Call(x, y)),
  1118  		},
  1119  		{
  1120  			note:  "set containing bitwise or - middle",
  1121  			input: "{z,x|y,a}",
  1122  			exp:   SetTerm(z, Or.Call(x, y), a),
  1123  		},
  1124  		{
  1125  			note:  "set containing single bitwise or",
  1126  			input: "{x|y,}",
  1127  			exp:   SetTerm(Or.Call(x, y)),
  1128  		},
  1129  		{
  1130  			note:  "object containing bitwise or",
  1131  			input: "{x:y|z,a:b}",
  1132  			exp:   ObjectTerm([2]*Term{x, Or.Call(y, z)}, [2]*Term{a, b}),
  1133  		},
  1134  		{
  1135  			note:  "object containing single bitwise or",
  1136  			input: "{x:y|z,}",
  1137  			exp:   ObjectTerm([2]*Term{x, Or.Call(y, z)}),
  1138  		},
  1139  	}
  1140  
  1141  	for _, tc := range tests {
  1142  		t.Run(tc.note, func(t *testing.T) {
  1143  
  1144  			term, err := ParseTerm(tc.input)
  1145  			if err != nil {
  1146  				t.Fatal(err)
  1147  			}
  1148  
  1149  			if !term.Equal(tc.exp) {
  1150  				t.Fatalf("Expected %v but got %v", tc.exp, term)
  1151  			}
  1152  		})
  1153  	}
  1154  
  1155  }
  1156  
  1157  func TestPackage(t *testing.T) {
  1158  	ref1 := RefTerm(DefaultRootDocument, StringTerm("foo"))
  1159  	assertParsePackage(t, "single", `package foo`, &Package{Path: ref1.Value.(Ref)})
  1160  	ref2 := RefTerm(DefaultRootDocument, StringTerm("f00"), StringTerm("bar_baz"), StringTerm("qux"))
  1161  	assertParsePackage(t, "multiple", `package f00.bar_baz.qux`, &Package{Path: ref2.Value.(Ref)})
  1162  	ref3 := RefTerm(DefaultRootDocument, StringTerm("foo"), StringTerm("bar baz"))
  1163  	assertParsePackage(t, "space", `package foo["bar baz"]`, &Package{Path: ref3.Value.(Ref)})
  1164  	assertParseError(t, "non-ground ref", "package foo[x]")
  1165  	assertParseError(t, "non-string value", "package foo.bar[42].baz")
  1166  	assertParseError(t, "invalid term", "package 42")
  1167  	assertParseError(t, "scanner error", "package foo.")
  1168  	assertParseError(t, "non-string first value", "package e().s")
  1169  }
  1170  
  1171  func TestImport(t *testing.T) {
  1172  	foo := RefTerm(VarTerm("input"), StringTerm("foo"))
  1173  	foobarbaz := RefTerm(VarTerm("input"), StringTerm("foo"), StringTerm("bar"), StringTerm("baz"))
  1174  	whitespace := RefTerm(VarTerm("input"), StringTerm("foo"), StringTerm("bar"), StringTerm("white space"))
  1175  	assertParseImport(t, "single-input", "import input", &Import{Path: RefTerm(InputRootDocument)})
  1176  	assertParseImport(t, "single-data", "import data", &Import{Path: RefTerm(DefaultRootDocument)})
  1177  	assertParseImport(t, "multiple", "import input.foo.bar.baz", &Import{Path: foobarbaz})
  1178  	assertParseImport(t, "single alias", "import input.foo as bar", &Import{Path: foo, Alias: Var("bar")})
  1179  	assertParseImport(t, "multiple alias", "import input.foo.bar.baz as qux", &Import{Path: foobarbaz, Alias: Var("qux")})
  1180  	assertParseImport(t, "white space", "import input.foo.bar[\"white space\"]", &Import{Path: whitespace})
  1181  	assertParseErrorContains(t, "non-ground ref", "import data.foo[x]", "rego_parse_error: unexpected var token: expecting string")
  1182  	assertParseErrorContains(t, "non-string", "import input.foo[0]", "rego_parse_error: unexpected number token: expecting string")
  1183  	assertParseErrorContains(t, "unknown root", "import foo.bar", "rego_parse_error: unexpected import path, must begin with one of: {data, future, input}, got: foo")
  1184  	assertParseErrorContains(t, "bad variable term", "import input as A(", "rego_parse_error: unexpected eof token: expected var")
  1185  
  1186  	_, _, err := ParseStatements("", "package foo\nimport bar.data\ndefault foo=1")
  1187  	if err == nil {
  1188  		t.Fatalf("Expected error, but got nil")
  1189  	}
  1190  	if len(err.(Errors)) > 1 {
  1191  		t.Fatalf("Expected a single error, got %s", err)
  1192  	}
  1193  	txt := err.(Errors)[0].Details.Lines()[0]
  1194  	expected := "import bar.data"
  1195  	if txt != expected {
  1196  		t.Fatalf("Expected error detail text '%s' but got '%s'", expected, txt)
  1197  	}
  1198  }
  1199  
  1200  func TestFutureImports(t *testing.T) {
  1201  	assertParseErrorContains(t, "future", "import future", "invalid import, must be `future.keywords`")
  1202  	assertParseErrorContains(t, "future.a", "import future.a", "invalid import, must be `future.keywords`")
  1203  	assertParseErrorContains(t, "unknown keyword", "import future.keywords.xyz", "unexpected keyword, must be one of [contains every if in]")
  1204  	assertParseErrorContains(t, "all keyword import + alias", "import future.keywords as xyz", "`future` imports cannot be aliased")
  1205  	assertParseErrorContains(t, "keyword import + alias", "import future.keywords.in as xyz", "`future` imports cannot be aliased")
  1206  
  1207  	assertParseImport(t, "import kw with kw in options",
  1208  		"import future.keywords.in", &Import{Path: RefTerm(VarTerm("future"), StringTerm("keywords"), StringTerm("in"))},
  1209  		ParserOptions{FutureKeywords: []string{"in"}})
  1210  	assertParseImport(t, "import kw with all kw in options",
  1211  		"import future.keywords.in", &Import{Path: RefTerm(VarTerm("future"), StringTerm("keywords"), StringTerm("in"))},
  1212  		ParserOptions{AllFutureKeywords: true})
  1213  
  1214  	mod := `
  1215  		package p
  1216  		import future.keywords
  1217  		import future.keywords.in
  1218  	`
  1219  	parsed := Module{
  1220  		Package: MustParseStatement(`package p`).(*Package),
  1221  		Imports: []*Import{
  1222  			MustParseStatement("import future.keywords").(*Import),
  1223  			MustParseStatement("import future.keywords.in").(*Import),
  1224  		},
  1225  	}
  1226  	assertParseModule(t, "multiple imports, all kw in options", mod, &parsed, ParserOptions{AllFutureKeywords: true})
  1227  	assertParseModule(t, "multiple imports, single in options", mod, &parsed, ParserOptions{FutureKeywords: []string{"in"}})
  1228  }
  1229  
  1230  func TestFutureImportsExtraction(t *testing.T) {
  1231  	// These tests assert that "import future..." statements in policies cause
  1232  	// the proper keywords to be added to the parser's list of known keywords.
  1233  	tests := []struct {
  1234  		note, imp string
  1235  		exp       map[string]tokens.Token
  1236  	}{
  1237  		{
  1238  			note: "simple import",
  1239  			imp:  "import future.keywords.in",
  1240  			exp:  map[string]tokens.Token{"in": tokens.In},
  1241  		},
  1242  		{
  1243  			note: "all keywords imported",
  1244  			imp:  "import future.keywords",
  1245  			exp:  map[string]tokens.Token{"in": tokens.In},
  1246  		},
  1247  		{
  1248  			note: "all keywords + single keyword imported",
  1249  			imp: `
  1250  				import future.keywords
  1251  				import future.keywords.in`,
  1252  			exp: map[string]tokens.Token{"in": tokens.In},
  1253  		},
  1254  	}
  1255  	for _, tc := range tests {
  1256  		t.Run(tc.note, func(t *testing.T) {
  1257  			parser := NewParser().WithFilename("").WithReader(bytes.NewBufferString(tc.imp))
  1258  			_, _, errs := parser.Parse()
  1259  			if exp, act := 0, len(errs); exp != act {
  1260  				t.Fatalf("expected %d errors, got %d: %v", exp, act, errs)
  1261  			}
  1262  			for kw, exp := range tc.exp {
  1263  				act := parser.s.s.Keyword(kw)
  1264  				if act != exp {
  1265  					t.Errorf("expected keyword %q to yield token %v, got %v", kw, exp, act)
  1266  				}
  1267  			}
  1268  		})
  1269  	}
  1270  }
  1271  
  1272  func TestIsValidImportPath(t *testing.T) {
  1273  	tests := []struct {
  1274  		path     string
  1275  		expected error
  1276  	}{
  1277  		{"[1,2,3]", fmt.Errorf("invalid path [1, 2, 3]: path must be ref or var")},
  1278  	}
  1279  
  1280  	for _, tc := range tests {
  1281  		path := MustParseTerm(tc.path).Value
  1282  		result := IsValidImportPath(path)
  1283  		if tc.expected == nil && result != nil {
  1284  			t.Errorf("Unexpected error for %v: %v", path, result)
  1285  		} else if !reflect.DeepEqual(tc.expected, result) {
  1286  			t.Errorf("For %v expected %v but got: %v", path, tc.expected, result)
  1287  		}
  1288  	}
  1289  
  1290  }
  1291  
  1292  func TestRule(t *testing.T) {
  1293  
  1294  	assertParseRule(t, "constant", `p = true { true }`, &Rule{
  1295  		Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1296  		Body: NewBody(
  1297  			&Expr{Terms: BooleanTerm(true)},
  1298  		),
  1299  	})
  1300  
  1301  	assertParseRule(t, "set", `p[x] { x = 42 }`, &Rule{
  1302  		Head: NewHead(Var("p"), VarTerm("x")),
  1303  		Body: NewBody(
  1304  			Equality.Expr(VarTerm("x"), IntNumberTerm(42)),
  1305  		),
  1306  	})
  1307  
  1308  	assertParseRule(t, "object", `p[x] = y { x = 42; y = "hello" }`, &Rule{
  1309  		Head: NewHead(Var("p"), VarTerm("x"), VarTerm("y")),
  1310  		Body: NewBody(
  1311  			Equality.Expr(VarTerm("x"), IntNumberTerm(42)),
  1312  			Equality.Expr(VarTerm("y"), StringTerm("hello")),
  1313  		),
  1314  	})
  1315  
  1316  	assertParseRule(t, "constant composite", `p = [{"foo": [1, 2, 3, 4]}] { true }`, &Rule{
  1317  		Head: NewHead(Var("p"), nil, ArrayTerm(
  1318  			ObjectTerm(Item(StringTerm("foo"), ArrayTerm(IntNumberTerm(1), IntNumberTerm(2), IntNumberTerm(3), IntNumberTerm(4)))))),
  1319  		Body: NewBody(
  1320  			&Expr{Terms: BooleanTerm(true)},
  1321  		),
  1322  	})
  1323  
  1324  	assertParseRule(t, "true", `p = true { true }`, &Rule{
  1325  		Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1326  		Body: NewBody(
  1327  			&Expr{Terms: BooleanTerm(true)},
  1328  		),
  1329  	})
  1330  
  1331  	assertParseRule(t, "composites in head", `p[[{"x": [a, b]}]] { a = 1; b = 2 }`, &Rule{
  1332  		Head: NewHead(Var("p"), ArrayTerm(
  1333  			ObjectTerm(
  1334  				Item(StringTerm("x"), ArrayTerm(VarTerm("a"), VarTerm("b"))),
  1335  			),
  1336  		)),
  1337  		Body: NewBody(
  1338  			Equality.Expr(VarTerm("a"), IntNumberTerm(1)),
  1339  			Equality.Expr(VarTerm("b"), IntNumberTerm(2)),
  1340  		),
  1341  	})
  1342  
  1343  	assertParseRule(t, "refs in head", `p = data.foo[x] { x = 1 }`, &Rule{
  1344  		Head: NewHead(Var("p"), nil, &Term{
  1345  			Value: MustParseRef("data.foo[x]"),
  1346  		}),
  1347  		Body: MustParseBody("x = 1"),
  1348  	})
  1349  
  1350  	assertParseRule(t, "refs in head", `p[data.foo[x]] { true }`, &Rule{
  1351  		Head: NewHead(Var("p"), &Term{
  1352  			Value: MustParseRef("data.foo[x]"),
  1353  		}),
  1354  		Body: MustParseBody("true"),
  1355  	})
  1356  
  1357  	assertParseRule(t, "refs in head", `p[data.foo[x]] = data.bar[y] { true }`, &Rule{
  1358  		Head: NewHead(Var("p"), &Term{
  1359  			Value: MustParseRef("data.foo[x]"),
  1360  		}, &Term{
  1361  			Value: MustParseRef("data.bar[y]"),
  1362  		}),
  1363  		Body: MustParseBody("true"),
  1364  	})
  1365  
  1366  	assertParseRule(t, "data", `data = true { true }`, &Rule{
  1367  		Head: NewHead(Var("data"), nil, MustParseTerm("true")),
  1368  		Body: MustParseBody("true"),
  1369  	})
  1370  
  1371  	assertParseRule(t, "input", `input = true { true }`, &Rule{
  1372  		Head: NewHead(Var("input"), nil, MustParseTerm("true")),
  1373  		Body: MustParseBody("true"),
  1374  	})
  1375  
  1376  	assertParseRule(t, "default", `default allow = false`, &Rule{
  1377  		Default: true,
  1378  		Head:    NewHead(Var("allow"), nil, MustParseTerm("false")),
  1379  		Body:    NewBody(NewExpr(BooleanTerm(true))),
  1380  	})
  1381  
  1382  	assertParseRule(t, "default w/ assignment", `default allow := false`, &Rule{
  1383  		Default: true,
  1384  		Head: &Head{
  1385  			Name:   "allow",
  1386  			Value:  BooleanTerm(false),
  1387  			Assign: true,
  1388  		},
  1389  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1390  	})
  1391  
  1392  	assertParseRule(t, "default w/ comprehension", `default widgets = [x | x = data.fooz[_]]`, &Rule{
  1393  		Default: true,
  1394  		Head:    NewHead(Var("widgets"), nil, MustParseTerm(`[x | x = data.fooz[_]]`)),
  1395  		Body:    NewBody(NewExpr(BooleanTerm(true))),
  1396  	})
  1397  
  1398  	assertParseRule(t, "one line with braces", `p[x] { x = data.a[_]; count(x, 3) }`, &Rule{
  1399  		Head: NewHead(Var("p"), VarTerm("x")),
  1400  		Body: MustParseBody(`x = data.a[_]; count(x, 3)`),
  1401  	})
  1402  
  1403  	assertParseRule(t, "multiple lines with braces", `p[[x, y]] { [data.a[0]] = [{"x": x}]; count(x, 3); sum(x, y); y > 100 }`,
  1404  
  1405  		&Rule{
  1406  			Head: NewHead(Var("p"), MustParseTerm("[x, y]")),
  1407  			Body: MustParseBody(`[data.a[0]] = [{"x": x}]; count(x, 3); sum(x, y); y > 100`),
  1408  		})
  1409  
  1410  	fxy := &Head{
  1411  		Name:  Var("f"),
  1412  		Args:  Args{VarTerm("x")},
  1413  		Value: VarTerm("y"),
  1414  	}
  1415  
  1416  	assertParseRule(t, "identity", `f(x) = y { y = x }`, &Rule{
  1417  		Head: fxy,
  1418  		Body: NewBody(
  1419  			Equality.Expr(VarTerm("y"), VarTerm("x")),
  1420  		),
  1421  	})
  1422  
  1423  	assertParseRule(t, "composite arg", `f([x, y]) = z { split(x, y, z) }`, &Rule{
  1424  		Head: &Head{
  1425  			Name:  Var("f"),
  1426  			Args:  Args{ArrayTerm(VarTerm("x"), VarTerm("y"))},
  1427  			Value: VarTerm("z"),
  1428  		},
  1429  		Body: NewBody(
  1430  			Split.Expr(VarTerm("x"), VarTerm("y"), VarTerm("z")),
  1431  		),
  1432  	})
  1433  
  1434  	assertParseRule(t, "composite result", `f(1) = [x, y] { split("foo.bar", x, y) }`, &Rule{
  1435  		Head: &Head{
  1436  			Name:  Var("f"),
  1437  			Args:  Args{IntNumberTerm(1)},
  1438  			Value: ArrayTerm(VarTerm("x"), VarTerm("y")),
  1439  		},
  1440  		Body: NewBody(
  1441  			Split.Expr(StringTerm("foo.bar"), VarTerm("x"), VarTerm("y")),
  1442  		),
  1443  	})
  1444  
  1445  	assertParseRule(t, "expr terms: key", `p[f(x) + g(x)] { true }`, &Rule{
  1446  		Head: &Head{
  1447  			Name: Var("p"),
  1448  			Key: Plus.Call(
  1449  				CallTerm(RefTerm(VarTerm("f")), VarTerm("x")),
  1450  				CallTerm(RefTerm(VarTerm("g")), VarTerm("x")),
  1451  			),
  1452  		},
  1453  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1454  	})
  1455  
  1456  	assertParseRule(t, "expr terms: value", `p = f(x) + g(x) { true }`, &Rule{
  1457  		Head: &Head{
  1458  			Name: Var("p"),
  1459  			Value: Plus.Call(
  1460  				CallTerm(RefTerm(VarTerm("f")), VarTerm("x")),
  1461  				CallTerm(RefTerm(VarTerm("g")), VarTerm("x")),
  1462  			),
  1463  		},
  1464  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1465  	})
  1466  
  1467  	assertParseRule(t, "expr terms: args", `p(f(x) + g(x)) { true }`, &Rule{
  1468  		Head: &Head{
  1469  			Name: Var("p"),
  1470  			Args: Args{
  1471  				Plus.Call(
  1472  					CallTerm(RefTerm(VarTerm("f")), VarTerm("x")),
  1473  					CallTerm(RefTerm(VarTerm("g")), VarTerm("x")),
  1474  				),
  1475  			},
  1476  			Value: BooleanTerm(true),
  1477  		},
  1478  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1479  	})
  1480  
  1481  	assertParseRule(t, "assignment operator", `x := 1 { true }`, &Rule{
  1482  		Head: &Head{
  1483  			Name:   Var("x"),
  1484  			Value:  IntNumberTerm(1),
  1485  			Assign: true,
  1486  		},
  1487  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1488  	})
  1489  
  1490  	assertParseRule(t, "else assignment", `x := 1 { false } else := 2`, &Rule{
  1491  		Head: &Head{
  1492  			Name:   "x",
  1493  			Value:  IntNumberTerm(1),
  1494  			Assign: true,
  1495  		},
  1496  		Body: NewBody(NewExpr(BooleanTerm(false))),
  1497  		Else: &Rule{
  1498  			Head: &Head{
  1499  				Name:   "x",
  1500  				Value:  IntNumberTerm(2),
  1501  				Assign: true,
  1502  			},
  1503  			Body: NewBody(NewExpr(BooleanTerm(true))),
  1504  		},
  1505  	})
  1506  
  1507  	assertParseRule(t, "partial assignment", `p[x] := y { true }`, &Rule{
  1508  		Head: &Head{
  1509  			Name:   "p",
  1510  			Value:  VarTerm("y"),
  1511  			Key:    VarTerm("x"),
  1512  			Assign: true,
  1513  		},
  1514  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1515  	})
  1516  
  1517  	assertParseRule(t, "function assignment", `f(x) := y { true }`, &Rule{
  1518  		Head: &Head{
  1519  			Name:  "f",
  1520  			Value: VarTerm("y"),
  1521  			Args: Args{
  1522  				VarTerm("x"),
  1523  			},
  1524  			Assign: true,
  1525  		},
  1526  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1527  	})
  1528  
  1529  	// TODO: expect expressions instead?
  1530  	assertParseErrorContains(t, "empty body", `f(_) = y {}`, "rego_parse_error: found empty body")
  1531  	assertParseErrorContains(t, "empty rule body", "p {}", "rego_parse_error: found empty body")
  1532  	assertParseErrorContains(t, "unmatched braces", `f(x) = y { trim(x, ".", y) `, `rego_parse_error: unexpected eof token: expected \n or ; or }`)
  1533  
  1534  	// TODO: how to highlight that assignment is incorrect here?
  1535  	assertParseErrorContains(t, "no output", `f(_) = { "foo" = "bar" }`, "rego_parse_error: unexpected eq token: expected rule value term")
  1536  	assertParseErrorContains(t, "no output", `f(_) := { "foo" = "bar" }`, "rego_parse_error: unexpected assign token: expected function value term")
  1537  	assertParseErrorContains(t, "no output", `f := { "foo" = "bar" }`, "rego_parse_error: unexpected assign token: expected rule value term")
  1538  	assertParseErrorContains(t, "no output", `f[_] := { "foo" = "bar" }`, "rego_parse_error: unexpected assign token: expected partial rule value term")
  1539  	assertParseErrorContains(t, "no output", `default f :=`, "rego_parse_error: unexpected assign token: expected default rule value term")
  1540  
  1541  	// TODO(tsandall): improve error checking here. This is a common mistake
  1542  	// and the current error message is not very good. Need to investigate if the
  1543  	// parser can be improved.
  1544  	assertParseError(t, "dangling semicolon", "p { true; false; }")
  1545  
  1546  	assertParseErrorContains(t, "default invalid rule name", `default 0[0`, "unexpected default keyword")
  1547  	assertParseErrorContains(t, "default invalid rule value", `default a[0`, "illegal default rule (must have a value)")
  1548  	assertParseRule(t, "default missing value", `default a`, &Rule{
  1549  		Default: true,
  1550  		Head: &Head{
  1551  			Name:  Var("a"),
  1552  			Value: BooleanTerm(true),
  1553  		},
  1554  		Body: NewBody(NewExpr(BooleanTerm(true))),
  1555  	})
  1556  	assertParseRule(t, "empty arguments", `f() { x := 1 }`, &Rule{
  1557  		Head: &Head{
  1558  			Name:  "f",
  1559  			Value: BooleanTerm(true),
  1560  		},
  1561  		Body: MustParseBody(`x := 1`),
  1562  	})
  1563  
  1564  	assertParseErrorContains(t, "default invalid rule head ref", `default a = b.c.d`, "illegal default rule (value cannot contain ref)")
  1565  	assertParseErrorContains(t, "default invalid rule head call", `default a = g(x)`, "illegal default rule (value cannot contain call)")
  1566  	assertParseErrorContains(t, "default invalid rule head builtin call", `default a = upper("foo")`, "illegal default rule (value cannot contain call)")
  1567  	assertParseErrorContains(t, "default invalid rule head call", `default a = b`, "illegal default rule (value cannot contain var)")
  1568  
  1569  	assertParseError(t, "extra braces", `{ a := 1 }`)
  1570  	assertParseError(t, "invalid rule name dots", `a.b = x { x := 1 }`)
  1571  	assertParseError(t, "invalid rule name dots and call", `a.b(x) { x := 1 }`)
  1572  	assertParseError(t, "invalid rule name hyphen", `a-b = x { x := 1 }`)
  1573  
  1574  	assertParseRule(t, "wildcard name", `_ { x == 1 }`, &Rule{
  1575  		Head: &Head{
  1576  			Name:  "$0",
  1577  			Value: BooleanTerm(true),
  1578  		},
  1579  		Body: MustParseBody(`x == 1`),
  1580  	})
  1581  
  1582  	assertParseRule(t, "partial object array key", `p[[a, 1, 2]] = x { a := 1; x := "foo" }`, &Rule{
  1583  		Head: &Head{
  1584  			Name:  "p",
  1585  			Key:   ArrayTerm(VarTerm("a"), NumberTerm("1"), NumberTerm("2")),
  1586  			Value: VarTerm("x"),
  1587  		},
  1588  		Body: MustParseBody(`a := 1; x := "foo"`),
  1589  	})
  1590  	assertParseError(t, "invalid rule body no separator", `p { a = "foo"bar }`)
  1591  	assertParseError(t, "invalid rule body no newline", `p { a b c }`)
  1592  }
  1593  
  1594  func TestRuleContains(t *testing.T) {
  1595  	opts := ParserOptions{FutureKeywords: []string{"contains"}}
  1596  
  1597  	tests := []struct {
  1598  		note string
  1599  		rule string
  1600  		exp  *Rule
  1601  	}{
  1602  		{
  1603  			note: "simple",
  1604  			rule: `p contains "x" { true }`,
  1605  			exp: &Rule{
  1606  				Head: NewHead(Var("p"), StringTerm("x")),
  1607  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1608  			},
  1609  		},
  1610  		{
  1611  			note: "no body",
  1612  			rule: `p contains "x"`,
  1613  			exp: &Rule{
  1614  				Head: NewHead(Var("p"), StringTerm("x")),
  1615  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1616  			},
  1617  		},
  1618  		{
  1619  			note: "set with var element",
  1620  			rule: `deny contains msg { msg := "nonono" }`,
  1621  			exp: &Rule{
  1622  				Head: NewHead(Var("deny"), VarTerm("msg")),
  1623  				Body: MustParseBody(`msg := "nonono"`),
  1624  			},
  1625  		},
  1626  		{
  1627  			note: "set with object elem",
  1628  			rule: `deny contains {"allow": false, "msg": msg} { msg := "nonono" }`,
  1629  			exp: &Rule{
  1630  				Head: NewHead(Var("deny"), MustParseTerm(`{"allow": false, "msg": msg}`)),
  1631  				Body: MustParseBody(`msg := "nonono"`),
  1632  			},
  1633  		},
  1634  	}
  1635  
  1636  	for _, tc := range tests {
  1637  		t.Run(tc.note, func(t *testing.T) {
  1638  			assertParseRule(t, tc.note, tc.rule, tc.exp, opts)
  1639  		})
  1640  	}
  1641  }
  1642  
  1643  func TestRuleIf(t *testing.T) {
  1644  	opts := ParserOptions{FutureKeywords: []string{"contains", "if", "every"}}
  1645  
  1646  	tests := []struct {
  1647  		note string
  1648  		rule string
  1649  		exp  *Rule
  1650  	}{
  1651  		{
  1652  			note: "complete",
  1653  			rule: `p if { true }`,
  1654  			exp: &Rule{
  1655  				Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1656  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1657  			},
  1658  		},
  1659  		{
  1660  			note: "complete, normal body",
  1661  			rule: `p if { x := 10; x > y }`,
  1662  			exp: &Rule{
  1663  				Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1664  				Body: MustParseBody(`x := 10; x > y`),
  1665  			},
  1666  		},
  1667  		{
  1668  			note: "complete+else, normal bodies, assign",
  1669  			rule: `p := "yes" if { 10 > y } else := "no" { 10 <= y }`,
  1670  			exp: &Rule{
  1671  				Head: &Head{
  1672  					Name:   Var("p"),
  1673  					Value:  StringTerm("yes"),
  1674  					Assign: true,
  1675  				},
  1676  				Body: MustParseBody(`10 > y`),
  1677  				Else: &Rule{
  1678  					Head: &Head{
  1679  						Name:   Var("p"),
  1680  						Value:  StringTerm("no"),
  1681  						Assign: true,
  1682  					},
  1683  					Body: MustParseBody(`10 <= y`),
  1684  				},
  1685  			},
  1686  		},
  1687  		{
  1688  			note: "complete, shorthand",
  1689  			rule: `p if true`,
  1690  			exp: &Rule{
  1691  				Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1692  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1693  			},
  1694  		},
  1695  		{
  1696  			note: "complete+not, shorthand",
  1697  			rule: `p if not q`,
  1698  			exp: &Rule{
  1699  				Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1700  				Body: MustParseBody(`not q`),
  1701  			},
  1702  		},
  1703  		{
  1704  			note: "complete+else, shorthand",
  1705  			rule: `p if 1 > 2 else = 42 { 2 > 1 }`,
  1706  			exp: &Rule{
  1707  				Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1708  				Body: MustParseBody(`1 > 2`),
  1709  				Else: &Rule{
  1710  					Head: &Head{
  1711  						Name:  Var("p"),
  1712  						Value: NumberTerm("42"),
  1713  					},
  1714  					Body: MustParseBody(`2 > 1`),
  1715  				},
  1716  			},
  1717  		},
  1718  		{
  1719  			note: "complete+call, shorthand",
  1720  			rule: `p if count(q) > 0`,
  1721  			exp: &Rule{
  1722  				Head: NewHead(Var("p"), nil, BooleanTerm(true)),
  1723  				Body: MustParseBody(`count(q) > 0`),
  1724  			},
  1725  		},
  1726  		{
  1727  			note: "function, shorthand",
  1728  			rule: `f(x) = y if y := x + 1`,
  1729  			exp: &Rule{
  1730  				Head: &Head{
  1731  					Name:  Var("f"),
  1732  					Args:  []*Term{VarTerm("x")},
  1733  					Value: VarTerm("y"),
  1734  				},
  1735  				Body: MustParseBody(`y := x + 1`),
  1736  			},
  1737  		},
  1738  		{
  1739  			note: "function+every, shorthand",
  1740  			rule: `f(xs) if every x in xs { x != 0 }`,
  1741  			exp: &Rule{
  1742  				Head: &Head{
  1743  					Name:  Var("f"),
  1744  					Args:  []*Term{VarTerm("xs")},
  1745  					Value: BooleanTerm(true),
  1746  				},
  1747  				Body: MustParseBodyWithOpts(`every x in xs { x != 0 }`, opts),
  1748  			},
  1749  		},
  1750  		{
  1751  			note: "object",
  1752  			rule: `p["foo"] = "bar" if { true }`,
  1753  			exp: &Rule{
  1754  				Head: NewHead(Var("p"), StringTerm("foo"), StringTerm("bar")),
  1755  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1756  			},
  1757  		},
  1758  		{
  1759  			note: "object, shorthand",
  1760  			rule: `p["foo"] = "bar" if true`,
  1761  			exp: &Rule{
  1762  				Head: NewHead(Var("p"), StringTerm("foo"), StringTerm("bar")),
  1763  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1764  			},
  1765  		},
  1766  		{
  1767  			note: "object with vars",
  1768  			rule: `p[x] = y if {
  1769  				x := "foo"
  1770  				y := "bar"
  1771  			}`,
  1772  			exp: &Rule{
  1773  				Head: NewHead(Var("p"), VarTerm("x"), VarTerm("y")),
  1774  				Body: MustParseBody(`x := "foo"; y := "bar"`),
  1775  			},
  1776  		},
  1777  		{
  1778  			note: "set",
  1779  			rule: `p contains "foo" if { true }`,
  1780  			exp: &Rule{
  1781  				Head: NewHead(Var("p"), StringTerm("foo")),
  1782  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1783  			},
  1784  		},
  1785  		{
  1786  			note: "set, shorthand",
  1787  			rule: `p contains "foo" if true`,
  1788  			exp: &Rule{
  1789  				Head: NewHead(Var("p"), StringTerm("foo")),
  1790  				Body: NewBody(NewExpr(BooleanTerm(true))),
  1791  			},
  1792  		},
  1793  		{
  1794  			note: "set+var+shorthand",
  1795  			rule: `p contains x if { x := "foo" }`,
  1796  			exp: &Rule{
  1797  				Head: NewHead(Var("p"), VarTerm("x")),
  1798  				Body: MustParseBody(`x := "foo"`),
  1799  			},
  1800  		},
  1801  	}
  1802  
  1803  	for _, tc := range tests {
  1804  		t.Run(tc.note, func(t *testing.T) {
  1805  			assertParseRule(t, tc.note, tc.rule, tc.exp, opts)
  1806  		})
  1807  	}
  1808  
  1809  	errors := []struct {
  1810  		note string
  1811  		rule string
  1812  		err  string
  1813  	}{
  1814  		{
  1815  			note: "partial set+if, shorthand",
  1816  			rule: `p[x] if x := 1`,
  1817  			err:  "rego_parse_error: unexpected if keyword: invalid for partial set rule p (use `contains`)",
  1818  		},
  1819  		{
  1820  			note: "partial set+if",
  1821  			rule: `p[x] if { x := 1 }`,
  1822  			err:  "rego_parse_error: unexpected if keyword: invalid for partial set rule p (use `contains`)",
  1823  		},
  1824  	}
  1825  	for _, tc := range errors {
  1826  		t.Run(tc.note, func(t *testing.T) {
  1827  			assertParseErrorContains(t, tc.note, tc.rule, tc.err, opts)
  1828  		})
  1829  	}
  1830  }
  1831  
  1832  func TestRuleElseKeyword(t *testing.T) {
  1833  	mod := `package test
  1834  
  1835  	p {
  1836  		"p0"
  1837  	}
  1838  
  1839  	p {
  1840  		"p1"
  1841  	} else {
  1842  		"p1_e1"
  1843  	} else = [null] {
  1844  		"p1_e2"
  1845  	} else = x {
  1846  		x = "p1_e3"
  1847  	}
  1848  
  1849  	p {
  1850  		"p2"
  1851  	}
  1852  
  1853  	f(x) {
  1854  		x < 100
  1855  	} else = false {
  1856  		x > 200
  1857  	} else {
  1858  		x != 150
  1859  	}
  1860  
  1861  	_ {
  1862  		x > 0
  1863  	} else {
  1864  	    x == -1
  1865  	} else {
  1866  		x > -100
  1867  	}
  1868  
  1869  	nobody = 1 {
  1870  		false
  1871  	} else = 7
  1872  
  1873  	nobody_f(x) = 1 {
  1874  		false
  1875  	} else = 7
  1876  	`
  1877  
  1878  	parsed, err := ParseModule("", mod)
  1879  	if err != nil {
  1880  		t.Fatalf("Unexpected parse error: %v", err)
  1881  	}
  1882  
  1883  	name := Var("p")
  1884  	tr := BooleanTerm(true)
  1885  	head := &Head{Name: name, Value: tr}
  1886  
  1887  	expected := &Module{
  1888  		Package: MustParsePackage(`package test`),
  1889  		Rules: []*Rule{
  1890  			{
  1891  				Head: head,
  1892  				Body: MustParseBody(`"p0"`),
  1893  			},
  1894  			{
  1895  				Head: head,
  1896  				Body: MustParseBody(`"p1"`),
  1897  				Else: &Rule{
  1898  					Head: head,
  1899  					Body: MustParseBody(`"p1_e1"`),
  1900  					Else: &Rule{
  1901  						Head: &Head{
  1902  							Name:  Var("p"),
  1903  							Value: ArrayTerm(NullTerm()),
  1904  						},
  1905  						Body: MustParseBody(`"p1_e2"`),
  1906  						Else: &Rule{
  1907  							Head: &Head{
  1908  								Name:  name,
  1909  								Value: VarTerm("x"),
  1910  							},
  1911  							Body: MustParseBody(`x = "p1_e3"`),
  1912  						},
  1913  					},
  1914  				},
  1915  			},
  1916  			{
  1917  				Head: head,
  1918  				Body: MustParseBody(`"p2"`),
  1919  			},
  1920  			{
  1921  				Head: &Head{
  1922  					Name:  Var("f"),
  1923  					Args:  Args{VarTerm("x")},
  1924  					Value: BooleanTerm(true),
  1925  				},
  1926  				Body: MustParseBody(`x < 100`),
  1927  				Else: &Rule{
  1928  					Head: &Head{
  1929  						Name:  Var("f"),
  1930  						Args:  Args{VarTerm("x")},
  1931  						Value: BooleanTerm(false),
  1932  					},
  1933  					Body: MustParseBody(`x > 200`),
  1934  					Else: &Rule{
  1935  						Head: &Head{
  1936  							Name:  Var("f"),
  1937  							Args:  Args{VarTerm("x")},
  1938  							Value: BooleanTerm(true),
  1939  						},
  1940  						Body: MustParseBody(`x != 150`),
  1941  					},
  1942  				},
  1943  			},
  1944  
  1945  			{
  1946  				Head: &Head{
  1947  					Name:  Var("$0"),
  1948  					Value: BooleanTerm(true),
  1949  				},
  1950  				Body: MustParseBody(`x > 0`),
  1951  				Else: &Rule{
  1952  					Head: &Head{
  1953  						Name:  Var("$0"),
  1954  						Value: BooleanTerm(true),
  1955  					},
  1956  					Body: MustParseBody(`x == -1`),
  1957  					Else: &Rule{
  1958  						Head: &Head{
  1959  							Name:  Var("$0"),
  1960  							Value: BooleanTerm(true),
  1961  						},
  1962  						Body: MustParseBody(`x > -100`),
  1963  					},
  1964  				},
  1965  			},
  1966  			{
  1967  				Head: &Head{
  1968  					Name:  Var("nobody"),
  1969  					Value: IntNumberTerm(1),
  1970  				},
  1971  				Body: MustParseBody("false"),
  1972  				Else: &Rule{
  1973  					Head: &Head{
  1974  						Name:  Var("nobody"),
  1975  						Value: IntNumberTerm(7),
  1976  					},
  1977  					Body: MustParseBody("true"),
  1978  				},
  1979  			},
  1980  			{
  1981  				Head: &Head{
  1982  					Name:  Var("nobody_f"),
  1983  					Args:  Args{VarTerm("x")},
  1984  					Value: IntNumberTerm(1),
  1985  				},
  1986  				Body: MustParseBody("false"),
  1987  				Else: &Rule{
  1988  					Head: &Head{
  1989  						Name:  Var("nobody_f"),
  1990  						Args:  Args{VarTerm("x")},
  1991  						Value: IntNumberTerm(7),
  1992  					},
  1993  					Body: MustParseBody("true"),
  1994  				},
  1995  			},
  1996  		},
  1997  	}
  1998  
  1999  	if parsed.Compare(expected) != 0 {
  2000  		t.Fatalf("Expected:\n%v\n\nGot:\n%v", expected, parsed)
  2001  	}
  2002  
  2003  	notExpected := &Module{
  2004  		Package: MustParsePackage(`package test`),
  2005  		Rules: []*Rule{
  2006  			{
  2007  				Head: head,
  2008  				Body: MustParseBody(`"p0"`),
  2009  			},
  2010  			{
  2011  				Head: head,
  2012  				Body: MustParseBody(`"p1"`),
  2013  				Else: &Rule{
  2014  					Head: head,
  2015  					Body: MustParseBody(`"p1_e1"`),
  2016  					Else: &Rule{
  2017  						Head: &Head{
  2018  							Name:  Var("p"),
  2019  							Value: ArrayTerm(NullTerm()),
  2020  						},
  2021  						Body: MustParseBody(`"p1_e2"`),
  2022  						Else: &Rule{
  2023  							Head: &Head{
  2024  								Name:  name,
  2025  								Value: VarTerm("x"),
  2026  							},
  2027  							Body: MustParseBody(`x = "p1_e4"`),
  2028  						},
  2029  					},
  2030  				},
  2031  			},
  2032  			{
  2033  				Head: head,
  2034  				Body: MustParseBody(`"p2"`),
  2035  			},
  2036  		},
  2037  	}
  2038  
  2039  	if parsed.Compare(notExpected) != -1 {
  2040  		t.Fatalf("Expected not equal:\n%v\n\nGot:\n%v", parsed, notExpected)
  2041  	}
  2042  
  2043  	_, err = ParseModule("", `
  2044  	package test
  2045  	p[1] { false } else { true }
  2046  	`)
  2047  
  2048  	if err == nil || !strings.Contains(err.Error(), "else keyword cannot be used on partial rules") {
  2049  		t.Fatalf("Expected parse error but got: %v", err)
  2050  	}
  2051  
  2052  	_, err = ParseModule("", `
  2053  	package test
  2054  	p { false } { false } else { true }
  2055  	`)
  2056  
  2057  	if err == nil || !strings.Contains(err.Error(), "unexpected else keyword") {
  2058  		t.Fatalf("Expected parse error but got: %v", err)
  2059  	}
  2060  
  2061  	_, err = ParseModule("", `
  2062  	package test
  2063  	p { false } else { false } { true }
  2064  	`)
  2065  
  2066  	if err == nil || !strings.Contains(err.Error(), "expected else keyword") {
  2067  		t.Fatalf("Expected parse error but got: %v", err)
  2068  	}
  2069  
  2070  }
  2071  
  2072  func TestMultipleEnclosedBodies(t *testing.T) {
  2073  
  2074  	result, err := ParseModule("", `package ex
  2075  
  2076  p[x] = y {
  2077  	x = "a"
  2078  	y = 1
  2079  } {
  2080  	x = "b"
  2081  	y = 2
  2082  }
  2083  
  2084  q = 1
  2085  
  2086  f(x) {
  2087  	x < 10
  2088  } {
  2089  	x > 1000
  2090  }
  2091  `,
  2092  	)
  2093  
  2094  	if err != nil {
  2095  		t.Fatalf("Unexpected parse error: %v", err)
  2096  	}
  2097  
  2098  	expected := MustParseModule(`package ex
  2099  
  2100  p[x] = y { x = "a"; y = 1 }
  2101  p[x] = y { x = "b"; y = 2 }
  2102  q = 1 { true }
  2103  f(x) { x < 10 }
  2104  f(x) { x > 1000 }`,
  2105  	)
  2106  
  2107  	if !expected.Equal(result) {
  2108  		t.Fatal("Expected modules to be equal but got:\n\n", result, "\n\nExpected:\n\n", expected)
  2109  	}
  2110  
  2111  }
  2112  
  2113  func TestEmptyModule(t *testing.T) {
  2114  	r, err := ParseModule("", "    ")
  2115  	if err == nil {
  2116  		t.Error("Expected error for empty module")
  2117  		return
  2118  	}
  2119  	if r != nil {
  2120  		t.Errorf("Expected nil for empty module: %v", r)
  2121  	}
  2122  }
  2123  
  2124  func TestComments(t *testing.T) {
  2125  
  2126  	testModule := `package a.b.c
  2127  
  2128      import input.e.f as g  # end of line
  2129      import input.h
  2130  
  2131      # by itself
  2132  
  2133      p[x] = y { y = "foo";
  2134          # inside a rule
  2135          x = "bar";
  2136          x != y;
  2137          q[x]
  2138  	}
  2139  
  2140      import input.xyz.abc
  2141  
  2142      q # interrupting
  2143  
  2144  	[a] # the head of a rule
  2145  
  2146  	{ m = [1,2,
  2147      3, ];
  2148      a = m[i]
  2149  
  2150  	}
  2151  
  2152  	r[x] { x = [ a | # inside comprehension
  2153  					  a = z[i]
  2154  	                  b[i].a = a ]
  2155  
  2156  		y = { a | # inside set comprehension
  2157  				a = z[i]
  2158  			b[i].a = a}
  2159  
  2160  		z = {a: i | # inside object comprehension
  2161  				a = z[i]
  2162  			b[i].a = a}
  2163  					  }`
  2164  
  2165  	assertParseModule(t, "module comments", testModule, &Module{
  2166  		Package: MustParseStatement(`package a.b.c`).(*Package),
  2167  		Imports: []*Import{
  2168  			MustParseStatement("import input.e.f as g").(*Import),
  2169  			MustParseStatement("import input.h").(*Import),
  2170  			MustParseStatement("import input.xyz.abc").(*Import),
  2171  		},
  2172  		Rules: []*Rule{
  2173  			MustParseStatement(`p[x] = y { y = "foo"; x = "bar"; x != y; q[x] }`).(*Rule),
  2174  			MustParseStatement(`q[a] { m = [1, 2, 3]; a = m[i] }`).(*Rule),
  2175  			MustParseStatement(`r[x] { x = [a | a = z[i]; b[i].a = a]; y = {a |  a = z[i]; b[i].a = a}; z = {a: i | a = z[i]; b[i].a = a} }`).(*Rule),
  2176  		},
  2177  	})
  2178  
  2179  	module, err := ParseModule("test.rego", testModule)
  2180  	if err != nil {
  2181  		t.Fatal("Unexpected error:", err)
  2182  	}
  2183  
  2184  	exp := []struct {
  2185  		text string
  2186  		row  int
  2187  		col  int
  2188  	}{
  2189  		{text: "end of line", row: 3, col: 28},
  2190  		{text: "by itself", row: 6, col: 5},
  2191  		{text: "inside a rule", row: 9, col: 9},
  2192  		{text: "interrupting", row: 17, col: 7},
  2193  		{text: "the head of a rule", row: 19, col: 6},
  2194  		{text: "inside comprehension", row: 27, col: 19},
  2195  		{text: "inside set comprehension", row: 31, col: 13},
  2196  		{text: "inside object comprehension", row: 35, col: 15},
  2197  	}
  2198  
  2199  	if len(module.Comments) != len(exp) {
  2200  		t.Fatalf("Expected %v comments but got %v", len(exp), len(module.Comments))
  2201  	}
  2202  
  2203  	for i := range exp {
  2204  
  2205  		expc := &Comment{
  2206  			Text: []byte(" " + exp[i].text),
  2207  			Location: &Location{
  2208  				File: "test.rego",
  2209  				Text: []byte("# " + exp[i].text),
  2210  				Row:  exp[i].row,
  2211  				Col:  exp[i].col,
  2212  			},
  2213  		}
  2214  
  2215  		if !expc.Equal(module.Comments[i]) {
  2216  			comment := module.Comments[i]
  2217  			fmt.Printf("comment: %v %v %v %v\n", comment.Location.File, comment.Location.Text, comment.Location.Col, comment.Location.Row)
  2218  			fmt.Printf("expcomm: %v %v %v %v\n", expc.Location.File, expc.Location.Text, expc.Location.Col, expc.Location.Row)
  2219  			t.Errorf("Expected %q but got: %q (want: %d:%d, got: %d:%d)", expc, comment, exp[i].row, exp[i].col, comment.Location.Row, comment.Location.Col)
  2220  		}
  2221  	}
  2222  }
  2223  
  2224  func TestCommentsWhitespace(t *testing.T) {
  2225  	cases := []struct {
  2226  		note     string
  2227  		module   string
  2228  		expected []string
  2229  	}{
  2230  		{
  2231  			note:     "trailing spaces",
  2232  			module:   "# a comment    \t   \n",
  2233  			expected: []string{" a comment    \t   "},
  2234  		},
  2235  		{
  2236  			note:     "trailing carriage return",
  2237  			module:   "# a comment\r\n",
  2238  			expected: []string{" a comment"},
  2239  		},
  2240  		{
  2241  			note:     "trailing carriage return double newline",
  2242  			module:   "# a comment\r\n\n",
  2243  			expected: []string{" a comment"},
  2244  		},
  2245  		{
  2246  			note:     "double trailing carriage return newline",
  2247  			module:   "#\r\r\n",
  2248  			expected: []string{"\r"},
  2249  		},
  2250  		{
  2251  			note:     "double trailing carriage return",
  2252  			module:   "#\r\r",
  2253  			expected: []string{"\r"},
  2254  		},
  2255  		{
  2256  			note:     "carriage return",
  2257  			module:   "#\r",
  2258  			expected: []string{""},
  2259  		},
  2260  		{
  2261  			note:     "carriage return in comment",
  2262  			module:   "# abc\rdef\r\n",
  2263  			expected: []string{" abc\rdef"},
  2264  		},
  2265  	}
  2266  
  2267  	for _, tc := range cases {
  2268  		t.Run(tc.note, func(t *testing.T) {
  2269  			_, comments, err := ParseStatements("", tc.module)
  2270  			if err != nil {
  2271  				t.Fatalf("Unexpected parse error: %s", err)
  2272  			}
  2273  
  2274  			for i, exp := range tc.expected {
  2275  				actual := string(comments[i].Text)
  2276  				if exp != actual {
  2277  					t.Errorf("Expected comment text (len %d):\n\n\t%q\n\nbut got (len %d):\n\n\t%q\n\n", len(exp), exp, len(actual), actual)
  2278  				}
  2279  			}
  2280  		})
  2281  	}
  2282  }
  2283  
  2284  func TestExample(t *testing.T) {
  2285  	assertParseModule(t, "example module", testModule, &Module{
  2286  		Package: MustParseStatement(`package opa.examples`).(*Package),
  2287  		Imports: []*Import{
  2288  			MustParseStatement("import data.servers").(*Import),
  2289  			MustParseStatement("import data.networks").(*Import),
  2290  			MustParseStatement("import data.ports").(*Import),
  2291  		},
  2292  		Rules: []*Rule{
  2293  			MustParseStatement(`violations[server] { server = servers[i]; server.protocols[j] = "http"; public_servers[server] }`).(*Rule),
  2294  			MustParseStatement(`public_servers[server] { server = servers[i]; server.ports[j] = ports[k].id; ports[k].networks[l] = networks[m].id; networks[m].public = true }`).(*Rule),
  2295  		},
  2296  	})
  2297  }
  2298  
  2299  func TestModuleParseErrors(t *testing.T) {
  2300  	input := `
  2301  	x = 1			# expect package
  2302  	package a  		# unexpected package
  2303  	1 = 2			# non-var head
  2304  	1 != 2			# non-equality expr
  2305  	x = y; x = 1    # multiple exprs
  2306  	`
  2307  
  2308  	mod, err := ParseModule("test.rego", input)
  2309  	if err == nil {
  2310  		t.Fatalf("Expected error but got: %v", mod)
  2311  	}
  2312  
  2313  	errs, ok := err.(Errors)
  2314  	if !ok {
  2315  		panic("unexpected error value")
  2316  	}
  2317  
  2318  	if len(errs) != 5 {
  2319  		t.Fatalf("Expected exactly 5 errors but got: %v", err)
  2320  	}
  2321  }
  2322  
  2323  func TestLocation(t *testing.T) {
  2324  	mod, err := ParseModule("test", testModule)
  2325  	if err != nil {
  2326  		t.Errorf("Unexpected error while parsing test module: %v", err)
  2327  		return
  2328  	}
  2329  	expr := mod.Rules[0].Body[0]
  2330  	if expr.Location.Col != 5 {
  2331  		t.Errorf("Expected column of %v to be 5 but got: %v", expr, expr.Location.Col)
  2332  	}
  2333  	if expr.Location.Row != 15 {
  2334  		t.Errorf("Expected row of %v to be 8 but got: %v", expr, expr.Location.Row)
  2335  	}
  2336  	if expr.Location.File != "test" {
  2337  		t.Errorf("Expected file of %v to be test but got: %v", expr, expr.Location.File)
  2338  	}
  2339  }
  2340  
  2341  func TestRuleFromBody(t *testing.T) {
  2342  	testModule := `package a.b.c
  2343  
  2344  pi = 3.14159
  2345  p[x] { x = 1 }
  2346  greeting = "hello"
  2347  cores = [{0: 1}, {1: 2}]
  2348  wrapper = cores[0][1]
  2349  pi = [3, 1, 4, x, y, z]
  2350  foo["bar"] = "buz"
  2351  foo["9"] = "10"
  2352  foo.buz = "bar"
  2353  bar[1]
  2354  bar[[{"foo":"baz"}]]
  2355  bar.qux
  2356  input = 1
  2357  data = 2
  2358  f(1) = 2
  2359  f(1)
  2360  d1 := 1234
  2361  `
  2362  
  2363  	assertParseModule(t, "rules from bodies", testModule, &Module{
  2364  		Package: MustParseStatement(`package a.b.c`).(*Package),
  2365  		Rules: []*Rule{
  2366  			MustParseRule(`pi = 3.14159 { true }`),
  2367  			MustParseRule(`p[x] { x = 1 }`),
  2368  			MustParseRule(`greeting = "hello" { true }`),
  2369  			MustParseRule(`cores = [{0: 1}, {1: 2}] { true }`),
  2370  			MustParseRule(`wrapper = cores[0][1] { true }`),
  2371  			MustParseRule(`pi = [3, 1, 4, x, y, z] { true }`),
  2372  			MustParseRule(`foo["bar"] = "buz" { true }`),
  2373  			MustParseRule(`foo["9"] = "10" { true }`),
  2374  			MustParseRule(`foo["buz"] = "bar" { true }`),
  2375  			MustParseRule(`bar[1] { true }`),
  2376  			MustParseRule(`bar[[{"foo":"baz"}]] { true }`),
  2377  			MustParseRule(`bar["qux"] { true }`),
  2378  			MustParseRule(`input = 1 { true }`),
  2379  			MustParseRule(`data = 2 { true }`),
  2380  			MustParseRule(`f(1) = 2 { true }`),
  2381  			MustParseRule(`f(1) = true { true }`),
  2382  			MustParseRule("d1 := 1234 { true }"),
  2383  		},
  2384  	})
  2385  
  2386  	// Verify the rule and rule and rule head col/loc values
  2387  	module, err := ParseModule("test.rego", testModule)
  2388  	if err != nil {
  2389  		t.Fatal(err)
  2390  	}
  2391  
  2392  	for i := range module.Rules {
  2393  		col := module.Rules[i].Location.Col
  2394  		if col != 1 {
  2395  			t.Fatalf("expected rule %v column to be 1 but got %v", module.Rules[i].Head.Name, col)
  2396  		}
  2397  		row := module.Rules[i].Location.Row
  2398  		if row != 3+i { // 'pi' rule stats on row 3
  2399  			t.Fatalf("expected rule %v row to be %v but got %v", module.Rules[i].Head.Name, 3+i, row)
  2400  		}
  2401  		col = module.Rules[i].Head.Location.Col
  2402  		if col != 1 {
  2403  			t.Fatalf("expected rule head %v column to be 1 but got %v", module.Rules[i].Head.Name, col)
  2404  		}
  2405  		row = module.Rules[i].Head.Location.Row
  2406  		if row != 3+i { // 'pi' rule stats on row 3
  2407  			t.Fatalf("expected rule head %v row to be %v but got %v", module.Rules[i].Head.Name, 3+i, row)
  2408  		}
  2409  	}
  2410  
  2411  	mockModule := `package ex
  2412  
  2413  input = {"foo": 1}
  2414  data = {"bar": 2}`
  2415  
  2416  	assertParseModule(t, "rule name: input/data", mockModule, &Module{
  2417  		Package: MustParsePackage(`package ex`),
  2418  		Rules: []*Rule{
  2419  			MustParseRule(`input = {"foo": 1} { true }`),
  2420  			MustParseRule(`data = {"bar": 2} { true }`),
  2421  		},
  2422  	})
  2423  
  2424  	multipleExprs := `
  2425      package a.b.c
  2426  
  2427      pi = 3.14159; pi > 3
  2428      `
  2429  
  2430  	nonEquality := `
  2431      package a.b.c
  2432  
  2433      pi > 3
  2434      `
  2435  
  2436  	nonVarName := `
  2437      package a.b.c
  2438  
  2439      "pi" = 3
  2440      `
  2441  
  2442  	withExpr := `
  2443  	package a.b.c
  2444  
  2445  	foo = input with input as 1
  2446  	`
  2447  
  2448  	badRefLen1 := `
  2449  	package a.b.c
  2450  
  2451  	p["x"].y = 1`
  2452  
  2453  	badRefLen2 := `
  2454  	package a.b.c
  2455  
  2456  	p["x"].y`
  2457  
  2458  	negated := `
  2459  	package a.b.c
  2460  
  2461  	not p = 1`
  2462  
  2463  	nonRefTerm := `
  2464  	package a.b.c
  2465  
  2466  	p`
  2467  
  2468  	zeroArgs := `
  2469  	package a.b.c
  2470  
  2471  	p()`
  2472  
  2473  	assignToTerm := `
  2474  	package a.b.c
  2475  
  2476  	"foo" := 1`
  2477  
  2478  	someDecl := `
  2479  	package a
  2480  
  2481  	some x`
  2482  
  2483  	arrayTerm := `
  2484  	package a
  2485  	[][0]
  2486  	`
  2487  
  2488  	callWithRuleKeyPartialSet := `
  2489  	package a
  2490  	f(x)[x] { true }`
  2491  
  2492  	callWithRuleKeyPartialObject := `
  2493  	package a
  2494  	f(x)[x] = x { true }`
  2495  
  2496  	assignNoOperands := `
  2497  	package a
  2498  	assign()`
  2499  
  2500  	assignOneOperand := `
  2501  	package a
  2502  	assign(x)`
  2503  
  2504  	eqNoOperands := `
  2505  	package a
  2506  	eq()`
  2507  
  2508  	eqOneOperand := `
  2509  	package a
  2510  	eq(x)`
  2511  
  2512  	assertParseModuleError(t, "multiple expressions", multipleExprs)
  2513  	assertParseModuleError(t, "non-equality", nonEquality)
  2514  	assertParseModuleError(t, "non-var name", nonVarName)
  2515  	assertParseModuleError(t, "with expr", withExpr)
  2516  	assertParseModuleError(t, "bad ref (too long)", badRefLen1)
  2517  	assertParseModuleError(t, "bad ref (too long)", badRefLen2)
  2518  	assertParseModuleError(t, "negated", negated)
  2519  	assertParseModuleError(t, "non ref term", nonRefTerm)
  2520  	assertParseModuleError(t, "zero args", zeroArgs)
  2521  	assertParseModuleError(t, "assign to term", assignToTerm)
  2522  	assertParseModuleError(t, "some decl", someDecl)
  2523  	assertParseModuleError(t, "array term", arrayTerm)
  2524  	assertParseModuleError(t, "call in ref partial set", "package test\nf().x {}")
  2525  	assertParseModuleError(t, "call in ref partial object", "package test\nf().x = y {}")
  2526  	assertParseModuleError(t, "number in ref", "package a\n12[3]()=4")
  2527  	assertParseModuleError(t, "rule with args and key", callWithRuleKeyPartialObject)
  2528  	assertParseModuleError(t, "rule with args and key", callWithRuleKeyPartialSet)
  2529  	assertParseModuleError(t, "assign without operands", assignNoOperands)
  2530  	assertParseModuleError(t, "assign with only one operand", assignOneOperand)
  2531  	assertParseModuleError(t, "eq without operands", eqNoOperands)
  2532  	assertParseModuleError(t, "eq with only one operand", eqOneOperand)
  2533  
  2534  	if _, err := ParseRuleFromExpr(&Module{}, &Expr{
  2535  		Terms: struct{}{},
  2536  	}); err == nil {
  2537  		t.Fatal("expected error for unknown expression term type")
  2538  	}
  2539  }
  2540  
  2541  func TestWildcards(t *testing.T) {
  2542  
  2543  	assertParseOneTerm(t, "ref", "a.b[_].c[_]", RefTerm(
  2544  		VarTerm("a"),
  2545  		StringTerm("b"),
  2546  		VarTerm("$0"),
  2547  		StringTerm("c"),
  2548  		VarTerm("$1"),
  2549  	))
  2550  
  2551  	assertParseOneTerm(t, "nested", `[{"a": a[_]}, _, {"b": _}]`, ArrayTerm(
  2552  		ObjectTerm(
  2553  			Item(StringTerm("a"), RefTerm(VarTerm("a"), VarTerm("$0"))),
  2554  		),
  2555  		VarTerm("$1"),
  2556  		ObjectTerm(
  2557  			Item(StringTerm("b"), VarTerm("$2")),
  2558  		),
  2559  	))
  2560  
  2561  	assertParseOneExpr(t, "expr", `_ = [a[_]]`, Equality.Expr(
  2562  		VarTerm("$0"),
  2563  		ArrayTerm(
  2564  			RefTerm(VarTerm("a"), VarTerm("$1")),
  2565  		)))
  2566  
  2567  	assertParseOneExpr(t, "comprehension", `_ = [x | a = a[_]]`, Equality.Expr(
  2568  		VarTerm("$0"),
  2569  		ArrayComprehensionTerm(
  2570  			VarTerm("x"),
  2571  			NewBody(
  2572  				Equality.Expr(
  2573  					VarTerm("a"),
  2574  					RefTerm(VarTerm("a"), VarTerm("$1")),
  2575  				),
  2576  			),
  2577  		)))
  2578  
  2579  	assertParseRule(t, "functions", `f(_) = y { true }`, &Rule{
  2580  		Head: &Head{
  2581  			Name: Var("f"),
  2582  			Args: Args{
  2583  				VarTerm("$0"),
  2584  			},
  2585  			Value: VarTerm("y"),
  2586  		},
  2587  		Body: NewBody(NewExpr(BooleanTerm(true))),
  2588  	})
  2589  }
  2590  
  2591  func TestRuleModulePtr(t *testing.T) {
  2592  	mod := `package test
  2593  
  2594  	p { true }
  2595  	p { true }
  2596  	q { true }
  2597  	r = 1
  2598  	default s = 2
  2599  	`
  2600  
  2601  	parsed, err := ParseModule("", mod)
  2602  	if err != nil {
  2603  		t.Fatalf("Unexpected parse error: %v", err)
  2604  	}
  2605  
  2606  	for _, rule := range parsed.Rules {
  2607  		if rule.Module != parsed {
  2608  			t.Fatalf("Expected module ptr to be %p but got %p", parsed, rule.Module)
  2609  		}
  2610  	}
  2611  }
  2612  
  2613  func TestNoMatchError(t *testing.T) {
  2614  	mod := `package test
  2615  
  2616  	p { true;
  2617  		 1 != 0; # <-- parse error: no match
  2618  	}`
  2619  
  2620  	_, err := ParseModule("foo.rego", mod)
  2621  
  2622  	expected := "1 error occurred: foo.rego:5: rego_parse_error: unexpected } token"
  2623  
  2624  	if !strings.HasPrefix(err.Error(), expected) {
  2625  		t.Fatalf("Bad parse error, expected %v but got: %v", expected, err)
  2626  	}
  2627  
  2628  	mod = `package test
  2629  
  2630  	p { true // <-- parse error: no match`
  2631  
  2632  	_, err = ParseModule("foo.rego", mod)
  2633  
  2634  	loc := NewLocation([]byte{'/'}, "foo.rego", 3, 12)
  2635  
  2636  	if !loc.Equal(err.(Errors)[0].Location) {
  2637  		t.Fatalf("Expected %v but got: %v", loc, err)
  2638  	}
  2639  }
  2640  
  2641  func TestBraceBracketParenMatchingErrors(t *testing.T) {
  2642  	// Checks to prevent regression on issue #4672.
  2643  	// Error location is important here, which is why we check
  2644  	// the error strings directly.
  2645  	tests := []struct {
  2646  		note  string
  2647  		err   string
  2648  		input string
  2649  	}{
  2650  		{
  2651  			note: "Unmatched ')' case",
  2652  			err: `1 error occurred: test.rego:4: rego_parse_error: unexpected , token: expected \n or ; or }
  2653  	y := contains("a"), "b")
  2654  	                  ^`,
  2655  			input: `package test
  2656  p {
  2657  	x := 5
  2658  	y := contains("a"), "b")
  2659  }`,
  2660  		},
  2661  		{
  2662  			note: "Unmatched '}' case",
  2663  			err: `1 error occurred: test.rego:4: rego_parse_error: unexpected , token: expected \n or ; or }
  2664  	y := {"a", "b", "c"}, "a"}
  2665  	                    ^`,
  2666  			input: `package test
  2667  p {
  2668  	x := 5
  2669  	y := {"a", "b", "c"}, "a"}
  2670  }`,
  2671  		},
  2672  		{
  2673  			note: "Unmatched ']' case",
  2674  			err: `1 error occurred: test.rego:4: rego_parse_error: unexpected , token: expected \n or ; or }
  2675  	y := ["a", "b", "c"], "a"]
  2676  	                    ^`,
  2677  			input: `package test
  2678  p {
  2679  	x := 5
  2680  	y := ["a", "b", "c"], "a"]
  2681  }`,
  2682  		},
  2683  		{
  2684  			note: "Unmatched '(' case",
  2685  			err: `1 error occurred: test.rego:5: rego_parse_error: unexpected } token: expected "," or ")"
  2686  	}
  2687  	^`,
  2688  			input: `package test
  2689  p {
  2690  	x := 5
  2691  	y := contains("a", "b"
  2692  }`,
  2693  		},
  2694  		{
  2695  			note: "Unmatched '{' case",
  2696  
  2697  			err: `1 error occurred: test.rego:5: rego_parse_error: unexpected eof token: expected \n or ; or }
  2698  	}
  2699  	^`,
  2700  			input: `package test
  2701  p {
  2702  	x := 5
  2703  	y := {{"a", "b", "c"}, "a"
  2704  }`,
  2705  		},
  2706  		{
  2707  			note: "Unmatched '[' case",
  2708  			err: `1 error occurred: test.rego:5: rego_parse_error: unexpected } token: expected "," or "]"
  2709  	}
  2710  	^`,
  2711  			input: `package test
  2712  p {
  2713  	x := 5
  2714  	y := [["a", "b", "c"], "a"
  2715  }`,
  2716  		},
  2717  	}
  2718  
  2719  	for _, tc := range tests {
  2720  		t.Run(tc.note, func(t *testing.T) {
  2721  			_, err := ParseModule("test.rego", tc.input)
  2722  			if err == nil {
  2723  				t.Fatal("Expected error")
  2724  			}
  2725  			if tc.err != "" && tc.err != err.Error() {
  2726  				t.Fatalf("Expected error string %q but got: %q", tc.err, err.Error())
  2727  			}
  2728  		})
  2729  	}
  2730  }
  2731  
  2732  func TestParseErrorDetails(t *testing.T) {
  2733  
  2734  	tests := []struct {
  2735  		note  string
  2736  		exp   *ParserErrorDetail
  2737  		err   string
  2738  		input string
  2739  	}{
  2740  		{
  2741  			note: "no match: bad rule name",
  2742  			exp: &ParserErrorDetail{
  2743  				Line: ".",
  2744  				Idx:  0,
  2745  			},
  2746  			input: `
  2747  package test
  2748  .`,
  2749  		},
  2750  		{
  2751  			note: "no match: bad termination for comprehension",
  2752  			exp: &ParserErrorDetail{
  2753  				Line: "p = [true | true}",
  2754  				Idx:  16,
  2755  			},
  2756  			input: `
  2757  package test
  2758  p = [true | true}`},
  2759  		{
  2760  			note: "no match: non-terminated comprehension",
  2761  			exp: &ParserErrorDetail{
  2762  				Line: "p = [true | true",
  2763  				Idx:  15,
  2764  			},
  2765  			input: `
  2766  package test
  2767  p = [true | true`},
  2768  		{
  2769  			note: "no match: expected expression",
  2770  			exp: &ParserErrorDetail{
  2771  				Line: "p { true; }",
  2772  				Idx:  10,
  2773  			},
  2774  			input: `
  2775  package test
  2776  p { true; }`},
  2777  		{
  2778  			note: "empty body",
  2779  			exp: &ParserErrorDetail{
  2780  				Line: "p { }",
  2781  				Idx:  4,
  2782  			},
  2783  			input: `
  2784  package test
  2785  p { }`},
  2786  		{
  2787  			note: "non-terminated string",
  2788  			exp: &ParserErrorDetail{
  2789  				Line: `p = "foo`,
  2790  				Idx:  4,
  2791  			},
  2792  			input: `
  2793  package test
  2794  p = "foo`},
  2795  		{
  2796  			note: "rule with error begins with one tab",
  2797  			exp: &ParserErrorDetail{
  2798  				Line: "\tas",
  2799  				Idx:  1,
  2800  			},
  2801  			input: `
  2802  package test
  2803  	as`,
  2804  			err: `1 error occurred: test.rego:3: rego_parse_error: unexpected as keyword
  2805  	as
  2806  	^`},
  2807  		{
  2808  			note: "rule term with error begins with two tabs",
  2809  			exp: &ParserErrorDetail{
  2810  				Line: "\t\tas",
  2811  				Idx:  2,
  2812  			},
  2813  			input: `
  2814  package test
  2815  p = true {
  2816  		as
  2817  }`,
  2818  			err: `1 error occurred: test.rego:4: rego_parse_error: unexpected as keyword
  2819  	as
  2820  	^`},
  2821  		{
  2822  			note: "input is tab and space tokens only",
  2823  			exp: &ParserErrorDetail{
  2824  				Line: "\t\v\f ",
  2825  				Idx:  0,
  2826  			},
  2827  			input: "\t\v\f ",
  2828  			// NOTE(sr): With the unprintable control characters, the output is pretty
  2829  			// useless. But it's also quite an edge case.
  2830  			err: "1 error occurred: test.rego:1: rego_parse_error: illegal token\n\t\v\f \n\t^",
  2831  		},
  2832  	}
  2833  
  2834  	for _, tc := range tests {
  2835  		t.Run(tc.note, func(t *testing.T) {
  2836  			_, err := ParseModule("test.rego", tc.input)
  2837  			if err == nil {
  2838  				t.Fatal("Expected error")
  2839  			}
  2840  			detail := err.(Errors)[0].Details
  2841  			if !reflect.DeepEqual(detail, tc.exp) {
  2842  				t.Errorf("Expected %v but got: %v", tc.exp, detail)
  2843  			}
  2844  			if tc.err != "" && tc.err != err.Error() {
  2845  				t.Fatalf("Expected error string %q but got: %q", tc.err, err.Error())
  2846  			}
  2847  		})
  2848  	}
  2849  }
  2850  
  2851  func TestNamespacedBuiltins(t *testing.T) {
  2852  
  2853  	tests := []struct {
  2854  		expr     string
  2855  		expected *Term
  2856  		wantErr  bool
  2857  	}{
  2858  		{`foo.bar.baz(1, 2)`, MustParseTerm("foo.bar.baz"), false},
  2859  		{`foo.(1,2)`, nil, true},
  2860  		{`foo.#.bar(1,2)`, nil, true},
  2861  	}
  2862  
  2863  	for _, tc := range tests {
  2864  		expr, err := ParseExpr(tc.expr)
  2865  		if !tc.wantErr {
  2866  			if err != nil {
  2867  				t.Fatalf("Unexpected parse error: %v", err)
  2868  			}
  2869  			terms, ok := expr.Terms.([]*Term)
  2870  			if !ok {
  2871  				t.Fatalf("Expected terms not: %T", expr.Terms)
  2872  			}
  2873  			if !terms[0].Equal(tc.expected) {
  2874  				t.Fatalf("Expected builtin-name to equal %v but got: %v", tc.expected, terms)
  2875  			}
  2876  		} else if err == nil {
  2877  			t.Fatalf("Expected error from %v but got: %v", tc.expr, expr)
  2878  		}
  2879  	}
  2880  }
  2881  
  2882  func TestRuleHeadLocation(t *testing.T) {
  2883  
  2884  	const input = `package pkg
  2885  
  2886  p[x] {
  2887  	x = "hi"
  2888  } {
  2889  	x = "bye"
  2890  }
  2891  
  2892  f(x) {
  2893  	false
  2894  } else = false {
  2895  	true
  2896  }
  2897  `
  2898  
  2899  	module := MustParseModule(input)
  2900  
  2901  	for _, tc := range []struct {
  2902  		note         string
  2903  		location     *Location
  2904  		expectedRow  int
  2905  		expectedText string
  2906  	}{
  2907  		{
  2908  			note:        "partial rule",
  2909  			location:    module.Rules[0].Location,
  2910  			expectedRow: 3,
  2911  			expectedText: `
  2912  p[x] {
  2913  	x = "hi"
  2914  }
  2915  			`,
  2916  		},
  2917  		{
  2918  			note:         "partial rule head",
  2919  			location:     module.Rules[0].Head.Location,
  2920  			expectedRow:  3,
  2921  			expectedText: `p[x]`,
  2922  		},
  2923  		{
  2924  			note:         "partial rule head key",
  2925  			location:     module.Rules[0].Head.Key.Location,
  2926  			expectedRow:  3,
  2927  			expectedText: `x`,
  2928  		},
  2929  		{
  2930  			note:        "chained rule",
  2931  			location:    module.Rules[1].Location,
  2932  			expectedRow: 5,
  2933  			expectedText: `
  2934  {
  2935  	x = "bye"
  2936  }
  2937  			`,
  2938  		},
  2939  		{
  2940  			note:        "chained rule head",
  2941  			location:    module.Rules[1].Head.Location,
  2942  			expectedRow: 5,
  2943  			expectedText: `
  2944  {
  2945  	x = "bye"
  2946  }
  2947  			`,
  2948  		},
  2949  		{
  2950  			note:        "chained rule head key",
  2951  			location:    module.Rules[1].Head.Key.Location,
  2952  			expectedRow: 5,
  2953  			expectedText: `
  2954  {
  2955  	x = "bye"
  2956  }
  2957  			`,
  2958  		},
  2959  		{
  2960  			note:        "rule with args",
  2961  			location:    module.Rules[2].Location,
  2962  			expectedRow: 9,
  2963  			expectedText: `
  2964  f(x) {
  2965  	false
  2966  } else = false {
  2967  	true
  2968  }
  2969  			`,
  2970  		},
  2971  		{
  2972  			note:         "rule with args head",
  2973  			location:     module.Rules[2].Head.Location,
  2974  			expectedRow:  9,
  2975  			expectedText: `f(x)`,
  2976  		},
  2977  		{
  2978  			note:         "rule with args head arg 0",
  2979  			location:     module.Rules[2].Head.Args[0].Location,
  2980  			expectedRow:  9,
  2981  			expectedText: `x`,
  2982  		},
  2983  		{
  2984  			note:        "else with args",
  2985  			location:    module.Rules[2].Else.Location,
  2986  			expectedRow: 11,
  2987  			expectedText: `
  2988  else = false {
  2989  	true
  2990  }
  2991  			`,
  2992  		},
  2993  		{
  2994  			note:         "else with args head",
  2995  			location:     module.Rules[2].Else.Head.Location,
  2996  			expectedRow:  11,
  2997  			expectedText: `else = false`,
  2998  		},
  2999  		{
  3000  			note:         "else with args head arg 0",
  3001  			location:     module.Rules[2].Else.Head.Args[0].Location,
  3002  			expectedRow:  9,
  3003  			expectedText: `x`,
  3004  		},
  3005  	} {
  3006  		t.Run(tc.note, func(t *testing.T) {
  3007  			if tc.location.Row != tc.expectedRow {
  3008  				t.Errorf("Expected %d but got %d", tc.expectedRow, tc.location.Row)
  3009  			}
  3010  			exp := strings.TrimSpace(tc.expectedText)
  3011  			if string(tc.location.Text) != exp {
  3012  				t.Errorf("Expected text:\n%s\n\ngot:\n%s\n\n", exp, tc.location.Text)
  3013  			}
  3014  		})
  3015  	}
  3016  }
  3017  
  3018  func TestParserText(t *testing.T) {
  3019  
  3020  	tests := []struct {
  3021  		note  string
  3022  		input string
  3023  		want  string
  3024  	}{
  3025  		{
  3026  			note:  "relational term",
  3027  			input: `(1 == (2 > 3))`,
  3028  		},
  3029  		{
  3030  			note:  "array - empty",
  3031  			input: `[ ]`,
  3032  		},
  3033  		{
  3034  			note:  "array - one element",
  3035  			input: `[ 1 ]`,
  3036  		},
  3037  		{
  3038  			note:  "array - multiple elements",
  3039  			input: `[1 , 2 , 3]`,
  3040  		},
  3041  		{
  3042  			note:  "object - empty",
  3043  			input: `{ }`,
  3044  		},
  3045  		{
  3046  			note:  "object - one element",
  3047  			input: `{ "foo": 1 }`,
  3048  		},
  3049  		{
  3050  			note:  "object - multiple elements",
  3051  			input: `{"foo": 1, "bar": 2}`,
  3052  		},
  3053  		{
  3054  			note:  "set - one element",
  3055  			input: `{ 1 }`,
  3056  		},
  3057  		{
  3058  			note:  "set - multiple elements",
  3059  			input: `{1 , 2 , 3}`,
  3060  		},
  3061  		{
  3062  			note:  "idents",
  3063  			input: "foo",
  3064  		},
  3065  		{
  3066  			note:  "ref",
  3067  			input: `data.foo[x].bar`,
  3068  		},
  3069  		{
  3070  			note:  "call",
  3071  			input: `data.foo.bar(x)`,
  3072  		},
  3073  		{
  3074  			note:  "ref and call",
  3075  			input: `data.foo[1](x).bar(y)[z]`,
  3076  		},
  3077  		{
  3078  			note:  "infix",
  3079  			input: "input = 1",
  3080  		},
  3081  		{
  3082  			note:  "negated",
  3083  			input: "not x = 1",
  3084  		},
  3085  		{
  3086  			note:  "expr with statements",
  3087  			input: "x = 1 with input as 2 with input as 3",
  3088  		},
  3089  	}
  3090  
  3091  	for _, tc := range tests {
  3092  		t.Run(tc.note, func(t *testing.T) {
  3093  			for _, suffix := range []string{"", "\t\n "} {
  3094  				input := tc.input + suffix
  3095  
  3096  				stmts, _, err := ParseStatements("test.rego", input)
  3097  				if err != nil {
  3098  					t.Fatal(err)
  3099  				}
  3100  
  3101  				if len(stmts) != 1 {
  3102  					t.Fatal("expected exactly one statement but got:", stmts)
  3103  				}
  3104  
  3105  				result := string(stmts[0].Loc().Text)
  3106  
  3107  				if result != tc.input {
  3108  					t.Fatalf("expected %q but got: %q", tc.input, result)
  3109  				}
  3110  			}
  3111  		})
  3112  	}
  3113  }
  3114  
  3115  func TestRuleText(t *testing.T) {
  3116  	input := ` package test
  3117  
  3118  r[x] = y {
  3119  	x = input.a
  3120  	x = "foo"
  3121  } {
  3122  	x = input.b
  3123  	x = "bar"
  3124  } {
  3125  	x = input.c
  3126  	x = "baz"
  3127  }
  3128  
  3129  r[x] = y {
  3130  	x = input.d
  3131  	x = "qux"
  3132  }
  3133  `
  3134  
  3135  	mod := MustParseModule(input)
  3136  	rules := mod.Rules
  3137  
  3138  	if len(rules) != 4 {
  3139  		t.Fatalf("Expected 4 rules, got %d", len(rules))
  3140  	}
  3141  
  3142  	expectedRuleText := []string{
  3143  		`
  3144  r[x] = y {
  3145  	x = input.a
  3146  	x = "foo"
  3147  }
  3148  		`,
  3149  		`
  3150  {
  3151  	x = input.b
  3152  	x = "bar"
  3153  }
  3154  		`,
  3155  		`
  3156  {
  3157  	x = input.c
  3158  	x = "baz"
  3159  }
  3160  		`,
  3161  		`
  3162  r[x] = y {
  3163  	x = input.d
  3164  	x = "qux"
  3165  }
  3166  		`,
  3167  	}
  3168  
  3169  	assertLocationText(t, strings.TrimSpace(expectedRuleText[0]), rules[0].Location)
  3170  	assertLocationText(t, "r[x] = y", rules[0].Head.Location)
  3171  	assertLocationText(t, "y", rules[0].Head.Value.Location)
  3172  
  3173  	// Chained rules recursively set text on heads to be the full rule
  3174  	for i := 1; i < len(expectedRuleText)-1; i++ {
  3175  		text := strings.TrimSpace(expectedRuleText[i])
  3176  		assertLocationText(t, text, rules[i].Location)
  3177  		assertLocationText(t, text, rules[i].Head.Location)
  3178  		assertLocationText(t, text, rules[i].Head.Value.Location)
  3179  	}
  3180  
  3181  	assertLocationText(t, strings.TrimSpace(expectedRuleText[3]), rules[3].Location)
  3182  	assertLocationText(t, "r[x] = y", rules[3].Head.Location)
  3183  	assertLocationText(t, "y", rules[3].Head.Value.Location)
  3184  }
  3185  
  3186  func TestRuleElseText(t *testing.T) {
  3187  	input := `
  3188  r1 = x {
  3189  	a == "foo"
  3190  } else = y {
  3191  	b == "bar"
  3192  }
  3193  
  3194  else {
  3195  	c == "baz"
  3196  }
  3197  
  3198  else = {
  3199  	"k1": 1,
  3200  	"k2": 2
  3201  } {
  3202  	true
  3203  }
  3204  `
  3205  
  3206  	rule := MustParseRule(input)
  3207  	assertLocationText(t, strings.TrimSpace(input), rule.Location)
  3208  	assertLocationText(t, "r1 = x", rule.Head.Location)
  3209  	assertLocationText(t, "x", rule.Head.Value.Location)
  3210  
  3211  	curElse := rule.Else
  3212  	if curElse == nil {
  3213  		t.Fatalf("Expected an else block, got nil")
  3214  	}
  3215  	assertLocationText(t, strings.TrimSpace(`
  3216  else = y {
  3217  	b == "bar"
  3218  }
  3219  
  3220  else {
  3221  	c == "baz"
  3222  }
  3223  
  3224  else = {
  3225  	"k1": 1,
  3226  	"k2": 2
  3227  } {
  3228  	true
  3229  }
  3230  	`), curElse.Location)
  3231  	assertLocationText(t, "else = y", curElse.Head.Location)
  3232  	assertLocationText(t, "y", curElse.Head.Value.Location)
  3233  
  3234  	curElse = curElse.Else
  3235  	if curElse == nil {
  3236  		t.Fatalf("Expected an else block, got nil")
  3237  	}
  3238  	assertLocationText(t, strings.TrimSpace(`
  3239  else {
  3240  	c == "baz"
  3241  }
  3242  
  3243  else = {
  3244  	"k1": 1,
  3245  	"k2": 2
  3246  } {
  3247  	true
  3248  }
  3249  	`), curElse.Location)
  3250  	assertLocationText(t, "else", curElse.Head.Location)
  3251  	if curElse.Head.Value.Location != nil {
  3252  		t.Errorf("Expected a nil location")
  3253  	}
  3254  
  3255  	curElse = curElse.Else
  3256  	if curElse == nil {
  3257  		t.Fatalf("Expected an else block, got nil")
  3258  	}
  3259  	assertLocationText(t, strings.TrimSpace(`
  3260  else = {
  3261  	"k1": 1,
  3262  	"k2": 2
  3263  } {
  3264  	true
  3265  }
  3266  	`), curElse.Location)
  3267  	assertLocationText(t, strings.TrimSpace(`
  3268  else = {
  3269  	"k1": 1,
  3270  	"k2": 2
  3271  }
  3272  	`), curElse.Head.Location)
  3273  	assertLocationText(t, strings.TrimSpace(`
  3274  {
  3275  	"k1": 1,
  3276  	"k2": 2
  3277  }
  3278  	`), curElse.Head.Value.Location)
  3279  }
  3280  
  3281  func TestAnnotations(t *testing.T) {
  3282  
  3283  	dataServers := MustParseRef("data.servers")
  3284  	dataNetworks := MustParseRef("data.networks")
  3285  	dataPorts := MustParseRef("data.ports")
  3286  
  3287  	schemaServers := MustParseRef("schema.servers")
  3288  	schemaNetworks := MustParseRef("schema.networks")
  3289  	schemaPorts := MustParseRef("schema.ports")
  3290  
  3291  	stringSchemaAsMap := map[string]interface{}{
  3292  		"type": "string",
  3293  	}
  3294  	var stringSchema interface{} = stringSchemaAsMap
  3295  
  3296  	tests := []struct {
  3297  		note           string
  3298  		module         string
  3299  		expNumComments int
  3300  		expAnnotations []*Annotations
  3301  		expError       string
  3302  	}{
  3303  		{
  3304  			note: "Single valid annotation",
  3305  			module: `
  3306  package opa.examples
  3307  
  3308  import data.servers
  3309  import data.networks
  3310  import data.ports
  3311  
  3312  # METADATA
  3313  # scope: rule
  3314  # schemas:
  3315  #   - data.servers: schema.servers
  3316  public_servers[server] {
  3317  	server = servers[i]; server.ports[j] = ports[k].id
  3318  	ports[k].networks[l] = networks[m].id;
  3319  	networks[m].public = true
  3320  }`,
  3321  			expNumComments: 4,
  3322  			expAnnotations: []*Annotations{
  3323  				{
  3324  					Schemas: []*SchemaAnnotation{
  3325  						{Path: dataServers, Schema: schemaServers},
  3326  					},
  3327  					Scope: annotationScopeRule,
  3328  				},
  3329  			},
  3330  		},
  3331  		{
  3332  			note: "Multiple annotations on multiple lines",
  3333  			module: `
  3334  package opa.examples
  3335  
  3336  import data.servers
  3337  import data.networks
  3338  import data.ports
  3339  
  3340  # METADATA
  3341  # scope: rule
  3342  # schemas:
  3343  #   - data.servers: schema.servers
  3344  #   - data.networks: schema.networks
  3345  #   - data.ports: schema.ports
  3346  public_servers[server] {
  3347  	server = servers[i]; server.ports[j] = ports[k].id
  3348  	ports[k].networks[l] = networks[m].id;
  3349  	networks[m].public = true
  3350  }`,
  3351  			expNumComments: 6,
  3352  			expAnnotations: []*Annotations{
  3353  				{
  3354  					Schemas: []*SchemaAnnotation{
  3355  						{Path: dataServers, Schema: schemaServers},
  3356  						{Path: dataNetworks, Schema: schemaNetworks},
  3357  						{Path: dataPorts, Schema: schemaPorts},
  3358  					},
  3359  					Scope: annotationScopeRule,
  3360  				},
  3361  			},
  3362  		},
  3363  		{
  3364  			note: "Comment in between metadata and rule (valid)",
  3365  			module: `
  3366  package opa.examples
  3367  
  3368  import data.servers
  3369  import data.networks
  3370  import data.ports
  3371  
  3372  # METADATA
  3373  # scope: rule
  3374  # schemas:
  3375  #   - data.servers: schema.servers
  3376  #   - data.networks: schema.networks
  3377  #   - data.ports: schema.ports
  3378  
  3379  # This is a comment after the metadata YAML
  3380  public_servers[server] {
  3381  	server = servers[i]; server.ports[j] = ports[k].id
  3382  	ports[k].networks[l] = networks[m].id;
  3383  	networks[m].public = true
  3384  }`,
  3385  			expNumComments: 7,
  3386  			expAnnotations: []*Annotations{
  3387  				{
  3388  					Schemas: []*SchemaAnnotation{
  3389  						{Path: dataServers, Schema: schemaServers},
  3390  						{Path: dataNetworks, Schema: schemaNetworks},
  3391  						{Path: dataPorts, Schema: schemaPorts},
  3392  					},
  3393  					Scope: annotationScopeRule,
  3394  				},
  3395  			},
  3396  		},
  3397  		{
  3398  			note: "Empty comment line in between metadata and rule (valid)",
  3399  			module: `
  3400  package opa.examples
  3401  
  3402  import data.servers
  3403  import data.networks
  3404  import data.ports
  3405  
  3406  # METADATA
  3407  # scope: rule
  3408  # schemas:
  3409  #   - data.servers: schema.servers
  3410  #   - data.networks: schema.networks
  3411  #   - data.ports: schema.ports
  3412  #
  3413  public_servers[server] {
  3414  	server = servers[i]; server.ports[j] = ports[k].id
  3415  	ports[k].networks[l] = networks[m].id;
  3416  	networks[m].public = true
  3417  }`,
  3418  			expNumComments: 7,
  3419  			expAnnotations: []*Annotations{
  3420  				{
  3421  					Schemas: []*SchemaAnnotation{
  3422  						{Path: dataServers, Schema: schemaServers},
  3423  						{Path: dataNetworks, Schema: schemaNetworks},
  3424  						{Path: dataPorts, Schema: schemaPorts},
  3425  					},
  3426  					Scope: annotationScopeRule,
  3427  				},
  3428  			},
  3429  		},
  3430  		{
  3431  			note: "Ill-structured (invalid) metadata start",
  3432  			module: `
  3433  package opa.examples
  3434  
  3435  import data.servers
  3436  import data.networks
  3437  import data.ports
  3438  
  3439  # METADATA
  3440  # scope: rule
  3441  # schemas:
  3442  #   - data.servers: schema.servers
  3443  #   - data.networks: schema.networks
  3444  #   - data.ports: schema.ports
  3445  # METADATA
  3446  public_servers[server] {
  3447  	server = servers[i]; server.ports[j] = ports[k].id
  3448  	ports[k].networks[l] = networks[m].id;
  3449  	networks[m].public = true
  3450  }`,
  3451  			expError: "test.rego:14: rego_parse_error: yaml: line 7: could not find expected ':'",
  3452  		},
  3453  		{
  3454  			note: "Ill-structured (invalid) annotation document path",
  3455  			module: `
  3456  package opa.examples
  3457  
  3458  import data.servers
  3459  import data.networks
  3460  import data.ports
  3461  
  3462  # METADATA
  3463  # scope: rule
  3464  # schemas:
  3465  #   - data/servers: schema.servers
  3466  public_servers[server] {
  3467  	server = servers[i]; server.ports[j] = ports[k].id
  3468  	ports[k].networks[l] = networks[m].id;
  3469  	networks[m].public = true
  3470  }`,
  3471  			expNumComments: 4,
  3472  			expError:       "rego_parse_error: invalid document reference",
  3473  		},
  3474  		{
  3475  			note: "Ill-structured (invalid) annotation schema path",
  3476  			module: `
  3477  package opa.examples
  3478  
  3479  import data.servers
  3480  import data.networks
  3481  import data.ports
  3482  
  3483  # METADATA
  3484  # scope: rule
  3485  # schemas:
  3486  #   - data.servers: schema/servers
  3487  public_servers[server] {
  3488  	server = servers[i]; server.ports[j] = ports[k].id
  3489  	ports[k].networks[l] = networks[m].id;
  3490  	networks[m].public = true
  3491  }`,
  3492  			expNumComments: 4,
  3493  			expError:       "rego_parse_error: invalid schema reference",
  3494  		},
  3495  		{
  3496  			note: "Ill-structured (invalid) annotation",
  3497  			module: `
  3498  package opa.examples
  3499  
  3500  import data.servers
  3501  import data.networks
  3502  import data.ports
  3503  
  3504  # METADATA
  3505  # scope: rule
  3506  # schemas:
  3507  #   - data.servers= schema
  3508  public_servers[server] {
  3509  	server = servers[i]; server.ports[j] = ports[k].id
  3510  	ports[k].networks[l] = networks[m].id;
  3511  	networks[m].public = true
  3512  }`,
  3513  			expNumComments: 5,
  3514  			expError:       "rego_parse_error: yaml: unmarshal errors:\n  line 3: cannot unmarshal !!str",
  3515  		},
  3516  		{
  3517  			note: "Indentation error in yaml",
  3518  			module: `
  3519  package opa.examples
  3520  
  3521  import data.servers
  3522  import data.networks
  3523  import data.ports
  3524  
  3525  # METADATA
  3526  # scope: rule
  3527  # schemas:
  3528  # - data.servers: schema.servers
  3529  #   - data.networks: schema.networks
  3530  #   - data.ports: schema.ports
  3531  public_servers[server] {
  3532  	server = servers[i]; server.ports[j] = ports[k].id
  3533  	ports[k].networks[l] = networks[m].id;
  3534  	networks[m].public = true
  3535  }`,
  3536  			expNumComments: 6,
  3537  			expError:       "rego_parse_error: yaml: line 3: did not find expected key",
  3538  		},
  3539  		{
  3540  			note: "Multiple rules with and without metadata",
  3541  			module: `
  3542  package opa.examples
  3543  
  3544  import data.servers
  3545  import data.networks
  3546  import data.ports
  3547  
  3548  # METADATA
  3549  # scope: rule
  3550  # schemas:
  3551  #   - data.servers: schema.servers
  3552  #   - data.networks: schema.networks
  3553  #   - data.ports: schema.ports
  3554  public_servers[server] {
  3555  	server = servers[i]; server.ports[j] = ports[k].id
  3556  	ports[k].networks[l] = networks[m].id;
  3557  	networks[m].public = true
  3558  }
  3559  
  3560  public_servers_1[server] {
  3561  	server = servers[i]; server.ports[j] = ports[k].id
  3562  	ports[k].networks[l] = networks[m].id;
  3563  	networks[m].public = true
  3564  	server.typo  # won't catch this type error since rule has no schema metadata
  3565  }`,
  3566  			expNumComments: 7,
  3567  			expAnnotations: []*Annotations{
  3568  				{
  3569  					Schemas: []*SchemaAnnotation{
  3570  						{Path: dataServers, Schema: schemaServers},
  3571  						{Path: dataNetworks, Schema: schemaNetworks},
  3572  						{Path: dataPorts, Schema: schemaPorts},
  3573  					},
  3574  					Scope: annotationScopeRule,
  3575  				},
  3576  			},
  3577  		},
  3578  		{
  3579  			note: "Multiple rules with metadata",
  3580  			module: `
  3581  package opa.examples
  3582  
  3583  import data.servers
  3584  import data.networks
  3585  import data.ports
  3586  
  3587  # METADATA
  3588  # scope: rule
  3589  # schemas:
  3590  #   - data.servers: schema.servers
  3591  public_servers[server] {
  3592  	server = servers[i]
  3593  }
  3594  
  3595  # METADATA
  3596  # scope: rule
  3597  # schemas:
  3598  #   - data.networks: schema.networks
  3599  #   - data.ports: schema.ports
  3600  public_servers_1[server] {
  3601  	ports[k].networks[l] = networks[m].id;
  3602  	networks[m].public = true
  3603  }`,
  3604  			expNumComments: 9,
  3605  			expAnnotations: []*Annotations{
  3606  				{
  3607  					Schemas: []*SchemaAnnotation{
  3608  						{Path: dataServers, Schema: schemaServers},
  3609  					},
  3610  					Scope: annotationScopeRule,
  3611  					node:  MustParseRule(`public_servers[server] { server = servers[i] }`),
  3612  				},
  3613  				{
  3614  					Schemas: []*SchemaAnnotation{
  3615  
  3616  						{Path: dataNetworks, Schema: schemaNetworks},
  3617  						{Path: dataPorts, Schema: schemaPorts},
  3618  					},
  3619  					Scope: annotationScopeRule,
  3620  					node:  MustParseRule(`public_servers_1[server] { ports[k].networks[l] = networks[m].id; networks[m].public = true }`),
  3621  				},
  3622  			},
  3623  		},
  3624  		{
  3625  			note: "multiple metadata blocks on a single rule",
  3626  			module: `package test
  3627  
  3628  # METADATA
  3629  # title: My rule
  3630  
  3631  # METADATA
  3632  # title: My rule 2
  3633  p { input = "str" }`,
  3634  			expNumComments: 4,
  3635  			expAnnotations: []*Annotations{
  3636  				{
  3637  					Scope: annotationScopeRule,
  3638  					Title: "My rule",
  3639  				},
  3640  				{
  3641  					Scope: annotationScopeRule,
  3642  					Title: "My rule 2",
  3643  				},
  3644  			},
  3645  		},
  3646  		{
  3647  			note: "Empty annotation error due to whitespace following METADATA hint",
  3648  			module: `package test
  3649  
  3650  # METADATA
  3651  
  3652  # scope: rule
  3653  p { input.x > 7 }`,
  3654  			expError: "test.rego:3: rego_parse_error: expected METADATA block, found whitespace",
  3655  		},
  3656  		{
  3657  			note: "Annotation on constant",
  3658  			module: `
  3659  package test
  3660  
  3661  # METADATA
  3662  # scope: rule
  3663  p := 7`,
  3664  			expNumComments: 2,
  3665  			expAnnotations: []*Annotations{
  3666  				{Scope: annotationScopeRule},
  3667  			},
  3668  		},
  3669  		{
  3670  			note: "annotation on package",
  3671  			module: `# METADATA
  3672  # title: My package
  3673  package test
  3674  
  3675  p { input = "str" }`,
  3676  			expNumComments: 2,
  3677  			expAnnotations: []*Annotations{
  3678  				{
  3679  					Scope: annotationScopePackage,
  3680  					Title: "My package",
  3681  				},
  3682  			},
  3683  		},
  3684  		{
  3685  			note: "annotation on import",
  3686  			module: `package test
  3687  
  3688  # METADATA
  3689  # title: My import
  3690  import input.foo
  3691  
  3692  p { input = "str" }`,
  3693  			expNumComments: 2,
  3694  			expError:       "1 error occurred: test.rego:3: rego_parse_error: invalid annotation scope 'import'",
  3695  		},
  3696  		{
  3697  			note: "Default rule scope",
  3698  			module: `
  3699  package test
  3700  
  3701  # METADATA
  3702  # {}
  3703  p := 7`,
  3704  			expNumComments: 2,
  3705  			expAnnotations: []*Annotations{
  3706  				{Scope: annotationScopeRule},
  3707  			},
  3708  		},
  3709  		{
  3710  			note: "Unknown scope",
  3711  			module: `
  3712  package test
  3713  
  3714  # METADATA
  3715  # scope: deadbeef
  3716  p := 7`,
  3717  			expNumComments: 2,
  3718  			expError:       "invalid annotation scope 'deadbeef'",
  3719  		},
  3720  		{
  3721  			note: "Invalid rule scope/attachment",
  3722  			module: `
  3723  # METADATA
  3724  # scope: rule
  3725  package test
  3726  
  3727  p := 7`,
  3728  			expNumComments: 2,
  3729  			expError:       "test.rego:2: rego_parse_error: annotation scope 'rule' must be applied to rule (have package)",
  3730  		},
  3731  		{
  3732  			note: "Scope attachment error: document on import",
  3733  			module: `package test
  3734  # METADATA
  3735  # scope: document
  3736  import data.foo.bar`,
  3737  			expError: "test.rego:2: rego_parse_error: annotation scope 'document' must be applied to rule (have import)",
  3738  		},
  3739  		{
  3740  			note: "Scope attachment error: unattached",
  3741  			module: `package test
  3742  
  3743  # METADATA
  3744  # scope: package`,
  3745  			expError: "test.rego:3: rego_parse_error: annotation scope 'package' must be applied to package",
  3746  		},
  3747  		{
  3748  			note: "Scope attachment error: package on non-package",
  3749  			module: `package test
  3750  # METADATA
  3751  # scope: package
  3752  import data.foo`,
  3753  			expError: "test.rego:2: rego_parse_error: annotation scope 'package' must be applied to package (have import)",
  3754  		},
  3755  		{
  3756  			note: "Inline schema definition",
  3757  			module: `package test
  3758  
  3759  # METADATA
  3760  # schemas:
  3761  # - input: {"type": "string"}
  3762  p { input = "str" }`,
  3763  			expNumComments: 3,
  3764  			expAnnotations: []*Annotations{
  3765  				{
  3766  					Schemas: []*SchemaAnnotation{
  3767  						{Path: InputRootRef, Definition: &stringSchema},
  3768  					},
  3769  					Scope: annotationScopeRule,
  3770  				},
  3771  			},
  3772  		},
  3773  		{
  3774  			note: "Rich meta",
  3775  			module: `package test
  3776  
  3777  # METADATA
  3778  # title: My rule
  3779  # description: |
  3780  #  My rule has a
  3781  #  multiline description.
  3782  # organizations:
  3783  # - Acme Corp.
  3784  # - Soylent Corp.
  3785  # - Tyrell Corp.
  3786  # related_resources:
  3787  # - https://example.com
  3788  # - 
  3789  #  ref: http://john:123@do.re/mi?foo=bar#baz
  3790  #  description: foo bar
  3791  # authors:
  3792  # - John Doe <john@example.com>
  3793  # - name: Jane Doe
  3794  #   email: jane@example.com
  3795  # custom:
  3796  #  list:
  3797  #   - a
  3798  #   - b
  3799  #  map:
  3800  #   a: 1
  3801  #   b: 2.2
  3802  #   c:
  3803  #    "3": d
  3804  #    "4": e
  3805  #  number: 42
  3806  #  string: foo bar baz
  3807  #  flag:
  3808  p { input = "str" }`,
  3809  			expNumComments: 31,
  3810  			expAnnotations: []*Annotations{
  3811  				{
  3812  					Scope:         annotationScopeRule,
  3813  					Title:         "My rule",
  3814  					Description:   "My rule has a\nmultiline description.\n",
  3815  					Organizations: []string{"Acme Corp.", "Soylent Corp.", "Tyrell Corp."},
  3816  					RelatedResources: []*RelatedResourceAnnotation{
  3817  						{
  3818  							Ref: mustParseURL("https://example.com"),
  3819  						},
  3820  						{
  3821  							Ref:         mustParseURL("http://john:123@do.re/mi?foo=bar#baz"),
  3822  							Description: "foo bar",
  3823  						},
  3824  					},
  3825  					Authors: []*AuthorAnnotation{
  3826  						{
  3827  							Name:  "John Doe",
  3828  							Email: "john@example.com",
  3829  						},
  3830  						{
  3831  							Name:  "Jane Doe",
  3832  							Email: "jane@example.com",
  3833  						},
  3834  					},
  3835  					Custom: map[string]interface{}{
  3836  						"list": []interface{}{
  3837  							"a", "b",
  3838  						},
  3839  						"map": map[string]interface{}{
  3840  							"a": 1,
  3841  							"b": 2.2,
  3842  							"c": map[string]interface{}{
  3843  								"3": "d",
  3844  								"4": "e",
  3845  							},
  3846  						},
  3847  						"number": 42,
  3848  						"string": "foo bar baz",
  3849  						"flag":   nil,
  3850  					},
  3851  				},
  3852  			},
  3853  		},
  3854  	}
  3855  
  3856  	for _, tc := range tests {
  3857  		t.Run(tc.note, func(t *testing.T) {
  3858  			mod, err := ParseModuleWithOpts("test.rego", tc.module, ParserOptions{
  3859  				ProcessAnnotation: true,
  3860  			})
  3861  			if err != nil {
  3862  				if tc.expError == "" || !strings.Contains(err.Error(), tc.expError) {
  3863  					t.Fatalf("Unexpected parse error when getting annotations: %v", err)
  3864  				}
  3865  				return
  3866  			} else if tc.expError != "" {
  3867  				t.Fatalf("Expected err: %v but no error from parse module", tc.expError)
  3868  			}
  3869  
  3870  			if len(mod.Comments) != tc.expNumComments {
  3871  				t.Fatalf("Expected %v comments but got %v", tc.expNumComments, len(mod.Comments))
  3872  			}
  3873  
  3874  			if annotationsCompare(tc.expAnnotations, mod.Annotations) != 0 {
  3875  				t.Fatalf("expected %v but got %v", tc.expAnnotations, mod.Annotations)
  3876  			}
  3877  		})
  3878  	}
  3879  }
  3880  
  3881  func TestAuthorAnnotation(t *testing.T) {
  3882  	tests := []struct {
  3883  		note     string
  3884  		raw      interface{}
  3885  		expected interface{}
  3886  	}{
  3887  		{
  3888  			note:     "no name",
  3889  			raw:      "",
  3890  			expected: fmt.Errorf("author is an empty string"),
  3891  		},
  3892  		{
  3893  			note:     "only whitespaces",
  3894  			raw:      " \t",
  3895  			expected: fmt.Errorf("author is an empty string"),
  3896  		},
  3897  		{
  3898  			note:     "one name only",
  3899  			raw:      "John",
  3900  			expected: AuthorAnnotation{Name: "John"},
  3901  		},
  3902  		{
  3903  			note:     "multiple names",
  3904  			raw:      "John Jr.\tDoe",
  3905  			expected: AuthorAnnotation{Name: "John Jr. Doe"},
  3906  		},
  3907  		{
  3908  			note:     "email only",
  3909  			raw:      "<john@example.com>",
  3910  			expected: AuthorAnnotation{Email: "john@example.com"},
  3911  		},
  3912  		{
  3913  			note:     "name and email",
  3914  			raw:      "John Doe <john@example.com>",
  3915  			expected: AuthorAnnotation{Name: "John Doe", Email: "john@example.com"},
  3916  		},
  3917  		{
  3918  			note:     "empty email",
  3919  			raw:      "John Doe <>",
  3920  			expected: AuthorAnnotation{Name: "John Doe"},
  3921  		},
  3922  		{
  3923  			note:     "name with reserved characters",
  3924  			raw:      "John Doe < >",
  3925  			expected: AuthorAnnotation{Name: "John Doe < >"},
  3926  		},
  3927  		{
  3928  			note:     "name with reserved characters (email with space)",
  3929  			raw:      "<john@ example.com>",
  3930  			expected: AuthorAnnotation{Name: "<john@ example.com>"},
  3931  		},
  3932  		{
  3933  			note: "map with name",
  3934  			raw: map[string]interface{}{
  3935  				"name": "John Doe",
  3936  			},
  3937  			expected: AuthorAnnotation{Name: "John Doe"},
  3938  		},
  3939  		{
  3940  			note: "map with email",
  3941  			raw: map[string]interface{}{
  3942  				"email": "john@example.com",
  3943  			},
  3944  			expected: AuthorAnnotation{Email: "john@example.com"},
  3945  		},
  3946  		{
  3947  			note: "map with name and email",
  3948  			raw: map[string]interface{}{
  3949  				"name":  "John Doe",
  3950  				"email": "john@example.com",
  3951  			},
  3952  			expected: AuthorAnnotation{Name: "John Doe", Email: "john@example.com"},
  3953  		},
  3954  		{
  3955  			note: "map with extra entry",
  3956  			raw: map[string]interface{}{
  3957  				"name":  "John Doe",
  3958  				"email": "john@example.com",
  3959  				"foo":   "bar",
  3960  			},
  3961  			expected: AuthorAnnotation{Name: "John Doe", Email: "john@example.com"},
  3962  		},
  3963  		{
  3964  			note:     "empty map",
  3965  			raw:      map[string]interface{}{},
  3966  			expected: fmt.Errorf("'name' and/or 'email' values required in object"),
  3967  		},
  3968  		{
  3969  			note: "map with empty name",
  3970  			raw: map[string]interface{}{
  3971  				"name": "",
  3972  			},
  3973  			expected: fmt.Errorf("'name' and/or 'email' values required in object"),
  3974  		},
  3975  		{
  3976  			note: "map with email and empty name",
  3977  			raw: map[string]interface{}{
  3978  				"name":  "",
  3979  				"email": "john@example.com",
  3980  			},
  3981  			expected: AuthorAnnotation{Email: "john@example.com"},
  3982  		},
  3983  		{
  3984  			note: "map with empty email",
  3985  			raw: map[string]interface{}{
  3986  				"email": "",
  3987  			},
  3988  			expected: fmt.Errorf("'name' and/or 'email' values required in object"),
  3989  		},
  3990  		{
  3991  			note: "map with name and empty email",
  3992  			raw: map[string]interface{}{
  3993  				"name":  "John Doe",
  3994  				"email": "",
  3995  			},
  3996  			expected: AuthorAnnotation{Name: "John Doe"},
  3997  		},
  3998  	}
  3999  
  4000  	for _, tc := range tests {
  4001  		t.Run(tc.note, func(t *testing.T) {
  4002  			parsed, err := parseAuthor(tc.raw)
  4003  
  4004  			switch expected := tc.expected.(type) {
  4005  			case AuthorAnnotation:
  4006  				if err != nil {
  4007  					t.Fatal(err)
  4008  				}
  4009  
  4010  				if parsed.Compare(&expected) != 0 {
  4011  					t.Fatalf("expected %v but got %v", tc.expected, parsed)
  4012  				}
  4013  			case error:
  4014  				if err == nil {
  4015  					t.Fatalf("expected '%v' error but got %v", tc.expected, parsed)
  4016  				}
  4017  
  4018  				if strings.Compare(expected.Error(), err.Error()) != 0 {
  4019  					t.Fatalf("expected %v but got %v", tc.expected, err)
  4020  				}
  4021  			default:
  4022  				t.Fatalf("Unexpected result type: %T", expected)
  4023  			}
  4024  		})
  4025  	}
  4026  }
  4027  
  4028  func TestRelatedResourceAnnotation(t *testing.T) {
  4029  	tests := []struct {
  4030  		note     string
  4031  		raw      interface{}
  4032  		expected interface{}
  4033  	}{
  4034  		{
  4035  			note:     "empty ref URL",
  4036  			raw:      "",
  4037  			expected: fmt.Errorf("ref URL may not be empty string"),
  4038  		},
  4039  		{
  4040  			note:     "only whitespaces in ref URL",
  4041  			raw:      " \t",
  4042  			expected: fmt.Errorf("parse \" \\t\": net/url: invalid control character in URL"),
  4043  		},
  4044  		{
  4045  			note:     "invalid ref URL",
  4046  			raw:      "https://foo:bar",
  4047  			expected: fmt.Errorf("parse \"https://foo:bar\": invalid port \":bar\" after host"),
  4048  		},
  4049  		{
  4050  			note:     "ref URL as string",
  4051  			raw:      "https://example.com/foo?bar#baz",
  4052  			expected: RelatedResourceAnnotation{Ref: mustParseURL("https://example.com/foo?bar#baz")},
  4053  		},
  4054  		{
  4055  			note: "map with only ref",
  4056  			raw: map[string]interface{}{
  4057  				"ref": "https://example.com/foo?bar#baz",
  4058  			},
  4059  			expected: RelatedResourceAnnotation{Ref: mustParseURL("https://example.com/foo?bar#baz")},
  4060  		},
  4061  		{
  4062  			note: "map with only description",
  4063  			raw: map[string]interface{}{
  4064  				"description": "foo bar",
  4065  			},
  4066  			expected: fmt.Errorf("'ref' value required in object"),
  4067  		},
  4068  		{
  4069  			note: "map with ref and description",
  4070  			raw: map[string]interface{}{
  4071  				"ref":         "https://example.com/foo?bar#baz",
  4072  				"description": "foo bar",
  4073  			},
  4074  			expected: RelatedResourceAnnotation{
  4075  				Ref:         mustParseURL("https://example.com/foo?bar#baz"),
  4076  				Description: "foo bar",
  4077  			},
  4078  		},
  4079  		{
  4080  			note: "map with ref and description",
  4081  			raw: map[string]interface{}{
  4082  				"ref":         "https://example.com/foo?bar#baz",
  4083  				"description": "foo bar",
  4084  				"foo":         "bar",
  4085  			},
  4086  			expected: RelatedResourceAnnotation{
  4087  				Ref:         mustParseURL("https://example.com/foo?bar#baz"),
  4088  				Description: "foo bar",
  4089  			},
  4090  		},
  4091  		{
  4092  			note:     "empty map",
  4093  			raw:      map[string]interface{}{},
  4094  			expected: fmt.Errorf("'ref' value required in object"),
  4095  		},
  4096  		{
  4097  			note: "map with empty ref",
  4098  			raw: map[string]interface{}{
  4099  				"ref": "",
  4100  			},
  4101  			expected: fmt.Errorf("'ref' value required in object"),
  4102  		},
  4103  		{
  4104  			note: "map with only whitespace in ref",
  4105  			raw: map[string]interface{}{
  4106  				"ref": " \t",
  4107  			},
  4108  			expected: fmt.Errorf("'ref' value required in object"),
  4109  		},
  4110  	}
  4111  
  4112  	for _, tc := range tests {
  4113  		t.Run(tc.note, func(t *testing.T) {
  4114  			parsed, err := parseRelatedResource(tc.raw)
  4115  
  4116  			switch expected := tc.expected.(type) {
  4117  			case RelatedResourceAnnotation:
  4118  				if err != nil {
  4119  					t.Fatal(err)
  4120  				}
  4121  
  4122  				if parsed.Compare(&expected) != 0 {
  4123  					t.Fatalf("expected %v but got %v", tc.expected, parsed)
  4124  				}
  4125  			case error:
  4126  				if err == nil {
  4127  					t.Fatalf("expected '%v' error but got %v", tc.expected, parsed)
  4128  				}
  4129  
  4130  				if strings.Compare(expected.Error(), err.Error()) != 0 {
  4131  					t.Fatalf("expected %v but got %v", tc.expected, err)
  4132  				}
  4133  			default:
  4134  				t.Fatalf("Unexpected result type: %T", expected)
  4135  			}
  4136  		})
  4137  	}
  4138  }
  4139  
  4140  func assertLocationText(t *testing.T, expected string, actual *Location) {
  4141  	t.Helper()
  4142  	if actual == nil || actual.Text == nil {
  4143  		t.Errorf("Expected a non nil location and text")
  4144  		return
  4145  	}
  4146  	if string(actual.Text) != expected {
  4147  		t.Errorf("Unexpected Location text, got:\n%s\n\nExpected:\n%s\n\n", actual.Text, expected)
  4148  	}
  4149  }
  4150  
  4151  func assertParseError(t *testing.T, msg string, input string) {
  4152  	t.Helper()
  4153  	t.Run(msg, func(t *testing.T) {
  4154  		assertParseErrorFunc(t, msg, input, func(string) {})
  4155  	})
  4156  }
  4157  
  4158  func assertParseErrorContains(t *testing.T, msg string, input string, expected string, opts ...ParserOptions) {
  4159  	t.Helper()
  4160  	assertParseErrorFunc(t, msg, input, func(result string) {
  4161  		t.Helper()
  4162  		if !strings.Contains(result, expected) {
  4163  			t.Errorf("Error on test \"%s\": expected parse error to contain:\n\n%v\n\nbut got:\n\n%v", msg, expected, result)
  4164  		}
  4165  	}, opts...)
  4166  }
  4167  
  4168  func assertParseErrorFunc(t *testing.T, msg string, input string, f func(string), opts ...ParserOptions) {
  4169  	t.Helper()
  4170  	opt := ParserOptions{}
  4171  	if len(opts) == 1 {
  4172  		opt = opts[0]
  4173  	}
  4174  	stmts, _, err := ParseStatementsWithOpts("", input, opt)
  4175  	if err == nil && len(stmts) != 1 {
  4176  		err = fmt.Errorf("expected exactly one statement")
  4177  	}
  4178  	if err == nil {
  4179  		t.Errorf("Error on test \"%s\": expected parse error on %s: expected no statements, got %d: %v", msg, input, len(stmts), stmts)
  4180  		return
  4181  	}
  4182  	result := err.Error()
  4183  	// error occurred: <line>:<col>: <message>
  4184  	parts := strings.SplitN(result, ":", 4)
  4185  	result = strings.TrimSpace(parts[len(parts)-1])
  4186  	f(result)
  4187  }
  4188  
  4189  func assertParseImport(t *testing.T, msg string, input string, correct *Import, opts ...ParserOptions) {
  4190  	t.Helper()
  4191  	assertParseOne(t, msg, input, func(parsed interface{}) {
  4192  		t.Helper()
  4193  		imp := parsed.(*Import)
  4194  		if !imp.Equal(correct) {
  4195  			t.Errorf("Error on test \"%s\": imports not equal: %v (parsed), %v (correct)", msg, imp, correct)
  4196  		}
  4197  	}, opts...)
  4198  }
  4199  
  4200  func assertParseModule(t *testing.T, msg string, input string, correct *Module, opts ...ParserOptions) {
  4201  	opt := ParserOptions{}
  4202  	if len(opts) == 1 {
  4203  		opt = opts[0]
  4204  	}
  4205  	m, err := ParseModuleWithOpts("", input, opt)
  4206  	if err != nil {
  4207  		t.Errorf("Error on test \"%s\": parse error on %s: %s", msg, input, err)
  4208  		return
  4209  	}
  4210  
  4211  	if !m.Equal(correct) {
  4212  		t.Errorf("Error on test %s: modules not equal: %v (parsed), %v (correct)", msg, m, correct)
  4213  	}
  4214  
  4215  }
  4216  
  4217  func assertParseModuleError(t *testing.T, msg, input string) {
  4218  	m, err := ParseModule("", input)
  4219  	if err == nil {
  4220  		t.Errorf("Error on test \"%s\": expected parse error: %v (parsed)", msg, m)
  4221  	}
  4222  }
  4223  
  4224  func assertParsePackage(t *testing.T, msg string, input string, correct *Package) {
  4225  	assertParseOne(t, msg, input, func(parsed interface{}) {
  4226  		pkg := parsed.(*Package)
  4227  		if !pkg.Equal(correct) {
  4228  			t.Errorf("Error on test \"%s\": packages not equal: %v (parsed), %v (correct)", msg, pkg, correct)
  4229  		}
  4230  	})
  4231  }
  4232  
  4233  func assertParseOne(t *testing.T, msg string, input string, correct func(interface{}), opts ...ParserOptions) {
  4234  	t.Helper()
  4235  	opt := ParserOptions{}
  4236  	if len(opts) == 1 {
  4237  		opt = opts[0]
  4238  	}
  4239  	stmts, _, err := ParseStatementsWithOpts("", input, opt)
  4240  	if err != nil {
  4241  		t.Errorf("Error on test \"%s\": parse error on %s: %s", msg, input, err)
  4242  		return
  4243  	}
  4244  	if len(stmts) != 1 {
  4245  		t.Errorf("Error on test \"%s\": parse error on %s: expected exactly one statement, got %d: %v", msg, input, len(stmts), stmts)
  4246  		return
  4247  	}
  4248  	correct(stmts[0])
  4249  }
  4250  
  4251  func assertParseOneBody(t *testing.T, msg string, input string, correct Body) {
  4252  	t.Helper()
  4253  	body, err := ParseBody(input)
  4254  	if err != nil {
  4255  		t.Fatal(err)
  4256  	}
  4257  	if !body.Equal(correct) {
  4258  		t.Fatalf("Error on test \"%s\": bodies not equal:\n%v (parsed)\n%v (correct)", msg, body, correct)
  4259  	}
  4260  }
  4261  
  4262  func assertParseOneExpr(t *testing.T, msg string, input string, correct *Expr, opts ...ParserOptions) {
  4263  	t.Helper()
  4264  	assertParseOne(t, msg, input, func(parsed interface{}) {
  4265  		t.Helper()
  4266  		body := parsed.(Body)
  4267  		if len(body) != 1 {
  4268  			t.Errorf("Error on test \"%s\": parser returned multiple expressions: %v", msg, body)
  4269  			return
  4270  		}
  4271  		expr := body[0]
  4272  		if !expr.Equal(correct) {
  4273  			t.Errorf("Error on test \"%s\": expressions not equal:\n%v (parsed)\n%v (correct)", msg, expr, correct)
  4274  		}
  4275  	}, opts...)
  4276  }
  4277  
  4278  func assertParseOneExprNegated(t *testing.T, msg string, input string, correct *Expr) {
  4279  	correct.Negated = true
  4280  	assertParseOneExpr(t, msg, input, correct)
  4281  }
  4282  
  4283  func assertParseOneTerm(t *testing.T, msg string, input string, correct *Term) {
  4284  	t.Helper()
  4285  	t.Run(msg, func(t *testing.T) {
  4286  		assertParseOneExpr(t, msg, input, &Expr{Terms: correct})
  4287  	})
  4288  }
  4289  
  4290  func assertParseOneTermNegated(t *testing.T, msg string, input string, correct *Term) {
  4291  	t.Helper()
  4292  	assertParseOneExprNegated(t, msg, input, &Expr{Terms: correct})
  4293  }
  4294  
  4295  func assertParseRule(t *testing.T, msg string, input string, correct *Rule, opts ...ParserOptions) {
  4296  	t.Helper()
  4297  	assertParseOne(t, msg, input, func(parsed interface{}) {
  4298  		t.Helper()
  4299  		rule := parsed.(*Rule)
  4300  		if !rule.Equal(correct) {
  4301  			t.Errorf("Error on test \"%s\": rules not equal: %v (parsed), %v (correct)", msg, rule, correct)
  4302  		}
  4303  	},
  4304  		opts...)
  4305  }