Пример #1
0
 private TypeSymbol(string name, ITypeScope enclosingScope, IType type, TypeSymbolKind kind)
     : base(name, type, new ClassScope(enclosingScope))
 {
     _superClass = null;
     Kind = kind;
     ((ClassScope)Scope).Symbol = this;
 }
        public void TypeDefinitionKey_is_based_only_on_king_and_naked_type_name(string decl, string typeDefinitionKey)
        {
            ITypeDefinerScope scope = CreateTypeDefinerScope();
            ITypeScope        type  = scope.CreateType(decl);

            type.Definition.Name.Key.Should().Be(typeDefinitionKey);
        }
 public CompilerContext(IScriptScope scriptScope, ITypeScope typeScope, IImportScope importScope, CompilerOptions options)
 {
     this.m_scriptScope = scriptScope;
     this.m_typeScope   = typeScope;
     this.m_importScope = importScope;
     this.m_options     = options;
 }
Пример #4
0
        public DecoratorDef([NotNull] ITypeScope parent, [NotNull] String name, [CanBeNull, ItemNotNull] List <String> comments = null)
            : base(name, parent, comments)
        {
            Type     = new TypeDecorator(this);
            FullName = parent is FileDef ? Name : $"{((ItemDef) parent).FullName}.{Name}";

            parent.DefinedDecorators.Add(this);
        }
        public void list_created_types()
        {
            ITypeDefinerScope scope = CreateTypeDefinerScope();
            ITypeScope        t1    = scope.CreateType(s => s.Append("public class C1"));
            ITypeScope        t2    = scope.CreateType(s => s.Append("public class C2"));

            scope.Types.Should().BeEquivalentTo(new[] { t1, t2 });
        }
Пример #6
0
        /// <summary>
        /// Creates all (or filtered set) constructors from a type (that should be the base type)
        /// to this type which simply relay the call to the base class.
        /// </summary>
        /// <param name="this">This type scope.</param>
        /// <param name="baseType">The base type.</param>
        /// <param name="accessBuilder">
        /// Optional filter (returning null skips the constructor) and
        /// access protection builder. The default access protection is "public ".
        /// </param>
        /// <returns>This function scopes created.</returns>
        public static List <IFunctionScope> CreatePassThroughConstructors(this ITypeScope @this, Type baseType, Func <ConstructorInfo, string?>?accessBuilder = null)
        {
            if (@this == null)
            {
                throw new ArgumentNullException(nameof(@this));
            }
            if (baseType == null)
            {
                throw new ArgumentNullException(nameof(baseType));
            }
            List <IFunctionScope> result = new List <IFunctionScope>();

            foreach (var c in baseType.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                     .Where(c => c.IsPublic || c.IsFamily || c.IsFamilyOrAssembly))
            {
                string?access = "public ";
                if (accessBuilder != null && (access = accessBuilder(c)) == null)
                {
                    continue;
                }

                IFunctionScope built = @this.CreateFunction(scope =>
                {
                    if (access.Length > 0)
                    {
                        scope.Append(access);
                        if (!Char.IsWhiteSpace(access, access.Length - 1))
                        {
                            scope.Space();
                        }
                    }
                    var parameters = c.GetParameters();
                    scope.Append(Helper.RemoveGenericParameters(@this.Name))
                    .AppendParameters(parameters);

                    if (parameters.Length > 0)
                    {
                        scope.Append(" : base( ");
                        bool atLeastOne = false;
                        foreach (var p in parameters)
                        {
                            if (atLeastOne)
                            {
                                scope.Append(", ");
                            }
                            else
                            {
                                atLeastOne = true;
                            }
                            scope.Append(p.Name);
                        }
                        scope.Append(" )");
                    }
                });
                result.Add(built);
            }
            return(result);
        }
Пример #7
0
 /// <summary>
 /// Creates an overridden method.
 /// The <paramref name="method"/> must be virtual (not static nor sealed) and not purely internal.
 /// </summary>
 /// <param name="this">This type scope.</param>
 /// <param name="method">The method description.</param>
 /// <returns>The newly created function scope.</returns>
 public static IFunctionScope CreateOverride(this ITypeScope @this, MethodInfo method)
 {
     if (@this == null)
     {
         throw new ArgumentNullException(nameof(@this));
     }
     Helper.CheckIsOverridable(method);
     return(@this.CreateFunction(h => h.DoAppendSignature(AccessProtectionOption.ThrowOnPureInternal, "override ", method)));
 }
        public void creating_type_and_finding_them_back(string decl, string finder)
        {
            ITypeDefinerScope scope = CreateTypeDefinerScope();
            ITypeScope        type  = scope.CreateType(decl);

            scope.FindType(finder).Should().BeSameAs(type);

            scope.Invoking(sut => sut.CreateType(decl)).Should().Throw <ArgumentException>();
        }
Пример #9
0
        public ClassDef([NotNull] ITypeScope parent, [NotNull] String name, Boolean isFinal, [CanBeNull, ItemNotNull] List <String> comments = null)
            : base(name, parent, comments)
        {
            Type     = new TypeClass(this);
            FullName = parent is FileDef ? Name : $"{((ItemDef) parent).FullName}.{Name}";
            IsFinal  = isFinal;

            parent.DefinedClasses.Add(this);
        }
