// Copyright 2025 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 is implicitly defined by the package noder.

At the highest level, a package encoded in UIR follows the grammar
below.

    File        = Header Payload fingerprint .
    Header      = version [ flags ] sectionEnds elementEnds .

    version     = uint32 .     // used for backward compatibility
    flags       = uint32 .     // feature flags used across versions
    sectionEnds = [10]uint32 . // defines section boundaries
    elementEnds = []uint32 .   // defines element boundaries
    fingerprint = [8]byte .    // sha256 fingerprint

The payload is a series of sections. Each section has a kind which
determines its index in the series.

    SectionKind = Uint64 .
    Payload     = SectionString
                  SectionMeta
                  SectionPosBase
                  SectionPkg
                  SectionName
                  SectionType
                  SectionObj
                  SectionObjExt  // TODO(markfreeman) Define.
                  SectionObjDict // TODO(markfreeman) Define.
                  SectionBody    // TODO(markfreeman) Define.
                  .

# Sections
A section is a series of elements of a type determined by the section's
kind. Go constructs are mapped onto one or more elements with possibly
different types; in that case, the elements are in different sections.

Elements are accessed using an element index relative to the start of
the section.

    RelElemIdx = Uint64 .

## String Section
String values are stored as elements in the string section. Elements
outside the string section access string values by reference.

    SectionString = { String } .

Note that despite being an element, a string does not begin with a
reference table.

## Meta Section
The meta section provides fundamental information for a package. It
contains exactly two elements — a public root and a private root.

    SectionMeta = PublicRoot
                  PrivateRoot     // TODO(markfreeman): Define.
                  .

The public root element identifies the package and provides references
for all exported objects it contains.

    PublicRoot  = RefTable
                  [ Sync ]
                  PkgRef
                  [ HasInit ]
                  ObjectRefCount // TODO(markfreeman): Define.
                  { ObjectRef }  // TODO(markfreeman): Define.
                  .
    HasInit     = Bool .         // Whether the package uses any
                                 // initialization functions.

## PosBase Section
This section provides position information. It is a series of PosBase
elements.

    SectionPosBase = { PosBase } .

A base is either a file base or line base (produced by a line
directive). Every base has a position, line, and column; these are
constant for file bases and hence not encoded.

    PosBase = RefTable
              [ Sync ]
              StringRef       // the (absolute) file name for the base
              Bool            // true if a file base, else a line base
              // The below is ommitted for file bases.
              [ Pos
                Uint64        // line
                Uint64 ]      // column
              .

A source position Pos represents a file-absolute (line, column) pair
and a PosBase indicating the position Pos is relative to. Positions
without a PosBase have no line or column.

    Pos     = [ Sync ]
              Bool             // true if the position has a base
              // The below is ommitted if the position has no base.
              [ Ref[PosBase]
                Uint64         // line
                Uint64 ]       // column
              .

## Package Section
The package section holds package information. It is a series of Pkg
elements.

    SectionPkg = { Pkg } .

A Pkg element contains a (path, name) pair and a series of imported
packages. The below package paths have special meaning.

    +--------------+-----------------------------------+
    | package path |             indicates             |
    +--------------+-----------------------------------+
    | ""           | the current package               |
    | "builtin"    | the fake builtin package          |
    | "unsafe"     | the compiler-known unsafe package |
    +--------------+-----------------------------------+

    Pkg        = RefTable
                 [ Sync ]
                 StringRef      // path
                 // The below is ommitted for the special package paths
                 // "builtin" and "unsafe".
                 [ StringRef    // name
                   Imports ]
                 .
    Imports    = Uint64         // the number of declared imports
                 { PkgRef }     // references to declared imports
                 .

Note, a PkgRef is *not* equivalent to Ref[Pkg] due to an extra marker.

    PkgRef     = [ Sync ]
                 Ref[Pkg]
                 .

## Type Section
The type section is a series of type definition elements.

    SectionType = { TypeDef } .

