private IWorkshopTree ParseVirtual(ActionSet actionSet, MethodCall methodCall)
        {
            // Create the switch that chooses the overload.
            SwitchBuilder typeSwitch = new SwitchBuilder(actionSet);

            // Loop through all potential methods.
            IMethod[] options = Attributes.AllOverrideOptions();

            // Get the call settings.
            MethodCall callSettings = new MethodCall(methodCall.ParameterValues, methodCall.AdditionalParameterData)
            {
                ResolveOverrides     = false,
                ResolveReturnHandler = false,
                ReturnHandler        = new ReturnHandler(actionSet, Name, true)
            };

            // Parse the current overload.
            typeSwitch.NextCase(new V_Number(((ClassType)Attributes.ContainingType).Identifier));
            Parse(actionSet, callSettings);

            foreach (IMethod option in options)
            {
                // The action set for the overload.
                ActionSet optionSet = actionSet.New(actionSet.IndexAssigner.CreateContained());

                // Add the object variables of the selected method.
                option.Attributes.ContainingType.AddObjectVariablesToAssigner(optionSet.CurrentObject, optionSet.IndexAssigner);

                // Go to next case then parse the block.
                typeSwitch.NextCase(new V_Number(((ClassType)option.Attributes.ContainingType).Identifier));
                option.Parse(optionSet, callSettings);
            }

            ClassData classData = actionSet.Translate.DeltinScript.SetupClasses();

            // Finish the switch.
            typeSwitch.Finish(Element.Part <V_ValueInArray>(classData.ClassIndexes.GetVariable(), actionSet.CurrentObject));

            callSettings.ReturnHandler.ApplyReturnSkips();
            return(callSettings.ReturnHandler.GetReturnedValue());
        }
        public void Translate(ActionSet actionSet)
        {
            IWorkshopTree expression = Expression.Parse(actionSet);

            switchBuilder           = new SwitchBuilder(actionSet);
            switchBuilder.AutoBreak = false;

            foreach (SwitchSection section in paths)
            {
                foreach (IExpression caseExpression in section.Cases)
                {
                    switchBuilder.NextCase((Element)caseExpression.Parse(actionSet));
                }

                if (section.IsDefault)
                {
                    switchBuilder.AddDefault();
                }
                section.Block.Translate(actionSet);
            }

            switchBuilder.Finish((Element)expression);
        }
        private void ParseVirtual()
        {
            // Loop through all potential methods.
            DefinedMethod[] options = Array.ConvertAll(Method.Attributes.AllOverrideOptions(), iMethod => (DefinedMethod)iMethod);

            // Create the switch that chooses the overload.
            SwitchBuilder typeSwitch = new SwitchBuilder(BuilderSet);

            // Parse the current overload.
            if (Method.Attributes.Virtual)
            {
                typeSwitch.AddDefault();
            }
            else
            {
                typeSwitch.NextCase(new V_Number(((ClassType)Method.Attributes.ContainingType).Identifier));
            }
            TranslateSegment(BuilderSet, Method);

            foreach (DefinedMethod option in options)
            {
                // The action set for the overload.
                ActionSet optionSet = BuilderSet.New(BuilderSet.IndexAssigner.CreateContained());

                // Add the object variables of the selected method.
                option.Attributes.ContainingType.AddObjectVariablesToAssigner(optionSet.CurrentObject, optionSet.IndexAssigner);

                // Go to next case then parse the block.
                typeSwitch.NextCase(new V_Number(((ClassType)option.Attributes.ContainingType).Identifier));

                // Iterate through every type.
                foreach (CodeType type in BuilderSet.Translate.DeltinScript.Types.AllTypes)
                {
                    // If 'type' does not equal the current virtual option's containing class...
                    if (option.Attributes.ContainingType != type
                        // ...and 'type' implements the containing class...
                        && type.Implements(option.Attributes.ContainingType)
                        // ...and 'type' does not have their own function implementation...
                        && AutoImplemented(option.Attributes.ContainingType, options.Select(o => o.Attributes.ContainingType).ToArray(), type))
                    {
                        // ...then add an additional case for 'type's class identifier.
                        typeSwitch.NextCase(new V_Number(((ClassType)type).Identifier));
                    }
                }

                if (option.subroutineInfo == null)
                {
                    TranslateSegment(optionSet, option);
                }
                else
                {
                    option.SetupSubroutine();
                    BuilderSet.AddAction(Element.Part <A_StartRule>(option.subroutineInfo.Subroutine, EnumData.GetEnumValue(IfAlreadyExecuting.DoNothing)));
                    if (Method.DoesReturnValue)
                    {
                        ReturnHandler.ReturnValue(option.subroutineInfo.ReturnHandler.GetReturnedValue());
                    }
                }

                if (Method.IsSubroutine)
                {
                    option.virtualSubroutineAssigned = Method;
                }
            }

            ClassData classData = BuilderSet.Translate.DeltinScript.GetComponent <ClassData>();

            // Finish the switch.
            typeSwitch.Finish(Element.Part <V_ValueInArray>(classData.ClassIndexes.GetVariable(), BuilderSet.CurrentObject));
        }