Пример #10
0
        public InterfaceDef([NotNull] ITypeScope parent, [NotNull] String name, [CanBeNull, ItemNotNull] List <String> comments = null)
            : base(name, parent, comments)
        {
            Type = new TypeInterface(this);

            FullName = parent is FileDef ? Name : $"{((ItemDef) parent).FullName}.{Name}";
            Methods  = new List <InterfaceMethodDef>();

            parent.DefinedInterfaces.Add(this);
        }
Пример #11
0
 /// <summary>
 /// Initializes a new <see cref="JsonSerializationCodeGen"/>.
 /// Basic types are immediately allowed.
 /// </summary>
 /// <param name="monitor">The monitor to capture.</param>
 /// <param name="pocoDirectory">The poco directory object.</param>
 public JsonSerializationCodeGen(IActivityMonitor monitor, ITypeScope pocoDirectory)
 {
     _monitor         = monitor;
     _pocoDirectory   = pocoDirectory;
     _map             = new Dictionary <object, JsonCodeGenHandler>();
     _typeInfos       = new List <JsonTypeInfo>();
     _reentrancy      = new Stack <NullableTypeTree>();
     _finalReadWrite  = new List <Action <IActivityMonitor> >();
     _standardReaders = new List <ECMAScriptStandardReader>();
     InitializeBasicTypes();
 }
Пример #12
0
        protected CompositeTypeScope([NotNull] String name, [NotNull] ITypeScope parent, [CanBeNull, ItemNotNull] List <String> comments)
            : base(name, comments)
        {
            Parent = parent;
            File   = parent.File;

            DefinedClasses      = new List <ClassDef>();
            DefinedEnumerations = new List <EnumerationDef>();
            DefinedInterfaces   = new List <InterfaceDef>();
            DefinedDecorators   = new List <DecoratorDef>();
        }
        public void created_type_has_normalized_Name(string decl, string typeName)
        {
            ITypeDefinerScope scope = CreateTypeDefinerScope();
            ITypeScope        type  = scope.CreateType(h => h.Append(decl));

            type.Name.Should().Be(typeName);
            type.FullName.Should().Be($"{scope.FullName}.{typeName}");

            scope.FindType(typeName).Should().BeSameAs(type);

            scope.Invoking(sut => sut.CreateType(decl)).Should().Throw <ArgumentException>();
        }
Пример #14
0
        public EnumerationDef([NotNull] ITypeScope parent, [NotNull] String name, IntegralType underlyingType, [CanBeNull, ItemNotNull] List <String> comments = null)
            : base(name, comments)
        {
            UnderlyingType = underlyingType;
            Parent         = parent;

            File     = parent.File;
            Members  = new List <EnumerationMemberDef>();
            Type     = new TypeEnumeration(this);
            FullName = parent is FileDef ? Name : $"{((ItemDef) parent).FullName}.{Name}";

            parent.DefinedEnumerations.Add(this);
        }
Пример #15
0
        CSCodeGenerationResult DoImplement(IActivityMonitor monitor,
                                           Type classType,
                                           ICSCodeGenerationContext c,
                                           ITypeScope scope,
                                           IPocoSupportResult poco,
                                           Setup.Json.JsonSerializationCodeGen?json = null)
        {
            if (classType != typeof(CrisCommandDirectoryLike))
            {
                throw new InvalidOperationException("Applies only to the CrisCommandDirectoryLike class.");
            }

            // In real Cris, there is a CommandRegistry that registers the commands/handlers/service etc. into an intermediate Entry descriptor
            // with the final (most specific) TResult.
            // Here we shortcut the process and work with the basic IPocoRootInfo:
            if (!poco.OtherInterfaces.TryGetValue(typeof(ICommand), out IReadOnlyList <IPocoRootInfo>?commandPocos))
            {
                commandPocos = Array.Empty <IPocoRootInfo>();
            }

            CodeWriterExtensions.Append(scope, "public ").Append(scope.Name).Append("() : base( CreateCommands() ) {}").NewLine();

            scope.Append("static IReadOnlyList<ICommandModel> CreateCommands()").NewLine()
            .OpenBlock()
            .Append("var list = new ICommandModel[]").NewLine()
            .Append("{").NewLine();
            int idx = 0;

            foreach (var e in commandPocos)
            {
                var f = c.Assembly.FindOrCreateAutoImplementedClass(monitor, e.PocoFactoryClass);
                f.Definition.BaseTypes.Add(new ExtendedTypeName("ICommandModel"));
                f.Append("public Type CommandType => PocoClassType;").NewLine()
                .Append("public int CommandIdx => ").Append(idx++).Append(";").NewLine()
                .Append("public string CommandName => Name;").NewLine()
                .Append("ICommand ICommandModel.Create() => (ICommand)Create();").NewLine();

                // The CommandModel is the _factory field.
                var p = c.Assembly.FindOrCreateAutoImplementedClass(monitor, e.PocoClass);
                p.Append("public ICommandModel CommandModel => _factory;").NewLine();

                scope.Append(p.FullName).Append("._factory,").NewLine();
            }
            scope.Append("};").NewLine()
            .Append("return list;")
            .CloseBlock();

            return(CSCodeGenerationResult.Success);
        }
        public CSCodeGenerationResult Implement(IActivityMonitor monitor,
                                                MethodInfo m,
                                                ICSCodeGenerationContext codeGenContext,
                                                ITypeScope typeBuilder)
        {
            IFunctionScope mB = typeBuilder.CreateOverride(m);

            Debug.Assert(mB.Parent == typeBuilder, "The function is ready to be implemented.");
            if (_attr.IsLambda)
            {
                mB.Append("=> ").Append(_attr.ActualCode).Append(';').NewLine();
            }
            else
            {
                mB.Append(_attr.ActualCode).NewLine();
            }
            return(CSCodeGenerationResult.Success);
        }
