Exemple #1
0
 /// <summary>
 /// Writes the declaration of a new class to the source writer.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 /// <param name="className">The name of the class.</param>
 /// <param name="inheritsOrImplements">The set of <see cref="Type" />s that the class either inherits from, or implements.</param>
 public static void StartClass(this ISourceWriter writer, string className, params Type[] inheritsOrImplements)
 {
     if (inheritsOrImplements.Length == 0)
     {
         writer.Block($"public class {className}");
     }
     else
     {
         var tempQualifier = inheritsOrImplements.Select(x => x.FullNameInCode());
         writer.Block($"public class {className} : {string.Join(", ", tempQualifier)}");
     }
 }
Exemple #2
0
        protected void LoopAttributes(IMethodVariables variables, ISourceWriter writer, string methodCall)
        {
            var resultsVariable = variables.FindVariable(typeof(ValidationFailures));
            var attributeType   = typeof(T).FullNameInCode();
            var awaitMethod     = this.IsAsync ? "await" : string.Empty;

            writer.Comment($"{this._property.PropertyInfoVariable} == {this._property.PropertyInfoVariable.Property.DeclaringType.Name}.{this._property.PropertyInfoVariable.Property.Name}");
            writer.Block($"foreach (var attribute in {this._property.PropertyAttributesVariable})");
            writer.Block($"if (attribute is {attributeType} x)");
            writer.WriteLine($"var result = {awaitMethod} x.{methodCall};");
            writer.Block($"if (result != {Variable.StaticFrom<ValidationResult>(nameof(ValidationResult.Success))})");
            writer.WriteLine($"{resultsVariable}.{nameof(ValidationFailures.AddFailure)}(result);");
            writer.FinishBlock();
            writer.FinishBlock();
            writer.FinishBlock();
        }
Exemple #3
0
 /// <summary>
 /// Writes "try ([declaration])" into the code and starts a new code
 /// block with a leading '{' character.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 /// <param name="inner">The action that writes the body of the try block, passed the same writer to avoid closure allocation.</param>
 public static void Try(
     this ISourceWriter writer,
     Action <ISourceWriter> inner)
 {
     writer.Block("try");
     inner(writer);
     writer.FinishBlock();
 }
