Пример #1
0
        bool DefineSliceOnValueDiscriminator(Int32 index,
                                             CodeBlockNested sliceDiscriminators,
                                             ElementDefinitionNode sliceNode,
                                             String varName,
                                             ElementDefinition.DiscriminatorComponent discriminator,
                                             String valueFilterMethod,
                                             String leafType)
        {
            const String fcn = nameof(DefineSliceOnValueDiscriminator);

            var     selectedNodes = sliceNode.Select(discriminator.Path).ToArray();
            var     fixedNodes    = selectedNodes.FixedValues().ToArray();
            Element fixedValue    = fixedNodes.SingleOrDefault();

            if (fixedValue == null)
            {
                this.gen.ConversionError(this.GetType().Name, fcn, $"Slice node lacks fixed element {discriminator.Path}");
                return(false);
            }

            String sliceName = sliceNode.Element.SliceName;

            CodeBlockNested valueMethodBlock = sliceClassMethods.AppendBlock();

            valueFilterMethod = CSMisc.ValueFilterName(CSMisc.MakePath(sliceNode.SlicePath(), discriminator.Path));
            // Note: We are defining method here, after we know the return value type.
            valueMethodBlock
            .BlankLine()
            .SummaryOpen()
            .AppendCode($"/// Return all elements for discriminator # {index+1}'")
            .SummaryLines(discriminator.ToFormatedJson())
            .SummaryClose()
            ;

            {
                GenerateFhirPathSearch g = new GenerateFhirPathSearch(this.gen);
                if (g.Generate(valueMethodBlock, "static", valueFilterMethod, elementNode, discriminator.Path, out Type leaf) == false)
                {
                    return(false);
                }
                leafType = leaf.FriendlyName();
            }


            String tempVarName = $"sliceOnValueDiscriminator";

            sliceDiscriminators
            .OpenBrace()
            .AppendLine($"/// Define discriminator'")
            .AppendLines("/// ", discriminator.ToFormatedJson().ToLines())
            .AppendCode($"var {tempVarName} = new SliceOnValueDiscriminator<{baseItemTypeName}, {leafType}>()")
            .OpenBrace()
            .AppendCode($"Path = \"{discriminator.Path}\",")
            .AppendCode($"ValueFilter = {valueFilterMethod}")
            .CloseBrace(";")
            ;

            ElementFixCode.Construct(sliceDiscriminators, fixedValue, $"{tempVarName}.Pattern", out String propertyType);

            sliceDiscriminators
            .AppendCode($"{varName} = {tempVarName};")
            .CloseBrace("")
            ;

            return(true);
        }
