Grammar
This annex uses ABNF (RFC 5234). WSP, DIGIT, HEXDIG, and DQUOTE are the core rules of that document.
Interpolation
Section titled “Interpolation”interpolation = "{{" *WSP expression *WSP "}}"The typing rules state how a scalar that holds interpolations yields a value.
Expressions
Section titled “Expressions”expression = conditionalconditional = or-expr [ 1*WSP "if" 1*WSP or-expr 1*WSP "else" 1*WSP conditional ]or-expr = and-expr *( 1*WSP "or" 1*WSP and-expr )and-expr = equality *( 1*WSP "and" 1*WSP equality )equality = relational [ ( *WSP eq-op *WSP / 1*WSP "in" 1*WSP ) relational ]eq-op = "==" / "!="relational = additive [ *WSP rel-op *WSP additive ]rel-op = "<=" / ">=" / "<" / ">"additive = multiplicative *( *WSP add-op *WSP multiplicative )add-op = "+" / "-"multiplicative = unary *( *WSP mul-op *WSP unary )mul-op = "*" / "/" / "%"unary = ( "not" 1*WSP unary ) / ( "-" unary ) / postfixpostfix = primary *( member / index / filter )member = "." nameindex = "[" *WSP expression *WSP "]"filter = *WSP "|" *WSP filter-name [ "(" *WSP [ arg-list ] *WSP ")" ]filter-name = name [ "." name ]arg-list = expression *( *WSP "," *WSP expression )primary = literal / name / list-lit / map-lit / groupgroup = "(" *WSP expression *WSP ")"list-lit = "[" *WSP [ expression *( *WSP "," *WSP expression ) ] *WSP "]"map-lit = "{" *WSP [ map-entry *( *WSP "," *WSP map-entry ) ] *WSP "}"map-entry = ( string-lit / name ) *WSP ":" *WSP expressionequality and relational are non-associative: a < b < c is a syntax error, and parentheses express the intended grouping.
A filter-name with one component names a core filter. A filter-name with two components names an extension filter.
literal = string-lit / duration-lit / number-lit / bool-lit / "null"bool-lit = "true" / "false"
name = %x61-7A *( %x61-7A / DIGIT / "_" )
string-lit = DQUOTE *dq-char DQUOTE / "'" *sq-char "'"dq-char = %x20-21 / %x23-5B / %x5D-10FFFF / escapesq-char = %x20-26 / %x28-5B / %x5D-10FFFF / escapeescape = "\" ( "\" / DQUOTE / "'" / "n" / "r" / "t" / unicode-esc )unicode-esc = "u{" 1*6HEXDIG "}"
number-lit = float-lit / int-litint-lit = 1*DIGITfloat-lit = 1*DIGIT "." 1*DIGIT [ exponent ] / 1*DIGIT exponentexponent = ( "e" / "E" ) [ "+" / "-" ] 1*DIGITA term is matched by the longest alternative that succeeds. 1 is an int-lit, and 1d is a duration-lit.
A negative number is the unary - operator applied to a literal. There is no negative literal.
Durations
Section titled “Durations”duration-lit = 1*duration-partduration-part = 1*DIGIT duration-unitduration-unit = "ms" / "s" / "m" / "h" / "d"Units MUST appear in strictly descending order of magnitude, and each unit MUST appear at most once. 1h30m and 500ms are valid. 30m1h and 1h1h are not.
A day is exactly 86400000 milliseconds, and has no calendar or daylight-saving meaning. A duration literal is never negative.
Timestamps
Section titled “Timestamps”A timestamp is written as an RFC 3339 date-time with a mandatory time offset. A second value of 60 MUST be rejected.
There is no timestamp term in the expression grammar. Where a value of type timestamp is expected, implementations MUST accept a string in this form and convert it.
Type expressions
Section titled “Type expressions”type-expr = "string" / "int" / "float" / "bool" / "timestamp" / "duration" / "file" / "json" / enum-type / list-type / map-typeenum-type = "enum[" member *( "," *WSP member ) "]"member = 1*( %x61-7A / DIGIT / "_" )list-type = "list[" type-expr "]"map-type = "map[string," *WSP type-expr "]"An object type is expressed as JSON Schema rather than as a type expression. The serialization rules require that a type expression is always quoted.