// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
The Unified IR (UIR) format for primitive types is implicitly defined by the
package pkgbits.

The most basic primitives are laid out as below.

       Bool    = [ Sync ] byte .
       Int64   = [ Sync ] zvarint .
       Uint64  = [ Sync ] uvarint .

       zvarint = (* a zig-zag encoded signed variable-width integer *) .
       uvarint = (* an unsigned variable-width integer *) .

# References
References specify the location of a value. While the representation here is
fixed, the interpretation of a reference is left to other packages.

       Ref[T] = [ Sync ] Uint64 . // points to a value of type T

# Markers
Markers provide a mechanism for asserting that encoders and decoders
are synchronized. If an unexpected marker is found, decoding panics.

       Sync = uvarint          // indicates what should follow if synchronized
              WriterPCs
              .

A marker also records a configurable number of program counters (PCs) during
encoding to assist with debugging.

       WriterPCs = uvarint     // the number of PCs that follow
                   { uvarint } // the PCs
                   .

Note that markers are always defined using terminals — they never contain a
marker themselves.

# Strings
A string is a series of bytes.

       // TODO(markfreeman): Does this need a marker?
       String    = { byte } .

Strings are typically not encoded directly. Rather, they are deduplicated
during encoding and referenced where needed; this process is called interning.

       StringRef = [ Sync ] Ref[String] .

Note that StringRef is *not* equivalent to Ref[String] due to the extra marker.

# Slices
Slices are a convenience for encoding a series of values of the same type.

       // TODO(markfreeman): Does this need a marker?
       Slice[T]  = Uint64 // the number of values in the slice
                   { T }  // the values
                   .

# Constants
Constants appear as defined via the package constant.

       Constant = [ Sync ]
                  Bool       // whether the constant is a complex number
                  Scalar     // the real part
                  [ Scalar ] // if complex, the imaginary part
                  .

A scalar represents a value using one of several potential formats. The exact
format and interpretation is distinguished by a code preceding the value.

       Scalar   = [ Sync ]
                  Uint64      // the code indicating the type of Val
                  Val
                  .

       Val      = Bool
                | Int64
                | StringRef
                | Term        // big integer
                | Term Term   // big ratio, numerator / denominator
                | BigBytes    // big float, precision 512
                .

       Term     = BigBytes
                  Bool        // whether the term is negative
                  .

       BigBytes = StringRef . // bytes of a big value
*/

// Package pkgbits implements low-level coding abstractions for Unified IR's
// (UIR) binary export data format.
//
// At a low-level, the exported objects of a package are encoded as a byte
// array. This array contains byte representations of primitive, potentially
// variable-length values, such as integers, booleans, strings, and constants.
//
// Additionally, the array may contain values which denote indices in the byte
// array itself. These are termed "relocations" and allow for references.
//
// The details of mapping high-level Go constructs to primitives are left to
// other packages.
package pkgbits
