Esempio n. 1
0
        private static Dictionary <Symbol, LNode> ScanForVariables(LNode code)
        {
            var nameTable = new Dictionary <Symbol, LNode>();

            code.ReplaceRecursive(n =>
            {
                if (n.IsId)
                {
                    nameTable[n.Name] = n;
                }
                else
                {
                    LNode id = LNodeExt.GetCaptureIdentifier(n);
                    if (id != null)
                    {
                        if (!nameTable.ContainsKey(n.Name))
                        {
                            nameTable[id.Name] = n;
                        }
                        return(n);
                    }
                }
                return(null);
            });
            return(nameTable);
        }
Esempio n. 2
0
        private static void DoDeconstruct(LNode arg, IMacroContext context, bool printErrorOnFailure)
        {
            LNode patternSpec = arg.Args[0, LNode.Missing], input = arg.Args[1, LNode.Missing];

            if (!arg.Calls(S.Assign, 2))
            {
                if (arg.Calls(S.Lambda, 2))
                {
                    G.Swap(ref patternSpec, ref input);
                }
                else
                {
                    context.Sink.Error(arg, "expected an assignment (`patterns = input`)");
                    return;
                }
            }

            // Build list of patterns out of the binary operator series p1 | p2 | p3
            var patterns = new FVList <LNode>();

            while (patternSpec.Calls(S.OrBits, 2) && !patternSpec.IsParenthesizedExpr())
            {
                patterns.Add(patternSpec[1]);
                patternSpec = patternSpec[0];
            }
            patterns.Add(patternSpec);

            // Remove outer braces, then run macros
            patterns = patterns.SmartSelect(p => p.Calls(S.Braces, 1) ? p[0] : p);
            input    = input.Calls(S.Braces, 1) ? input[0] : input;
            input    = context.PreProcess(input);

            // Perform matching & capturing
            foreach (var pattern in patterns)
            {
                IDictionary <Symbol, LNode> captures;
                if (LNodeExt.MatchesPattern(input, pattern, out captures))
                {
                    if (captures.Count == 0)
                    {
                        context.Write(printErrorOnFailure ? Severity.Warning : Severity.Error, pattern,
                                      "This pattern has no effect, since it does not use `$` to capture any variables.");
                    }
                    SetSyntaxVariables(captures, context);
                    return;
                }
            }

            if (printErrorOnFailure)
            {
                context.Sink.Error(arg, "Deconstruction failed.");
            }
        }
Esempio n. 3
0
        public static LNode staticMatches(LNode node, IMacroContext context)
        {
            if (node.ArgCount != 2)
            {
                return(null);
            }

            LNode candidate = context.PreProcess(UnwrapBraces(node[0]));
            LNode pattern   = UnwrapBraces(node[1]);
            MMap <Symbol, LNode> captures = new MMap <Symbol, LNode>();

            if (LNodeExt.MatchesPattern(candidate, pattern, ref captures, out LNodeList _))
            {
                SetSyntaxVariables(captures, context);
                return(F.True);
            }
            return(F.False);
        }
Esempio n. 4
0
        public static LNode static_matchCode(LNode node, IMacroContext context)
        {
            if (node.AttrNamed(S.Static) == null && !node.HasSpecialName)
            {
                return(null);                // handled by normal matchCode macro
            }
            var           args_body = context.GetArgsAndBody(false);
            VList <LNode> args = args_body.Item1, body = args_body.Item2;

            if (args.Count != 1)
            {
                return(Reject(context, args[1], "Expected only one expression to match"));
            }

            var expression = context.PreProcess(AutoStripBraces(args[0]));

            var cases = GetCases(body, context.Sink);

            // The `default:` case is represented by an empty list of patterns.
            if (cases.WithoutLast(1).Any(pair => pair.Key.IsEmpty))
            {
                context.Write(Severity.Error, node, "The `default:` case must be the last one, because the cases are tested in the order they appear, so no case after `default:` can be matched.");
            }

            MMap <Symbol, LNode> captures = new MMap <Symbol, LNode>();

            foreach (Pair <VList <LNode>, VList <LNode> > pair in cases)
            {
                var patterns = pair.Key.IsEmpty ? new VList <LNode>((LNode)null) : pair.Key;
                foreach (var pattern in patterns)
                {
                    captures.Clear();
                    VList <LNode> _;
                    if (pattern == null || LNodeExt.MatchesPattern(expression, pattern, ref captures, out _))
                    {
                        captures[_hash] = expression;                         // define $#
                        captures.Remove(__);
                        return(ReplaceCaptures(pair.Value.AsLNode(S.Splice), captures));
                    }
                }
            }
            return(F.Call(S.Splice));            // none of the cases matched
        }