Пример #17
0
        public void playing_with_parts()
        {
            INamespaceScope     g                      = CodeWorkspace.Create().Global;
            INamespaceScopePart gSub                   = g.CreatePart();
            INamespaceScopePart gSub2                  = gSub.CreatePart();
            ITypeScope          gSub2Type1             = gSub2.CreateType("class GSub2Type1");
            ITypeScope          gSub2Type2             = gSub2.CreateType("class GSub2Type2");
            ITypeScopePart      gSub2Type1Part1        = gSub2Type1.CreatePart();
            ITypeScopePart      gSub2Type1Part2        = gSub2Type1.CreatePart();
            IFunctionScope      gSub2Type1Part2F1      = gSub2Type1Part2.CreateFunction("void Action()");
            IFunctionScopePart  gSub2Type1Part2F1Part1 = gSub2Type1Part2F1.CreatePart();

            g.Append("g:");
            gSub.Append("gSub:");
            gSub2.Append("gSub2:");
            gSub2Type1.Append("gSub2Type1:");
            gSub2Type2.Append("gSub2Type2:");
            gSub2Type1Part1.Append("gSub2Type1Part1:");
            gSub2Type1Part2.Append("gSub2Type1Part2:");
            gSub2Type1Part2F1.Append("gSub2Type1Part2F1:");
            gSub2Type1Part2F1Part1.Append("gSub2Type1Part2F1Part1:");

            var s = g.ToString().Trim();

            s.Should().Be(@"
gSub2:
gSub:
g:
class GSub2Type1
{
gSub2Type1Part1:
gSub2Type1Part2:
gSub2Type1:
void Action()
{
gSub2Type1Part2F1Part1:
gSub2Type1Part2F1:
}
}
class GSub2Type2
{
gSub2Type2:
}".Trim().ReplaceLineEndings());
        }
Пример #18
0
 private static void SaveTypeScope(ITypeScope scope, CodeWriter writer)
 {
     foreach (DecoratorDef decoratorDef in scope.DefinedDecorators)
     {
         writer.NewLine();
         SaveDecorator(decoratorDef, writer);
     }
     foreach (EnumerationDef enumerationDef in scope.DefinedEnumerations)
     {
         writer.NewLine();
         SaveEnumeration(enumerationDef, writer);
     }
     foreach (InterfaceDef interfaceDef in scope.DefinedInterfaces)
     {
         writer.NewLine();
         SaveInterface(interfaceDef, writer);
     }
     foreach (ClassDef decortorDef in scope.DefinedClasses)
     {
         writer.NewLine();
         SaveClass(decortorDef, writer);
     }
 }
Пример #19
0
        public void full_run_test()
        {
            var f = TestHelper.TestProjectFolder.AppendPart("TestCodeProject");

            TestHelper.CleanupFolder(f);
            ICodeProject project = CodeWorkspace.CreateProject("MyProject");

            project.TargetFrameworks.Add("netcoreapp3.1");
            project.OutputType = "Exe";

            project.Code.Global.EnsureUsing("System");
            ITypeScope     program = project.Code.Global.CreateType("public static class Program");
            IFunctionScope main    = program.GeneratedByComment()
                                     .CreateFunction("public static int Main()");

            main.Append("Console.WriteLine(").AppendSourceString("Hop!").Append(" );").NewLine();
            main.Append("return 0;");

            var projectFolder = WriteProjectFolder(f, project);

            Run(projectFolder, "dotnet", "run", out string output);
            output.Should().Contain("Hop!");
        }
 CSCodeGenerationResult DoImplement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope, ISourceCodeHelper helper)
 {
     c.Should().NotBeNull();
     scope.Should().NotBeNull();
     monitor.Info($"AutoImpl2: {helper.IHelpTheCodeGeneration()}.");
     return(new CSCodeGenerationResult(nameof(FinalizeImpl)));
 }
		protected virtual string GetTemplateString(ITypeScope scope)
		{
			string[] generic_params = scope.TemplateArguments;
			if (generic_params != null && generic_params.Length > 0)
			{
				ITypeScope[] gen_insts = scope.GenericInstances;
				if (gen_insts == null || gen_insts.Length == 0)
				{
					System.Text.StringBuilder sb = new System.Text.StringBuilder();
					sb.Append('<');
					for (int i=0; i<generic_params.Length; i++)
					{
						sb.Append(generic_params[i]);
						if (i < generic_params.Length -1)
						sb.Append(',');
					}
					sb.Append('>');
					return sb.ToString();
				}
				else
				{
					System.Text.StringBuilder sb = new System.Text.StringBuilder();
					sb.Append('<');
					for (int i=0; i<gen_insts.Length; i++)
					{
						sb.Append(GetSimpleDescriptionWithoutNamespace(gen_insts[i]));
						if (i < gen_insts.Length -1)
						sb.Append(',');
					}
					sb.Append('>');
					return sb.ToString();
				}
			}
			return null;
		}
