예제 #1
0
        public static ValidationData Validated(this INode node, ComputationContext ctx)
        {
            var evaluable = node as IEvaluable;

            if (evaluable != null && evaluable.Validation != null)
            {
                return(evaluable.Validation);
            }

            if (!ctx.AddVisited(node))
            {
                return(evaluable?.Validation);
            }

            ValidationData result = ValidationData.Create();

            INameRegistryExtension.CreateRegistry(INameRegistryExtension.EnterNode(node, ctx.ValAssignTracker),
                                                  ref ctx.ValAssignTracker, () => new AssignmentTracker());

            if (node is Loop)
            {
                ++ctx.ValLoopLevel;
            }


            {
                if (node is VariableDeclaration decl)
                {
                    ctx.ValAssignTracker?.Add(decl, ctx.ValLoopLevel);
                }
            }

            if (node is IExpression expr)
            {
                AssignmentTracker parent_tracker = ctx.ValAssignTracker;

                validateExecutionPath(node, expr.Flow.AlwaysPath, ctx, ref result);

                if (expr.Flow.ThenMaybePath != null || expr.Flow.ElseMaybePath != null)
                {
                    var branch_results = new List <ValidationData>();

                    foreach (ExecutionPath maybes in expr.Flow.ForkMaybePaths)
                    {
                        {
                            AssignmentTracker cont_tracker = null;
                            if (maybes == expr.Flow.ThenMaybePath)
                            {
                                cont_tracker = parent_tracker?.ThenBranch;
                            }
                            else if (maybes == expr.Flow.ElseMaybePath)
                            {
                                cont_tracker = parent_tracker?.ElseBranch;
                            }
                            ctx.ValAssignTracker = (cont_tracker ?? parent_tracker)?.Clone();
                        }
                        ValidationData branch_result = result.Clone();

                        validateExecutionPath(node, maybes, ctx, ref branch_result);

                        // time to remove "continue", because we are about to process
                        // step and post-check of the (could be) loop
                        if (node is IAnchor loop)
                        {
                            branch_result.RemoveInterruptionFor(loop, isBreak: false);
                        }

                        if (maybes == expr.Flow.ThenMaybePath && expr.Flow.ThenPostMaybes != null)
                        {
                            validateExecutionPath(node, expr.Flow.ThenPostMaybes, ctx, ref branch_result);
                        }

                        // we need to store the branch or kill it, because few lines below we compute intersection of the branches
                        // so we don't want to intersect with some artifact from the previous tracker
                        if (maybes == expr.Flow.ThenMaybePath)
                        {
                            parent_tracker.ThenBranch = branch_result.IsTerminated
                                ? null : (ctx.ValAssignTracker.ThenBranch ?? ctx.ValAssignTracker);
                        }
                        else if (maybes == expr.Flow.ElseMaybePath)
                        {
                            parent_tracker.ElseBranch = branch_result.IsTerminated
                                ? null : (ctx.ValAssignTracker.ElseBranch ?? ctx.ValAssignTracker);
                        }
                        else
                        {
                            throw new Exception();
                        }

                        branch_results.Add(branch_result);
                    }

                    if (expr.Flow.ExhaustiveMaybes)
                    {
                        parent_tracker?.MergeInitializations();
                    }
                    parent_tracker?.MergeAssigments();

                    result.Combine(branch_results);
                }

                ctx.ValAssignTracker = parent_tracker; // restore original tracker

                foreach (IExpression sub in expr.Flow.Enumerate)
                {
                    validateReadingValues(sub, ctx);
                }
            }


            node.ChildrenNodes.ForEach(it => Validated(it, ctx));

            if (node is IValidable verificable)
            {
                verificable.Validate(ctx);
            }

            if (node is IFunctionExit)
            {
                result.AddExit();
            }
            else if (node is LoopInterrupt loop_interrupt)
            {
                result.AddInterruption(loop_interrupt);
            }
            else if (node is IAnchor loop)
            {
                result.RemoveInterruptionFor(loop, isBreak: true);
            }
            else if (node is FunctionDefinition)
            {
                result = ValidationData.Create(); // clear it, function scope should not leak any info outside
            }
            if (evaluable != null)
            {
                evaluable.Validation = result;
            }

            ctx.RemoveVisited(node);

            return((node as IEvaluable)?.Validation);
        }