Language Cheatsheet

Assignment and Equality

  1. # assign variable x to value of field foo.bar.baz in input
  2. x := input.foo.bar.baz
  3. # check if variable x has same value as variable y
  4. x == y
  5. # check if variable x is a set containing "foo" and "bar"
  6. x == {"foo", "bar"}
  7. # OR
  8. {"foo", "bar"} == x

Lookup

Arrays

  1. # lookup value at index 0
  2. val := arr[0]
  3. # check if value at index 0 is "foo"
  4. "foo" == arr[0]
  5. # find all indices i that have value "foo"
  6. "foo" == arr[i]
  7. # lookup last value
  8. val := arr[count(arr)-1]

Objects

  1. # lookup value for key "foo"
  2. val := obj["foo"]
  3. # check if value for key "foo" is "bar"
  4. "bar" == obj["foo"]
  5. # OR
  6. "bar" == obj.foo
  7. # check if key "foo" exists and is not false
  8. obj.foo
  9. # check if key assigned to variable k exists
  10. k := "foo"
  11. obj[k]
  12. # check if path foo.bar.baz exists and is not false
  13. obj.foo.bar.baz
  14. # check if path foo.bar.baz, foo.bar, or foo does not exist or is false
  15. not obj.foo.bar.bar

Sets

  1. # check if "foo" belongs to the set
  2. a_set["foo"]
  3. # check if "foo" DOES NOT belong to the set
  4. not a_set["foo"]
  5. # check if the array ["a", "b", "c"] belongs to the set
  6. a_set[["a", "b", "c"]]
  7. # find all arrays of the form [x, "b", z] in the set
  8. a_set[[x, "b", z]]

Iteration

Arrays

  1. # iterate over indices i
  2. arr[i]
  3. # iterate over values
  4. val := arr[_]
  5. # iterate over index/value pairs
  6. val := arr[i]

Objects

  1. # iterate over keys
  2. obj[key]
  3. # iterate over values
  4. val := obj[_]
  5. # iterate over key/value pairs
  6. val := obj[key]

Sets

  1. # iterate over values
  2. set[val]

Advanced

  1. # nested: find key k whose bar.baz array index i is 7
  2. foo[k].bar.baz[i] == 7
  3. # simultaneous: find keys in objects foo and bar with same value
  4. foo[k1] == bar[k2]
  5. # simultaneous self: find 2 keys in object foo with same value
  6. foo[k1] == foo[k2]; k1 != k2
  7. # multiple conditions: k has same value in both conditions
  8. foo[k].bar.baz[i] == 7; foo[k].qux > 3

For All

  1. # assert no values in set match predicate
  2. count({x | set[x]; f(x)}) == 0
  3. # assert all values in set make function f true
  4. count({x | set[x]; f(x)}) == count(set)
  5. # assert no values in set make function f true (using negation and helper rule)
  6. not any_match
  7. # assert all values in set make function f true (using negation and helper rule)
  8. not any_not_match
  1. any_match {
  2. set[x]
  3. f(x)
  4. }
  5. any_not_match {
  6. set[x]
  7. not f(x)
  8. }

Rules

In the examples below ... represents one or more conditions.

Constants

  1. a = {1, 2, 3}
  2. b = {4, 5, 6}
  3. c = a | b

Conditionals (Boolean)

  1. # p is true if ...
  2. p = true { ...}
  3. # OR
  4. p { ... }

Conditionals

  1. default a = 1
  2. a = 5 { ... }
  3. a = 100 { ... }

Incremental

  1. # a_set will contain values of x and values of y
  2. a_set[x] { ... }
  3. a_set[y] { ... }
  4. # a_map will contain key->value pairs x->y and w->z
  5. a_map[x] = y { ... }
  6. a_map[w] = z { ... }

Ordered (Else)

  1. default a = 1
  2. a = 5 { ... }
  3. else = 10 { ... }

Functions (Boolean)

  1. f(x, y) {
  2. ...
  3. }
  4. # OR
  5. f(x, y) = true {
  6. ...
  7. }

Functions (Conditionals)

  1. f(x) = "A" { x >= 90 }
  2. f(x) = "B" { x >= 80; x < 90 }
  3. f(x) = "C" { x >= 70; x < 80 }

Patterns

Merge Objects

  1. merge_objects({"a": true, "b": false}, {"b": "foo", "c": 4})
  1. has_key(x, k) { _ = x[k] }
  2. pick_first(k, a, b) = a[k]
  3. pick_first(k, a, b) = b[k] { not has_key(a, k) }
  4. merge_objects(a, b) = c {
  5. ks := {k | some k; _ = a[k]} | {k | some k; _ = b[k]}
  6. c := {k: v | some k; ks[k]; v := pick_first(k, b, a)}
  7. }

Tests

  1. # define a rule that starts with test_
  2. test_NAME { ... }
  3. # override input.foo value using the 'with' keyword
  4. data.foo.bar.deny with input.foo as {"bar": [1,2,3]}}