Пример #22
0
 public override CSCodeGenerationResult Implement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope)
 {
     return(CSCodeGenerationResult.Success);
 }
        static (ITypeScopePart, ITypeScopePart) GenerateReadBody(IPocoRootInfo pocoInfo, ITypeScope pocoClass)
        {
            pocoClass.GeneratedByComment().NewLine().Append("public void Read( ref System.Text.Json.Utf8JsonReader r, PocoJsonSerializerOptions options )")
            .OpenBlock()
            .GeneratedByComment()
            .CreatePart(out var readHeader)
            .Append(@"
bool isDef = r.TokenType == System.Text.Json.JsonTokenType.StartArray;
if( isDef )
{
    r.Read();
    string name = r.GetString();
    if( name != ").AppendSourceString(pocoInfo.Name);
            if (pocoInfo.PreviousNames.Count > 0)
            {
                pocoClass.Append(" && !").AppendArray(pocoInfo.PreviousNames).Append(".Contains( name )");
            }
            pocoClass.Append(@" )
    {
        throw new System.Text.Json.JsonException( ""Expected '""+ ").AppendSourceString(pocoInfo.Name).Append(@" + $""' Poco type, but found '{name}'."" );
    }
    r.Read();
}
if( r.TokenType != System.Text.Json.JsonTokenType.StartObject ) throw new System.Text.Json.JsonException( ""Expecting '{' to start a Poco."" );
r.Read();
while( r.TokenType == System.Text.Json.JsonTokenType.PropertyName )
{
    var n = r.GetString();
    r.Read();
    switch( n )
    {
").NewLine();
            var read = pocoClass.CreatePart();

            pocoClass.Append(@"
        default:
        {
            var t = r.TokenType; 
            r.Skip();
            if( t == System.Text.Json.JsonTokenType.StartArray || t == System.Text.Json.JsonTokenType.StartObject ) r.Read();
            break;
        }
    }
}
if( r.TokenType != System.Text.Json.JsonTokenType.EndObject ) throw new System.Text.Json.JsonException( ""Expecting '}' to end a Poco."" );
r.Read();
if( isDef )
{
    if( r.TokenType != System.Text.Json.JsonTokenType.EndArray ) throw new System.Text.Json.JsonException( ""Expecting ']' to end a Poco array."" );
    r.Read();
}
").CloseBlock();
            return(readHeader, read);
        }
Пример #24
0
 public static TypeSymbol MakeScalarTypeSymbol(string typeName, ITypeScope enclosingScope)
 {
     var type = new ScalarType(typeName);
     return new TypeSymbol(typeName, enclosingScope, type, TypeSymbolKind.Scalar);
 }
Пример #25
0
 protected override string GetTemplateString(ITypeScope scope)
 {
     string[] generic_params = scope.TemplateArguments;
     if (generic_params != null && generic_params.Length > 0)
     {
         System.Text.StringBuilder sb = new System.Text.StringBuilder();
         sb.Append('(');
         for (int i = 0; i < generic_params.Length; i++)
         {
             sb.Append("Of ");
             sb.Append(generic_params[i]);
             if (i < generic_params.Length - 1)
                 sb.Append(',');
         }
         sb.Append(')');
         return sb.ToString();
     }
     return null;
 }
		public virtual string GetSimpleDescriptionWithoutNamespace(ITypeScope scope)
		{
			ICompiledTypeScope cts = scope as ICompiledTypeScope;
			if (cts == null)
				return GetSimpleDescription(scope);
			string s = GetShortTypeName(cts);
			ITypeScope[] instances = scope.GenericInstances;
			if (instances != null && instances.Length > 0)
			{
				System.Text.StringBuilder sb = new System.Text.StringBuilder();
				int ind = s.IndexOf('<');
				if (ind != -1) sb.Append(s.Substring(0,ind));
				else
				sb.Append(s);
				sb.Append('<');
				for (int i=0; i<instances.Length; i++)
				{
					sb.Append(GetSimpleDescriptionWithoutNamespace(instances[i]));
					if (i < instances.Length - 1) sb.Append(',');
				}
				sb.Append('>');
				s = sb.ToString();
			}
			return s;
		}
		public string GetSynonimDescription(ITypeScope scope)
		{
			return "type "+scope.Name+" = "+scope.Description;
		}
		protected override string GetDescriptionForType(ITypeScope scope)
		{
			string template_str=GetTemplateString(scope);
			switch(scope.ElemKind)
			{
				case SymbolKind.Class : 
					if (scope.TopScope != null && scope.TopScope.Name != "")
						return (scope.IsFinal?"sealed ":"")+"class "+scope.TopScope.Name + "::" +scope.Name+template_str;
					else return (scope.IsFinal?"sealed ":"")+"class "+scope.Name+template_str;
				case SymbolKind.Interface :
					if (scope.TopScope != null && scope.TopScope.Name != "")
					return "interface class"+scope.TopScope.Name + "::" +scope.Name+template_str;
					else return "interface class"+scope.Name+template_str;
				case SymbolKind.Enum :
					if (scope.TopScope != null && scope.TopScope.Name != "")
					return "enum "+scope.TopScope.Name + "::" +scope.Name;
					else return "enum "+scope.Name;
				case SymbolKind.Delegate :
					if (scope.TopScope != null && scope.TopScope.Name != "")
					return "delegate "+scope.TopScope.Name + "::" +scope.Name+template_str;
					else return "delegate "+scope.Name+template_str;
				case SymbolKind.Struct :
					if (scope.TopScope != null && scope.TopScope.Name != "")
					return "struct "+scope.TopScope.Name + "::" +scope.Name+template_str;
					else return "struct "+scope.Name+template_str;
			}
			
			if (scope.TopScope != null)
			return scope.TopScope.Name + "::" +scope.Name;
			else return scope.Name;
		}
		protected virtual string GetSimpleDescriptionForType(ITypeScope scope)
		{
			string template_str=GetTemplateString(scope);
			if (scope.Name.StartsWith("$"))
				return scope.Name.Substring(1,scope.Name.Length-1)+template_str;
			return scope.Name+template_str;
		}
		protected virtual string GetDescriptionForType(ITypeScope scope)
		{
			string template_str=GetTemplateString(scope);
			switch(scope.ElemKind)
			{
				case SymbolKind.Class : 
					if (scope.TopScope != null && scope.TopScope.Name != "" && !scope.TopScope.Name.Contains("$"))
						return (scope.IsFinal?"final ":"")+"class "+scope.TopScope.Name + "." +scope.Name+template_str;
					else return (scope.IsFinal?"final ":"")+"class "+scope.Name+template_str;
				case SymbolKind.Interface :
					if (scope.TopScope != null && scope.TopScope.Name != "" && !scope.TopScope.Name.Contains("$"))
					return "interface "+scope.TopScope.Name + "." +scope.Name+template_str;
					else return "interface "+scope.Name+template_str;
				case SymbolKind.Enum :
					if (scope.TopScope != null && scope.TopScope.Name != "" && !scope.TopScope.Name.Contains("$"))
					return "enum "+scope.TopScope.Name + "." +scope.Name;
					else return "enum "+scope.Name;
				case SymbolKind.Delegate :
					if (scope.TopScope != null && scope.TopScope.Name != "" && !scope.TopScope.Name.Contains("$"))
					return "delegate "+scope.TopScope.Name + "." +scope.Name+template_str;
					else return "delegate "+scope.Name+template_str;
				case SymbolKind.Struct :
					if (scope.TopScope != null && scope.TopScope.Name != "" && !scope.TopScope.Name.Contains("$"))
					return "record "+scope.TopScope.Name + "." +scope.Name+template_str;
					else return "record "+scope.Name+template_str;
			}
			
			if (scope.TopScope != null)
			return scope.TopScope.Name + "." +scope.Name;
			else return scope.Name;
		}
 bool FinalizeImpl(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope, ISourceCodeHelper helper)
 {
     monitor.Info($"AutoImpl in another pass: {helper.IHelpTheCodeGeneration()}.");
     return(true);
 }
        /// <summary>
        /// Generates the <paramref name="scope"/> that is the PocoDirectory_CK class and
        /// all the factories (<see cref="IPocoFactory"/> implementations) and the Poco class (<see cref="IPoco"/> implementations).
        /// </summary>
        /// <param name="monitor">The monitor to use.</param>
        /// <param name="classType">The <see cref="PocoDirectory"/> type.</param>
        /// <param name="c">Code generation context.</param>
        /// <param name="scope">The PocoDirectory_CK type scope.</param>
        /// <returns>Always <see cref="CSCodeGenerationResult.Success"/>.</returns>
        public override CSCodeGenerationResult Implement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope)
        {
            Debug.Assert(scope.FullName == "CK.Core.PocoDirectory_CK", "We can use the PocoDirectory_CK type name to reference the PocoDirectory implementation.");

            IPocoSupportResult r = c.Assembly.GetPocoSupportResult();

            Debug.Assert(r == c.CurrentRun.ServiceContainer.GetService(typeof(IPocoSupportResult)), "The PocoSupportResult is also available at the GeneratedBinPath.");

            // PocoDirectory_CK class.
            scope.GeneratedByComment().NewLine()
            .FindOrCreateFunction("internal PocoDirectory_CK()")
            .Append("Instance = this;").NewLine();

            scope.Append("internal static PocoDirectory_CK Instance;").NewLine()
            // The _factories field
            .Append("static readonly Dictionary<string,IPocoFactory> _factoriesN = new Dictionary<string,IPocoFactory>( ").Append(r.NamedRoots.Count).Append(" );").NewLine()
            .Append("static readonly Dictionary<Type,IPocoFactory> _factoriesT = new Dictionary<Type,IPocoFactory>( ").Append(r.AllInterfaces.Count).Append(" );").NewLine()
            .Append("public override IPocoFactory Find( string name ) => _factoriesN.GetValueOrDefault( name );").NewLine()
            .Append("public override IPocoFactory Find( Type t ) => _factoriesT.GetValueOrDefault( t );").NewLine()
            .Append("internal static void Register( IPocoFactory f )").OpenBlock()
            .Append("_factoriesN.Add( f.Name, f );").NewLine()
            .Append("foreach( var n in f.PreviousNames ) _factoriesN.Add( n, f );").NewLine()
            .Append("foreach( var i in f.Interfaces ) _factoriesT.Add( i, f );").NewLine()
            .CloseBlock();

            if (r.AllInterfaces.Count == 0)
            {
                return(CSCodeGenerationResult.Success);
            }

            foreach (var root in r.Roots)
            {
                // PocoFactory class.
                var tFB = c.Assembly.FindOrCreateAutoImplementedClass(monitor, root.PocoFactoryClass);
                tFB.Definition.Modifiers |= Modifiers.Sealed;
                string factoryClassName = tFB.Definition.Name.Name;

                // Poco class.
                var tB = c.Assembly.FindOrCreateAutoImplementedClass(monitor, root.PocoClass);
                tB.Definition.Modifiers |= Modifiers.Sealed;

                // The Poco's static _factory field is internal and its type is the exact class: extended code
                // can refer to the _factory to access the factory extended code without cast.
                //
                // This static internal field is an awful shortcut but it makes things simpler and more efficient
                // than looking up the factory in the DI (and downcasting it) each time we need it.
                // This simplification has been done for Cris Command implementation: a ICommand exposes
                // its ICommandModel: we used to inject the ICommandModel (that is the extended PocoFactory) in the ICommand
                // PocoClass ctor from the factory methods. It worked but it was complex... and, eventually, there
                // can (today) but most importantly there SHOULD, be only one StObjMap/Concrete generated code in an
                // assembly. Maybe one day, the StObj instances themselves can be made static (since they are some kind of
                // "absolute singletons").
                //
                // Note to myself: this "static shortcut" is valid because we are on a "final generation", not on a
                // local, per-module, intermediate, code generation like .Net 5 Code Generators.
                // How this kind of shortcuts could be implemented with .Net 5 Code Generators? It seems that it could but
                // there will be as many "intermediate statics" as there are "levels of assemblies"? Or, there will be only
                // one static (the first one) and the instance will be replaced by the subsequent assemblies? In all cases,
                // diamond problem will have to be ultimately resolved at the final leaf... Just like we do!
                //
                tB.Append("internal static ").Append(tFB.Name).Append(" _factory;")
                .NewLine();
                tB.Append("IPocoFactory IPocoGeneratedClass.Factory => _factory;").NewLine();

                // Always create the constructor so that other code generators
                // can always find it.
                // We support the interfaces here: if other participants have already created this type, it is
                // up to us, here, to handle the "exact" type definition.
                tB.Definition.BaseTypes.Add(new ExtendedTypeName("IPocoGeneratedClass"));
                tB.Definition.BaseTypes.AddRange(root.Interfaces.Select(i => new ExtendedTypeName(i.PocoInterface.ToCSharpName())));

                IFunctionScope ctorB = tB.CreateFunction($"public {root.PocoClass.Name}()");

                foreach (var p in root.PropertyList)
                {
                    Type propType    = p.PropertyType;
                    bool isUnionType = p.PropertyUnionTypes.Any();

                    var    typeName  = propType.ToCSharpName();
                    string fieldName = "_v" + p.Index;
                    tB.Append(typeName).Space().Append(fieldName);
                    if (p.DefaultValueSource == null)
                    {
                        tB.Append(";");
                    }
                    else
                    {
                        tB.Append(" = ").Append(p.DefaultValueSource).Append(";");
                    }
                    tB.NewLine();

                    tB.Append("public ").Append(typeName).Space().Append(p.PropertyName);
                    Debug.Assert(!p.IsReadOnly || p.DefaultValueSource == null, "Readonly with [DefaultValue] has already raised an error.");

                    if (p.IsReadOnly)
                    {
                        // Generates in constructor.
                        r.GenerateAutoInstantiatedNewAssignation(ctorB, fieldName, p.PropertyType);
                    }

                    tB.OpenBlock()
                    .Append("get => ").Append(fieldName).Append(";").NewLine();

                    if (!p.IsReadOnly)
                    {
                        tB.Append("set")
                        .OpenBlock();

                        bool isTechnicallyNullable = p.PropertyNullableTypeTree.Kind.IsTechnicallyNullable();
                        bool isNullable            = p.PropertyNullableTypeTree.Kind.IsNullable();

                        if (isTechnicallyNullable && !isNullable)
                        {
                            tB.Append("if( value == null ) throw new ArgumentNullException();").NewLine();
                        }

                        if (isUnionType)
                        {
                            if (isNullable)
                            {
                                tB.Append("if( value != null )")
                                .OpenBlock();
                            }
                            tB.Append("Type tV = value.GetType();").NewLine()
                            .Append("if( !_c").Append(fieldName)
                            .Append(".Any( t => t.IsAssignableFrom( tV ) ))")
                            .OpenBlock()
                            .Append("throw new ArgumentException( $\"Unexpected Type '{tV}' in UnionType. Allowed types are: ")
                            .Append(p.PropertyUnionTypes.Select(tU => tU.ToString()).Concatenate())
                            .Append(".\");")
                            .CloseBlock();
                            if (isNullable)
                            {
                                tB.CloseBlock();
                            }
                        }
                        tB.Append(fieldName).Append(" = value;")
                        .CloseBlock();
                    }
                    tB.CloseBlock();

                    if (isUnionType)
                    {
                        tB.Append("static readonly Type[] _c").Append(fieldName).Append("=").AppendArray(p.PropertyUnionTypes.Select(u => u.Type)).Append(";").NewLine();
                    }
                }

                // PocoFactory class.

                tFB.Append("PocoDirectory IPocoFactory.PocoDirectory => PocoDirectory_CK.Instance;").NewLine();

                tFB.Append("public Type PocoClassType => typeof(").Append(root.PocoClass.Name).Append(");")
                .NewLine();

                tFB.Append("public IPoco Create() => new ").Append(root.PocoClass.Name).Append("();")
                .NewLine();

                tFB.Append("public string Name => ").AppendSourceString(root.Name).Append(";")
                .NewLine();

                tFB.Append("public IReadOnlyList<string> PreviousNames => ").AppendArray(root.PreviousNames).Append(";")
                .NewLine();

                tFB.Append("public IReadOnlyList<Type> Interfaces => ").AppendArray(root.Interfaces.Select(i => i.PocoInterface)).Append(";")
                .NewLine();

                tFB.CreateFunction("public " + factoryClassName + "()")
                .Append("PocoDirectory_CK.Register( this );").NewLine()
                .Append(tB.Name).Append("._factory = this;");

                foreach (var i in root.Interfaces)
                {
                    tFB.Definition.BaseTypes.Add(new ExtendedTypeName(i.PocoFactoryInterface.ToCSharpName()));
                    tFB.AppendCSharpName(i.PocoInterface, true, true, true)
                    .Space()
                    .AppendCSharpName(i.PocoFactoryInterface, true, true, true)
                    .Append(".Create() => new ").AppendCSharpName(i.Root.PocoClass, true, true, true).Append("();")
                    .NewLine();
                }
            }
            return(CSCodeGenerationResult.Success);
        }
 // We choose to implement all the properties as a whole in Implement method below: by returning CSCodeGenerationResult.Success
 // we tell the engine: "Okay, I handled it, please continue your business."
 // (We can also implement each property here and do nothing in the Implement method.)
 CSCodeGenerationResult IAutoImplementor <PropertyInfo> .Implement(IActivityMonitor monitor, PropertyInfo p, ICSCodeGenerationContext c, ITypeScope typeBuilder) => CSCodeGenerationResult.Success;
Пример #34
0
 public static TypeSymbol MakeArrayTypeSymbol(ScalarType elementType, ITypeScope enclosingScope)
 {
     var type = new ArrayType(elementType);
     return new TypeSymbol(type.Name, enclosingScope, type, TypeSymbolKind.Array);
 }
 public CSCodeGenerationResult Implement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope)
 {
     foreach (var p in classType.GetProperties())
     {
         scope.Append("public override ").Append(p.PropertyType.FullName !).Append(" ").Append(p.Name).Append(" => ");
         if (typeof(int).IsAssignableFrom(p.PropertyType))
         {
             scope.Append(_attr.Value);
         }
         else if (typeof(string).IsAssignableFrom(p.PropertyType))
         {
             scope.AppendSourceString($@"Value is ""{_attr.Value}""...");
         }
         else
         {
             scope.Append("default(").AppendCSharpName(p.PropertyType, true, true, true).Append(")");
         }
         scope.Append(";").NewLine();
     }
     return(CSCodeGenerationResult.Success);
 }
        bool ExtendPocoClass(IActivityMonitor monitor, IPocoRootInfo pocoInfo, JsonSerializationCodeGen jsonCodeGen, ITypeScope pocoClass)
        {
            bool success = true;

            // Each Poco class is a IWriter and has a constructor that accepts a Utf8JsonReader.
            pocoClass.Definition.BaseTypes.Add(new ExtendedTypeName("CK.Core.PocoJsonSerializer.IWriter"));

            // Defines ToString() to return the Json representation only if it is not already defined.
            var toString = FunctionDefinition.Parse("public override string ToString()");

            if (pocoClass.FindFunction(toString.Key, false) == null)
            {
                pocoClass
                .CreateFunction(toString)
                .GeneratedByComment().NewLine()
                .Append("var m = new System.Buffers.ArrayBufferWriter<byte>();").NewLine()
                .Append("using( var w = new System.Text.Json.Utf8JsonWriter( m ) )").NewLine()
                .OpenBlock()
                .Append("Write( w, false, null );").NewLine()
                .Append("w.Flush();").NewLine()
                .CloseBlock()
                .Append("return Encoding.UTF8.GetString( m.WrittenMemory.Span );");
            }

            // The Write method:
            //  - The writeHeader part may contain the ECMAScriptStandard non compliant exception (if it appears that a UnionType is not compliant).
            //  - The write part will be filled with the properties (name and writer code).
            pocoClass.Append("public void Write( System.Text.Json.Utf8JsonWriter w, bool withType, PocoJsonSerializerOptions options )")
            .OpenBlock()
            .GeneratedByComment().NewLine()
            .CreatePart(out var writeHeader)
            .Append("bool usePascalCase = options != null && options.ForJsonSerializer.PropertyNamingPolicy != System.Text.Json.JsonNamingPolicy.CamelCase;").NewLine()
            .Append("if( withType ) { w.WriteStartArray(); w.WriteStringValue( ").AppendSourceString(pocoInfo.Name).Append("); }").NewLine()
            .Append("w.WriteStartObject();")
            .CreatePart(out var write)
            .Append("w.WriteEndObject();").NewLine()
            .Append("if( withType ) w.WriteEndArray();").NewLine()
            .CloseBlock();

            // The constructor calls the private Read method.
            pocoClass.Append("public ").Append(pocoClass.Name).Append("( ref System.Text.Json.Utf8JsonReader r, PocoJsonSerializerOptions options ) : this()")
            .OpenBlock()
            .Append("Read( ref r, options );")
            .CloseBlock();

            // Poco has a Read method but it is not (currently) exposed.
            // This returns two parts: a header (to inject the ECMAScriptStandard non compliant
            // exception if it appears that a UnionType is not compliant) and the switch-case part on the
            // property names with their reader code.
            var(readHeader, read) = GenerateReadBody(pocoInfo, pocoClass);

            bool isECMAScriptStandardCompliant = true;
            var  jsonProperties = new PocoJsonPropertyInfo[pocoInfo.PropertyList.Count];

            foreach (var p in pocoInfo.PropertyList)
            {
                var mainHandler = jsonCodeGen.GetHandler(p.PropertyNullableTypeTree);
                if (mainHandler == null)
                {
                    success = false;
                    continue;
                }

                PocoJsonPropertyInfo?pJ;
                if (p.PropertyUnionTypes.Any())
                {
                    pJ = HandleUnionType(p, monitor, jsonCodeGen, write, read, ref isECMAScriptStandardCompliant, mainHandler);
                    if (pJ == null)
                    {
                        success = false;
                        break;
                    }
                }
                else
                {
                    var handlers = new[] { mainHandler };
                    pJ = new PocoJsonPropertyInfo(p, handlers, mainHandler.HasECMAScriptStandardJsonName && isECMAScriptStandardCompliant ? handlers : null);
                    // Actual Read/Write generation cannot be done here (it must be postponed).
                    // This loop registers/allows the poco property types (the call to GetHandler triggers
                    // the type registration) but writing them requires to know whether those types are final or not .
                    // We store (using closure) the property, the write and read parts and the handler(s)
                    // (to avoid another lookup) and wait for the FinalizeJsonSupport to be called.
                    _finalReadWrite.Add(() =>
                    {
                        var fieldName = "_v" + p.Index;

                        write.Append("w.WritePropertyName( usePascalCase ? ")
                        .AppendSourceString(p.PropertyName)
                        .Append(" : ")
                        .AppendSourceString(System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(p.PropertyName))
                        .Append(" );").NewLine();
                        mainHandler.GenerateWrite(write, fieldName);
                        write.NewLine();

                        var camel = System.Text.Json.JsonNamingPolicy.CamelCase.ConvertName(p.PropertyName);
                        if (camel != p.PropertyName)
                        {
                            read.Append("case ").AppendSourceString(camel).Append(": ");
                        }
                        read.Append("case ").AppendSourceString(p.PropertyName).Append(": ")
                        .OpenBlock();
                        mainHandler.GenerateRead(read, fieldName, assignOnly: !p.IsReadOnly);
                        read.Append("break; ")
                        .CloseBlock();
                    });
                }
                p.AddAnnotation(pJ);
                jsonProperties[p.Index] = pJ;
            }
            if (success)
            {
                if (!isECMAScriptStandardCompliant)
                {
                    writeHeader.And(readHeader).Append("if( options != null && options.Mode == PocoJsonSerializerMode.ECMAScriptStandard ) throw new NotSupportedException( \"Poco '")
                    .Append(pocoInfo.Name)
                    .Append("' is not compliant with the ECMAScripStandard mode.\" );").NewLine();
                }
                var info = new PocoJsonInfo(pocoInfo, isECMAScriptStandardCompliant, jsonProperties);
                pocoInfo.AddAnnotation(info);
            }
            return(success);
        }
 public override CSCodeGenerationResult Implement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope)
 {
     c.CurrentRun.ServiceContainer.Add(new SourceCodeHelper2());
     return(new CSCodeGenerationResult(typeof(ActualImpl2)));
 }
Пример #38
0
 internal static TypeSymbol CreateAndDefineClass(string name, ITypeScope scope)
 {
     var sym = TypeSymbol.MakeScalarTypeSymbol(name, scope);
     scope.Define(sym);
     return sym;
 }
 public override CSCodeGenerationResult Implement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope)
 {
     monitor.Info($"ActualImpl2: {_h1.IHelpTheCodeGeneration()}, {_h2.IAlsoHelpTheCodeGeneration()}.");
     return(CSCodeGenerationResult.Success);
 }
Пример #40
0
 public ClassScope(ITypeScope enclosingScope)
     : base(enclosingScope)
 {
 }
 public override CSCodeGenerationResult Implement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope)
 {
     c.CurrentRun.ServiceContainer.Add <ISourceCodeHelper>(new SourceCodeHelper());
     return(CSCodeGenerationResult.Success);
 }
 public override CSCodeGenerationResult Implement(IActivityMonitor monitor, Type classType, ICSCodeGenerationContext c, ITypeScope scope)
 {
     return(new CSCodeGenerationResult(nameof(DoImplement)));
 }
		protected override string GetSimpleDescriptionForType(ITypeScope scope)
		{
			string template_str=GetTemplateString(scope);
			return scope.Name+template_str;
		}