Esempio n. 1
0
        private ProgramSet LearnTree(PremSpec <TInput, SyntaxNode> spec)
        {
            // Case 1: leaf nodes, using `Leaf`.
            if (spec.Forall((i, o) => o is Token))
            {
#if DEBUG
                Log.Tree("Leaf |- {0}", spec);
#endif
                Label label;
                if (spec.Identical((i, o) => o.label, out label))
                {
#if DEBUG
                    Log.IncIndent();
                    Log.Tree("label = {0}", label);
#endif
                    var tokenSpace = Intersect(spec.Select(p => LearnToken(p.Key, p.Value.code)));
#if DEBUG
                    Log.DecIndent();
#endif
                    if (!tokenSpace.IsEmpty)
                    {
                        return(ProgramSet.Join(Op(nameof(Semantics.Leaf)),
                                               ProgramSet.List(Symbol("label"), Label(label)), tokenSpace));
                    }
                }
                // else: Inconsistent specification.
            }

            // Case 2: nodes/lists, copy a reference from old tree.
            if (spec.Forall((i, o) => o.matches.Any()))
            {
#if DEBUG
                Log.Tree("Copy |- {0}", spec);
                Log.IncIndent();
#endif
                var refSpecs  = spec.FlatMap((i, o) => o.matches);
                var refSpaces = new List <ProgramSet>();
#if DEBUG
                var total = refSpecs.Count();
                var count = 1;
#endif
                foreach (var refSpec in refSpecs)
                {
#if DEBUG
                    Log.Tree("{0}/{1} ref |- {2}", count, total, refSpec);
                    Log.IncIndent();
#endif
                    var space = LearnRef(refSpec);
                    if (!space.IsEmpty)
                    {
                        refSpaces.Add(space);
                        break;
                    }
#if DEBUG
                    Log.DecIndent();
                    count++;
#endif
                }
#if DEBUG
                Log.DecIndent();
#endif
                var refSpace = Union(refSpaces);
                if (!refSpace.IsEmpty)
                {
                    return(ProgramSet.Join(Op(nameof(Semantics.Copy)), refSpace));
                }
            }

            // Case 3: constructor nodes, using `Node`.
            if (spec.Forall((i, o) => o is Node))
            {
                var childrenSpace = Optional <ProgramSet> .Nothing;
#if DEBUG
                Log.Tree("Node |- {0}", spec);
#endif
                Label label;
                if (spec.Identical((i, o) => o.label, out label))
                {
                    var labelSpace   = ProgramSet.List(Symbol("Label"), Label(label));
                    var childrenSpec = spec.MapOutputs((i, o) => o.GetChildren());
#if DEBUG
                    Log.IncIndent();
                    Log.Tree("label = {0}", label);
#endif
                    int arity;
                    // Same number of children, learn one-by-one.
                    if (childrenSpec.Identical((i, cs) => cs.Count(), out arity))
                    {
#if DEBUG
                        Log.Tree("children |- {0}", childrenSpec);
                        Log.IncIndent();
#endif
                        childrenSpace = LearnChildren(childrenSpec);
#if DEBUG
                        Log.DecIndent();
#endif
                        if (childrenSpace.HasValue && !childrenSpace.Value.IsEmpty)
                        {
                            return(ProgramSet.Join(Op(nameof(Semantics.Node)),
                                                   ProgramSet.List(Symbol("label"), Label(label)), childrenSpace.Value));
                        }
                    }
                    else // Different number of children, try `Append`.
                    {
#if DEBUG
                        Log.Tree("append |- {0}", childrenSpec);
                        Log.IncIndent();
#endif
                        for (int k = 1; k <= 2; k++)
                        {
                            childrenSpace = LearnAppend(childrenSpec, k);
                            if (childrenSpace.HasValue)
                            {
                                break;
                            }
                        }
#if DEBUG
                        Log.DecIndent();
#endif
                    }
#if DEBUG
                    Log.DecIndent();
#endif
                    if (childrenSpace.HasValue && !childrenSpace.Value.IsEmpty)
                    {
                        return(ProgramSet.Join(Op(nameof(Semantics.Node)), labelSpace, childrenSpace.Value));
                    }
                }
            }

            // else: Inconsistent specification.
            return(ProgramSet.Empty(Symbol("tree")));
        }