Exemple #4
0
 /// <summary>
 /// Writes "catch ([declaration])" into the code and starts a new code
 /// block with a leading '{' character.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 /// <param name="declaration">The code that goes within the parenthesis of this catch block (i.e. at a minimum the exception type).</param>
 /// <param name="inner">The action that writes the body of the catch block, passed the same writer to avoid closure allocation.</param>
 public static void Catch(
     this ISourceWriter writer,
     string declaration,
     Action <ISourceWriter> inner)
 {
     writer.Block("catch (" + declaration + ")");
     inner(writer);
     writer.FinishBlock();
 }
        private void WriteConstructorMethod(ISourceWriter writer, HashSet <InjectedField> args)
        {
            var tempQualifier = args.Select(x => x.CtorArgDeclaration);
            var ctorArgs      = string.Join(", ", tempQualifier);
            var declaration   = $"public {this.TypeName}({ctorArgs})";

            if (this.BaseConstructorArguments.Any())
            {
                var tempQualifier1 = this.BaseConstructorArguments.Select(x => x.ArgumentName);
                declaration = $"{declaration} : base({string.Join(", ", tempQualifier1)})";
            }

            writer.Block(declaration);

            foreach (var field in args)
            {
                field.WriteAssignment(writer);
            }

            writer.FinishBlock();
        }
        /// <summary>
        /// Writes the code for this method to the specified <see cref="ISourceWriter" />.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method will perform the necessary work to collect variables, both created in this method
        /// and by external <see cref="IVariableSource"/>s.
        /// </para>
        /// <para>
        /// This method does a lot of bookkeeping to keep track of <see cref="Frame"/>s and <see cref="Variable"/>s that
        /// are created and used by any added frames. The "top" <see cref="Frame"/> will have it's <see cref="Frame.Generate"/>
        /// method called twice, which in turn is expected to flow through all frames (using the assigned <see cref="Frame.NextFrame" />
        /// property.
        /// </para>
        /// <para>
        /// The <see cref="Frame.Generate" /> method is called twice to allow the first run-through to create the required variables
        /// and to declare the dependencies. During this process we collect this information and, potentially, add in extra <see cref="Frame"/>s
        /// as required by the <see cref="IVariableSource"/>s that declare on-the-fly variables. The second time we will already have
        /// determined the variables and will actually write the code to the supplied <see cref="ISourceWriter" />.
        /// </para>
        /// </remarks>
        /// <param name="writer">The writer to output the code to.</param>
        public void WriteMethod(ISourceWriter writer)
        {
            // 1. Chain all existing frames together (setting their NextFrame property).
            var topFrame = ChainFrames(this.Frames);

            // 2. Clear out "all registered frames" to enable this method to be called multiple times.
            this._allRegisteredFrames.Clear();

            // 3. The first time around is used for discovering the variables, ensuring frames
            // are fully created etc. No actual writing will occur
            var trackingWriter = new TrackingVariableWriter(this);

            topFrame.GenerateCode(trackingWriter, this, new MethodSourceWriter(trackingWriter, this, trackingWriter));

            // 4. Determine the async mode of this method, which determines the result type and how
            // the actual return value is generated. Only do this is asyncMode is not set to
            // something else to allow overriding externally
            if (this.AsyncMode == AsyncMode.None)
            {
                this.AsyncMode = AsyncMode.AsyncTask;

                if (this._allRegisteredFrames.All(x => !x.IsAsync))
                {
                    this.AsyncMode = AsyncMode.None;
                }
                else
                {
                    var lastFrame = this._allRegisteredFrames.Last();

                    if (this._allRegisteredFrames.Count(x => x.IsAsync) == 1 && lastFrame.IsAsync && lastFrame.CanReturnTask())
                    {
                        this.AsyncMode = AsyncMode.ReturnFromLastNode;
                    }
                }
            }

            // 5. Now find various types of variables to push to the GeneratedType, in addition to also
            // adding the creation frames to this method's collection if they do not already exist
            foreach (var variable in this._variables.Values.TopologicalSort(v => v.Dependencies))
            {
                if (variable.Creator != null && !this._allRegisteredFrames.Contains(variable.Creator))
                {
                    // Find the first usage of this variable and place the frame before that.
                    var firstUsage = this._allRegisteredFrames.FirstOrDefault(f => f.Uses.Contains(variable));

                    if (firstUsage == null)
                    {
                        this.Frames.Insert(0, variable.Creator);

                        // throw new InvalidOperationException(
                        //     $"The variable '{variable}' has a creator Frame that has not been appended to this GeneratedMethod, " +
                        //     "nor does any Frame exist that Uses it, therefore we cannot determine where to place the creator Frame.");
                    }
                    else
                    {
                        this.Frames.Insert(this.Frames.IndexOf(firstUsage), variable.Creator);
                    }

                    this._allRegisteredFrames.Add(variable.Creator);
                }

                switch (variable)
                {
                case InjectedField field:
                    this.GeneratedType.AllInjectedFields.Add(field);
                    break;

                case Setter setter:
                    this.GeneratedType.Setters.Add(setter);
                    break;

                case StaticField staticField:
                    this.GeneratedType.AllStaticFields.Add(staticField);
                    break;
                }
            }

            // 6. Re-chain all existing frames as we may have pushed new ones
            topFrame = ChainFrames(this.Frames);

            // 7. We now have all frames & variables collected, lets do the final generation of code
            var returnValue = this.DetermineReturnExpression();

            if (this.Overrides)
            {
                returnValue = "override " + returnValue;
            }

            var tempQualifier = this.Arguments.Select(x => x.Declaration);
            var arguments     = string.Join(", ", tempQualifier);

            writer.Block($"public {returnValue} {this.MethodName}({arguments})");

            // 7.1. Clear out "all registered frames" so we do not end up with large duplicated List
            this._allRegisteredFrames.Clear();

            topFrame.GenerateCode(trackingWriter, this, new MethodSourceWriter(trackingWriter, this, writer));

            this.WriteReturnStatement(writer);

            writer.FinishBlock();
        }
 private void WriteDeclaration(ISourceWriter writer)
 {
     writer.Block($"{this.GetDeclaration()}");
 }
Exemple #8
0
 /// <summary>
 /// Writes "using ([declaration])" into the code and starts a new code
 /// block with a leading '{' character.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 /// <param name="declaration">The code that goes within the parenthesis of this using block (i.e. the expression that generates and optionally sets, the disposable object).</param>
 /// <param name="inner">The action that writes the body of the using block, passed the same writer to avoid closure allocation.</param>
 public static void Using(this ISourceWriter writer, string declaration, Action <ISourceWriter> inner)
 {
     writer.Block($"using ({declaration})");
     inner(writer);
     writer.FinishBlock();
 }
Exemple #9
0
 /// <summary>
 /// Adds a "namespace [@namespace]" declaration into the code, and starts a new
 /// code block with a leading '{' character.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 /// <param name="namespace">The namespace.</param>
 public static void Namespace(this ISourceWriter writer, string @namespace)
 {
     writer.Block($"namespace {@namespace}");
 }
Exemple #10
0
 /// <summary>
 /// Starts a finally block in code with the opening brace and indention for following lines.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 public static void Finally(this ISourceWriter writer)
 {
     writer.FinishBlock();
     writer.Block("finally");
 }
Exemple #11
0
 /// <summary>
 /// Starts a try block in code with the opening brace and indention for following lines.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 public static void Try(this ISourceWriter writer)
 {
     writer.Block("try");
 }
Exemple #12
0
 /// <summary>
 /// Starts an else block in code with the opening brace and indention for following lines.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 public static void Else(this ISourceWriter writer)
 {
     writer.Block("else");
 }
Exemple #13
0
 /// <summary>
 /// Starts an if block in code with the opening brace and indention for following lines.
 /// </summary>
 /// <param name="writer">Where to write to.</param>
 /// <param name="statement">The statement to put inside the if block.</param>
 public static void If(this ISourceWriter writer, string statement)
 {
     writer.Block($"if ({statement})");
 }