Пример #2
0
        void CreateSliceAccessorClass(ElementDefinitionNode sliceNode,
                                      out String sliceClassName,
                                      out String sliceInterfaceName)
        {
            const String fcn = nameof(CreateSliceAccessorClass);

            String sliceName = sliceNode.Element.SliceName.ToMachineName();

            sliceClassName     = $"{sliceName}Impl";
            sliceInterfaceName = $"I{sliceName}";
            String sliceBaseClassName;
            String sliceBaseInterfaceName;
            String baseType = elementNode.FhirType.FriendlyName();

            // Debug.Assert(sliceClassName != "BreastradAbnormalityDensityImpl");

            switch (SliceAccessorType(sliceNode))
            {
            case SliceAccessorTypes.Error:
                sliceBaseClassName     = "??";
                sliceBaseInterfaceName = "??";
                break;

            case SliceAccessorTypes.Single:
                sliceBaseClassName     = $"SliceListAccessorSingle<{accessorType}>";
                sliceBaseInterfaceName = $"ISliceAccessorSingle<{accessorType}>";
                break;

            case SliceAccessorTypes.Multiple:
                sliceBaseClassName     = $"SliceListAccessorMultiple<{accessorType}>";
                sliceBaseInterfaceName = $"ISliceAccessorMultiple<{accessorType}>";
                break;

            default:
                throw new NotImplementedException("Unknown SliceAccessorTypes value");
            }

            String elementJson = sliceNode.Element.ToFormatedJson();

            this.subClassBlock
            .BlankLine()
            .SummaryOpen()
            .Summary($"public interface that implements the functionality of slice {sliceClassName}")
            .SummaryClose()
            .AppendCode($"public interface {sliceInterfaceName} : {sliceBaseInterfaceName}")
            .OpenBrace()
            .CloseBrace()
            .BlankLine()
            .SummaryOpen()
            .Summary($"private class that implements the functionality of slice {sliceClassName}")
            .Summary("")
            .Summary(elementJson.ToLines())
            .SummaryClose()
            .AppendCode($"class {sliceClassName} : {sliceBaseClassName}, {sliceInterfaceName}")
            .OpenBrace()
            .DefineBlock(out this.sliceStaticFields)
            .DefineBlock(out CodeBlockNested staticConstructorHeader)
            .DefineBlock(out this.sliceClassFields)
            .DefineBlock(out this.sliceClassMethods)
            .CloseBrace()
            ;

            staticConstructorHeader
            .SummaryOpen()
            .Summary("Static constructor")
            .SummaryClose()
            .AppendLine("[System.Diagnostics.CodeAnalysis.SuppressMessage(\"Performance\", \"CA1810:Initialize reference type static fields inline\")]")
            .AppendCode($"static {sliceClassName}()")
            .OpenBrace()
            .DefineBlock(out this.sliceStaticConstructor)
            .CloseBrace()
            ;

            if (sliceName == null)
            {
                this.gen.ConversionError(this.GetType().Name, fcn, $"Slice node '{elementNode.FullPath()}' lacks slice name");
                retVal = false;
            }
            else
            {
                const String sliceFieldName = "slicing";

                CreateConstructor(sliceClassName, sliceFieldName);

                this.sliceStaticFields
                .BlankLine()
                .SummaryOpen()
                .Summary($"slicing discriminator for {elementNode.FullPath()} slice {sliceName}")
                .SummaryClose()
                .AppendCode($"static Slicing<{baseItemTypeName}> {sliceFieldName};")
                ;

                this.sliceStaticConstructor
                .BlankLine()
                ;

                this.sliceStaticConstructor
                .AppendLine("// Instantiate slicing discriminator")
                .OpenBrace()
                .AppendCode($"ISliceDiscriminator<{baseItemTypeName}>[] discriminators = ")
                .AppendCode($"    new ISliceDiscriminator<{baseItemTypeName}>[{discriminators.Length}];")
                ;

                for (Int32 i = 0; i < discriminators.Length; i++)
                {
                    if (DefineDiscriminator(i, this.sliceStaticConstructor, sliceNode, $"discriminators[{i}]", discriminators[i]) == false)
                    {
                        retVal = false;
                    }
                }

                this.sliceStaticConstructor
                .AppendCode($"{sliceFieldName} = new Slicing<{baseItemTypeName}>")
                .OpenBrace()
                .AppendCode($"Discriminators = discriminators")
                .CloseBrace(";")
                .CloseBrace()
                ;
            }

            // Recursively create code to set values that are fixed in object.
            // If a child object needs to be fixed, make sure that parent objects are created
            // as well.
            // i.e. if a.b.c = fix(...)
            // than we need to create a and a.b as well as setting a.b.c.
            void SetFixedValues(ElementDefinitionNode setNode,
                                String propertyPath)
            {
                Int32 varNum = 0;

                foreach (ElementDefinitionNode setNodeChild in setNode.ChildNodes)
                {
                    String childPropertyPath = $"{propertyPath}.{setNodeChild.PropertyName}";

                    String childItemTypeName = setNodeChild.FhirItemType.FriendlyName();
                    if (setNodeChild.IsFixed)
                    {
                        if (setNodeChild.IsListType)
                        {
                            String varName = $"var{varNum}";
                            varNum += 1;
                            ElementFixCode.Construct(sliceClassMethods, setNodeChild.Element.Fixed, $"{varName}", out String propertyType);
                            sliceClassMethods.AppendCode($"{childPropertyPath}.Add({varName});");
                        }
                        else
                        {
                            ElementFixCode.Construct(sliceClassMethods, setNodeChild.Element.Fixed, childPropertyPath, out String propertyType);
                        }
                    }
                    else if (setNodeChild.HasFixedChild)
                    {
                        String varName = $"var{varNum}";
                        varNum += 1;
                        sliceClassMethods.AppendCode($"{childItemTypeName} {varName} = new {childItemTypeName}();");
                        if (setNodeChild.IsListType)
                        {
                            sliceClassMethods.AppendCode($"{childPropertyPath}.Add({varName});");
                        }
                        else
                        {
                            sliceClassMethods.AppendCode($"{childPropertyPath} = {varName};");
                        }
                        SetFixedValues(setNodeChild, varName);
                    }
                    else if (setNodeChild.HasFixedSlice)
                    {
                        String varName = $"var{varNum}";
                        varNum += 1;
                        sliceClassMethods.AppendCode($"// {childItemTypeName} {varName} = xxyyz;");
                        //methods.AppendCode($"{childItemTypeName} {varName} = new {childItemTypeName}();");
                        //if (setNodeChild.IsListType)
                        //    methods.AppendCode($"{childPropertyPath}.Add({varName});");
                        //else
                        //    methods.AppendCode($"{childPropertyPath} = {varName};");
                        //SetFixedValues(setNodeChild, varName);
                    }
                }
            }

            sliceClassMethods
            .BlankLine()
            .SummaryOpen()
            .Summary($"Create and initialize a new item")
            .SummaryClose()
            .AppendCode($"protected override {accessorType} Create()")
            .OpenBrace()
            .AppendCode($"{accessorType} retVal = new {accessorType}();")
            ;
            SetFixedValues(sliceNode, "retVal");
            sliceClassMethods
            .AppendCode($"return retVal;")
            .CloseBrace()
            ;
        }