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; }
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 }); }
/// <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); }
/// <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>(); }
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); }
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); }
/// <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(); }
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>(); }
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); }
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); }
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()); }
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); } }
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; }
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); }
public static TypeSymbol MakeScalarTypeSymbol(string typeName, ITypeScope enclosingScope) { var type = new ScalarType(typeName); return new TypeSymbol(typeName, enclosingScope, type, TypeSymbolKind.Scalar); }
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;
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))); }
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); }
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; }