A type definition can be in one of several formats, which are identified
by their TypeSpec code.

    TypeDef     = RefTable
                  [ Sync ]
                  [ Sync ]
                  Uint64            // denotes which TypeSpec to use
                  TypeSpec
                  .

    TypeSpec    = TypeSpecBasic     // TODO(markfreeman): Define.
                | TypeSpecNamed     // TODO(markfreeman): Define.
                | TypeSpecPointer   // TODO(markfreeman): Define.
                | TypeSpecSlice     // TODO(markfreeman): Define.
                | TypeSpecArray     // TODO(markfreeman): Define.
                | TypeSpecChan      // TODO(markfreeman): Define.
                | TypeSpecMap       // TODO(markfreeman): Define.
                | TypeSpecSignature // TODO(markfreeman): Define.
                | TypeSpecStruct    // TODO(markfreeman): Define.
                | TypeSpecInterface // TODO(markfreeman): Define.
                | TypeSpecUnion     // TODO(markfreeman): Define.
                | TypeSpecTypeParam // TODO(markfreeman): Define.
                  .

// TODO(markfreeman): Document the reader dictionary once we understand it more.
To use a type elsewhere, a TypeUse is encoded.

    TypeUse     = [ Sync ]
                  Bool              // whether it is a derived type
                  [ Uint64 ]        // if derived, an index into the reader dictionary
                  [ Ref[TypeDef] ]  // else, a reference to the type
                  .

## Object Sections
Information about an object (e.g. variable, function, type name, etc.)
is split into multiple elements in different sections. Those elements
have the same section-relative element index.

### Name Section
The name section holds a series of names.

    SectionName = { Name } .

Names are elements holding qualified identifiers and type information
for objects.

    Name        = RefTable
                  [ Sync ]
                  [ Sync ]
                  PkgRef    // the object's package
                  StringRef // the object's package-local name
                  [ Sync ]
                  Uint64    // the object's type (e.g. Var, Func, etc.)
                  .

### Definition Section
The definition section holds definitions for objects defined by the target
package; it does not contain definitions for imported objects.

    SectionObj = { ObjectDef } .

Object definitions can be in one of several formats. To determine the correct
format, the name section must be referenced; it contains a code indicating
the object's type.

    ObjectDef = RefTable
                [ Sync ]
                ObjectSpec
                .

    ObjectSpec = ObjectSpecConst     // TODO(markfreeman) Define.
               | ObjectSpecFunc      // TODO(markfreeman) Define.
               | ObjectSpecAlias     // TODO(markfreeman) Define.
               | ObjectSpecNamedType // TODO(markfreeman) Define.
               | ObjectSpecVar       // TODO(markfreeman) Define.
                 .

To use an object definition elsewhere, an ObjectUse is encoded.

    ObjectUse  = [ Sync ]
                 [ Bool ]
                 Ref[ObjectDef]
                 Uint64              // the number of type arguments
                 { TypeUse }         // references to the type arguments
                 .

# References
A reference table precedes every element. Each entry in the table
contains a (section, index) pair denoting the location of the
referenced element.

    RefTable      = [ Sync ]
                    Uint64            // the number of table entries
                    { RefTableEntry }
                    .
    RefTableEntry = [ Sync ]
                    SectionKind
                    RelElemIdx
                    .

Elements encode references to other elements as an index in the
reference table — not the location of the referenced element directly.

    RefTableIdx   = Uint64 .

To do this, the Ref[T] primitive is used as below; note that this is
the same shape as provided by package pkgbits, just with new
interpretation applied.

    Ref[T]        = [ Sync ]
                    RefTableIdx       // the Uint64
                    .

# Primitives
Primitive encoding is handled separately by the pkgbits package. Check
there for definitions of the below productions.

    * Bool
    * Int64
    * Uint64
    * String
    * Ref[T]
    * Sync
*/

package noder
