public static CsCodeWriter CreateCode(string leftName, string rightName,
                                              string op, NullableArguments nullableArguments)
        {
            var cw = Ext.Create <MultiplyAlgebraGenerator>();
            var n1 = new NullableArgument(leftName, (nullableArguments & NullableArguments.Left) != 0);
            var n2 = new NullableArgument(rightName, (nullableArguments & NullableArguments.Right) != 0);
            var a = new[] { n1, n2 }.Where(q => q._isNullable).Select(q => q.IsNullCondition);

            cw.SingleLineIf(string.Join(" || ", a), "return null;");
            cw.WriteLine($"return {n1.Value} {op} {n2.Value};");
            return(cw);
        }
        private void CreateOperator(TypesGroup left, TypesGroup right, TypesGroup result, string op,
                                    bool areRelatedUnits, NullableArguments nullableArguments, OperatorHints operatorHints)
        {
            var leftValue  = left.Value.ValueTypeName;
            var rightValue = right.Value.ValueTypeName;

            if ((nullableArguments & NullableArguments.Left) != 0)
            {
                leftValue += "?";
            }
            if ((nullableArguments & NullableArguments.Right) != 0)
            {
                rightValue += "?";
            }

            var operatorGenerationKey = new OperatorGenerationKey(leftValue, rightValue, op);

            var tResult = result.Value;

            if (_done.TryGetValue(operatorGenerationKey, out var resultType))
            {
                if (resultType != tResult.ValueTypeName)
                {
                    throw new NotSupportedException();
                }
                return;
            }

            _done[operatorGenerationKey] = tResult.ValueTypeName;

            var info = op == "/" ? OperatorInfo.Div : OperatorInfo.Mul;

            var leftName  = info.Left.Name;
            var rightName = info.Right.Name;

            if (left.Value != right.Value)
            {
                leftName  = left.Value.FirstLower();
                rightName = right.Value.FirstLower();
            }

            var cl = GetClass(operatorGenerationKey.GetOperatorTargetType());

            cl.Kind = CsNamespaceMemberKind.Struct;

            // cw.WriteLine("// " + key + " " + areRelatedUnits);

            var rightFraction = FractionUnitDefs.IsFraction(right);
            var leftFraction  = FractionUnitDefs.IsFraction(left);

            var rightUnit  = "rightUnit";
            var resultUnit = "resultUnit";

            CsCodeWriter PrepareCode()
            {
                if (nullableArguments == NullableArguments.None)
                {
                    var ppp = new OperatorParams(left, right, result, leftName, rightName, op, operatorHints);
                    if (areRelatedUnits)
                    {
                        return(CreateCodeForRelatedUnits(ppp, ref rightUnit, ref resultUnit));
                    }
                    if (leftFraction != null)
                    {
                        if (rightFraction == null)
                        {
                            return(CreateCodeForLeftFractionValue(ppp, leftFraction));
                        }

                        {
                            var cw = Ext.Create <Self>();

                            if (TryHint(ppp, cw))
                            {
                                cw.WriteLine("// scenario F1");
                                return(cw);
                            }

                            cw.WriteLine("// scenario F2");
                            cw.WithThrowNotImplementedException();
                            return(cw);
                        }
                    }

                    if (rightFraction != null)
                    {
                        return(CreateCodeForRightFractionValue(rightFraction, ppp));
                    }

                    {
                        var cw = Ext.Create <Self>();

                        if (TryHint(ppp, cw))
                        {
                            cw.WriteLine("// scenario F3");
                            return(cw);
                        }
                    }
                    return(CreateCodeForFractionalResult(ppp));
                }

                return(NullableArgument.CreateCode(leftName, rightName, op, nullableArguments));
            }

            var cw1 = PrepareCode();

            var method = cl.AddMethod(op, tResult + (nullableArguments == NullableArguments.None ? "" : "?"),
                                      info.Description)
                         .WithBody(cw1);

            var p = method.AddParam(leftName, leftValue);

            p.Description = info.Left.Desctiption;
            p             = method.AddParam(rightName, rightValue);
            p.Description = info.Right.Desctiption;
        }