doc/tutorial/basics: reorganize and simplify intro

Change-Id: I5a15ac437b24e7116b09a68ddd2c1c070f3cf85f
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3542
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/doc/tutorial/basics/intro/10_fieldname.txt b/doc/tutorial/basics/intro/10_json.txt
similarity index 70%
rename from doc/tutorial/basics/intro/10_fieldname.txt
rename to doc/tutorial/basics/intro/10_json.txt
index 256c115..c8b7ac4 100644
--- a/doc/tutorial/basics/intro/10_fieldname.txt
+++ b/doc/tutorial/basics/intro/10_json.txt
@@ -1,4 +1,4 @@
-cue export fieldname.cue
+cue export json.cue
 cmp stdout expect-stdout-cue
 
 -- frontmatter.toml --
@@ -13,16 +13,26 @@
 Double quotes may be omitted from field names if their name contains no
 special characters and does not start with a number:
 
--- fieldname.cue --
-{
-    one: 1,
-    two: 2,
+-- json.cue --
+one: 1
+two: 2
 
-    "two-and-a-half": 2.5
-}
+// A field using quotes.
+"two-and-a-half": 2.5
+
+list: [
+	1,
+	2,
+	3,
+]
 
 -- expect-stdout-cue --
 {
+    "list": [
+        1,
+        2,
+        3
+    ],
     "one": 1,
     "two": 2,
     "two-and-a-half": 2.5
diff --git a/doc/tutorial/basics/intro/20_commas.txt b/doc/tutorial/basics/intro/20_commas.txt
deleted file mode 100644
index 3035ebc..0000000
--- a/doc/tutorial/basics/intro/20_commas.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-cue export commas.cue
-cmp stdout expect-stdout-cue
-
--- frontmatter.toml --
-title = "Commas are Optional after Fields"
-description = ""
-
--- text.md --
-Commas are optional at the end of fields.
-This is also true for the last field.
-The convention is to omit them.
-
-<!-- Side Note -->
-_CUE borrows a trick from Go to achieve this: the formal grammar still
-requires commas, but the scanner inserts commas according to a small set
-of simple rules._
-
--- commas.cue --
-{
-    one: 1
-    two: 2
-
-    "two-and-a-half": 2.5
-}
-
--- expect-stdout-cue --
-{
-    "one": 1,
-    "two": 2,
-    "two-and-a-half": 2.5
-}
diff --git a/doc/tutorial/basics/intro/20_cue.txt b/doc/tutorial/basics/intro/20_cue.txt
new file mode 100644
index 0000000..19579cc
--- /dev/null
+++ b/doc/tutorial/basics/intro/20_cue.txt
@@ -0,0 +1,51 @@
+
+-- frontmatter.toml --
+title = "Commas are Optional after Fields"
+description = ""
+
+-- text.md --
+CUE merges the concepts of values and types.
+Below is a demonstration of this concept,
+showing respectively
+some data, a possible schema for this data,
+and something in between: a typical CUE constraint.
+
+{{< blocks/sidebyside >}}
+<div class="col">
+<i>Data</i>
+{{< highlight go >}}
+moscow: {
+  name:    "Moscow"
+  pop:     11.92M
+  capital: true
+}
+{{< /highlight >}}
+</div>
+
+<div class="col">
+<i>Schema</i>
+{{< highlight go >}}
+municipality: {
+  name:    string
+  pop:     int
+  capital: bool
+}
+{{< /highlight >}}
+</div>
+
+<div class="col">
+<i>CUE</i>
+{{< highlight go >}}
+largeCapital: {
+  name:    string
+  pop:     >5M
+  capital: true
+}
+{{< /highlight >}}
+</div>
+{{< /blocks/sidebyside >}}
+
+In general, in CUE one starts with a broad definition of a schema,
+describing all possible instances,
+and then narrows down these definitions for particular use cases
+until a concrete data instance remains.
diff --git a/doc/tutorial/basics/intro/25_commaslists.txt b/doc/tutorial/basics/intro/25_commaslists.txt
deleted file mode 100644
index fe4c127..0000000
--- a/doc/tutorial/basics/intro/25_commaslists.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-cue export commas2.cue
-cmp stdout expect-stdout-cue
-
--- frontmatter.toml --
-title = "Commas are Still Required in Lists"
-description = ""
-
--- text.md --
-Commas are still required as separators in lists.
-The last element of a list may also have a comma.
-
--- commas2.cue --
-[
-    1,
-    2,
-    3,
-]
-
--- expect-stdout-cue --
-[
-    1,
-    2,
-    3
-]
diff --git a/doc/tutorial/basics/intro/30_curly.txt b/doc/tutorial/basics/intro/30_curly.txt
deleted file mode 100644
index 66ae11d..0000000
--- a/doc/tutorial/basics/intro/30_curly.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-cue export curly.cue
-cmp stdout expect-stdout-cue
-
--- frontmatter.toml --
-title = "Curly Braces"
-description = ""
-
--- text.md --
-The outer curly braces may be omitted for the top-level struct.
-CUE also allows both, which has a specific meaning.
-[We will come back to that later](emit.md).
-
--- curly.cue --
-one: 1
-two: 2
-
-"two-and-a-half": 2.5
-
--- expect-stdout-cue --
-{
-    "one": 1,
-    "two": 2,
-    "two-and-a-half": 2.5
-}
diff --git a/doc/tutorial/basics/intro/30_order.txt b/doc/tutorial/basics/intro/30_order.txt
new file mode 100644
index 0000000..b38cd3e
--- /dev/null
+++ b/doc/tutorial/basics/intro/30_order.txt
@@ -0,0 +1,33 @@
+cue eval -i order.cue
+cmp stdout expect-stdout-cue
+
+-- frontmatter.toml --
+title = "Order is irrelevant"
+description = ""
+
+-- text.md --
+CUE's basic operations are defined in a way that the order in which
+you combine two configurations is irrelevant to the outcome.
+
+This is crucial property of CUE
+that makes it easy for humans _and_ machines to reason over values and
+makes advanced tooling and automation possible.
+
+If you can think of an example where order matters, it is not valid CUE.
+
+-- order.cue --
+a: {x: 1, y: int}
+a: {x: int, y: 2}
+
+b: {x: int, y: 2}
+b: {x: 1, y: int}
+
+-- expect-stdout-cue --
+a: {
+    x: 1
+    y: 2
+}
+b: {
+    x: 1
+    y: 2
+}
diff --git a/doc/tutorial/basics/intro/32_validation.txt b/doc/tutorial/basics/intro/32_validation.txt
new file mode 100644
index 0000000..0f3c4fe
--- /dev/null
+++ b/doc/tutorial/basics/intro/32_validation.txt
@@ -0,0 +1,43 @@
+! cue vet schema.cue data.yaml
+cmp stderr expect-stderr
+
+-- frontmatter.toml --
+title = "Validation"
+description = ""
+
+-- text.md --
+Constraints specify what values are allowed.
+To CUE they are just values like anything else,
+but conceptually they can be explained as something in between types and
+concrete values.
+
+Constraints can be used to validate values of concrete instances.
+They can be applied to CUE data, or directly to YAML or JSON.
+
+But constraints can also reduce boilerplate.
+If a constraints defines a concrete value, there is no need
+to specify it in values to which this constraint applies.
+
+-- schema.cue --
+Language :: {
+	tag:  string
+	name: =~"^\\p{Lu}" // Must start with an uppercase letter.
+}
+languages: [...Language]
+
+-- data.yaml --
+languages:
+  - tag: en
+    name: English
+  - tag: nl
+    name: dutch
+  - tag: no
+    name: Norwegian
+
+-- expect-stderr --
+languages.2.tag: conflicting values string and false (mismatched types string and bool):
+    ./data.yaml:6:11
+    ./schema.cue:2:8
+languages.1.name: invalid value "dutch" (does not match =~"^\\p{Lu}"):
+    ./schema.cue:3:8
+    ./data.yaml:5:12
diff --git a/doc/tutorial/basics/intro/35_duplicates.txt b/doc/tutorial/basics/intro/35_duplicates.txt
new file mode 100644
index 0000000..4085030
--- /dev/null
+++ b/doc/tutorial/basics/intro/35_duplicates.txt
@@ -0,0 +1,41 @@
+cue eval dup.cue
+cmp stdout expect-stdout-cue
+
+-- frontmatter.toml --
+title = "Duplicates"
+description = ""
+
+-- text.md --
+Constraints specify what values are allowed.
+To CUE they are just values like anything else,
+but conceptually they can be explained as something in between types and
+concrete values.
+
+Constraints can be used to validate values of concrete instances.
+They can be applied to CUE data, or directly to YAML or JSON.
+
+But constraints can also reduce boilerplate.
+If a constraints defines a concrete value, there is no need
+to specify it in values to which this constraint applies.
+
+-- dup.cue --
+a: 4
+a: 4
+
+s: {
+    x: 1
+}
+s: {
+    y: 2
+}
+
+l: [ 1, 2 ]
+l: [ 1, 2 ]
+
+-- expect-stdout-cue --
+a: 4
+s: {
+    x: 1
+    y: 2
+}
+l: [1, 2]
diff --git a/doc/tutorial/basics/intro/40_fold.txt b/doc/tutorial/basics/intro/40_fold.txt
index f39c9f7..a6bd0a9 100644
--- a/doc/tutorial/basics/intro/40_fold.txt
+++ b/doc/tutorial/basics/intro/40_fold.txt
@@ -6,16 +6,37 @@
 description = ""
 
 -- text.md --
-CUE allows a shorthand for structs with single members.
+In JSON, one defines nested values, one value at a time.
+Another way to look at this is that a JSON configuration is a set of
+path-value pairs.
+
+In CUE one defines a set of paths to which to apply
+a concrete value or constraint all at once.
+Because or CUE's order independence, values get merged
+
+This example shows some path-value pairs, as well as
+a constraint that is applied to those to validate them.
+<!--
+This also gives a handy shorthand for writing structs with single
+members.
+-->
 
 -- fold.cue --
-outer middle inner: 3
+// path-value pairs
+outer middle1 inner: 3
+outer middle2 inner: 7
+
+// collection-constraint pair
+outer <Any> inner: int
 
 -- expect-stdout-cue --
 {
     "outer": {
-        "middle": {
+        "middle1": {
             "inner": 3
+        },
+        "middle2": {
+            "inner": 7
         }
     }
 }
diff --git a/doc/tutorial/basics/intro/45_foldany.txt b/doc/tutorial/basics/intro/45_foldany.txt
deleted file mode 100644
index efa1519..0000000
--- a/doc/tutorial/basics/intro/45_foldany.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-cue export foldany.cue
-cmp stdout expect-stdout-cue
-
--- frontmatter.toml --
-title = "Folding all Fields"
-description = ""
-
--- text.md --
-This also works if a struct has more than one member.
-
-In general, any JSON object can be expressed as a collection of
-path-leaf pairs without using any curly braces.
-
--- foldany.cue --
-outer middle1 inner: 3
-outer middle2 inner: 7
-
--- expect-stdout-cue --
-{
-    "outer": {
-        "middle1": {
-            "inner": 3
-        },
-        "middle2": {
-            "inner": 7
-        }
-    }
-}
diff --git a/doc/tutorial/basics/intro/50_boilerplate.txt b/doc/tutorial/basics/intro/50_boilerplate.txt
new file mode 100644
index 0000000..2924ee4
--- /dev/null
+++ b/doc/tutorial/basics/intro/50_boilerplate.txt
@@ -0,0 +1,17 @@
+
+-- frontmatter.toml --
+title = "Templating"
+description = ""
+
+-- text.md --
+Constraints specify what values are allowed.
+To CUE they are just values like anything else,
+but conceptually they can be explained as something in between types and
+concrete values.
+
+Constraints can be used to validate values of concrete instances.
+They can be applied to CUE data, or directly to YAML or JSON.
+
+But constraints can also reduce boilerplate.
+If a constraints defines a concrete value, there is no need
+to specify it in values to which this constraint applies.
\ No newline at end of file
diff --git a/doc/tutorial/basics/intro/50_comments.txt b/doc/tutorial/basics/intro/50_comments.txt
deleted file mode 100644
index 7f21d7b..0000000
--- a/doc/tutorial/basics/intro/50_comments.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-cue export comments.cue
-cmp stdout expect-stdout-cue
-
--- frontmatter.toml --
-title = "Comments"
-description = ""
-
--- text.md --
-CUE supports C-style line comments.
-
--- comments.cue --
-// a doc comment
-one: 1
-two: 2 // a line comment
-
--- expect-stdout-cue --
-{
-    "one": 1,
-    "two": 2
-}
diff --git a/doc/tutorial/basics/types/05_types.txt b/doc/tutorial/basics/types/05_types.txt
new file mode 100644
index 0000000..ef85665
--- /dev/null
+++ b/doc/tutorial/basics/types/05_types.txt
@@ -0,0 +1,69 @@
+cue eval types.cue
+cmp stdout expect-stdout-cue
+
+-- frontmatter.toml --
+title = "Type Hierarchy"
+
+-- text.md --
+CUE defines the following type hierarchy
+
+```
+  null  bool  string  bytes  number  struct  list
+                             /   \
+                           int  float
+```
+In addition, CUE defines the values
+bottom, or error, (denoted `_|_`)
+that is an instance of all types and
+top, or any, (denoted `_`) of which all types are an instance.
+
+Note how we use the terms types and values interchangeably.
+CUE does not distinguish between types and values.
+The term "type" merely refers to the kind of a value,
+which may or may not be a concrete instance.
+
+In the example, `point` defines an arbitrary point, while `xaxis` and `yaxis`
+define the points on the respective lines.
+We say that `point`, `xaxis`, and `yaxis` are incomplete,
+as they do not specify a specific point.
+Incomplete values cannot be represented as JSON,
+as it can only represent concrete values.
+
+The only concrete point is `origin`.
+The `origin` is defined to be both on the x-axis and y-axis, which means it
+must be at `0, 0`.
+Here we see constraints in action:
+`origin` evalutes to `0, 0`, even though we did not specify its coordinates
+explicitly.
+
+-- types.cue --
+point: {
+    x: number
+    y: number
+}
+
+xaxis: point
+xaxis x: 0
+
+yaxis: point
+yaxis y: 0
+
+origin: xaxis & yaxis
+
+-- expect-stdout-cue --
+point: {
+    x: number
+    y: number
+}
+xaxis: {
+    x: 0
+    y: number
+}
+yaxis: {
+    x: number
+    y: 0
+}
+origin: {
+    x: 0
+    y: 0
+}
diff --git a/doc/tutorial/basics/types/40_unification.txt b/doc/tutorial/basics/types/40_unification.txt
deleted file mode 100644
index 0742194..0000000
--- a/doc/tutorial/basics/types/40_unification.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-cue eval -i unification.cue
-cmp stdout expect-stdout-cue
-
--- frontmatter.toml --
-title = "Order is Irrelevant"
-description = ""
-
--- text.md --
-As mentioned before, values of duplicates fields are combined.
-This process is called unification.
-Unification can also be written explicitly with the `&` operator.
-
-There is always a single unique result, possibly bottom,
-for unifying any two CUE values.
-
-Unification is commutative, associative, and idempotent.
-In other words, order doesn't matter and unifying a given set of values
-in any order always gives the same result.
-
--- unification.cue --
-a: { x: 1, y: 2 }
-b: { y: 2, z: 3 }
-c: { x: 1, z: 4 }
-
-q: a & b & c
-r: b & c & a
-s: c & b & a
-
--- expect-stdout-cue --
-a: {
-    x: 1
-    y: 2
-}
-b: {
-    y: 2
-    z: 3
-}
-c: {
-    x: 1
-    z: 4
-}
-q: {
-    x: 1
-    y: 2
-    z: _|_ // conflicting values 3 and 4
-}
-r: {
-    x: 1
-    y: 2
-    z: _|_ // conflicting values 3 and 4
-}
-s: {
-    x: 1
-    y: 2
-    z: _|_ // conflicting values 4 and 3
-}
diff --git a/doc/tutorial/basics/intro/60_numberlit.txt b/doc/tutorial/basics/types/45_numberlit.txt
similarity index 100%
rename from doc/tutorial/basics/intro/60_numberlit.txt
rename to doc/tutorial/basics/types/45_numberlit.txt
diff --git a/doc/tutorial/basics/intro/70_stringlit.txt b/doc/tutorial/basics/types/60_stringlit.txt
similarity index 100%
rename from doc/tutorial/basics/intro/70_stringlit.txt
rename to doc/tutorial/basics/types/60_stringlit.txt
diff --git a/doc/tutorial/basics/intro/75_stringraw.txt b/doc/tutorial/basics/types/65_stringraw.txt
similarity index 100%
rename from doc/tutorial/basics/intro/75_stringraw.txt
rename to doc/tutorial/basics/types/65_stringraw.txt
diff --git a/doc/tutorial/basics/intro/80_bytes.txt b/doc/tutorial/basics/types/68_bytes.txt
similarity index 100%
rename from doc/tutorial/basics/intro/80_bytes.txt
rename to doc/tutorial/basics/types/68_bytes.txt
diff --git a/doc/tutorial/basics/types/80_lists.txt b/doc/tutorial/basics/types/80_lists.txt
index 3ecf475..652f118 100644
--- a/doc/tutorial/basics/types/80_lists.txt
+++ b/doc/tutorial/basics/types/80_lists.txt
@@ -26,7 +26,9 @@
 IP: 4 * [ uint8 ]
 
 PrivateIP: IP
-PrivateIP: [10, ...uint8] | [192, 168, ...] | [172, >=16 & <=32, ...]
+PrivateIP: [10, ...uint8] |
+    [192, 168, ...] |
+    [172, >=16 & <=32, ...]
 
 myIP: PrivateIP
 myIP: [10, 2, 3, 4]