this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

doc/ref: refine default values, references and evaluation

The current spec allows for an interpretation that makes default values not commutative:

A: *0 | 1
A: C - B
B: *0 | 1
B: C - A
C: 1

could evaluate to {A: 0, B: 1, C: 1} or {A: 1, B:0, C:1}

With the refined semantics, there is only one interpretation. Expressed in terms of value-default pairs:

A: (0|1 & 1-B, 0 & 1-B) => (0|1 & 1-B, _|_)
B: (0|1 & 1-A, 0 & 1-A) => (0|1 & 1-A, _|_)
C: 1

This updated spec also clarifies how references are resolved.

It also now officially allows an integer literal to be used as an index value.

Note there is now no point during evaluation anymore where a default value is taken over the regular value. Defaults are now only selected over another value when reading a configuration after full evaluation.

Change-Id: Iaea62a5d41c49889f4b5395027bab19e892f166b
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/1784
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>

authored by

Marcel van Lohuizen and committed by
Marcel van Lohuizen
fe4abac6 412e5ffd

+171 -37
+171 -37
doc/ref/spec.md
··· 43 43 CUE draws its influence from many languages. 44 44 Its main influences were BCL/ GCL (internal to Google), 45 45 LKB (LinGO), Go, and JSON. 46 - Others are Swift, Javascript, Prolog, NCL (internal to Google), Jsonnet, HCL, 47 - Flabbergast, JSONPath, Haskell, Objective-C, and Python. 46 + Others are Swift, Typescript, Javascript, Prolog, NCL (internal to Google), 47 + Jsonnet, HCL, Flabbergast, JSONPath, Haskell, Objective-C, and Python. 48 48 49 49 50 50 ## Notation ··· 697 697 D2: (v1, d1) | (v2, d2) => (v1|v2, d1|d2) 698 698 ``` 699 699 700 - For any other operation, such as arithmetic expressions, indices, slices, and 701 - selectors, the value `(v, d)` yields `d` if it is not bottom, or `v` otherwise. 702 - 703 700 Default values may be introduced within disjunctions 704 701 by _marking_ terms of a disjunction with an asterisk `*` 705 702 ([a unary expression](#Operators)). ··· 707 704 of those marked terms, applying the following rules for marks: 708 705 709 706 ``` 710 - M1: *v => (v, v) 707 + M1: *v => (v, v) 711 708 M2: *(v1, d1) => (v1, d1) 712 709 ``` 713 710 711 + In general, any operation in CUE involving default values proceeds along the 712 + following lines 713 + ``` 714 + O1: f((v1, d1), ..., (vn, dn)) => (fn(v1, ..., vn), fn(d1, ..., dn)) 715 + ``` 716 + where, with the exception of disjunction, a value `v` without a default 717 + value is promoted to `(v, v)`. 718 + 719 + 714 720 ``` 715 721 Expression Value-default pair Rules applied 716 722 *"tcp" | "udp" ("tcp"|"udp", "tcp") M1, D1 ··· 723 729 (*1|2|3) | (1|*2|3)&2 (1|2|3, 1|2) M1, D1, U1, D2 724 730 725 731 (*1|2) & (1|*2) (1|2, _|_) M1, D1, U2 732 + 733 + (*1|2) + (1|*2) ((1|2)+(1|2), 3) M1, D1, O1 726 734 ``` 727 735 728 736 The rules of subsumption for defaults can be derived from the above definitions ··· 783 791 ({a:1}|*{b:1}) & ({a:1}|*{b:1}) {b:1} // after eliminating {a:1,b:1} by normalization 784 792 ``` 785 793 786 - <!-- 787 - TODO: to be consistent, we should probably drop this requirement and define 788 - for such operation which which types a value is unified. 789 - 790 - For instance, right now [1, 2][0.0] is not allowed, 791 - whereas [1, 2][0] is (implicitly unified with int). 792 - It would be consistent to allow [1, 2]["foo" | 0] to work as well. 793 - The alternative is to disallow [1, 2][0], which would be quite annoying. 794 - --> 795 - 796 - A disjunction always evaluates to the same default value, regardless of 797 - the context in which the value is used. 798 - For instance, `[1, 3][*"a" | 1]` will result in an error, as `"a"` will be 799 - selected as the default value. 800 - 801 - ``` 802 - [1, 2][*"a" | 1] // _|_ // "a" is not an integer value 803 - [1, 2][(*"a" | 1) & int] // 2, as "a" is eliminated before choosing a default. 804 - ``` 805 - 806 794 807 795 ### Bottom and errors 808 796 ··· 1104 1092 } 1105 1093 ``` 1106 1094 1095 + 1107 1096 #### Optional fields 1108 1097 1109 1098 An identifier or string label may be followed by a question mark `?` ··· 1343 1332 exception of identifiers starting with an underscore '_'. 1344 1333 The latter represent hidden fields and are treated in a different namespace. 1345 1334 1335 + If an expression may result in a value associated with a default value 1336 + as described in [default values](#default-values), the field binds to this 1337 + value-default pair. 1338 + 1346 1339 <!-- TODO: disallow creating identifiers starting with __ 1347 1340 ...and reserve them for builtin values. 1348 1341 ··· 1354 1347 allowing generated code (normal code would keep using `string`) to refer 1355 1348 to these directly. 1356 1349 --> 1350 + 1357 1351 1358 1352 ### Alias declarations 1359 1353 ··· 1369 1363 An expression specifies the computation of a value by applying operators and 1370 1364 built-in functions to operands. 1371 1365 1366 + Expressions that require concrete values are called _incomplete_ if any of 1367 + their operands are not concrete, but define a value that would be legal for 1368 + that expression. 1369 + Incomplete expressions may be left unevaluated until a concrete value is 1370 + requested at the application level. 1372 1371 1373 1372 ### Operands 1374 1373 ··· 1400 1399 math.Sin // denotes the Sin function in package math 1401 1400 ``` 1402 1401 1402 + ### References 1403 + 1404 + An identifier operand refers to a field and is called a reference. 1405 + The value of a reference is a copy of the expression associated with the field 1406 + that it is bound to, 1407 + with any references within that expression bound to the respective copies of 1408 + the fields they were originally bound to. 1409 + Implementations may use a different mechanism to evaluate as long as 1410 + these semantics are maintained. 1411 + 1412 + ``` 1413 + a: { 1414 + place: string 1415 + greeting: "Hello, \(place)!" 1416 + } 1417 + 1418 + b: a & { place: "world" } 1419 + c: a & { place: "you" } 1420 + 1421 + d: b.greeting // "Hello, world!" 1422 + e: c.greeting // "Hello, you!" 1423 + ``` 1424 + 1425 + 1403 1426 1404 1427 ### Primary expressions 1405 1428 1406 1429 Primary expressions are the operands for unary and binary expressions. 1407 - A default expression is only valid as an operand to a disjunction. 1430 + 1408 1431 1432 + ``` 1433 + 1434 + Slice: indices must be complete 1435 + ([0, 1, 2, 3] | [2, 3])[0:2] => [0, 1] | [2, 3] 1436 + 1437 + ([0, 1, 2, 3] | *[2, 3])[0:2] => [0, 1] | [2, 3] 1438 + ([0,1,2,3]|[2,3], [2,3])[0:2] => ([0,1]|[2,3], [2,3]) 1439 + 1440 + Index 1441 + a: (1|2, 1) 1442 + b: ([0,1,2,3]|[2,3], [2,3])[a] => ([0,1,2,3]|[2,3][a], 3) 1443 + 1444 + Binary operation 1445 + A binary is only evaluated if its operands are complete. 1446 + 1447 + Input Maximum allowed evaluation 1448 + a: string string 1449 + b: 2 2 1450 + c: a * b a * 2 1451 + 1452 + An error in a struct is if the evaluation of any expression results in 1453 + bottom, where an incomplete expression is not considered bottom. 1454 + ``` 1409 1455 <!-- TODO(mpvl) 1410 1456 Conversion | 1411 1457 --> ··· 1453 1499 The type of the selector expression is the type of `f`. 1454 1500 If `x` is a package name, see the section on [qualified identifiers]. 1455 1501 1502 + <!-- 1503 + TODO: consider allowing this and also for selectors. It needs to be considered 1504 + how defaults are corried forward in cases like: 1505 + 1506 + x: { a: string | *"foo" } | *{ a: int | *4 } 1507 + y: x.a & string 1508 + 1509 + What is y in this case? 1510 + (x.a & string, _|_) 1511 + (string|"foo", _|_) 1512 + (string|"foo", "foo) 1513 + If the latter, then why? 1514 + 1515 + For a disjunction of the form `x1 | ... | xn`, 1516 + the selector is applied to each element `x1.f | ... | xn.f`. 1517 + --> 1518 + 1456 1519 Otherwise, if `x` is not a struct, or if `f` does not exist in `x`, 1457 1520 the result of the expression is bottom (an error). 1521 + In the latter case the expression is incomplete. 1522 + The operand of a selector may be associated with a default. 1458 1523 1459 1524 ``` 1460 1525 T: { ··· 1465 1530 a: T.x // int 1466 1531 b: T.y // 3 1467 1532 c: T.z // _|_ // field 'z' not found in T 1533 + 1534 + e: {a: 1|*2} | *{a: 3|*4} 1535 + f: e.a // 4 (default value) 1468 1536 ``` 1469 1537 1538 + <!-- 1539 + ``` 1540 + (v, d).f => (v.f, d.f) 1541 + 1542 + e: {a: 1|*2} | *{a: 3|*4} 1543 + f: e.a // 4 after selecting default from (({a: 1|*2} | {a: 3|*4}).a, 4) 1544 + 1545 + ``` 1546 + --> 1547 + 1470 1548 1471 1549 ### Index expressions 1472 1550 ··· 1482 1560 1483 1561 If `a` is not a struct: 1484 1562 1485 - - the index `x` must be a concrete integer. 1486 - If `x` is a disjunction, the default, if any will be selected without unifying 1487 - `x` with `int` beforehand. 1488 - - the index `x` is in range if `0 <= x < len(a)`, otherwise it is out of range 1563 + - `a` is a concrete string or bytes type or a list (which need not be complete) 1564 + - the index `x` unified with `int` must be concrete. 1565 + - the index `x` is in range if `0 <= x < len(a)`, where only the 1566 + explicitly defined values of an open-ended list are considered, 1567 + otherwise it is out of range 1489 1568 1490 1569 The result of `a[x]` is 1491 1570 1492 - for `a` of list type (including single quoted strings, which are lists of bytes): 1571 + for `a` of list or bytes type: 1493 1572 1494 - - the list element at index `x`, if `x` is within range, where only the 1495 - explicitly defined values of an open-ended list are considered 1573 + - the list or byte element at index `x`, if `x` is within range 1496 1574 - bottom (an error), otherwise 1497 1575 1498 1576 for `a` of string type: ··· 1503 1581 1504 1582 for `a` of struct type: 1505 1583 1584 + - the index `x` unified with `string` must be concrete. 1506 1585 - the value of the field named `x` of struct `a`, if this field exists 1507 1586 - bottom (an error), otherwise 1508 1587 1588 + 1509 1589 ``` 1510 1590 [ 1, 2 ][1] // 2 1511 1591 [ 1, 2 ][2] // _|_ ··· 1518 1598 "He\u0300?"[5] // _|_ 1519 1599 ``` 1520 1600 1601 + Both the operand and index value may be a value-default pair. 1602 + ``` 1603 + va[vi] => va[vi] 1604 + va[(vi, di)] => (va[vi], va[di]) 1605 + (va, da)[vi] => (va[vi], da[vi]) 1606 + (va, da)[(vi, di)] => (va[vi], da[di]) 1607 + ``` 1608 + 1609 + ``` 1610 + Fields Result 1611 + x: [1, 2] | *[3, 4] ([1,2]|[3,4], [3,4]) 1612 + i: int | *1 (int, 1) 1613 + 1614 + v: x[i] (x[i], 4) 1615 + ``` 1521 1616 1522 1617 ### Slice expressions 1523 1618 1524 - Slice expressions construct a substring or slice from a string or list. 1619 + Slice expressions construct a substring or slice from a string, bytes, 1620 + or list value. 1525 1621 1526 - For strings or lists, the primary expression 1622 + For strings, bytes or lists, the primary expression 1527 1623 ``` 1528 1624 a[low : high] 1529 1625 ``` ··· 1534 1630 After slicing the list `a` 1535 1631 <!-- TODO(jba): how does slicing open lists work? --> 1536 1632 1633 + <!-- TODO: consider this. 1634 + For `a` is a disjunction of the form `a1 | ... | an`, then the result is 1635 + `a1[low:high] | ... | an[low:high]` observing the above rules. 1636 + --> 1537 1637 ``` 1538 1638 a := [1, 2, 3, 4, 5] 1539 1639 s := a[1:4] ··· 1570 1670 The result of a successful slice operation is a value of the same type 1571 1671 as the operand. 1572 1672 1673 + Both the slice operand and the slice indices may be associated with a default. 1674 + 1675 + <!-- 1676 + ``` 1677 + va[vs:ve] => va[vs:ve] 1678 + va[vs:(ve, de)] => (va[vs:ve], va[vs:de]) 1679 + va[(vs, ds):ve] => (va[vs:ve], va[ds:ve]) 1680 + va[(vs, ds):(ve, de)] => (va[vs:ve], va[ds:de]) 1681 + (va, da)[vs:ve] => (va[vs:ve], da[vs:ve]) 1682 + (va, da)[vs:(ve, de)] => (va[vs:ve], da[vs:de]) 1683 + (va, da)[(vs, ds):ve] => (va[vs:ve], da[ds:ve]) 1684 + (va, da)[(vs, ds):(ve, de)] => (va[vs:ve], da[ds:de]) 1685 + ``` 1686 + --> 1573 1687 1574 1688 ### Operators 1575 1689 ··· 1596 1710 operand. 1597 1711 --> 1598 1712 1713 + Operands of unary and binary expressions may be associated with a default using 1714 + the following 1715 + <!-- 1716 + ``` 1717 + O1: op (v1, d1) => (op v1, op d1) 1718 + 1719 + O2: (v1, d1) op (v2, d2) => (v1 op v2, d1 op d2) 1720 + and because v => (v, v) 1721 + O3: v1 op (v2, d2) => (v1 op v2, v1 op d2) 1722 + O4: (v1, d1) op v2 => (v1 op v2, d1 op v2) 1723 + ``` 1724 + --> 1725 + 1726 + ``` 1727 + Field Resulting Value-Default pair 1728 + a: *1|2 (1|2, 1) 1729 + b: -a (-a, -1) 1730 + 1731 + c: a + 2 (a+2, 3) 1732 + d: a + a (a+a, 2) 1733 + ``` 1599 1734 1600 1735 #### Operator precedence 1601 1736 ··· 1651 1786 quo quotient integers 1652 1787 rem remainder integers 1653 1788 ``` 1654 - 1655 1789 1656 1790 #### Integer operators 1657 1791