doc/ref/spec: attribute changes

- support attributes for structs and packages
- relax unification rules for field attributes

In all cases, the presence of attributes can never
fail unification in the new definition. It is now fully
up to the consumer how to interpret duplicates.

Struct and package attributes are handy in several locations,
as it turns out. For instance, CUE has a shared name
space for definitions and values. In JSON schema, for
instance, this is not the case. so a CUE mapping will
have to be structured differently. Recording this mapping
in field attributes is awkward.

See also Issue #259
Issue #190

Change-Id: Ia7b79ca6165faa5eea11fef3cc4c456054632233
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4602
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/doc/ref/spec.md b/doc/ref/spec.md
index 1d745f3..a9e207b 100644
--- a/doc/ref/spec.md
+++ b/doc/ref/spec.md
@@ -1112,8 +1112,8 @@
 
 ```
 StructLit       = "{" { Declaration "," } [ "..." ] "}" .
-Declaration     = Field | Comprehension | AliasExpr .
-Field           = LabelSpec { LabelSpec } Expression .
+Declaration     = Field | Comprehension | AliasExpr | attribute .
+Field           = LabelSpec { LabelSpec } Expression { attribute } .
 LabelSpec       = Label ( ":" | "::" ) .
 Label           = LabelName [ "?" ] | "[" AliasExpr "]".
 LabelName       = identifier | simple_string_lit  .
@@ -1375,34 +1375,37 @@
 --->
 
 
-#### Field attributes
+#### Attributes
 
-Fields may be associated with attributes.
-Attributes define additional information about a field,
+Attributes allow associating meta information with values.
+Their primary purpose is to define mappings between CUE and
+other representations.
+Attributes do not influence the evaluation of CUE.
+
+An attribute associates an identifier with a value, a balanced token sequence,
+which is a sequence of CUE tokens with balanced brackets (`()`, `[]`, and `{}`).
+The sequence may not contain interpolations.
+
+Fields, structs and packages can be associated with a set of attributes.
+Attributes accumulate during unification, but implementations may remove
+duplicates that have the same source string representation.
+The interpretation of an attribute, including the handling of multiple
+attributes for a given identifier, is up to the consumer of the attribute.
+
+Field attributes define additional information about a field,
 such as a mapping to a protocol buffer <!-- TODO: add link --> tag or alternative
 name of the field when mapping to a different language.
 
-<!-- TODO define attribute syntax here, before getting into semantics. -->
-
-If a field has multiple attributes their identifiers must be unique.
-Attributes accumulate when unifying two fields, removing duplicate entries.
-It is an error for the resulting field to have two different attributes
-with the same identifier.
-
-Attributes are not directly part of the data model, but may be
-accessed through the API or other means of reflection.
-The interpretation of the attribute value
-(a comma-separated list of attribute elements) depends on the attribute.
-Interpolations are not allowed in attribute strings.
-
-The recommended convention, however, is to interpret the first
-`n` arguments as positional arguments,
-where duplicate conflicting entries are an error,
-and the remaining arguments as a combination of flags
-(an identifier) and key value pairs, separated by a `=`.
 
 ```
+// Package attribute
+@protobuf(proto3)
+
 myStruct1: {
+    // Struct attribute:
+    @jsonschema(id="https://example.org/mystruct1.json")
+
+    // Field attributes
     field: string @go(Field)
     attr:  int    @xml(,attr) @go(Attr)
 }
@@ -2839,7 +2842,7 @@
 to a data format
 
 ```
-SourceFile      = [ PackageClause "," ] { ImportDecl "," } { Declaration "," } .
+SourceFile      = { attribute "," } [ PackageClause "," ] { ImportDecl "," } { Declaration "," } .
 ```
 
 ```