Esempio n. 5
0
        static LNode TryReplaceHere(LNode node, LNode pattern, LNode replacement, MMap <Symbol, LNode> captures, Pair <LNode, LNode>[] allPatterns)
        {
            if (LNodeExt.MatchesPattern(node, pattern, ref captures, out LNodeList attrs))
            {
                foreach (var pair in captures)
                {
                    var input = pair.Value.AsList(S.Splice);
                    int c;
                    var output = Replace(input, allPatterns, out c);
                    if (output != input)
                    {
                        captures[pair.Key] = output.AsLNode(S.Splice);
                    }
                }
                return(ReplaceCaptures(replacement, captures).PlusAttrs(attrs));
            }

            return(null);
        }
Esempio n. 6
0
 /// <summary>Finds capture variables like <c>$x</c> and replaces them with values
 /// from <c>captures</c> (e.g. <c>captures[(Symbol)"x"]</c> for <c>$x</c>)</summary>
 public static LNode ReplaceCaptures(LNode outputSpec, MMap <Symbol, LNode> captures)
 {
     if (captures.Count != 0)
     {
         // TODO: EXPAND SPLICES! Generally it works anyway though because
         // the macro processor has built-in support for #splice.
         return(outputSpec.ReplaceRecursive(n => {
             LNode id, cap;
             if ((id = LNodeExt.GetCaptureIdentifier(n)) != null)
             {
                 if (captures.TryGetValue(id.Name, out cap))
                 {
                     return cap;
                 }
             }
             return null;
         }));
     }
     return(outputSpec);
 }
Esempio n. 7
0
        public static LNode replace(LNode node, IMacroContext context)
        {
            var args_body = context.GetArgsAndBody(true);
            var args      = args_body.A;
            var body      = args_body.B;

            if (args.Count == 1 && args[0].Calls(S.Tuple))
            {
                args = args[0].Args;                                                        // LESv2
            }
            if (args.Count >= 1)
            {
                bool preprocess = node.Calls("replacePP");

                var patterns = new Pair <LNode, LNode> [args.Count];
                for (int i = 0; i < patterns.Length; i++)
                {
                    var pair = args[i];
                    if (pair.Calls(S.Lambda, 2))
                    {
                        LNode pattern = pair[0], repl = pair[1];
                        if (preprocess)
                        {
                            pattern = context.PreProcess(pattern);
                            repl    = context.PreProcess(repl);
                        }
                        if (pattern.Calls(S.Braces))
                        {
                            if (pattern.ArgCount == 1)
                            {
                                pattern = pattern.Args[0];
                            }
                            else
                            {
                                context.Write(Severity.Error, pattern, "The braces must contain only a single statement. To search for braces literally, use `{{ ... }}`");
                            }
                        }
                        if (repl.Calls(S.Braces))
                        {
                            repl = repl.Args.AsLNode(S.Splice);
                        }

                        // Avoid StackOverflowException when pattern is $Id (sadly, it
                        // is uncatchable so it can crash LeMP.exe and even Visual Studio)
                        if (LNodeExt.GetCaptureIdentifier(pattern) != null)
                        {
                            return(Reject(context, pattern, "The left side of `=>` cannot be a capture. Remove the `$`."));
                        }

                        patterns[i] = Pair.Create(pattern, repl);
                    }
                    else
                    {
                        string msg = "Expected 'pattern => replacement'.";
                        if (pair.Descendants().Any(n => n.Calls(S.Lambda, 2)))
                        {
                            msg += " " + "(Using '=>' already? Put the pattern on the left-hand side in parentheses.)";
                        }
                        return(Reject(context, pair, msg));
                    }
                }

                int replacementCount;
                var output = Replace(body, patterns, out replacementCount);
                if (replacementCount == 0)
                {
                    context.Sink.Warning(node, "No patterns recognized; no replacements were made.");
                }
                return(output.AsLNode(S.Splice));
            }
            return(null);
        }