generateSumType function

String generateSumType(
  1. SumTypeSpec spec
)

Implementation

String generateSumType(SumTypeSpec spec) => [
      "// ignore_for_file: unused_element\n",
      // The sum-type base class
      classDecl(
        abstract: true,
        name: spec.sumTypeBaseName,
        typeParams: spec.typeParams,
        body: [
          // The unsafe constructor
          constructor(
            isConst: true,
            type: spec.sumTypeBaseName,
            namedParams: [
              for (final caseSpec in spec.cases)
                param(name: "this.${caseSpec.name}"),
            ],
            initializers: [
              "assert(${invariant(spec.cases)})",
            ],
          ),
          loadFromRecord(spec),
          dumpToRecord(spec),
          exhaustiveSwitch(spec: spec, implement: true),
          inexhaustiveSwitch(spec: spec, implement: true),
          // Equality test
          "@override",
          expressionFunction(
            type: "bool",
            name: "operator ==",
            posParams: [param(type: "Object", name: "other")],
            body: [
              [
                "other.runtimeType == runtimeType",
                "other is ${spec.sumTypeName}",
                for (final caseSpec in spec.cases)
                  "other.${caseSpec.name} == ${caseSpec.name}"
              ].join("&&"),
            ],
          ),
          // Hash function
          "@override",
          getter(
            type: "int",
            name: "hashCode",
            body: [
              "var result = 17;",
              for (final caseSpec in spec.cases)
                "result = 37 * result + ${caseSpec.name}.hashCode;",
              "return result;",
            ],
          ),
          // To string conversion
          "@override",
          function(
            type: "String",
            name: "toString",
            body: [
              "final ctor = iswitch(",
              ...spec.cases
                  .map((caseSpec) => [
                        "${caseSpec.name}: ",
                        if (caseSpec.type.requiresPayload)
                          "(value) => \"${caseSpec.name}(\$value)\""
                        else
                          "() => \"${caseSpec.name}()\"",
                      ].join())
                  .map(appendComma),
              ");",
              "return \"\$runtimeType.\$ctor\";",
            ],
          ),
          // Fields
          for (final caseSpec in spec.cases) ...[
            "@protected",
            finalField(
              type: "${caseSpec.type.name}?",
              name: caseSpec.name,
            ),
          ],
        ],
      ),
      // The read-only record-type interface
      classDecl(
        abstract: true,
        name: spec.recordIfaceName,
        typeParams: [
          const TypeParamSpec(name: "Self"),
          ...spec.typeParams,
        ],
        body: [
          for (final caseSpec in spec.cases)
            getter(
              type:
                  "${caseSpec.type.isDirectlyRecursive ? "Self" : caseSpec.type.name}?",
              name: caseSpec.name,
            ),
        ],
      ),
    ].join(" ");