Documentation

Strata.CodeGen.TypeShape

Language-Neutral Type Shape Analysis #

Shared front end for the Ion serializer generators (getIonSerializer% for Java in Strata.Java.Gen, getIonGoSerializer% for Go in Strata.Go.Gen).

Every such generator needs the same answer to the same question: what shape does this Lean type have, and what is in each of its fields? That answer depends only on the Lean environment, not on the target language, so it lives here and each backend consumes it. Only the naming, type mapping and code emission are language-specific and stay in the backends.

What a shape is #

analyzeType reduces a Lean declaration to one of three TypeShapes, matching the three Ion encodings the deserializer understands:

TypeShapeLean declarationIon encoding
.structa structureIon struct, keys = field names
.singleCtoran inductive with one constructorIon struct, keys _0, _1, …
.multiCtoran inductive with zero or 2+ constructorsIon sexp (ctorName arg …)

Deliberately, a TypeShape carries no target-language name: the Lean Name is the only identity it records, and each backend derives its own identifier from it (Strata.Java.javaClassName, Strata.Go.goTypeName). A single shared name would have to pick one language's escaping rules, and the two disagree — Java reserves String and record, Go reserves string and range.

Supported field types #

Leaves are Nat, Int, Float, String, Bool and StrataDDM.Decimal; containers are List α and Option α, nestable to any depth; anything else that is a structure or an inductive is a .compound reference that pulls that type into the generated closure (see collectNestedTypes).

Name utilities #

Convert a Lean identifier to PascalCase: split on _, drop empty segments, upcase the first character of each remaining segment, and concatenate.

Used for both type and member names, so my_ctor and myCtor both land on MyCtor — see disambiguate for why that is safe.

Equations
  • One or more equations did not get rendered due to their size.
Instances For

    Return a variant of base that is not already in usedNames, adding a _ (then _2, _3, …) suffix on collision, along with the extended set.

    Escaping is not injective: a backend's escape function strips characters the target language does not allow in identifiers and toPascalCase upcases segment heads, so distinct Lean names can fold to one target identifier (foo and Foo both become Foo; so do myCtor and my_ctor). Emitting the folded name twice would declare the same type or the same field twice, which does not compile.

    Comparison is case-insensitive because members that differ only in case are still confusable, and because each generated type becomes a file on a possibly case-insensitive filesystem.

    Equations
    Instances For

      Disambiguate a whole list of names left to right, so earlier names keep their unsuffixed form and only later collisions are renamed.

      Equations
      • One or more equations did not get rendered due to their size.
      Instances For

        Leaf and compound type detection #

        The Lean types that serialize directly to an Ion scalar. Everything else is either a container (List/Option) or a .compound reference.

        Equations
        Instances For

          Shape description #

          What a single field's Lean type maps to, stripped of everything a code generator does not need to know.

          Instances For

            One field of a structure, or one argument of a constructor. name is the Lean name and stays the Ion key; the backend derives its own identifier.

            Instances For

              One constructor of an inductive.

              • name : Lean.Name

                The fully qualified constructor name.

              • shortName : String

                The last component of name, which is the Ion sexp tag for .multiCtor.

              • fields : Array FieldShape

                The constructor's arguments, in declaration order.

              Instances For

                The analyzed shape of a Lean type: which of the three Ion encodings it uses and what it contains. Carries no target-language name by design — see the module docstring.

                Instances For

                  Whether name names a type the generator should emit a declaration for, as opposed to a leaf it maps to a built-in.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For

                    Type parameter tagging #

                    Lean constructor types are forallE telescopes whose leading binders are the type's parameters. To see which fields mention which parameter, the parameters have to be instantiated with something recognisable before the field types are inspected. extractCtorFields substitutes a Sort whose universe is a Level parameter tagged with typeParamPlaceholderPrefix, and extractTypeParamName recovers the parameter name from it.

                    This is a marker, not a real universe parameter: nothing ever elaborates these levels, they only survive long enough for classifyFieldType to read them back.

                    Analysis #

                    Reduce a Lean type declaration to its TypeShape. Throws if typeName is neither a structure nor an inductive.

                    Equations
                    • One or more equations did not get rendered due to their size.
                    Instances For

                      Breadth-first closure of the compound types reachable from rootName, starting with rootName itself. This is the set of types a generator must emit.

                      Equations
                      • One or more equations did not get rendered due to their size.
                      Instances For