doc/tutorial/basics: add basics tutorial
Change-Id: I350244d6db5e20be4ab3913dc864f61923b2738f
diff --git a/README.md b/README.md
index 62a1c06..720e4f5 100644
--- a/README.md
+++ b/README.md
@@ -62,8 +62,11 @@
### Learning CUE
-A demonstration of how to convert and restructure an existing
-set of Kubernetes configurations is available in
+The fastest way to learn the basics is to follow the
+[tutorial on basic language constructs](./doc/tutorial/basics/Readme.md).
+
+A more elaborate tutorial demonstrating of how to convert and restructure
+an existing set of Kubernetes configurations is available in
[written form](./doc/tutorial/kubernetes/README.md).
### References
diff --git a/doc/ref/spec.md b/doc/ref/spec.md
index 06bf5ef..fec6f02 100644
--- a/doc/ref/spec.md
+++ b/doc/ref/spec.md
@@ -273,10 +273,6 @@
/ :: ; = ... .. .
div mod quo rem _|_ <- ,
```
-Optional:
-```
--> _|_
-```
### Integer literals
@@ -523,7 +519,7 @@
Support for other values:
- Duration literals
-- regualr expessions: `re("[a-z]")`
+- regular expessions: `re("[a-z]")`
-->
## Prototypes
@@ -829,7 +825,7 @@
We denote the value for a label `f` defined for `a` as `δ(f, a)`.
A struct `a` is an instance of `b`, or `a ⊑ b`, if for any label `f`
-defined for `b` label `f` is also defiend for `a` and `δ(f, a) ⊑ δ(f, b)`.
+defined for `b` label `f` is also defined for `a` and `δ(f, a) ⊑ δ(f, b)`.
Note that if `a` is an instance of `b` it may have fields with labels that
are not defined for `b`.
@@ -992,7 +988,7 @@
A block is mostly corresponds with the brace brackets of a struct literal
`{ ... }`, but also includes the following,
-- The _universe block_ encompases all CUE source text.
+- The _universe block_ encompasses all CUE source text.
- Each package has a _package block_ containing all CUE source text in that package.
- Each file has a _file block_ containing all CUE source text in that file.
- Each `for` and `let` clause in a comprehension is considered to be
@@ -1037,7 +1033,7 @@
The package clause is not a declaration;
the package name do not appear in any scope.
Its purpose is to identify the files belonging to the same package
-and tospecify the default name for import declarations.
+and to specify the default name for import declarations.
### Predeclared identifiers
@@ -1417,7 +1413,8 @@
For two integer values `x` and `y`,
the integer quotient `q = x div y` and remainder `r = x mod y `
-satisfy the following relationships:
+implement Euclidean division and
+satisfy the following relationship:
```
r = x - y*q with 0 <= r < |y|
@@ -1434,7 +1431,8 @@
For two integer values `x` and `y`,
the integer quotient `q = x quo y` and remainder `r = x rem y `
-satisfy the following relationships:
+implement truncated division and
+satisfy the following relationship:
```
x = q*y + r and |r| < |y|
@@ -1755,7 +1753,7 @@
```
--->
-#### Convesions between struct types
+#### Conversions between struct types
A conversion from `x` to `T`
is applied using the following rules:
diff --git a/doc/tutorial/basics/Readme.md b/doc/tutorial/basics/Readme.md
new file mode 100644
index 0000000..0a75cc7
--- /dev/null
+++ b/doc/tutorial/basics/Readme.md
@@ -0,0 +1,56 @@
+# CUE Tutorial
+
+## About this tutorial
+
+This tutorial teaches the fundamentals of CUE.
+To try out the examples in the tutorial you can follow the
+[installation instructions](../../install.md)
+to get a working setup of CUE.
+
+Use the `cue eval` or `cue export` commands to evaluate an example.
+
+[Click here to start](json.md)
+
+## TOC
+
+- [JSON Sugar and other Goodness](json.md)
+ - [Quotes are Optional for Field Names](fieldname.md)
+ - [Commas are Optional after Fields](commas.md)
+ - [Commas are Still Required in Lists](commaslists.md)
+ - [Curly Braces](curly.md)
+ - [Folding of Single-Field Structs](fold.md)
+ - [Folding all Fields](foldany.md)
+ - [Comments](comments.md)
+ - [Number Literals](numberlit.md)
+ - [String Literals](stringlit.md)
+ - [Bytes](bytes.md)
+- Scoping
+ - [References and Scopes](scopes.md)
+ - [Accessing Fields](selectors.md)
+ - [Aliases](aliases.md)
+ - [Emit Values](emit.md)
+ - [Hidden Values](hidden.md)
+- Types and Values
+ - [Duplicate Fields](duplicates.md)
+ - [Bottom / Error](bottom.md)
+ - [Basic Types](types.md)
+ - [Unification](unification.md)
+ - [Disjunctions](disjunctions.md)
+ - [Disjunctions of Structs](disjstruct.md)
+ - [Numbers](numbers.md)
+ - [Ranges](ranges.md)
+ - [Predefined Ranges](rangedef.md)
+ - [Lists](lists.md)
+- [Modules, Packages, and Instances](instances.md)
+ - [Packages](packages.md)
+ - [Imports](imports.md)
+- Expressions
+ - [Operators](operators.md)
+ - [Interpolation](interpolation.md)
+ - [Interpolation in Field Names](interpolfield.md)
+ - [List Comprehensions](listcomp.md)
+ - [Field Comprehensions](fieldcomp.md)
+ - [Conditional Fields](conditional.md)
+ - [Null or Error coalescing](coalescing.md)
+ <!-- - Conversions -->
+ <!-- - Functions (simulating) -->
diff --git a/doc/tutorial/basics/aliases.md b/doc/tutorial/basics/aliases.md
new file mode 100644
index 0000000..854d5db
--- /dev/null
+++ b/doc/tutorial/basics/aliases.md
@@ -0,0 +1,38 @@
+[TOC](Readme.md) [Prev](selectors.md) [Next](emit.md)
+
+# Aliases
+
+An alias defines a local macro.
+
+A typical use case is to provide access to a shadowed field.
+
+Alias are not members of a struct and thus are not part of the model and
+cannot be accessed.
+
+
+<!-- CUE editor -->
+```
+A = a // A is an alias to a
+a: {
+ d: 3
+}
+b: {
+ a: {
+ // A provides access to the outer "a" which would
+ // otherwise be hidden by the inner one.
+ c: A.d
+ }
+}
+```
+
+<!-- result -->
+```
+a: {
+ d: 3
+}
+b: {
+ a: {
+ c: 3
+ }
+}
+```
diff --git a/doc/tutorial/basics/bottom.md b/doc/tutorial/basics/bottom.md
new file mode 100644
index 0000000..c3cde6a
--- /dev/null
+++ b/doc/tutorial/basics/bottom.md
@@ -0,0 +1,28 @@
+[TOC](Readme.md) [Prev](duplicates.md) [Next](types.md)
+
+# Bottom
+
+Specifying duplicate fields with conflicting values results in an error,
+denoted `_|_`.
+
+Technically speaking, bottom is just a value like any other.
+But for all practical purposes it is okay to think of the bottom value
+as an error.
+
+Note that an error is different from `null`: `null` is a valid JSON value,
+whereas `_|_` is not.
+
+<!-- CUE editor -->
+```
+a: 4
+a: 5
+
+l: [ 1, 2 ]
+l: [ 1, 3 ]
+```
+
+<!-- result -->
+```
+a: _|_
+l: _|_
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/bytes.md b/doc/tutorial/basics/bytes.md
new file mode 100644
index 0000000..bf8d050
--- /dev/null
+++ b/doc/tutorial/basics/bytes.md
@@ -0,0 +1,24 @@
+[TOC](Readme.md) [Prev](stringlit.md) [Next](scopes.md)
+
+# Bytes
+
+CUE distinguishes between a `string` and a `bytes` type.
+Bytes are converted to base64 when emitting JSON.
+Byte literals are defined with single quotes.
+The following additional escape sequences are allowed in byte literals:
+
+ \xnn // arbitrary byte value defined as a 2-digit hexadecimal number
+ \0nnn // arbitrary byte value defined as a 3-digit octal number
+
+
+<!-- CUE editor -->
+```
+a: '\x03abc'
+```
+
+<!-- JSON result -->
+```json
+{
+ a: "A2FiYw=="
+}
+```
diff --git a/doc/tutorial/basics/coalesce.md b/doc/tutorial/basics/coalesce.md
new file mode 100644
index 0000000..312fa14
--- /dev/null
+++ b/doc/tutorial/basics/coalesce.md
@@ -0,0 +1,26 @@
+[TOC](Readme.md) [Prev](conditional.md) _Next_
+
+# Null Coalescing
+
+With null coalescing we really mean error, or bottom, coalescing.
+The defaults mechanism for disjunctions can also be
+used to provide fallback values in case an expression evaluates to bottom.
+
+In the example the fallback values are specified
+for `a` and `b` in case the list index is out of bounds.
+
+<!-- CUE editor -->
+```
+list: [ "Cat", "Mouse", "Dog" ]
+
+a: list[0] | "None"
+b: list[5] | "None"
+```
+
+<!-- result -->
+```
+list: [ "Cat", "Mouse", "Dog" ]
+
+a: "Cat"
+b: "None"
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/commas.md b/doc/tutorial/basics/commas.md
new file mode 100644
index 0000000..c92ec4e
--- /dev/null
+++ b/doc/tutorial/basics/commas.md
@@ -0,0 +1,32 @@
+[TOC](Readme.md) [Prev](fieldname.md) [Next](commaslists.md)
+
+# Commas are Optional after Fields
+
+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._
+
+<!-- CUE editor -->
+```
+{
+ one: 1
+ two: 2
+
+ "two-and-a-half": 2.5
+}
+```
+
+
+<!-- JSON result -->
+```json
+{
+ "one": 1,
+ "two": 2,
+ "two-and-a-half": 2.5
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/commaslists.md b/doc/tutorial/basics/commaslists.md
new file mode 100644
index 0000000..977c4bc
--- /dev/null
+++ b/doc/tutorial/basics/commaslists.md
@@ -0,0 +1,25 @@
+[TOC](Readme.md) [Prev](commas.md) [Next](curly.md)
+
+# Commas are Still Required in Lists
+
+
+Commas are still required as separators in lists.
+The last element of a list may also have a comma.
+
+<!-- CUE editor -->
+```
+[
+ 1,
+ 2,
+ 3,
+]
+```
+
+<!-- JSON result -->
+```json
+[
+ 1,
+ 2,
+ 3
+]
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/comments.md b/doc/tutorial/basics/comments.md
new file mode 100644
index 0000000..76d6ace
--- /dev/null
+++ b/doc/tutorial/basics/comments.md
@@ -0,0 +1,25 @@
+[TOC](Readme.md) [Prev](foldany.md) [Next](numberlit.md)
+
+# Comments
+
+CUE supports C-style block and line comments.
+
+<!-- CUE editor -->
+```
+// whole numbers
+one: 1
+two: 2
+
+/* fractions
+ */
+"two-and-a-half": 2.5
+```
+
+<!-- JSON result -->
+```json
+{
+ "one": 1,
+ "two": 2,
+ "two-and-a-half": 2.5
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/conditional.md b/doc/tutorial/basics/conditional.md
new file mode 100644
index 0000000..5fc6a4f
--- /dev/null
+++ b/doc/tutorial/basics/conditional.md
@@ -0,0 +1,26 @@
+[TOC](Readme.md) [Prev](fieldcomp.md) [Next](coalesce.md)
+
+# Conditional Fields
+
+Field comprehensions can also be used to
+add a single field conditionally.
+
+Converting the resulting configuration to JSON results in an error
+as `justification` is required yet no concrete value is given.
+
+
+<!-- CUE editor -->
+```
+price: float
+
+// Require a justification if price is too high
+justification: string if price > 100
+
+price: 200
+```
+
+<!-- result -->
+```
+price: 200
+justification: string
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/curly.md b/doc/tutorial/basics/curly.md
new file mode 100644
index 0000000..c847ee1
--- /dev/null
+++ b/doc/tutorial/basics/curly.md
@@ -0,0 +1,24 @@
+[TOC](Readme.md) [Prev](commaslists.md) [Next](fold.md)
+
+# Curly Braces
+
+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).
+
+```
+one: 1
+two: 2
+
+"two-and-a-half": 2.5
+```
+
+<!-- JSON result -->
+```json
+{
+ "one": 1,
+ "two": 2,
+ "two-and-a-half": 2.5
+}
+```
+
diff --git a/doc/tutorial/basics/defaults.md b/doc/tutorial/basics/defaults.md
new file mode 100644
index 0000000..145057e
--- /dev/null
+++ b/doc/tutorial/basics/defaults.md
@@ -0,0 +1,30 @@
+# Default Values
+
+If at the time of evaluation a sum type still has more than one possible
+value, the first error-free value is taken.
+A value is error free if it is not an error, it is a list with only error-free
+elements, or it is a struct where all field values are error-free.
+The default value must also not be ambiguous.
+
+In the example, `replicas` defaults to `1`.
+In the case of `protocol`, however, there are multiple definitions with
+different, mutually incompatible defaults.
+It is still possible to resolve this error by explicitly setting the value
+for protocol.
+Try it!
+<!-- CUE editor -->
+```
+// any positive number, 1 is the default
+replicas: 1 | uint
+
+// the default value is ambiguous
+protocol: "tcp" | "udp"
+protocol: "udp" | "tcp"
+```
+
+<!-- result -->
+```
+replicas: 1
+
+protocol: _|_
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/disjstruct.md b/doc/tutorial/basics/disjstruct.md
new file mode 100644
index 0000000..f1566e8
--- /dev/null
+++ b/doc/tutorial/basics/disjstruct.md
@@ -0,0 +1,26 @@
+[TOC](Readme.md) [Prev](disjunctions.md) [Next](numbers.md)
+
+# Disjunctions of Structs
+
+Disjunction work for any type.
+
+In this example we see that a `floor` of some specific house
+has an exit on level 0 and 1, but not on any other floor.
+
+<!-- CUE editor -->
+```
+// floor defines the specs of a floor in some house.
+floor: {
+ level: int // the level on which this floor resides
+ hasExit: bool // is there a door to exit the house?
+}
+
+// constraints on the possible values of floor.
+floor: {
+ level: 0 | 1
+ hasExit: true
+} | {
+ level: -1 | 2 | 3
+ hasExit: false
+}
+```
diff --git a/doc/tutorial/basics/disjunctions.md b/doc/tutorial/basics/disjunctions.md
new file mode 100644
index 0000000..11fd875
--- /dev/null
+++ b/doc/tutorial/basics/disjunctions.md
@@ -0,0 +1,25 @@
+[TOC](Readme.md) [Prev](unification.md) [Next](disjstruct.md)
+
+# Disjunctions
+
+Disjunctions, or sum types, define a new type that is one of several things.
+
+In the example, `conn` defines a `protocol` field that must be one of two
+values: `"tcp"` or `"upd"`.
+It is an error for a concrete `conn`
+to define anything else than these two values.
+
+<!-- CUE editor -->
+```
+conn: {
+ address: string
+ port: int
+ protocol: "tcp" | "udp"
+}
+
+lossy: {
+ address: "1.2.3.4"
+ port: 8888
+ protocol: "udp"
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/duplicates.md b/doc/tutorial/basics/duplicates.md
new file mode 100644
index 0000000..2b12d45
--- /dev/null
+++ b/doc/tutorial/basics/duplicates.md
@@ -0,0 +1,38 @@
+[TOC](Readme.md) [Prev](hidden.md) [Next](bottom.md)
+
+# Duplicate Fields
+
+CUE allows duplicated field definitions as long as they don't conflict.
+
+For values of basic types this means they must be equal.
+
+For structs, fields are merged and duplicated fields are handled recursively.
+
+For lists, all elements must match accordingly
+([we discuss open-ended lists later](lists.md).)
+
+<!-- CUE editor -->
+```
+a: 4
+a: 4
+
+s: {
+ x: 1
+}
+s: {
+ y: 2
+}
+
+l: [ 1, 2 ]
+l: [ 1, 2 ]
+```
+
+<!-- result -->
+```
+a: 4
+s: {
+ x: 1
+ y: 2
+}
+l: [1, 2]
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/emit.md b/doc/tutorial/basics/emit.md
new file mode 100644
index 0000000..9268db3
--- /dev/null
+++ b/doc/tutorial/basics/emit.md
@@ -0,0 +1,29 @@
+[TOC](Readme.md) [Prev](aliases.md) [Next](hidden.md)
+
+# Emit Values
+
+By default all top-level fields are emitted when evaluating a configuration.
+CUE files may define a top-level value that is emitted instead.
+
+Values within the emit value may refer to fields defined outside of it.
+
+Emit values allow CUE configurations, like JSON,
+to define any type, instead of just structs, while keeping the common case
+of defining structs light.
+
+<!-- CUE editor -->
+```
+{
+ a: A
+ b: B
+}
+
+A: 1
+B: 2
+```
+
+<!-- result -->
+```
+a: 1
+b: 2
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/fieldcomp.md b/doc/tutorial/basics/fieldcomp.md
new file mode 100644
index 0000000..1c39f05
--- /dev/null
+++ b/doc/tutorial/basics/fieldcomp.md
@@ -0,0 +1,42 @@
+[TOC](Readme.md) [Prev](listcomp.md) [Next](conditional.md)
+
+# Field Comprehensions
+
+CUE also supports comprehensions for fields.
+
+One cannot refer to generated fields with references.
+Instead, one must use indexing.
+
+<!-- CUE editor -->
+```
+import "strings"
+
+a: [ "Barcelona", "Shanghai", "Munich" ]
+
+{
+ "\( strings.ToLower(v) )": {
+ pos: k
+ name: v
+ nameLen: len(v)
+ } for k, v in a
+}
+```
+
+<!-- result -->
+```
+barcelona: {
+ pos: 1
+ name: "Barcelona"
+ nameLen: 9
+}
+shanghai: {
+ pos: 2
+ name: "Shanghai"
+ nameLen: 9
+}
+munich: {
+ pos: 3
+ name: "Munich"
+ nameLen: 9
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/fieldname.md b/doc/tutorial/basics/fieldname.md
new file mode 100644
index 0000000..42c8e9b
--- /dev/null
+++ b/doc/tutorial/basics/fieldname.md
@@ -0,0 +1,28 @@
+[TOC](Readme.md) [Prev](json.md) [Next](commas.md)
+
+# Quotes are Optional for Field Names
+
+JSON objects are called structs in CUE.
+An object member is called a field.
+
+
+Double quotes may be omitted from field names if their name contains no
+special characters and does not start with a number:
+
+<!-- CUE editor -->
+```
+{
+ one: 1,
+ two: 2,
+ "two-and-a-half": 2.5
+}
+```
+
+<!-- JSON result -->
+```json
+{
+ "one": 1,
+ "two": 2,
+ "two-and-a-half": 2.5
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/fold.md b/doc/tutorial/basics/fold.md
new file mode 100644
index 0000000..eabdc9b
--- /dev/null
+++ b/doc/tutorial/basics/fold.md
@@ -0,0 +1,19 @@
+[TOC](Readme.md) [Prev](curly.md) [Next](foldany.md)
+
+# Folding of Single-Field Structs
+
+CUE allows a shorthand for structs with single members.
+
+<!-- CUE editor -->
+```
+outer middle inner: 3
+```
+
+<!-- JSON result -->
+```json
+"outer": {
+ "middle": {
+ "inner": 3
+ }
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/foldany.md b/doc/tutorial/basics/foldany.md
new file mode 100644
index 0000000..f24097e
--- /dev/null
+++ b/doc/tutorial/basics/foldany.md
@@ -0,0 +1,26 @@
+[TOC](Readme.md) [Prev](fold.md) [Next](comments.md)
+
+# Folding all Fields
+
+This also works if a struct has more than one member.
+
+In general, any JSON configuration can be expressed as a collection of
+path-leaf pairs without using any curly braces.
+
+<!-- CUE editor -->
+```
+outer middle1 inner: 3
+outer middle2 inner: 7
+```
+
+<!-- JSON result -->
+```json
+"outer": {
+ "middle1": {
+ "inner": 3
+ },
+ "middle2": {
+ "inner": 7
+ }
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/hidden.md b/doc/tutorial/basics/hidden.md
new file mode 100644
index 0000000..37537eb
--- /dev/null
+++ b/doc/tutorial/basics/hidden.md
@@ -0,0 +1,24 @@
+[TOC](Readme.md) [Prev](emit.md) [Next](duplicates.md)
+
+# Hidden Fields
+
+A non-quoted field name that starts with an underscore (`_`) is not
+emitted from the output.
+To includes fields in the configuration that start with an underscore
+put them in quotes.
+
+Quoted an non-quoted fields share the same namespace unless they start
+with an underscore.
+
+<!-- CUE editor -->
+```
+"_foo": 2
+_foo: 3
+foo: 4
+```
+
+<!-- result -->
+```
+"_foo": 2
+foo: 4
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/imports.md b/doc/tutorial/basics/imports.md
new file mode 100644
index 0000000..a05dce3
--- /dev/null
+++ b/doc/tutorial/basics/imports.md
@@ -0,0 +1,34 @@
+[TOC](Readme.md) [Prev](packages.md) [Next](operators.md)
+
+# Imports
+
+A CUE file may import definitions from builtin or user-defined packages.
+The CUE file itself does not need to be part of a package to use imports.
+
+The example here shows the use of builtin packages.
+
+This code groups the imports into a parenthesized, "factored" import statement.
+
+You can also write multiple import statements, like:
+
+```
+import "encoding/json"
+import "math"
+```
+
+But it is good style to use the factored import statement.
+
+<!-- CUE editor -->
+```
+import (
+ "encoding/json"
+ "math"
+)
+
+data: json.Marshal({ a: math.Sqrt(7) })
+```
+
+<!-- result -->
+```
+data: "{\"a\":2.6457513110645907}"
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/instances.md b/doc/tutorial/basics/instances.md
new file mode 100644
index 0000000..1b99949
--- /dev/null
+++ b/doc/tutorial/basics/instances.md
@@ -0,0 +1,39 @@
+[TOC](Readme.md) [Prev](lists.md) [Next](packages.md)
+
+# Modules, Packages, and Instances
+
+## Packages
+
+A CUE file is a standalone file by default.
+A `package` clause allows a single configuration to be split across multiple
+files.
+
+[Packages tutorial](packages.md)
+
+## Instances
+
+All files within a directory hierarchy with the same package identifier belong
+to the same package.
+Each directory within this hierarchy provides a different "view" of this package
+called an _instance_.
+An instance of a package for a directory is defined by all CUE files in that
+directory and all of its ancestor directories, belonging to the same package.
+This allows common configuration to be shared and policies to be enforced
+across a collection of related configurations.
+
+See the [Kubernetes Tutorial](../kubernetes/Readme.md) for a concrete example
+of instances.
+
+
+## Modules
+
+A _module_ is the directory hierarchy containing the CUE files of a package.
+The root of this directory hierarchy is the _module root_.
+It may be explicitly marked with a `cue.mod` file.
+
+<!-- TODO:
+The module root may contain a `pkg` directory containing packages that are
+importable with import.
+The convention is to use the URL from which the package is retrieved.
+-->
+
diff --git a/doc/tutorial/basics/interpolation.md b/doc/tutorial/basics/interpolation.md
new file mode 100644
index 0000000..43aa635
--- /dev/null
+++ b/doc/tutorial/basics/interpolation.md
@@ -0,0 +1,21 @@
+[TOC](Readme.md) [Prev](operators.md) [Next](interpolfield.md)
+
+# Interpolation
+
+String and bytes literals support interpolation.
+
+Any valid CUE expression may be used inside the escaped parentheses.
+Interpolation may also be used in multiline string and byte literals.
+
+<!-- CUE editor -->
+```
+"You are \( cost - budget ) dollars over budget!"
+
+cost: 102
+budget: 88
+```
+
+<!-- result -->
+```
+"You are 14 dollars over budget!"
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/interpolfield.md b/doc/tutorial/basics/interpolfield.md
new file mode 100644
index 0000000..c93ef77
--- /dev/null
+++ b/doc/tutorial/basics/interpolfield.md
@@ -0,0 +1,27 @@
+[TOC](Readme.md) [Prev](interpolation.md) [Next](listcomp.md)
+
+# Interpolation of Field Names
+
+String interpolations may also be used in field names.
+
+One cannot refer to generated fields with references.
+
+<!-- CUE editor -->
+```
+sandwich: {
+ type: "Cheese"
+ "has\(type)": true
+ hasButter: true
+ butterAndCheese: hasButter && hasCheese
+}
+```
+
+<!-- result -->
+```
+sandwich: {
+ type: "Cheese"
+ hasCheese: true
+ hasButter: true
+ butterAndCheese: _|_ // unknown reference 'hasCheese'
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/json.md b/doc/tutorial/basics/json.md
new file mode 100644
index 0000000..0bc70bb
--- /dev/null
+++ b/doc/tutorial/basics/json.md
@@ -0,0 +1,10 @@
+[TOC](Readme.md) _Prev_ [Next](fieldname.md)
+
+
+# JSON sugar and other Goodness
+
+CUE is an extension of JSON.
+This improves familiarity and makes it easy to get going quickly.
+
+In its simplist use case, CUE can substitute for a more pleasent way to write
+JSON.
diff --git a/doc/tutorial/basics/listcomp.md b/doc/tutorial/basics/listcomp.md
new file mode 100644
index 0000000..1329751
--- /dev/null
+++ b/doc/tutorial/basics/listcomp.md
@@ -0,0 +1,20 @@
+[TOC](Readme.md) [Prev](interpolfield.md) [Next](fieldcomp.md)
+
+# List Comprehensions
+
+Lists can be created with list comprehensions.
+
+The example shows the use of `for` loops and `if` guards.
+
+
+<!-- CUE editor -->
+```
+[ x*x for x in items if x rem 2 == 0]
+
+items: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
+```
+
+<!-- result -->
+```
+[4, 16, 36, 64]
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/lists.md b/doc/tutorial/basics/lists.md
new file mode 100644
index 0000000..9d5f55b
--- /dev/null
+++ b/doc/tutorial/basics/lists.md
@@ -0,0 +1,45 @@
+[TOC](Readme.md) [Prev](ranges.md) [Next](instances.md)
+
+# Lists
+
+Lists define arbitrary sequences of CUE values.
+A list can be closed or open ended.
+Open-ended lists may have some predefined elements, but may have number of
+additional, possibly typed elements.
+
+In the example we define `IP` to be a list of `4` elements of type `uint8`, which
+is a predeclared value of `0..255`.
+`PrivateIP` defines the IP ranges defined for private use.
+Note that as it is already defined to be an `IP`, the length of the list
+is already fixed at `4` and we do not have to specify all elements.
+Also note that instead of writing `...uint8`, we could have written `...`
+as the type constraint is already already implied by `IP`.
+
+The output contains a valid private IP addresses `myIP`, and an invalid
+one `yourIP`.
+
+<!-- CUE editor -->
+```
+IP: 4 * [ uint8 ]
+
+PrivateIP: IP
+PrivateIP: [10, ...uint8] | [192, 168, ...] | [172, 16..32, ...]
+
+myIP: PrivateIP
+myIP: [10, 2, 3, 4]
+
+yourIP: PrivateIP
+yourIP: [11, 1, 2, 3]
+```
+
+<!-- result -->
+```
+IP: [0..255, 0..255, 0..255, 0..255]
+PrivateIP:
+ [10, 0..255, 0..255, 0..255] |
+ [192, 168, 0..255, 0..255] |
+ [172, 16..32, 0..255, 0..255]
+
+myIP: [10, 2, 3, 4]
+yourIP: _|_
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/numberlit.md b/doc/tutorial/basics/numberlit.md
new file mode 100644
index 0000000..2e336c0
--- /dev/null
+++ b/doc/tutorial/basics/numberlit.md
@@ -0,0 +1,26 @@
+[TOC](Readme.md) [Prev](comments.md) [Next](stringlit.md)
+
+# Number Literals
+
+
+CUE adds a variety of sugar for writing numbers.
+
+<!-- CUE editor -->
+```
+[
+ 1_234, // 1234
+ 5M, // 5_000_000
+ 1.5Gi, // 1_610_612_736
+ 0x1000_0000, // 268_435_456
+]
+```
+
+<!-- JSON result -->
+```json
+[
+ 1234,
+ 5000000,
+ 1610612736,
+ 268435456
+]
+```
diff --git a/doc/tutorial/basics/numbers.md b/doc/tutorial/basics/numbers.md
new file mode 100644
index 0000000..f1d458e
--- /dev/null
+++ b/doc/tutorial/basics/numbers.md
@@ -0,0 +1,35 @@
+[TOC](Readme.md) [Prev](disjunctions.md) [Next](ranges.md)
+
+# Numbers
+
+CUE defines two kinds of numbers.
+Integers, denoted `int`, are whole, or integral, numbers.
+Floats, denoted `float`, are decimal floating point numbers.
+
+An integer literal (e.g. `4`) can be of either type, but defaults to `int`.
+A floating point literal (e.g. `4.0`) is only compatible with `float`.
+
+In the example, the result of `b` is a `float` and cannot be
+used as an `int` without conversion.
+
+<!-- CUE editor -->
+```
+a: int
+a: 4 // type int
+
+b: float
+b: 4 // type float
+
+c: int
+c: 4.0
+
+d: 4 // will evaluate to type int (default)
+```
+
+<!-- result -->
+```
+a: 4
+b: 4.0
+c: _|_
+d: 4
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/operators.md b/doc/tutorial/basics/operators.md
new file mode 100644
index 0000000..bb09a3b
--- /dev/null
+++ b/doc/tutorial/basics/operators.md
@@ -0,0 +1,29 @@
+[TOC](Readme.md) [Prev](imports.md) [Next](interpolation.md)
+
+# Operators
+
+CUE supports many common arithmetic and boolean operators.
+
+The operators for division and remainder are different for `int` and `float`.
+CUE supports both Euclidean division (`div` and `mod`)
+and truncated division (`quo` and `rem`).
+
+<!-- CUE editor -->
+```
+a: 3 / 2 // type float
+b: 3 div 2 // type int: Euclidean division
+
+c: 3 * "blah"
+d: 3 * [1, 2, 3]
+
+e: 8 < 10
+```
+
+<!-- result -->
+```
+a: 1.5
+b: 1
+c: "blahblahblah"
+d: [1, 2, 3, 1, 2, 3, 1, 2, 3]
+e: true
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/packages.md b/doc/tutorial/basics/packages.md
new file mode 100644
index 0000000..a61800d
--- /dev/null
+++ b/doc/tutorial/basics/packages.md
@@ -0,0 +1,39 @@
+[TOC](Readme.md) [Prev](instances.md) [Next](imports.md)
+
+# Packages
+
+A CUE file is a standalone file by default.
+A `package` clause allows a single configuration to be split across multiple
+files.
+
+The configuration for a package is defined by the concatenation of all its
+files, after stripping the package clauses and not considering imports for now.
+
+Duplicate definitions are treated analogously to duplicate definitions within
+the same file.
+The order in which files are loaded is undefined, but any order will result
+in the same outcome, given that order does not matter.
+
+<!-- CUE editor tab 1-->
+File a.cue
+```
+package config
+
+foo: 100
+bar: int
+```
+
+<!-- CUE editor tab 2-->
+File b.cue
+```
+package config
+
+bar: 200
+```
+
+<!-- result -->
+Result
+```
+foo: 100
+bar: 200
+```
diff --git a/doc/tutorial/basics/rangedef.md b/doc/tutorial/basics/rangedef.md
new file mode 100644
index 0000000..6bb34eb
--- /dev/null
+++ b/doc/tutorial/basics/rangedef.md
@@ -0,0 +1,45 @@
+[TOC](Readme.md) [Prev](ranges.md) [Next](lists.md)
+
+# Predefined Ranges
+
+Numbers if CUE have arbitrary precision.
+Also there is no unsigned integer type.
+
+CUE defines the following predefined identifiers to restrict the ranges of
+integers to common values.
+
+```
+uint 0..int
+uint8 0..255
+int8 -128..127
+uint16 0..65536
+int16 -32_768...32_767
+rune 0..0x10FFFF
+uint32 0..4_294_967_296
+int32 -2_147_483_648..2_147_483_647
+uint64 0..18_446_744_073_709_551_615
+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
+uint128 0..340_282_366_920_938_463_463_374_607_431_768_211_455
+```
+
+<!-- CUE editor -->
+```
+positive: uint
+byte: uint8
+word: int32
+
+{
+ a: positive & -1
+ b: byte & 128
+ c: word & 2_000_000_000
+}
+```
+
+<!-- result -->
+```
+a: _|_
+b: 128
+c: 2000000000
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/ranges.md b/doc/tutorial/basics/ranges.md
new file mode 100644
index 0000000..7817d04
--- /dev/null
+++ b/doc/tutorial/basics/ranges.md
@@ -0,0 +1,40 @@
+[TOC](Readme.md) [Prev](numbers.md) [Next](rangedef.md)
+
+# Ranges
+
+Ranges define an inclusive range of valid values.
+They work on numbers, strings, and bytes.
+
+The type of a range is the unification of the types of the start and end
+value.
+
+Unifying two ranges results in the overlapping range or an error if there
+is no overlap.
+
+<!-- CUE editor -->
+```
+rn: 3..5 // type int | float
+ri: 3..5 & int // type int
+rf: 3..5.0 // type float
+rs: "a".."mo"
+
+{
+ a: rn & 3.5
+ b: ri & 3.5
+ c: rf & 3
+ d: "ma"
+ e: "mu"
+
+ r1: 0..7 & 3..10
+}
+```
+
+<!-- result -->
+```
+a: 3.5
+b: _|_
+c: 3
+d: "ma"
+e: _|_
+r1: 3..7
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/scopes.md b/doc/tutorial/basics/scopes.md
new file mode 100644
index 0000000..df45986
--- /dev/null
+++ b/doc/tutorial/basics/scopes.md
@@ -0,0 +1,35 @@
+[TOC](Readme.md) [Prev](json.md) [Next](selectors.md)
+
+# References and Scopes
+
+A reference refers to the value of the field defined within nearest
+enclosing scope.
+
+If no field matches the reference within the file, it may match a top-level
+field of the same package.
+
+If there is still no match, it may match a predefined value.
+
+<!-- CUE editor -->
+```
+v: 1
+a: {
+ v: 2
+ b: v // matches the inner v
+}
+a: {
+ c: v // matches the top-level v
+}
+b: v
+```
+
+<!-- result -->
+```
+v: 1
+a: {
+ v: 2
+ b: 2
+ c: 1
+}
+b: 1
+```
diff --git a/doc/tutorial/basics/selectors.md b/doc/tutorial/basics/selectors.md
new file mode 100644
index 0000000..f64fadb
--- /dev/null
+++ b/doc/tutorial/basics/selectors.md
@@ -0,0 +1,27 @@
+[TOC](Readme.md) [Prev](scopes.md) [Next](aliases.md)
+
+# Accessing Fields
+
+Selectors access fields within a struct using the `.` notation.
+This only works if a field name is a valid identifier and it is not computed.
+For other cases one can use the indexing notation.
+
+
+<!-- CUE editor -->
+```
+a: {
+ b: 2
+ "c-e": 5
+}
+v: a.b
+w: a["c-e"]
+```
+
+<!-- result -->
+```
+a: {
+ b: 2
+}
+v: 2
+w: 5
+```
diff --git a/doc/tutorial/basics/stringlit.md b/doc/tutorial/basics/stringlit.md
new file mode 100644
index 0000000..65a78e9
--- /dev/null
+++ b/doc/tutorial/basics/stringlit.md
@@ -0,0 +1,33 @@
+[TOC](Readme.md) [Prev](numberlit.md) [Next](bytes.md)
+
+# String Literals
+
+CUE stings allow a richer set of escape sequences.
+
+CUE also supports multi-line strings, enclosed by a pair of triple quotes `"""`.
+The opening quote must be followed by a newline.
+The closing quote must also be on a newline.
+The whitespace directly preceding the closing quote must match the preceding
+whitespace on all other lines and is removed from these lines.
+
+Strings may also contain [interpolations](interpolation.md).
+
+<!-- CUE editor -->
+```
+// 21-bit unicode characters
+a: "\U0001F60E" // 😎
+
+// multiline strings
+b: """
+ Hello
+ World!
+ """
+```
+
+<!-- JSON result -->
+```json
+{
+ a: "😎"
+ b: "Hello\nWorld!"
+}
+```
diff --git a/doc/tutorial/basics/types.md b/doc/tutorial/basics/types.md
new file mode 100644
index 0000000..baea3ca
--- /dev/null
+++ b/doc/tutorial/basics/types.md
@@ -0,0 +1,73 @@
+[TOC](Readme.md) [Prev](bottom.md) [Next](unification.md)
+
+# Basic Types
+
+CUE defines the following basic types
+
+```
+null
+bool
+string
+bytes
+int
+float
+```
+
+CUE does not distinguish between types and values.
+A field value can be a type (using one of the above names), a concrete value,
+or, in case of composite types (lists and structs), anything in between.
+
+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 abstract points, as these
+points are underspecified.
+Such abstract values cannot be represented as JSON,
+which requires all values to be concrete.
+
+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.
+
+
+<!-- CUE editor -->
+```
+point: {
+ x: float
+ y: float
+}
+
+xaxis: point
+xaxis x: 0
+
+yaxis: point
+yaxis y: 0
+
+origin: xaxis
+origin: yaxis
+```
+
+<!-- result -->
+```
+point: {
+ x: float
+ y: float
+}
+
+xaxis: {
+ x: 0
+ y: float
+}
+
+yaxis: {
+ x: float
+ y: 0
+}
+
+origin: {
+ x: 0
+ y: 0
+}
+```
\ No newline at end of file
diff --git a/doc/tutorial/basics/unification.md b/doc/tutorial/basics/unification.md
new file mode 100644
index 0000000..eb659e6
--- /dev/null
+++ b/doc/tutorial/basics/unification.md
@@ -0,0 +1,36 @@
+[TOC](Readme.md) [Prev](types.md) [Next](disjunctions.md)
+
+# Order is Irrelevant
+
+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 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.
+
+<!-- CUE editor -->
+```
+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
+```
+
+<!-- result -->
+```
+a: { x: 1, y: 2 }
+b: { y: 2, z: 3 }
+c: { x: 1, z: 4 }
+
+q: { x: 1, y: 2, z: _|_ }
+r: { x: 1, y: 2, z: _|_ }
+s: { x: 1, y: 2, z: _|_ }
+```
\ No newline at end of file