diff --git a/Cql/CodeGeneration.NET/CSharpSourceCodeWriter.cs b/Cql/CodeGeneration.NET/CSharpSourceCodeWriter.cs index 5724d795e..68d7e5442 100644 --- a/Cql/CodeGeneration.NET/CSharpSourceCodeWriter.cs +++ b/Cql/CodeGeneration.NET/CSharpSourceCodeWriter.cs @@ -198,44 +198,21 @@ private void writeClass(DefinitionDictionary definitions, writer.WriteLine(indentLevel, $"[CqlLibrary(\"{libraryAttribute}\", \"{versionAttribute}\")]"); var className = VariableNameGenerator.NormalizeIdentifier(libraryName); if (PartialClass) - writer.WriteLine(indentLevel, $"partial class {className}"); + writer.WriteLine(indentLevel, $"partial static class {className}"); else - writer.WriteLine(indentLevel, $"public class {className}"); + writer.WriteLine(indentLevel, $"public static class {className}"); writer.WriteLine(indentLevel, "{"); writer.WriteLine(); indentLevel += 1; // Class { - writer.WriteLine(); - - writer.WriteLine(indentLevel, $"{AccessModifierString(ContextAccessModifier)} CqlContext context;"); - writer.WriteLine(); - writeCachedValues(definitions, libraryName, writer, indentLevel); - - // Write constructor - writer.WriteLine(indentLevel, $"public {className}(CqlContext context)"); - writer.WriteLine(indentLevel, "{"); - { - indentLevel += 1; - - writer.WriteLine(indentLevel, "this.context = context ?? throw new ArgumentNullException(\"context\");"); - writer.WriteLine(); - - writeDependencies(dependencyGraph, libraryNameToClassName, libraryName, writer, indentLevel); - writer.WriteLine(); - writeCachedValueNames(definitions, libraryName, writer, indentLevel); - indentLevel -= 1; - } - writer.WriteLine(indentLevel, "}"); - - WriteLibraryMembers(writer, dependencyGraph, libraryName, libraryNameToClassName!, indentLevel); - writeMemoizedInstanceMethods(definitions, libraryName, writer, indentLevel); + writeMethods(definitions, libraryName, writer, indentLevel); indentLevel -= 1; writer.WriteLine(indentLevel, "}"); } } - private void writeMemoizedInstanceMethods(DefinitionDictionary definitions, string libraryName, StreamWriter writer, int indentLevel) + private void writeMethods(DefinitionDictionary definitions, string libraryName, StreamWriter writer, int indentLevel) { foreach (var kvp in definitions.DefinitionsForLibrary(libraryName)) { @@ -247,62 +224,7 @@ private void writeMemoizedInstanceMethods(DefinitionDictionary } } } - - private void writeCachedValueNames(DefinitionDictionary definitions, string libraryName, StreamWriter writer, int indentLevel) - { - foreach (var kvp in definitions.DefinitionsForLibrary(libraryName)) - { - foreach (var overload in kvp.Value) - { - if (isDefinition(overload.Item2)) - { - var methodName = VariableNameGenerator.NormalizeIdentifier(kvp.Key); - var cachedValueName = DefinitionCacheKeyForMethod(methodName!); - var returnType = ExpressionConverter.PrettyTypeName(overload.Item2.ReturnType); - var privateMethodName = PrivateMethodNameFor(methodName!); - writer.WriteLine(indentLevel, $"{cachedValueName} = new Lazy<{returnType}>(this.{privateMethodName});"); - } - } - } - } - - private static void writeDependencies(DirectedGraph dependencyGraph, Func libraryNameToClassName, string libraryName, StreamWriter writer, int indentLevel) - { - var node = dependencyGraph.Nodes[libraryName]; - var requiredLibraries = node.ForwardEdges? - .Select(edge => edge.ToId) - .Except(new[] { dependencyGraph.EndNode.NodeId }) - .Distinct(); - foreach (var dependentLibrary in requiredLibraries!) - { - var typeName = libraryNameToClassName!(dependentLibrary); - var memberName = typeName; - writer.WriteLine(indentLevel, $"{memberName} = new {typeName}(context);"); - } - } - - private void writeCachedValues(DefinitionDictionary definitions, string libraryName, StreamWriter writer, int indentLevel) - { - writer.WriteLine(indentLevel, "#region Cached values"); - writer.WriteLine(); - var accessModifier = AccessModifierString(DefinesAccessModifier); - foreach (var kvp in definitions.DefinitionsForLibrary(libraryName)) - { - foreach (var overload in kvp.Value) - { - if (isDefinition(overload.T)) - { - var methodName = VariableNameGenerator.NormalizeIdentifier(kvp.Key); - var cachedValueName = DefinitionCacheKeyForMethod(methodName!); - var returnType = ExpressionConverter.PrettyTypeName(overload.T.ReturnType); - writer.WriteLine(indentLevel, $"{accessModifier} Lazy<{returnType}> {cachedValueName};"); - } - } - } - writer.WriteLine(); - writer.WriteLine(indentLevel, "#endregion"); - } - + private void writeTupleTypes(IEnumerable tupleTypes, Func libraryNameToStream, bool closeStream) { if (tupleTypes.Any()) @@ -346,36 +268,6 @@ private static bool isDefinition(LambdaExpression overload) => overload.Parameters.Count == 1 && overload.Parameters[0].Type == typeof(CqlContext); - private void WriteLibraryMembers(TextWriter writer, - DirectedGraph dependencyGraph, - string libraryName, - Func libraryNameToClassName, - int indent) - { - var node = dependencyGraph.Nodes[libraryName]; - var requiredLibraries = node.ForwardEdges? - .Select(edge => edge.ToId) - .Except(new[] { dependencyGraph.EndNode.NodeId }) - .Distinct(); - if (requiredLibraries != null) - { - - writer.WriteLine(indent, "#region Dependencies"); - writer.WriteLine(); - - foreach (var dependentLibrary in requiredLibraries) - { - var typeName = libraryNameToClassName(dependentLibrary); - var memberName = typeName; - writer.WriteLine(indent, $"public {typeName} {memberName} {{ get; }}"); - } - - writer.WriteLine(); - writer.WriteLine(indent, "#endregion"); - writer.WriteLine(); - } - } - private IList DetermineBuildOrder(DirectedGraph minimalGraph) { var sorted = minimalGraph.TopologicalSort() @@ -385,14 +277,6 @@ private IList DetermineBuildOrder(DirectedGraph minimalGraph) return sorted; } - private string DefinitionCacheKeyForMethod(string methodName) - { - if (methodName[0] == '@') - return "__" + methodName.Substring(1); - else return "__" + methodName; - } - private string PrivateMethodNameFor(string methodName) => methodName + "_Value"; - private void WriteMemoizedInstanceMethod(string libraryName, TextWriter writer, int indentLevel, string cqlName, LambdaExpression overload, @@ -419,16 +303,6 @@ private void WriteMemoizedInstanceMethod(string libraryName, TextWriter writer, if (isDef) { - // Definitions, which are CQL expressions without parameter, can be memoized, - // so we generate a "generator" function (name ending in _Value) and a - // getter function, which just calls triggers the lazy to invoke this - // first _Value method. - var cachedValueName = DefinitionCacheKeyForMethod(methodName!); - var privateMethodName = PrivateMethodNameFor(methodName!); - - var func = expressionConverter.ConvertTopLevelFunctionDefinition(indentLevel, overload, privateMethodName, "private"); - writer.Write(func); - writer.WriteLine(); writer.WriteLine(indentLevel, $"[CqlDeclaration(\"{cqlName}\")]"); WriteTags(writer, indentLevel, tags); @@ -447,20 +321,14 @@ private void WriteMemoizedInstanceMethod(string libraryName, TextWriter writer, } } - var lazyType = typeof(Lazy<>).MakeGenericType(visitedBody.Type); - var valueFunc = - Expression.Lambda( - Expression.MakeMemberAccess( - Expression.Parameter(lazyType, cachedValueName), - lazyType.GetMember("Value").Single())); - - writer.Write(expressionConverter.ConvertTopLevelFunctionDefinition(indentLevel, valueFunc, methodName!, "public")); + var func = expressionConverter.ConvertTopLevelFunctionDefinition(indentLevel, overload, methodName!, "public static"); + writer.Write(func); } else { writer.WriteLine(indentLevel, $"[CqlDeclaration(\"{cqlName}\")]"); WriteTags(writer, indentLevel, tags); - writer.Write(expressionConverter.ConvertTopLevelFunctionDefinition(indentLevel, overload, methodName!, "public")); + writer.Write(expressionConverter.ConvertTopLevelFunctionDefinition(indentLevel, overload, methodName!, "public static")); // writer.WriteLine(); } } diff --git a/Cql/CodeGeneration.NET/ExpressionConverter.cs b/Cql/CodeGeneration.NET/ExpressionConverter.cs index d1dcce69d..d9cc143d8 100644 --- a/Cql/CodeGeneration.NET/ExpressionConverter.cs +++ b/Cql/CodeGeneration.NET/ExpressionConverter.cs @@ -65,12 +65,11 @@ private string convertDefinitionCallExpression(int indent, string leadingIndentS { var sb = new StringBuilder(); sb.Append(leadingIndentString); - - var target = dce.LibraryName == LibraryName ? "this" : - VariableNameGenerator.NormalizeIdentifier(dce.LibraryName); + + var target = VariableNameGenerator.NormalizeIdentifier(dce.LibraryName); var csFunctionName = VariableNameGenerator.NormalizeIdentifier(dce.DefinitionName); - sb.Append(CultureInfo.InvariantCulture, $"{target}.{csFunctionName}()"); + sb.Append(CultureInfo.InvariantCulture, $"{target}.{csFunctionName}(context)"); return sb.ToString(); } @@ -80,12 +79,11 @@ private string convertFunctionCallExpression(int indent, string leadingIndentStr var sb = new StringBuilder(); sb.Append(leadingIndentString); - var target = fce.LibraryName == LibraryName ? "this" : - VariableNameGenerator.NormalizeIdentifier(fce.LibraryName); + var target = VariableNameGenerator.NormalizeIdentifier(fce.LibraryName); var csFunctionName = VariableNameGenerator.NormalizeIdentifier(fce.FunctionName); sb.Append(CultureInfo.InvariantCulture, $"{target}.{csFunctionName}"); - sb.Append(convertArguments(indent, fce.Arguments.Skip(1))); // skip cqlContext + sb.Append(convertArguments(indent, fce.Arguments)); return sb.ToString(); } @@ -417,7 +415,12 @@ private string convertLambdaExpression(int indent, string leadingIndentString, L var lambdaSb = new StringBuilder(); lambdaSb.Append(leadingIndentString); - var lambdaParameters = $"({string.Join(", ", lambda.Parameters.Select(p => $"{PrettyTypeName(p.Type)} {escapeKeywords(p.Name!)}"))})"; + var parameters = lambda.Parameters.Select(p => $"{PrettyTypeName(p.Type)} {escapeKeywords(p.Name!)}").ToList(); + // inserts the context parameter in the start of the lambda expression + if (indent == 1) + parameters.Insert(0, "CqlContext context"); + + var lambdaParameters = $"({string.Join(", ", parameters)})"; lambdaSb.Append(lambdaParameters); if (lambda.Body is BlockExpression)