Expressions



Mathematical Operations

Cue has the typical math operations for numbers. Multiplication also works for strings and lists.

math-ops.cue

// mathematical!
n1: 3 + 2
n2: 3 - 2
n3: 3 * 2
n4: 3 / 2

// Truncated division
q: quo(-5,2)
r: rem(-5,2)
// Euclidean division
d: div(-5,2)
m: mod(-5,2)

// math on strings and lists
s: 3 * "for he's a jolly good fellow\n" + "which nobody can deny"
l: 5 * ["eye"]

cue eval math-ops.cue

n1: 5
n2: 1
n3: 6
n4: 1.5
q:  -2
r:  -1
d:  -3
m:  1
s: """
    for he's a jolly good fellow
    for he's a jolly good fellow
    for he's a jolly good fellow
    which nobody can deny
    """
l: ["eye", "eye", "eye", "eye", "eye"]

Additional math operations can be found in the Cue’s math package .

Comparison Operations

Cue has the expected relative comparison operators and semantics. Equality checks are handled by value unification.

compare-ops.cue

// number constraints
positive: >0  // numbers
doubledig: >=10 & <100 & int

// lexical comparison
lowercase: >="a" & <="z"

notone: <1 | >1
notone: 1  // error, empty disjuntion

cue eval compare-ops.cue

positive:  >0
doubledig: uint & >=10 & <100
lowercase: >="a" & <="z"
notone:    <1 | >1

Predefined Bounds

Cue has the following predefined bounds for sized numbers

int8      >=-128 & <=127
int16     >=-32_768 & <=32_767
int32     >=-2_147_483_648 & <=2_147_483_647
int64     >=-9_223_372_036_854_775_808 & <=9_223_372_036_854_775_807
int128    >=-170_141_183_460_469_231_731_687_303_715_884_105_728 &
              <=170_141_183_460_469_231_731_687_303_715_884_105_727

uint      >=0
uint8     >=0 & <=255
uint16    >=0 & <=65536
uint32    >=0 & <=4_294_967_296
uint64    >=0 & <=18_446_744_073_709_551_615
uint128   >=0 & <=340_282_366_920_938_463_463_374_607_431_768_211_455

rune      >=0 & <=0x10FFFF

Regular Expressions

Cue supports regular expression constraints with the =~ and !~ operators.

regexp.cue

a: "hello world" & =~"^hello [a-z]+$"
b: "hello" & !~ "^[A-Z]+"

lowercase: =~ "^[a-z]+$"

c: "hello" & lowercase
d: "Hello" & lowercase // error

cue eval regexp.cue

a:         "hello world"
b:         "hello"
lowercase: =~"^[a-z]+$"
c:         "hello"

They are based on Go’s regular expressions. Cue also has some additional regexp helpers .:w

Interpolation

Cue supports interpolation in strings and bytes with \(<expr>)

interpolate.cue

container: {
	repo: "docker.io/cuelang"
	image: "cue"
	version: "v0.3.0"
	full: "\(repo)/\(image):\(version)"
}

name: "Tony"
msg: "Hello \(name)"
// conver string to bytes
b: '\(msg)'
// convert bytes to string
s: "\(b)"

cue eval interpolate.cue

container: {
    repo:    "docker.io/cuelang"
    image:   "cue"
    version: "v0.3.0"
    full:    "docker.io/cuelang/cue:v0.3.0"
}
name: "Tony"
msg:  "Hello Tony"
b:    'Hello Tony'
s:    "Hello Tony"

For more complicated scenarios, you can use the text/template package.

You can also interpolate field names. (as we will see shortly)

List Comprehensions

Cue has list comprehensions to dynamically create lists. You can iterate over both lists and struct fields.

The form is [ for key, val in <iterable> [condition] { production } ]

* key is the index for lists and the label for fields

list-comp.cue

nums: [1,2,3,4,5,6]
sqrd: [ for _, n in nums { n*n } ]
even: [ for _, n in nums if mod(n,2) == 0 { n } ]

listOfStructs: [ for p, n in nums {
	pos: p
	val: n
}]

extractVals: [ for p, S in listOfStructs { S.val } ]

cue eval list-comp.cue

nums: [1, 2, 3, 4, 5, 6]
sqrd: [1, 4, 9, 16, 25, 36]
even: [2, 4, 6]
listOfStructs: [{
    pos: 0
    val: 1
}, {
    pos: 1
    val: 2
}, {
    pos: 2
    val: 3
}, {
    pos: 3
    val: 4
}, {
    pos: 4
    val: 5
}, {
    pos: 5
    val: 6
}]
extractVals: [1, 2, 3, 4, 5, 6]

Field Comprehensions

Cue also has the ability to comprehend fields.

field-comp.cue

apps: ["nginx", "express", "postgres"]
#labels: [string]: string
stack: {
	for i, app in apps {
		"\(app)": {
			name: app
			labels: #labels & {
				app: "foo"
				tier: "\(i)"
			}
		}
	}
}

cue eval field-comp.cue

apps: ["nginx", "express", "postgres"]
#labels: {}
stack: {
    nginx: {
        name: "nginx"
        labels: {
            app:  "foo"
            tier: "0"
        }
    }
    express: {
        name: "express"
        labels: {
            app:  "foo"
            tier: "1"
        }
    }
    postgres: {
        name: "postgres"
        labels: {
            app:  "foo"
            tier: "2"
        }
    }
}

Conditional Fields

Conditional fields, or guarded fields (if technically means guard), are another form of field comprehension.

Some important notes to make from the usual understanding of if’s:

  • there is not an else statement, you have to have two with opposite conditions
  • there is no shortcircuiting of booleans, all conditions will be evaluated

guards.cue

app: {
	name: string
	tech: string
	mem: int

	if tech == "react" {
		tier: "frontend"
	}
	if tech != "react" {
		tier: "backend"
	}

	if mem < 1Gi {
		footprint: "small"
	}
	if mem >= 1Gi && mem < 4Gi {
		footprint: "medium"
	}
	if mem  >= 4Gi {
		footprint: "large"
	}
}



2021 Hofstadter, Inc