Exemple #1
0
        public Task <SyntaxList <MemberDeclarationSyntax> > GenerateAsync(
            TransformationContext context,
            IProgress <Diagnostic> progress,
            CancellationToken cancellationToken)
        {
            if (context.ProcessingNode is TypeDeclarationSyntax applyTo &&
                (applyTo is ClassDeclarationSyntax || (applyTo is StructDeclarationSyntax)))
            {
                var record = CodeGenUtil.MakeCaseType(
                    context,
                    applyTo.Identifier,
                    applyTo.Members,
                    applyTo.TypeParameterList,
                    applyTo.Modifiers,
                    applyTo.ConstraintClauses,
                    applyTo.Identifier,
                    null,
                    CodeGenUtil.GetState(context, progress, AllowedType.ClassOrStruct, "Record code-gen").Fields,
                    BaseSpec.None,
                    caseIsClass: applyTo is ClassDeclarationSyntax,
                    caseIsPartial: true,
                    -1);


                return(Task.FromResult(List <MemberDeclarationSyntax>().Add(record)));
            }
Exemple #2
0
        public Task <SyntaxList <MemberDeclarationSyntax> > GenerateAsync(
            TransformationContext context,
            IProgress <Diagnostic> progress,
            CancellationToken cancellationToken)
        {
            try
            {
                if (context.ProcessingNode is InterfaceDeclarationSyntax applyTo)
                {
                    if (applyTo.TypeParameterList.Parameters.Count > 1)
                    {
                        CodeGenUtil.ReportError($"Free monads must have only one generic argument", "Free monad Code-Gen", context.ProcessingNode, progress);
                        return(Task.FromResult(List <MemberDeclarationSyntax>()));
                    }
                    if (applyTo.TypeParameterList.Parameters.Count == 0)
                    {
                        CodeGenUtil.ReportError($"Free monads must a generic argument", "Free monad Code-Gen", context.ProcessingNode, progress);
                        return(Task.FromResult(List <MemberDeclarationSyntax>()));
                    }

                    var genA = applyTo.TypeParameterList.Parameters.First().ToString();
                    var genB = CodeGenUtil.NextGenName(genA);
                    var genC = CodeGenUtil.NextGenName(genB);

                    var thisType = ParseTypeName($"{applyTo.Identifier.Text}{applyTo.TypeParameterList}");

                    var typeA   = MakeTypeName(applyTo.Identifier.Text, genA);
                    var typeB   = MakeTypeName(applyTo.Identifier.Text, genB);
                    var mapFunc = ParseTypeName($"System.Func<{genA}, {genB}>");

                    var mapIsStatic = applyTo.Members
                                      .OfType <MethodDeclarationSyntax>()
                                      .Where(m => m.Identifier.Text == "Map")
                                      .Where(m => m.ParameterList.Parameters.Count == 2)
                                      .Where(m => m.Modifiers.Any(mo => mo.IsKind(SyntaxKind.StaticKeyword)))
                                      .Where(m => m.Modifiers.Any(mo => mo.IsKind(SyntaxKind.PublicKeyword)))
                                      // .Where(m => m.ReturnType.IsEquivalentTo(typeB))
                                      // .Where(m => m.ParameterList.Parameters[0].Type.IsEquivalentTo(typeA))
                                      // .Where(m => m.ParameterList.Parameters[1].Type.IsEquivalentTo(mapFunc))
                                      .Any();

                    var caseMethods = applyTo.Members
                                      .OfType <MethodDeclarationSyntax>()
                                      .Where(m => !m.Modifiers.Any(mo => mo.IsKind(SyntaxKind.StaticKeyword)))
                                      .Select(m => MakeFree(m, thisType))
                                      .ToArray();

                    var firstPure = caseMethods.Where(HasPureAttr)
                                    .Where(m => m.ParameterList.Parameters.Count == 1)
                                    .Where(m => m.ReturnType.IsEquivalentTo(typeA))
                                    .Where(m => m.ParameterList.Parameters.First().Type.ToString() == genA)
                                    .FirstOrDefault();

                    if (firstPure == null)
                    {
                        CodeGenUtil.ReportError($"Type can't be made into a free monad because no method in the interface has [Pure] attribute that takes a single argument of type '{genA}' and returns a '{genA}'", "Free monad Code-Gen", context.ProcessingNode, progress);
                        return(Task.FromResult(List <MemberDeclarationSyntax>()));
                    }

                    var caseRes = caseMethods
                                  .Zip(Enumerable.Range(1, int.MaxValue), (m, i) => (m, i))
                                  .Select(m => CodeGenUtil.MakeCaseType(
                                              context,
                                              progress,
                                              applyTo.Identifier,
                                              applyTo.Members,
                                              applyTo.TypeParameterList,
                                              applyTo.Modifiers,
                                              applyTo.ConstraintClauses,
                                              m.m.Identifier,
                                              m.m.TypeParameterList,
                                              m.m.ParameterList
                                              .Parameters
                                              .Select(p => (p.Identifier, p.Type, p.Modifiers, p.AttributeLists))
                                              .ToList(),
                                              BaseSpec.Interface,
                                              caseIsClass: true,
                                              caseIsPartial: false,
                                              includeWithAndLenses: false,
                                              m.i))
                                  .ToList();

                    var ok    = caseRes.All(x => x.Success);
                    var cases = caseRes.Select(c => c.Type);

                    var staticCtorClass = MakeStaticClass(
                        applyTo.Identifier,
                        caseMethods,
                        applyTo.TypeParameterList,
                        applyTo.ConstraintClauses,
                        firstPure,
                        mapIsStatic);

                    if (ok)
                    {
                        return(Task.FromResult(List <MemberDeclarationSyntax>().AddRange(cases).Add(staticCtorClass)));
                    }
                    else
                    {
                        return(Task.FromResult(List <MemberDeclarationSyntax>()));
                    }
                }
                else
                {
                    CodeGenUtil.ReportError($"Type can't be made into a free monad.  It must be an interface", "Free monad Code-Gen", context.ProcessingNode, progress);
                    return(Task.FromResult(List <MemberDeclarationSyntax>()));
                }
            }
            catch (Exception e)
            {
                CodeGenUtil.ReportError(e.Message, "Free monad Code-Gen", context.ProcessingNode, progress);
                foreach (var line in e.StackTrace.Split('\n'))
                {
                    CodeGenUtil.ReportError(line, "Free monad Code-Gen", context.ProcessingNode, progress);
                }

                return(Task.FromResult(List <MemberDeclarationSyntax>()));
            }
        }